@tsonic/emitter 0.0.72 → 0.0.74
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapter-generator.d.ts.map +1 -1
- package/dist/adapter-generator.js +2 -1
- package/dist/adapter-generator.js.map +1 -1
- package/dist/constants.d.ts +3 -2
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +15 -6
- package/dist/constants.js.map +1 -1
- package/dist/core/format/attributes.d.ts.map +1 -1
- package/dist/core/format/attributes.js +5 -56
- package/dist/core/format/attributes.js.map +1 -1
- package/dist/core/format/attributes.test.js +1 -1
- package/dist/core/format/attributes.test.js.map +1 -1
- package/dist/core/format/backend-ast/builders.d.ts +13 -0
- package/dist/core/format/backend-ast/builders.d.ts.map +1 -0
- package/dist/core/format/backend-ast/builders.js +169 -0
- package/dist/core/format/backend-ast/builders.js.map +1 -0
- package/dist/core/format/backend-ast/builders.test.d.ts +2 -0
- package/dist/core/format/backend-ast/builders.test.d.ts.map +1 -0
- package/dist/core/format/backend-ast/builders.test.js +258 -0
- package/dist/core/format/backend-ast/builders.test.js.map +1 -0
- package/dist/core/format/backend-ast/index.d.ts +3 -2
- package/dist/core/format/backend-ast/index.d.ts.map +1 -1
- package/dist/core/format/backend-ast/index.js +2 -1
- package/dist/core/format/backend-ast/index.js.map +1 -1
- package/dist/core/format/backend-ast/invariants.test.d.ts +2 -0
- package/dist/core/format/backend-ast/invariants.test.d.ts.map +1 -0
- package/dist/core/format/backend-ast/invariants.test.js +72 -0
- package/dist/core/format/backend-ast/invariants.test.js.map +1 -0
- package/dist/core/format/backend-ast/printer.d.ts +1 -1
- package/dist/core/format/backend-ast/printer.d.ts.map +1 -1
- package/dist/core/format/backend-ast/printer.js +362 -119
- package/dist/core/format/backend-ast/printer.js.map +1 -1
- package/dist/core/format/backend-ast/printer.test.d.ts +2 -0
- package/dist/core/format/backend-ast/printer.test.d.ts.map +1 -0
- package/dist/core/format/backend-ast/printer.test.js +796 -0
- package/dist/core/format/backend-ast/printer.test.js.map +1 -0
- package/dist/core/format/backend-ast/types.d.ts +66 -14
- package/dist/core/format/backend-ast/types.d.ts.map +1 -1
- package/dist/core/format/backend-ast/utils.d.ts +12 -8
- package/dist/core/format/backend-ast/utils.d.ts.map +1 -1
- package/dist/core/format/backend-ast/utils.js +222 -19
- package/dist/core/format/backend-ast/utils.js.map +1 -1
- package/dist/core/format/backend-ast/utils.test.d.ts +2 -0
- package/dist/core/format/backend-ast/utils.test.d.ts.map +1 -0
- package/dist/core/format/backend-ast/utils.test.js +142 -0
- package/dist/core/format/backend-ast/utils.test.js.map +1 -0
- package/dist/core/format/module-emitter/assembly.d.ts +2 -2
- package/dist/core/format/module-emitter/assembly.d.ts.map +1 -1
- package/dist/core/format/module-emitter/assembly.js +7 -3
- package/dist/core/format/module-emitter/assembly.js.map +1 -1
- package/dist/core/format/module-emitter/header.d.ts +2 -1
- package/dist/core/format/module-emitter/header.d.ts.map +1 -1
- package/dist/core/format/module-emitter/header.js +2 -2
- package/dist/core/format/module-emitter/header.js.map +1 -1
- package/dist/core/format/module-emitter/orchestrator.js +1 -1
- package/dist/core/format/module-emitter/orchestrator.js.map +1 -1
- package/dist/core/format/module-emitter/static-container.d.ts.map +1 -1
- package/dist/core/format/module-emitter/static-container.js +3 -5
- package/dist/core/format/module-emitter/static-container.js.map +1 -1
- package/dist/core/module-emitter.test.js +1 -0
- package/dist/core/module-emitter.test.js.map +1 -1
- package/dist/core/semantic/boolean-context.d.ts.map +1 -1
- package/dist/core/semantic/boolean-context.js +45 -49
- package/dist/core/semantic/boolean-context.js.map +1 -1
- package/dist/core/semantic/imports.d.ts.map +1 -1
- package/dist/core/semantic/imports.js +25 -15
- package/dist/core/semantic/imports.js.map +1 -1
- package/dist/core/semantic/imports.test.js +43 -0
- package/dist/core/semantic/imports.test.js.map +1 -1
- package/dist/core/semantic/type-resolution.d.ts +1 -0
- package/dist/core/semantic/type-resolution.d.ts.map +1 -1
- package/dist/core/semantic/type-resolution.js +166 -5
- package/dist/core/semantic/type-resolution.js.map +1 -1
- package/dist/core/semantic/type-resolution.test.js +35 -0
- package/dist/core/semantic/type-resolution.test.js.map +1 -1
- package/dist/emitter-types/core.d.ts +24 -10
- package/dist/emitter-types/core.d.ts.map +1 -1
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +124 -44
- package/dist/emitter.js.map +1 -1
- package/dist/expression-emitter.d.ts.map +1 -1
- package/dist/expression-emitter.js +797 -17
- package/dist/expression-emitter.js.map +1 -1
- package/dist/expressions/access.d.ts.map +1 -1
- package/dist/expressions/access.js +65 -25
- package/dist/expressions/access.js.map +1 -1
- package/dist/expressions/calls/call-analysis.d.ts +0 -10
- package/dist/expressions/calls/call-analysis.d.ts.map +1 -1
- package/dist/expressions/calls/call-analysis.js +3 -62
- package/dist/expressions/calls/call-analysis.js.map +1 -1
- package/dist/expressions/calls/call-emitter.d.ts.map +1 -1
- package/dist/expressions/calls/call-emitter.js +97 -196
- package/dist/expressions/calls/call-emitter.js.map +1 -1
- package/dist/expressions/calls/new-emitter.d.ts.map +1 -1
- package/dist/expressions/calls/new-emitter.js +36 -69
- package/dist/expressions/calls/new-emitter.js.map +1 -1
- package/dist/expressions/collections.d.ts +3 -0
- package/dist/expressions/collections.d.ts.map +1 -1
- package/dist/expressions/collections.js +238 -57
- package/dist/expressions/collections.js.map +1 -1
- package/dist/expressions/functions.d.ts.map +1 -1
- package/dist/expressions/functions.js +1 -7
- package/dist/expressions/functions.js.map +1 -1
- package/dist/expressions/identifiers.d.ts.map +1 -1
- package/dist/expressions/identifiers.js +24 -38
- package/dist/expressions/identifiers.js.map +1 -1
- package/dist/expressions/index.test.js +245 -0
- package/dist/expressions/index.test.js.map +1 -1
- package/dist/expressions/literals.d.ts.map +1 -1
- package/dist/expressions/literals.js +9 -41
- package/dist/expressions/literals.js.map +1 -1
- package/dist/expressions/operators/assignment-emitter.d.ts.map +1 -1
- package/dist/expressions/operators/assignment-emitter.js +2 -6
- package/dist/expressions/operators/assignment-emitter.js.map +1 -1
- package/dist/expressions/operators/binary-emitter.d.ts.map +1 -1
- package/dist/expressions/operators/binary-emitter.js +102 -77
- package/dist/expressions/operators/binary-emitter.js.map +1 -1
- package/dist/expressions/operators/logical-emitter.d.ts.map +1 -1
- package/dist/expressions/operators/logical-emitter.js +1 -3
- package/dist/expressions/operators/logical-emitter.js.map +1 -1
- package/dist/expressions/operators/unary-emitter.d.ts.map +1 -1
- package/dist/expressions/operators/unary-emitter.js +9 -20
- package/dist/expressions/operators/unary-emitter.js.map +1 -1
- package/dist/expressions/other.d.ts.map +1 -1
- package/dist/expressions/other.js +57 -4
- package/dist/expressions/other.js.map +1 -1
- package/dist/generator-exchange.d.ts.map +1 -1
- package/dist/generator-exchange.js +3 -2
- package/dist/generator-exchange.js.map +1 -1
- package/dist/generator-wrapper.d.ts.map +1 -1
- package/dist/generator-wrapper.js +27 -56
- package/dist/generator-wrapper.js.map +1 -1
- package/dist/integration.test.js +393 -5
- package/dist/integration.test.js.map +1 -1
- package/dist/json-aot-generic.test.js +3 -0
- package/dist/json-aot-generic.test.js.map +1 -1
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +19 -40
- package/dist/patterns.js.map +1 -1
- package/dist/specialization/type-aliases.test.js +8 -0
- package/dist/specialization/type-aliases.test.js.map +1 -1
- package/dist/statements/classes/members/methods.d.ts.map +1 -1
- package/dist/statements/classes/members/methods.js +5 -22
- package/dist/statements/classes/members/methods.js.map +1 -1
- package/dist/statements/classes/parameters.d.ts.map +1 -1
- package/dist/statements/classes/parameters.js +2 -1
- package/dist/statements/classes/parameters.js.map +1 -1
- package/dist/statements/classes/properties.d.ts.map +1 -1
- package/dist/statements/classes/properties.js +5 -16
- package/dist/statements/classes/properties.js.map +1 -1
- package/dist/statements/control/conditionals/guard-analysis.d.ts +44 -1
- package/dist/statements/control/conditionals/guard-analysis.d.ts.map +1 -1
- package/dist/statements/control/conditionals/guard-analysis.js +301 -125
- package/dist/statements/control/conditionals/guard-analysis.js.map +1 -1
- package/dist/statements/control/conditionals/if-emitter.d.ts.map +1 -1
- package/dist/statements/control/conditionals/if-emitter.js +182 -53
- package/dist/statements/control/conditionals/if-emitter.js.map +1 -1
- package/dist/statements/control/exceptions.d.ts.map +1 -1
- package/dist/statements/control/exceptions.js +2 -4
- package/dist/statements/control/exceptions.js.map +1 -1
- package/dist/statements/control/loops.d.ts.map +1 -1
- package/dist/statements/control/loops.js +3 -5
- package/dist/statements/control/loops.js.map +1 -1
- package/dist/statements/declarations/classes.d.ts.map +1 -1
- package/dist/statements/declarations/classes.js +2 -4
- package/dist/statements/declarations/classes.js.map +1 -1
- package/dist/statements/declarations/functions.d.ts.map +1 -1
- package/dist/statements/declarations/functions.js +38 -79
- package/dist/statements/declarations/functions.js.map +1 -1
- package/dist/statements/declarations/interfaces-mutable-storage.test.js +10 -2
- package/dist/statements/declarations/interfaces-mutable-storage.test.js.map +1 -1
- package/dist/statements/declarations/interfaces.d.ts.map +1 -1
- package/dist/statements/declarations/interfaces.js +4 -12
- package/dist/statements/declarations/interfaces.js.map +1 -1
- package/dist/statements/declarations/type-aliases.d.ts.map +1 -1
- package/dist/statements/declarations/type-aliases.js +5 -9
- package/dist/statements/declarations/type-aliases.js.map +1 -1
- package/dist/statements/declarations/variables.d.ts.map +1 -1
- package/dist/statements/declarations/variables.js +55 -51
- package/dist/statements/declarations/variables.js.map +1 -1
- package/dist/statements/index.test.js +1026 -0
- package/dist/statements/index.test.js.map +1 -1
- package/dist/types/dictionaries.d.ts.map +1 -1
- package/dist/types/dictionaries.js +5 -5
- package/dist/types/dictionaries.js.map +1 -1
- package/dist/types/functions.d.ts.map +1 -1
- package/dist/types/functions.js +5 -25
- package/dist/types/functions.js.map +1 -1
- package/dist/types/primitives.d.ts.map +1 -1
- package/dist/types/primitives.js.map +1 -1
- package/dist/types/references.d.ts.map +1 -1
- package/dist/types/references.js +65 -128
- package/dist/types/references.js.map +1 -1
- package/dist/types/references.test.js +170 -46
- package/dist/types/references.test.js.map +1 -1
- package/dist/types/tuples.d.ts.map +1 -1
- package/dist/types/tuples.js +7 -17
- package/dist/types/tuples.js.map +1 -1
- package/dist/types/unions.d.ts.map +1 -1
- package/dist/types/unions.js +2 -5
- package/dist/types/unions.js.map +1 -1
- package/package.json +2 -2
- package/dist/expressions/parentheses.d.ts +0 -4
- package/dist/expressions/parentheses.d.ts.map +0 -1
- package/dist/expressions/parentheses.js +0 -91
- package/dist/expressions/parentheses.js.map +0 -1
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { IrExpression, IrStatement, IrType } from "@tsonic/frontend";
|
|
9
9
|
import { EmitterContext, NarrowedBinding } from "../../../types.js";
|
|
10
|
+
import type { CSharpTypeAst } from "../../../core/format/backend-ast/types.js";
|
|
10
11
|
/**
|
|
11
12
|
* Information extracted from a type predicate guard call.
|
|
12
13
|
* Used to generate Union.IsN()/AsN() narrowing code.
|
|
@@ -16,6 +17,9 @@ export type GuardInfo = {
|
|
|
16
17
|
readonly targetType: IrType;
|
|
17
18
|
readonly memberN: number;
|
|
18
19
|
readonly unionArity: number;
|
|
20
|
+
readonly runtimeUnionArity: number;
|
|
21
|
+
readonly candidateMemberNs: readonly number[];
|
|
22
|
+
readonly candidateMembers: readonly IrType[];
|
|
19
23
|
readonly ctxWithId: EmitterContext;
|
|
20
24
|
readonly narrowedName: string;
|
|
21
25
|
readonly escapedOrig: string;
|
|
@@ -29,7 +33,7 @@ export type GuardInfo = {
|
|
|
29
33
|
*/
|
|
30
34
|
export type InstanceofGuardInfo = {
|
|
31
35
|
readonly originalName: string;
|
|
32
|
-
readonly
|
|
36
|
+
readonly rhsTypeAst: CSharpTypeAst;
|
|
33
37
|
readonly ctxWithId: EmitterContext;
|
|
34
38
|
readonly ctxAfterRhs: EmitterContext;
|
|
35
39
|
readonly narrowedName: string;
|
|
@@ -55,6 +59,9 @@ export type InGuardInfo = {
|
|
|
55
59
|
readonly propertyName: string;
|
|
56
60
|
readonly memberN: number;
|
|
57
61
|
readonly unionArity: number;
|
|
62
|
+
readonly runtimeUnionArity: number;
|
|
63
|
+
readonly candidateMemberNs: readonly number[];
|
|
64
|
+
readonly candidateMembers: readonly IrType[];
|
|
58
65
|
readonly ctxWithId: EmitterContext;
|
|
59
66
|
readonly narrowedName: string;
|
|
60
67
|
readonly escapedOrig: string;
|
|
@@ -83,12 +90,43 @@ export type DiscriminantEqualityGuardInfo = {
|
|
|
83
90
|
readonly operator: "===" | "!==" | "==" | "!=";
|
|
84
91
|
readonly memberN: number;
|
|
85
92
|
readonly unionArity: number;
|
|
93
|
+
readonly runtimeUnionArity: number;
|
|
94
|
+
readonly candidateMemberNs: readonly number[];
|
|
95
|
+
readonly candidateMembers: readonly IrType[];
|
|
86
96
|
readonly ctxWithId: EmitterContext;
|
|
87
97
|
readonly narrowedName: string;
|
|
88
98
|
readonly escapedOrig: string;
|
|
89
99
|
readonly escapedNarrow: string;
|
|
90
100
|
readonly narrowedMap: Map<string, NarrowedBinding>;
|
|
91
101
|
};
|
|
102
|
+
/**
|
|
103
|
+
* Information extracted from a truthy/falsy property guard:
|
|
104
|
+
* if (result.success) { ... }
|
|
105
|
+
* if (!result.success) { ... }
|
|
106
|
+
*
|
|
107
|
+
* Supports the airplane-grade case where a union member property is definitively
|
|
108
|
+
* truthy or falsy by literal/nullish contract, and exactly one member matches the
|
|
109
|
+
* condition branch.
|
|
110
|
+
*/
|
|
111
|
+
export type PropertyTruthinessGuardInfo = {
|
|
112
|
+
readonly originalName: string;
|
|
113
|
+
readonly propertyName: string;
|
|
114
|
+
readonly memberN: number;
|
|
115
|
+
readonly unionArity: number;
|
|
116
|
+
readonly runtimeUnionArity: number;
|
|
117
|
+
readonly candidateMemberNs: readonly number[];
|
|
118
|
+
readonly candidateMembers: readonly IrType[];
|
|
119
|
+
readonly ctxWithId: EmitterContext;
|
|
120
|
+
readonly narrowedName: string;
|
|
121
|
+
readonly escapedOrig: string;
|
|
122
|
+
readonly escapedNarrow: string;
|
|
123
|
+
readonly narrowedMap: Map<string, NarrowedBinding>;
|
|
124
|
+
};
|
|
125
|
+
export type RuntimeUnionFrame = {
|
|
126
|
+
readonly members: readonly IrType[];
|
|
127
|
+
readonly candidateMemberNs: readonly number[];
|
|
128
|
+
readonly runtimeUnionArity: number;
|
|
129
|
+
};
|
|
92
130
|
/**
|
|
93
131
|
* Information extracted from a nullable guard condition.
|
|
94
132
|
* Used to generate .Value access for narrowed nullable value types.
|
|
@@ -109,6 +147,11 @@ export type NullableGuardInfo = {
|
|
|
109
147
|
* TypeScript flow analysis, by mapping the literal to exactly one union member.
|
|
110
148
|
*/
|
|
111
149
|
export declare const tryResolveDiscriminantEqualityGuard: (condition: IrExpression, context: EmitterContext) => DiscriminantEqualityGuardInfo | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* Try to extract guard info from `x.prop` / `!x.prop` where the property acts as a
|
|
152
|
+
* boolean-style discriminant over a runtime union.
|
|
153
|
+
*/
|
|
154
|
+
export declare const tryResolvePropertyTruthinessGuard: (condition: IrExpression, context: EmitterContext) => PropertyTruthinessGuardInfo | undefined;
|
|
112
155
|
/**
|
|
113
156
|
* Try to extract guard info from an `("prop" in x)` binary expression.
|
|
114
157
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard-analysis.d.ts","sourceRoot":"","sources":["../../../../src/statements/control/conditionals/guard-analysis.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EACL,cAAc,EAEd,eAAe,EAChB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"guard-analysis.d.ts","sourceRoot":"","sources":["../../../../src/statements/control/conditionals/guard-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,77 +7,44 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { emitExpressionAst } from "../../../expression-emitter.js";
|
|
9
9
|
import { emitIdentifier } from "../../../expressions/identifiers.js";
|
|
10
|
+
import { emitTypeAst } from "../../../type-emitter.js";
|
|
10
11
|
import { extractCalleeNameFromAst } from "../../../core/format/backend-ast/utils.js";
|
|
11
12
|
/**
|
|
12
13
|
* Extract the identifier string from an expression AST that is known to be
|
|
13
14
|
* an identifierExpression. Falls back to extractCalleeNameFromAst for other shapes.
|
|
14
15
|
*/
|
|
15
16
|
const extractIdentifierText = (ast) => extractCalleeNameFromAst(ast);
|
|
16
|
-
import { resolveTypeAlias, stripNullish, findUnionMemberIndex, getPropertyType,
|
|
17
|
+
import { hasDeterministicPropertyMembership, resolveTypeAlias, stripNullish, findUnionMemberIndex, getPropertyType, isDefinitelyValueType, } from "../../../core/semantic/type-resolution.js";
|
|
17
18
|
import { escapeCSharpIdentifier } from "../../../emitter-types/index.js";
|
|
18
19
|
import { emitRemappedLocalName } from "../../../core/format/local-names.js";
|
|
19
20
|
/**
|
|
20
21
|
* Check if a local nominal type (class/interface) has a property with the given TS name.
|
|
21
22
|
*/
|
|
22
|
-
const
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!info)
|
|
27
|
-
return false;
|
|
28
|
-
if (info.kind === "interface") {
|
|
29
|
-
const props = getAllPropertySignatures(type, context);
|
|
30
|
-
return props?.some((p) => p.name === propertyName) ?? false;
|
|
31
|
-
}
|
|
32
|
-
if (info.kind === "class") {
|
|
33
|
-
return info.members.some((m) => m.kind === "propertyDeclaration" && m.name === propertyName);
|
|
23
|
+
const getGuardPropertyType = (type, propertyName, context) => {
|
|
24
|
+
if (type.kind === "objectType") {
|
|
25
|
+
const prop = type.members.find((member) => member.kind === "propertySignature" && member.name === propertyName);
|
|
26
|
+
return prop?.type;
|
|
34
27
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* For same-module types, consult `context.localTypes`.
|
|
41
|
-
* For cross-module types, consult the batch `typeMemberIndex` and resolve the
|
|
42
|
-
* member's fully-qualified name deterministically.
|
|
43
|
-
*/
|
|
44
|
-
const hasProperty = (type, propertyName, context) => {
|
|
45
|
-
if (hasLocalProperty(type, propertyName, context)) {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
const index = context.options.typeMemberIndex;
|
|
49
|
-
if (!index)
|
|
50
|
-
return false;
|
|
51
|
-
const stripGlobalPrefix = (name) => name.startsWith("global::") ? name.slice("global::".length) : name;
|
|
52
|
-
const candidates = [];
|
|
53
|
-
if (type.resolvedClrType) {
|
|
54
|
-
candidates.push(stripGlobalPrefix(type.resolvedClrType));
|
|
55
|
-
}
|
|
56
|
-
else if (type.name.includes(".")) {
|
|
57
|
-
candidates.push(type.name);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
// Resolve by suffix match in the type member index.
|
|
61
|
-
const matches = [];
|
|
62
|
-
for (const fqn of index.keys()) {
|
|
63
|
-
if (fqn.endsWith(`.${type.name}`) ||
|
|
64
|
-
fqn.endsWith(`.${type.name}__Alias`)) {
|
|
65
|
-
matches.push(fqn);
|
|
66
|
-
}
|
|
28
|
+
if (type.kind === "referenceType") {
|
|
29
|
+
if (type.structuralMembers?.length) {
|
|
30
|
+
const prop = type.structuralMembers.find((member) => member.kind === "propertySignature" && member.name === propertyName);
|
|
31
|
+
if (prop)
|
|
32
|
+
return prop.type;
|
|
67
33
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const
|
|
74
|
-
|
|
34
|
+
const localTypes = resolveLocalTypesForReference(type, context);
|
|
35
|
+
if (localTypes) {
|
|
36
|
+
const lookupName = type.name.includes(".")
|
|
37
|
+
? (type.name.split(".").pop() ?? type.name)
|
|
38
|
+
: type.name;
|
|
39
|
+
const localPropType = getPropertyType({ ...type, name: lookupName }, propertyName, { ...context, localTypes });
|
|
40
|
+
if (localPropType)
|
|
41
|
+
return localPropType;
|
|
75
42
|
}
|
|
43
|
+
const resolvedPropType = getPropertyType(type, propertyName, context);
|
|
44
|
+
if (resolvedPropType)
|
|
45
|
+
return resolvedPropType;
|
|
76
46
|
}
|
|
77
|
-
return
|
|
78
|
-
const perType = index.get(fqn);
|
|
79
|
-
return perType?.has(propertyName) ?? false;
|
|
80
|
-
});
|
|
47
|
+
return undefined;
|
|
81
48
|
};
|
|
82
49
|
/**
|
|
83
50
|
* Resolve a reference type's LocalTypeInfo map (possibly from a different module).
|
|
@@ -149,6 +116,90 @@ const tryGetLiteralSet = (type, context) => {
|
|
|
149
116
|
}
|
|
150
117
|
return undefined;
|
|
151
118
|
};
|
|
119
|
+
const isClrUnionName = (name) => /^Union_[2-8]$/.test(name) || name === "Union" || name.endsWith(".Union");
|
|
120
|
+
const stripGlobalPrefix = (name) => name.startsWith("global::") ? name.slice("global::".length) : name;
|
|
121
|
+
const extractUnionMembers = (type, context) => {
|
|
122
|
+
const resolvedBase = resolveTypeAlias(stripNullish(type), context);
|
|
123
|
+
const resolved = resolvedBase.kind === "intersectionType"
|
|
124
|
+
? (resolvedBase.types.find((member) => member.kind === "referenceType" && isClrUnionName(member.name)) ?? resolvedBase)
|
|
125
|
+
: resolvedBase;
|
|
126
|
+
if (resolved.kind === "unionType") {
|
|
127
|
+
return resolved.types;
|
|
128
|
+
}
|
|
129
|
+
if (resolved.kind === "referenceType" &&
|
|
130
|
+
isClrUnionName(resolved.name) &&
|
|
131
|
+
resolved.typeArguments &&
|
|
132
|
+
resolved.typeArguments.length >= 2 &&
|
|
133
|
+
resolved.typeArguments.length <= 8) {
|
|
134
|
+
return resolved.typeArguments;
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
};
|
|
138
|
+
const resolveRuntimeUnionFrame = (originalName, unionSourceType, context) => {
|
|
139
|
+
const members = extractUnionMembers(unionSourceType, context);
|
|
140
|
+
if (!members)
|
|
141
|
+
return undefined;
|
|
142
|
+
const narrowed = context.narrowedBindings?.get(originalName);
|
|
143
|
+
if (!narrowed) {
|
|
144
|
+
return {
|
|
145
|
+
members,
|
|
146
|
+
candidateMemberNs: members.map((_, index) => index + 1),
|
|
147
|
+
runtimeUnionArity: members.length,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (narrowed.kind !== "runtimeSubset") {
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
if (narrowed.runtimeMemberNs.length !== members.length) {
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
members,
|
|
158
|
+
candidateMemberNs: [...narrowed.runtimeMemberNs],
|
|
159
|
+
runtimeUnionArity: narrowed.runtimeUnionArity,
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
const buildRenameNarrowedMap = (originalName, narrowedName, memberType, ctxWithId) => {
|
|
163
|
+
const narrowedMap = new Map(ctxWithId.narrowedBindings ?? []);
|
|
164
|
+
narrowedMap.set(originalName, {
|
|
165
|
+
kind: "rename",
|
|
166
|
+
name: narrowedName,
|
|
167
|
+
type: memberType,
|
|
168
|
+
});
|
|
169
|
+
return narrowedMap;
|
|
170
|
+
};
|
|
171
|
+
const isDefinitelyTruthyLiteral = (value) => {
|
|
172
|
+
if (typeof value === "string")
|
|
173
|
+
return value.length > 0;
|
|
174
|
+
if (typeof value === "number")
|
|
175
|
+
return value !== 0 && !Number.isNaN(value);
|
|
176
|
+
return value === true;
|
|
177
|
+
};
|
|
178
|
+
const isDefinitelyFalsyType = (type, context) => {
|
|
179
|
+
const resolved = resolveTypeAlias(type, context);
|
|
180
|
+
if (resolved.kind === "literalType") {
|
|
181
|
+
const value = resolved.value;
|
|
182
|
+
return value === false || value === 0 || value === "";
|
|
183
|
+
}
|
|
184
|
+
if (resolved.kind === "primitiveType") {
|
|
185
|
+
return resolved.name === "undefined" || resolved.name === "null";
|
|
186
|
+
}
|
|
187
|
+
if (resolved.kind === "unionType") {
|
|
188
|
+
return resolved.types.every((member) => isDefinitelyFalsyType(member, context));
|
|
189
|
+
}
|
|
190
|
+
return false;
|
|
191
|
+
};
|
|
192
|
+
const isDefinitelyTruthyType = (type, context) => {
|
|
193
|
+
const literals = tryGetLiteralSet(type, context);
|
|
194
|
+
if (literals) {
|
|
195
|
+
return Array.from(literals).every(isDefinitelyTruthyLiteral);
|
|
196
|
+
}
|
|
197
|
+
const resolved = resolveTypeAlias(type, context);
|
|
198
|
+
if (resolved.kind === "unionType") {
|
|
199
|
+
return resolved.types.every((member) => isDefinitelyTruthyType(member, context));
|
|
200
|
+
}
|
|
201
|
+
return false;
|
|
202
|
+
};
|
|
152
203
|
/**
|
|
153
204
|
* Try to extract guard info from `x.prop === <literal>` or `x.prop !== <literal>`.
|
|
154
205
|
*
|
|
@@ -211,70 +262,52 @@ export const tryResolveDiscriminantEqualityGuard = (condition, context) => {
|
|
|
211
262
|
return undefined;
|
|
212
263
|
const { receiver, propertyName, literal } = match;
|
|
213
264
|
const originalName = receiver.name;
|
|
214
|
-
// If this identifier is already narrowed (union guard emitted earlier), do NOT try to
|
|
215
|
-
// apply another union narrowing rule. This avoids mis-emitting `.IsN()` on a narrowed member type.
|
|
216
|
-
if (context.narrowedBindings?.has(originalName))
|
|
217
|
-
return undefined;
|
|
218
265
|
const unionSourceType = receiver.inferredType;
|
|
219
266
|
if (!unionSourceType)
|
|
220
267
|
return undefined;
|
|
221
|
-
const
|
|
222
|
-
if (
|
|
268
|
+
const frame = resolveRuntimeUnionFrame(originalName, unionSourceType, context);
|
|
269
|
+
if (!frame)
|
|
223
270
|
return undefined;
|
|
224
|
-
const
|
|
271
|
+
const { members, candidateMemberNs, runtimeUnionArity } = frame;
|
|
272
|
+
const unionArity = members.length;
|
|
225
273
|
if (unionArity < 2 || unionArity > 8)
|
|
226
274
|
return undefined;
|
|
227
275
|
// Find which union members have a discriminant property type that includes the literal.
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
276
|
+
const matchingIndices = [];
|
|
277
|
+
const matchingMemberNs = [];
|
|
278
|
+
for (let i = 0; i < members.length; i++) {
|
|
279
|
+
const member = members[i];
|
|
231
280
|
if (!member)
|
|
232
281
|
continue;
|
|
233
|
-
|
|
234
|
-
if (member.kind === "objectType") {
|
|
235
|
-
const prop = member.members.find((m) => m.kind === "propertySignature" && m.name === propertyName);
|
|
236
|
-
propType = prop?.type;
|
|
237
|
-
}
|
|
238
|
-
else if (member.kind === "referenceType") {
|
|
239
|
-
const localTypes = resolveLocalTypesForReference(member, context);
|
|
240
|
-
if (!localTypes)
|
|
241
|
-
continue;
|
|
242
|
-
const lookupName = member.name.includes(".")
|
|
243
|
-
? (member.name.split(".").pop() ?? member.name)
|
|
244
|
-
: member.name;
|
|
245
|
-
// Use the target module's localTypes for property type resolution.
|
|
246
|
-
propType = getPropertyType({ ...member, name: lookupName }, propertyName, { ...context, localTypes });
|
|
247
|
-
}
|
|
248
|
-
else {
|
|
249
|
-
continue;
|
|
250
|
-
}
|
|
282
|
+
const propType = getGuardPropertyType(member, propertyName, context);
|
|
251
283
|
if (!propType)
|
|
252
284
|
continue;
|
|
253
285
|
const literals = tryGetLiteralSet(propType, context);
|
|
254
286
|
if (!literals)
|
|
255
287
|
continue;
|
|
256
288
|
if (literals.has(literal)) {
|
|
257
|
-
|
|
289
|
+
matchingIndices.push(i);
|
|
290
|
+
matchingMemberNs.push(candidateMemberNs[i] ?? i + 1);
|
|
258
291
|
}
|
|
259
292
|
}
|
|
260
293
|
// Only support the common airplane-grade case: exactly one matching member.
|
|
261
|
-
if (
|
|
294
|
+
if (matchingMemberNs.length !== 1)
|
|
262
295
|
return undefined;
|
|
263
|
-
const memberN =
|
|
296
|
+
const memberN = matchingMemberNs[0];
|
|
264
297
|
if (!memberN)
|
|
265
298
|
return undefined;
|
|
299
|
+
const matchingIndex = matchingIndices[0];
|
|
300
|
+
if (matchingIndex === undefined)
|
|
301
|
+
return undefined;
|
|
266
302
|
const nextId = (context.tempVarId ?? 0) + 1;
|
|
267
303
|
const ctxWithId = { ...context, tempVarId: nextId };
|
|
268
304
|
const narrowedName = `${originalName}__${memberN}_${nextId}`;
|
|
269
305
|
const escapedOrig = emitRemappedLocalName(originalName, context);
|
|
270
306
|
const escapedNarrow = escapeCSharpIdentifier(narrowedName);
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
name: narrowedName,
|
|
276
|
-
type: memberType,
|
|
277
|
-
});
|
|
307
|
+
const memberType = members[matchingIndex];
|
|
308
|
+
if (!memberType)
|
|
309
|
+
return undefined;
|
|
310
|
+
const narrowedMap = buildRenameNarrowedMap(originalName, narrowedName, memberType, ctxWithId);
|
|
278
311
|
return {
|
|
279
312
|
originalName,
|
|
280
313
|
propertyName,
|
|
@@ -282,6 +315,129 @@ export const tryResolveDiscriminantEqualityGuard = (condition, context) => {
|
|
|
282
315
|
operator: condition.operator,
|
|
283
316
|
memberN,
|
|
284
317
|
unionArity,
|
|
318
|
+
runtimeUnionArity,
|
|
319
|
+
candidateMemberNs,
|
|
320
|
+
candidateMembers: members,
|
|
321
|
+
ctxWithId,
|
|
322
|
+
narrowedName,
|
|
323
|
+
escapedOrig,
|
|
324
|
+
escapedNarrow,
|
|
325
|
+
narrowedMap,
|
|
326
|
+
};
|
|
327
|
+
};
|
|
328
|
+
/**
|
|
329
|
+
* Try to extract guard info from `x.prop` / `!x.prop` where the property acts as a
|
|
330
|
+
* boolean-style discriminant over a runtime union.
|
|
331
|
+
*/
|
|
332
|
+
export const tryResolvePropertyTruthinessGuard = (condition, context) => {
|
|
333
|
+
const extract = (expr) => {
|
|
334
|
+
if (expr.kind === "unary" && expr.operator === "!") {
|
|
335
|
+
const inner = extract(expr.expression);
|
|
336
|
+
return inner ? { ...inner, wantTruthy: !inner.wantTruthy } : undefined;
|
|
337
|
+
}
|
|
338
|
+
if (expr.kind !== "memberAccess")
|
|
339
|
+
return undefined;
|
|
340
|
+
if (expr.isOptional || expr.isComputed)
|
|
341
|
+
return undefined;
|
|
342
|
+
if (expr.object.kind !== "identifier")
|
|
343
|
+
return undefined;
|
|
344
|
+
if (typeof expr.property !== "string")
|
|
345
|
+
return undefined;
|
|
346
|
+
return {
|
|
347
|
+
receiver: expr.object,
|
|
348
|
+
propertyName: expr.property,
|
|
349
|
+
wantTruthy: true,
|
|
350
|
+
bindingType: expr.memberBinding?.type,
|
|
351
|
+
bindingValueTruthiness: expr.inferredType?.kind === "literalType"
|
|
352
|
+
? isDefinitelyTruthyLiteral(expr.inferredType.value)
|
|
353
|
+
: expr.inferredType?.kind === "primitiveType" &&
|
|
354
|
+
(expr.inferredType.name === "undefined" ||
|
|
355
|
+
expr.inferredType.name === "null")
|
|
356
|
+
? false
|
|
357
|
+
: undefined,
|
|
358
|
+
};
|
|
359
|
+
};
|
|
360
|
+
const match = extract(condition);
|
|
361
|
+
if (!match)
|
|
362
|
+
return undefined;
|
|
363
|
+
const { receiver, propertyName, wantTruthy, bindingType, bindingValueTruthiness, } = match;
|
|
364
|
+
const originalName = receiver.name;
|
|
365
|
+
const unionSourceType = receiver.inferredType;
|
|
366
|
+
if (!unionSourceType)
|
|
367
|
+
return undefined;
|
|
368
|
+
const frame = resolveRuntimeUnionFrame(originalName, unionSourceType, context);
|
|
369
|
+
if (!frame)
|
|
370
|
+
return undefined;
|
|
371
|
+
const { members, candidateMemberNs, runtimeUnionArity } = frame;
|
|
372
|
+
const unionArity = members.length;
|
|
373
|
+
if (unionArity < 2 || unionArity > 8)
|
|
374
|
+
return undefined;
|
|
375
|
+
const matchingIndices = [];
|
|
376
|
+
const matchingMemberNs = [];
|
|
377
|
+
if (bindingType && bindingValueTruthiness !== undefined) {
|
|
378
|
+
const bindingTypeName = stripGlobalPrefix(bindingType);
|
|
379
|
+
const boundMemberIndex = members.findIndex((member) => {
|
|
380
|
+
if (member?.kind !== "referenceType")
|
|
381
|
+
return false;
|
|
382
|
+
const candidateClr = member.resolvedClrType
|
|
383
|
+
? stripGlobalPrefix(member.resolvedClrType)
|
|
384
|
+
: undefined;
|
|
385
|
+
return (candidateClr === bindingTypeName || member.name === bindingTypeName);
|
|
386
|
+
});
|
|
387
|
+
if (boundMemberIndex >= 0) {
|
|
388
|
+
if (wantTruthy === bindingValueTruthiness) {
|
|
389
|
+
matchingIndices.push(boundMemberIndex);
|
|
390
|
+
matchingMemberNs.push(candidateMemberNs[boundMemberIndex] ?? boundMemberIndex + 1);
|
|
391
|
+
}
|
|
392
|
+
else if (unionArity === 2) {
|
|
393
|
+
const otherIndex = boundMemberIndex === 0 ? 1 : 0;
|
|
394
|
+
matchingIndices.push(otherIndex);
|
|
395
|
+
matchingMemberNs.push(candidateMemberNs[otherIndex] ?? otherIndex + 1);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (matchingMemberNs.length === 0) {
|
|
400
|
+
for (let i = 0; i < members.length; i++) {
|
|
401
|
+
const member = members[i];
|
|
402
|
+
if (!member)
|
|
403
|
+
continue;
|
|
404
|
+
const propType = getGuardPropertyType(member, propertyName, context);
|
|
405
|
+
if (!propType)
|
|
406
|
+
continue;
|
|
407
|
+
const matches = wantTruthy
|
|
408
|
+
? isDefinitelyTruthyType(propType, context)
|
|
409
|
+
: isDefinitelyFalsyType(propType, context);
|
|
410
|
+
if (matches) {
|
|
411
|
+
matchingIndices.push(i);
|
|
412
|
+
matchingMemberNs.push(candidateMemberNs[i] ?? i + 1);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (matchingMemberNs.length !== 1)
|
|
417
|
+
return undefined;
|
|
418
|
+
const memberN = matchingMemberNs[0];
|
|
419
|
+
if (!memberN)
|
|
420
|
+
return undefined;
|
|
421
|
+
const matchingIndex = matchingIndices[0];
|
|
422
|
+
if (matchingIndex === undefined)
|
|
423
|
+
return undefined;
|
|
424
|
+
const nextId = (context.tempVarId ?? 0) + 1;
|
|
425
|
+
const ctxWithId = { ...context, tempVarId: nextId };
|
|
426
|
+
const narrowedName = `${originalName}__${memberN}_${nextId}`;
|
|
427
|
+
const escapedOrig = emitRemappedLocalName(originalName, context);
|
|
428
|
+
const escapedNarrow = escapeCSharpIdentifier(narrowedName);
|
|
429
|
+
const memberType = members[matchingIndex];
|
|
430
|
+
if (!memberType)
|
|
431
|
+
return undefined;
|
|
432
|
+
const narrowedMap = buildRenameNarrowedMap(originalName, narrowedName, memberType, ctxWithId);
|
|
433
|
+
return {
|
|
434
|
+
originalName,
|
|
435
|
+
propertyName,
|
|
436
|
+
memberN,
|
|
437
|
+
unionArity,
|
|
438
|
+
runtimeUnionArity,
|
|
439
|
+
candidateMemberNs,
|
|
440
|
+
candidateMembers: members,
|
|
285
441
|
ctxWithId,
|
|
286
442
|
narrowedName,
|
|
287
443
|
escapedOrig,
|
|
@@ -310,46 +466,52 @@ export const tryResolveInGuard = (condition, context) => {
|
|
|
310
466
|
const unionSourceType = condition.right.inferredType;
|
|
311
467
|
if (!unionSourceType)
|
|
312
468
|
return undefined;
|
|
313
|
-
const
|
|
314
|
-
if (
|
|
469
|
+
const frame = resolveRuntimeUnionFrame(originalName, unionSourceType, context);
|
|
470
|
+
if (!frame)
|
|
315
471
|
return undefined;
|
|
316
|
-
const
|
|
472
|
+
const { members, candidateMemberNs, runtimeUnionArity } = frame;
|
|
473
|
+
const unionArity = members.length;
|
|
317
474
|
if (unionArity < 2 || unionArity > 8)
|
|
318
475
|
return undefined;
|
|
319
476
|
// Find which union members contain the property.
|
|
320
|
-
const
|
|
321
|
-
|
|
322
|
-
|
|
477
|
+
const matchingIndices = [];
|
|
478
|
+
const matchingMemberNs = [];
|
|
479
|
+
for (let i = 0; i < members.length; i++) {
|
|
480
|
+
const member = members[i];
|
|
323
481
|
if (!member || member.kind !== "referenceType")
|
|
324
482
|
continue;
|
|
325
|
-
if (
|
|
326
|
-
|
|
483
|
+
if (hasDeterministicPropertyMembership(member, propertyName, context) === true) {
|
|
484
|
+
matchingIndices.push(i);
|
|
485
|
+
matchingMemberNs.push(candidateMemberNs[i] ?? i + 1);
|
|
327
486
|
}
|
|
328
487
|
}
|
|
329
488
|
// Only support the common "exactly one matching member" narrowing case.
|
|
330
|
-
if (
|
|
489
|
+
if (matchingMemberNs.length !== 1)
|
|
331
490
|
return undefined;
|
|
332
|
-
const memberN =
|
|
491
|
+
const memberN = matchingMemberNs[0];
|
|
333
492
|
if (!memberN)
|
|
334
493
|
return undefined;
|
|
494
|
+
const matchingIndex = matchingIndices[0];
|
|
495
|
+
if (matchingIndex === undefined)
|
|
496
|
+
return undefined;
|
|
335
497
|
const nextId = (context.tempVarId ?? 0) + 1;
|
|
336
498
|
const ctxWithId = { ...context, tempVarId: nextId };
|
|
337
499
|
const narrowedName = `${originalName}__${memberN}_${nextId}`;
|
|
338
500
|
const [rhsAst] = emitIdentifier(condition.right, context);
|
|
339
501
|
const escapedOrig = extractIdentifierText(rhsAst);
|
|
340
502
|
const escapedNarrow = escapeCSharpIdentifier(narrowedName);
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
name: narrowedName,
|
|
346
|
-
type: memberType,
|
|
347
|
-
});
|
|
503
|
+
const memberType = members[matchingIndex];
|
|
504
|
+
if (!memberType)
|
|
505
|
+
return undefined;
|
|
506
|
+
const narrowedMap = buildRenameNarrowedMap(originalName, narrowedName, memberType, ctxWithId);
|
|
348
507
|
return {
|
|
349
508
|
originalName,
|
|
350
509
|
propertyName,
|
|
351
510
|
memberN,
|
|
352
511
|
unionArity,
|
|
512
|
+
runtimeUnionArity,
|
|
513
|
+
candidateMemberNs,
|
|
514
|
+
candidateMembers: members,
|
|
353
515
|
ctxWithId,
|
|
354
516
|
narrowedName,
|
|
355
517
|
escapedOrig,
|
|
@@ -395,31 +557,33 @@ export const tryResolvePredicateGuard = (call, context) => {
|
|
|
395
557
|
const unionSourceType = arg.inferredType;
|
|
396
558
|
if (!unionSourceType)
|
|
397
559
|
return undefined;
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
560
|
+
const frame = resolveRuntimeUnionFrame(originalName, unionSourceType, context);
|
|
561
|
+
if (!frame)
|
|
400
562
|
return undefined;
|
|
563
|
+
const resolved = {
|
|
564
|
+
kind: "unionType",
|
|
565
|
+
types: [...frame.members],
|
|
566
|
+
};
|
|
401
567
|
const idx = findUnionMemberIndex(resolved, narrowing.targetType, context);
|
|
402
568
|
if (idx === undefined)
|
|
403
569
|
return undefined;
|
|
404
|
-
const memberN = idx + 1;
|
|
405
|
-
const unionArity =
|
|
570
|
+
const memberN = frame.candidateMemberNs[idx] ?? idx + 1;
|
|
571
|
+
const unionArity = frame.members.length;
|
|
406
572
|
const nextId = (context.tempVarId ?? 0) + 1;
|
|
407
573
|
const ctxWithId = { ...context, tempVarId: nextId };
|
|
408
574
|
const narrowedName = `${originalName}__${memberN}_${nextId}`;
|
|
409
575
|
const [argAst] = emitIdentifier(arg, context);
|
|
410
576
|
const escapedOrig = extractIdentifierText(argAst);
|
|
411
577
|
const escapedNarrow = escapeCSharpIdentifier(narrowedName);
|
|
412
|
-
const narrowedMap =
|
|
413
|
-
narrowedMap.set(originalName, {
|
|
414
|
-
kind: "rename",
|
|
415
|
-
name: narrowedName,
|
|
416
|
-
type: narrowing.targetType,
|
|
417
|
-
});
|
|
578
|
+
const narrowedMap = buildRenameNarrowedMap(originalName, narrowedName, narrowing.targetType, ctxWithId);
|
|
418
579
|
return {
|
|
419
580
|
originalName,
|
|
420
581
|
targetType: narrowing.targetType,
|
|
421
582
|
memberN,
|
|
422
583
|
unionArity,
|
|
584
|
+
runtimeUnionArity: frame.runtimeUnionArity,
|
|
585
|
+
candidateMemberNs: frame.candidateMemberNs,
|
|
586
|
+
candidateMembers: frame.members,
|
|
423
587
|
ctxWithId,
|
|
424
588
|
narrowedName,
|
|
425
589
|
escapedOrig,
|
|
@@ -447,9 +611,21 @@ export const tryResolveInstanceofGuard = (condition, context) => {
|
|
|
447
611
|
const escapedOrig = extractIdentifierText(lhsAst);
|
|
448
612
|
const nextId = (ctxAfterLhs.tempVarId ?? 0) + 1;
|
|
449
613
|
const ctxWithId = { ...ctxAfterLhs, tempVarId: nextId };
|
|
450
|
-
|
|
451
|
-
const
|
|
452
|
-
|
|
614
|
+
const [rhsAst, rhsCtxAfterExpr] = emitExpressionAst(condition.right, ctxWithId);
|
|
615
|
+
const inferredRhsType = condition.right.inferredType;
|
|
616
|
+
let rhsTypeAst;
|
|
617
|
+
let ctxAfterRhs = rhsCtxAfterExpr;
|
|
618
|
+
if (rhsAst.kind === "typeReferenceExpression") {
|
|
619
|
+
rhsTypeAst = rhsAst.type;
|
|
620
|
+
}
|
|
621
|
+
else if (inferredRhsType) {
|
|
622
|
+
const [emittedTypeAst, nextCtx] = emitTypeAst(inferredRhsType, rhsCtxAfterExpr);
|
|
623
|
+
rhsTypeAst = emittedTypeAst;
|
|
624
|
+
ctxAfterRhs = nextCtx;
|
|
625
|
+
}
|
|
626
|
+
if (!rhsTypeAst) {
|
|
627
|
+
return undefined;
|
|
628
|
+
}
|
|
453
629
|
// Pattern variable name for the narrowed value.
|
|
454
630
|
const narrowedName = `${originalName}__is_${nextId}`;
|
|
455
631
|
const escapedNarrow = escapeCSharpIdentifier(narrowedName);
|
|
@@ -461,7 +637,7 @@ export const tryResolveInstanceofGuard = (condition, context) => {
|
|
|
461
637
|
});
|
|
462
638
|
return {
|
|
463
639
|
originalName,
|
|
464
|
-
|
|
640
|
+
rhsTypeAst,
|
|
465
641
|
ctxWithId,
|
|
466
642
|
ctxAfterRhs,
|
|
467
643
|
narrowedName,
|