@tsonic/frontend 0.0.60 → 0.0.62
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/dotnet-metadata.d.ts.map +1 -1
- package/dist/dotnet-metadata.js +3 -1
- package/dist/dotnet-metadata.js.map +1 -1
- package/dist/dotnet-metadata.test.js.map +1 -1
- package/dist/ir/binding/index.d.ts +24 -0
- package/dist/ir/binding/index.d.ts.map +1 -1
- package/dist/ir/binding/index.js +51 -7
- package/dist/ir/binding/index.js.map +1 -1
- package/dist/ir/binding-resolution.test.js +4 -1
- package/dist/ir/binding-resolution.test.js.map +1 -1
- package/dist/ir/bindings-disambiguation.test.js.map +1 -1
- package/dist/ir/builder/imports.d.ts.map +1 -1
- package/dist/ir/builder/imports.js +91 -5
- package/dist/ir/builder/imports.js.map +1 -1
- package/dist/ir/builder.test.js +233 -24
- package/dist/ir/builder.test.js.map +1 -1
- package/dist/ir/converters/expressions/access.d.ts.map +1 -1
- package/dist/ir/converters/expressions/access.js +94 -11
- package/dist/ir/converters/expressions/access.js.map +1 -1
- package/dist/ir/converters/expressions/calls.d.ts +1 -1
- package/dist/ir/converters/expressions/calls.d.ts.map +1 -1
- package/dist/ir/converters/expressions/calls.js +398 -7
- package/dist/ir/converters/expressions/calls.js.map +1 -1
- package/dist/ir/converters/expressions/collections.d.ts.map +1 -1
- package/dist/ir/converters/expressions/collections.js +19 -22
- package/dist/ir/converters/expressions/collections.js.map +1 -1
- package/dist/ir/converters/expressions/functions.js +2 -2
- package/dist/ir/converters/expressions/functions.js.map +1 -1
- package/dist/ir/converters/expressions/operators.d.ts.map +1 -1
- package/dist/ir/converters/expressions/operators.js +1 -1
- package/dist/ir/converters/expressions/operators.js.map +1 -1
- package/dist/ir/converters/expressions/other.d.ts.map +1 -1
- package/dist/ir/converters/expressions/other.js +16 -2
- package/dist/ir/converters/expressions/other.js.map +1 -1
- package/dist/ir/converters/flow-narrowing.d.ts.map +1 -1
- package/dist/ir/converters/flow-narrowing.js.map +1 -1
- package/dist/ir/converters/statements/control/loops.d.ts.map +1 -1
- package/dist/ir/converters/statements/control/loops.js +8 -2
- package/dist/ir/converters/statements/control/loops.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/constructors.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/constructors.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/methods.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/methods.js +70 -22
- package/dist/ir/converters/statements/declarations/classes/methods.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/orchestrator.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/orchestrator.js +10 -4
- package/dist/ir/converters/statements/declarations/classes/orchestrator.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/override-detection.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/override-detection.js +5 -1
- package/dist/ir/converters/statements/declarations/classes/override-detection.js.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/properties.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/classes/properties.js +2 -1
- package/dist/ir/converters/statements/declarations/classes/properties.js.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.d.ts.map +1 -1
- package/dist/ir/converters/statements/declarations/variables.js +1 -1
- package/dist/ir/converters/statements/declarations/variables.js.map +1 -1
- package/dist/ir/converters/statements/helpers.d.ts.map +1 -1
- package/dist/ir/converters/statements/helpers.js +10 -2
- package/dist/ir/converters/statements/helpers.js.map +1 -1
- package/dist/ir/converters/type-env.d.ts.map +1 -1
- package/dist/ir/converters/type-env.js.map +1 -1
- package/dist/ir/expression-converter.d.ts.map +1 -1
- package/dist/ir/expression-converter.js +25 -2
- package/dist/ir/expression-converter.js.map +1 -1
- package/dist/ir/field-marker.test.js.map +1 -1
- package/dist/ir/program-context.d.ts.map +1 -1
- package/dist/ir/program-context.js +6 -2
- package/dist/ir/program-context.js.map +1 -1
- package/dist/ir/this-parameter-inference-rewrap.test.d.ts +14 -0
- package/dist/ir/this-parameter-inference-rewrap.test.d.ts.map +1 -0
- package/dist/ir/this-parameter-inference-rewrap.test.js +110 -0
- package/dist/ir/this-parameter-inference-rewrap.test.js.map +1 -0
- package/dist/ir/this-parameter-inference.test.d.ts +13 -0
- package/dist/ir/this-parameter-inference.test.d.ts.map +1 -0
- package/dist/ir/this-parameter-inference.test.js +165 -0
- package/dist/ir/this-parameter-inference.test.js.map +1 -0
- package/dist/ir/type-system/internal/handle-types.d.ts +2 -0
- package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/nominal-env.d.ts.map +1 -1
- package/dist/ir/type-system/internal/nominal-env.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.js +3 -1
- package/dist/ir/type-system/internal/type-converter/orchestrator.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/references.js +204 -2
- package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-converter/utility-types.js +9 -4
- package/dist/ir/type-system/internal/type-converter/utility-types.js.map +1 -1
- package/dist/ir/type-system/internal/type-registry.d.ts.map +1 -1
- package/dist/ir/type-system/internal/type-registry.js +8 -4
- package/dist/ir/type-system/internal/type-registry.js.map +1 -1
- package/dist/ir/type-system/internal/universe/clr-catalog.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/clr-catalog.js +27 -10
- package/dist/ir/type-system/internal/universe/clr-catalog.js.map +1 -1
- package/dist/ir/type-system/internal/universe/source-catalog.js +3 -1
- package/dist/ir/type-system/internal/universe/source-catalog.js.map +1 -1
- package/dist/ir/type-system/internal/universe/types.d.ts +7 -0
- package/dist/ir/type-system/internal/universe/types.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/types.js.map +1 -1
- package/dist/ir/type-system/internal/universe/unified-universe.d.ts.map +1 -1
- package/dist/ir/type-system/internal/universe/unified-universe.js +16 -1
- package/dist/ir/type-system/internal/universe/unified-universe.js.map +1 -1
- package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts +2 -0
- package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts.map +1 -0
- package/dist/ir/type-system/internal/universe/unified-universe.test.js +87 -0
- package/dist/ir/type-system/internal/universe/unified-universe.test.js.map +1 -0
- package/dist/ir/type-system/type-system.d.ts +12 -0
- package/dist/ir/type-system/type-system.d.ts.map +1 -1
- package/dist/ir/type-system/type-system.js +291 -35
- package/dist/ir/type-system/type-system.js.map +1 -1
- package/dist/ir/types/ir-types.d.ts.map +1 -1
- package/dist/ir/types/module.d.ts +11 -0
- package/dist/ir/types/module.d.ts.map +1 -1
- package/dist/ir/validation/anonymous-type-lowering-pass.d.ts.map +1 -1
- package/dist/ir/validation/anonymous-type-lowering-pass.js +101 -49
- package/dist/ir/validation/anonymous-type-lowering-pass.js.map +1 -1
- package/dist/ir/validation/arrow-return-finalization-pass.js +13 -3
- package/dist/ir/validation/arrow-return-finalization-pass.js.map +1 -1
- package/dist/ir/validation/attribute-collection-pass.d.ts.map +1 -1
- package/dist/ir/validation/attribute-collection-pass.js +11 -3
- package/dist/ir/validation/attribute-collection-pass.js.map +1 -1
- package/dist/ir/validation/attribute-collection-pass.test.js +30 -13
- package/dist/ir/validation/attribute-collection-pass.test.js.map +1 -1
- package/dist/ir/validation/char-validation-pass.d.ts.map +1 -1
- package/dist/ir/validation/char-validation-pass.js +6 -3
- package/dist/ir/validation/char-validation-pass.js.map +1 -1
- package/dist/ir/validation/numeric-coercion-pass.d.ts.map +1 -1
- package/dist/ir/validation/numeric-coercion-pass.js.map +1 -1
- package/dist/ir/validation/numeric-invariants.test.js +46 -0
- package/dist/ir/validation/numeric-invariants.test.js.map +1 -1
- package/dist/ir/validation/numeric-proof-pass.d.ts.map +1 -1
- package/dist/ir/validation/numeric-proof-pass.js +68 -1
- package/dist/ir/validation/numeric-proof-pass.js.map +1 -1
- package/dist/ir/validation/rest-type-synthesis-pass.js +1 -1
- package/dist/ir/validation/rest-type-synthesis-pass.js.map +1 -1
- package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
- package/dist/ir/validation/soundness-gate.js +6 -4
- package/dist/ir/validation/soundness-gate.js.map +1 -1
- package/dist/ir/validation/soundness-gate.test.js +89 -0
- package/dist/ir/validation/soundness-gate.test.js.map +1 -1
- package/dist/program/bindings.d.ts +7 -0
- package/dist/program/bindings.d.ts.map +1 -1
- package/dist/program/bindings.js +17 -6
- package/dist/program/bindings.js.map +1 -1
- package/dist/program/clr-bindings-discovery.d.ts +19 -0
- package/dist/program/clr-bindings-discovery.d.ts.map +1 -0
- package/dist/program/clr-bindings-discovery.js +150 -0
- package/dist/program/clr-bindings-discovery.js.map +1 -0
- package/dist/program/clr-bindings-discovery.test.d.ts +2 -0
- package/dist/program/clr-bindings-discovery.test.d.ts.map +1 -0
- package/dist/program/clr-bindings-discovery.test.js +119 -0
- package/dist/program/clr-bindings-discovery.test.js.map +1 -0
- package/dist/program/creation.d.ts.map +1 -1
- package/dist/program/creation.js +2 -1
- package/dist/program/creation.js.map +1 -1
- package/dist/program/creation.test.js.map +1 -1
- package/dist/program/dependency-graph.d.ts +2 -2
- package/dist/program/dependency-graph.d.ts.map +1 -1
- package/dist/program/dependency-graph.js +26 -42
- package/dist/program/dependency-graph.js.map +1 -1
- package/dist/resolver/clr-bindings-resolver.d.ts.map +1 -1
- package/dist/resolver/clr-bindings-resolver.js +3 -1
- package/dist/resolver/clr-bindings-resolver.js.map +1 -1
- package/dist/resolver/clr-bindings-resolver.test.js.map +1 -1
- package/dist/resolver/namespace.d.ts.map +1 -1
- package/dist/resolver/namespace.js +1 -3
- package/dist/resolver/namespace.js.map +1 -1
- package/dist/tsbindgen/names.d.ts.map +1 -1
- package/dist/tsbindgen/names.js +4 -2
- package/dist/tsbindgen/names.js.map +1 -1
- package/dist/validation/core-intrinsics.d.ts.map +1 -1
- package/dist/validation/core-intrinsics.js +3 -1
- package/dist/validation/core-intrinsics.js.map +1 -1
- package/dist/validation/extension-methods.d.ts.map +1 -1
- package/dist/validation/extension-methods.js.map +1 -1
- package/dist/validation/generics.d.ts.map +1 -1
- package/dist/validation/generics.js +1 -1
- package/dist/validation/generics.js.map +1 -1
- package/dist/validation/static-safety.d.ts.map +1 -1
- package/dist/validation/static-safety.js +17 -2
- package/dist/validation/static-safety.js.map +1 -1
- package/dist/validator.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import * as ts from "typescript";
|
|
15
15
|
import { substituteIrType as irSubstitute, } from "../types/ir-substitution.js";
|
|
16
16
|
import { inferNumericKindFromRaw } from "../types/numeric-helpers.js";
|
|
17
|
-
import { getBinaryResultKind, TSONIC_TO_NUMERIC_KIND } from "../types/numeric-kind.js";
|
|
17
|
+
import { getBinaryResultKind, TSONIC_TO_NUMERIC_KIND, } from "../types/numeric-kind.js";
|
|
18
18
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
19
19
|
// BUILTIN NOMINAL MAPPING
|
|
20
20
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -144,6 +144,19 @@ export const createTypeSystem = (config) => {
|
|
|
144
144
|
// ─────────────────────────────────────────────────────────────────────────
|
|
145
145
|
// RAW SIGNATURE EXTRACTION
|
|
146
146
|
// ─────────────────────────────────────────────────────────────────────────
|
|
147
|
+
const addUndefinedToType = (type) => {
|
|
148
|
+
const undefinedType = {
|
|
149
|
+
kind: "primitiveType",
|
|
150
|
+
name: "undefined",
|
|
151
|
+
};
|
|
152
|
+
if (type.kind === "unionType") {
|
|
153
|
+
const hasUndefined = type.types.some((x) => x.kind === "primitiveType" && x.name === "undefined");
|
|
154
|
+
return hasUndefined
|
|
155
|
+
? type
|
|
156
|
+
: { ...type, types: [...type.types, undefinedType] };
|
|
157
|
+
}
|
|
158
|
+
return { kind: "unionType", types: [type, undefinedType] };
|
|
159
|
+
};
|
|
147
160
|
/**
|
|
148
161
|
* Get or compute raw signature info from SignatureId.
|
|
149
162
|
* Caches the result for subsequent calls.
|
|
@@ -156,7 +169,18 @@ export const createTypeSystem = (config) => {
|
|
|
156
169
|
if (!sigInfo)
|
|
157
170
|
return undefined;
|
|
158
171
|
// Convert parameter types from TypeNodes to IrTypes
|
|
159
|
-
const parameterTypes = sigInfo.parameters.map((p) =>
|
|
172
|
+
const parameterTypes = sigInfo.parameters.map((p) => {
|
|
173
|
+
const baseType = p.typeNode ? convertTypeNode(p.typeNode) : undefined;
|
|
174
|
+
if (!baseType)
|
|
175
|
+
return undefined;
|
|
176
|
+
// Optional/defaulted parameters must accept explicit `undefined` at call sites.
|
|
177
|
+
return p.isOptional ? addUndefinedToType(baseType) : baseType;
|
|
178
|
+
});
|
|
179
|
+
// Convert a TypeScript `this:` parameter type (if present) to an IrType.
|
|
180
|
+
const thisParameterType = (() => {
|
|
181
|
+
const n = sigInfo.thisTypeNode;
|
|
182
|
+
return n ? convertTypeNode(n) : undefined;
|
|
183
|
+
})();
|
|
160
184
|
// Extract parameter modes
|
|
161
185
|
const parameterModes = sigInfo.parameters.map((p) => p.mode ?? "value");
|
|
162
186
|
// Extract parameter names
|
|
@@ -179,7 +203,10 @@ export const createTypeSystem = (config) => {
|
|
|
179
203
|
// identity captured in Binding and the (class) type parameters captured for the
|
|
180
204
|
// constructor signature.
|
|
181
205
|
if (isConstructor && sigInfo.declaringTypeTsName) {
|
|
182
|
-
const typeArguments = typeParameters.map((tp) => ({
|
|
206
|
+
const typeArguments = typeParameters.map((tp) => ({
|
|
207
|
+
kind: "typeParameterType",
|
|
208
|
+
name: tp.name,
|
|
209
|
+
}));
|
|
183
210
|
return {
|
|
184
211
|
kind: "referenceType",
|
|
185
212
|
name: sigInfo.declaringTypeTsName,
|
|
@@ -209,6 +236,7 @@ export const createTypeSystem = (config) => {
|
|
|
209
236
|
}
|
|
210
237
|
const rawSig = {
|
|
211
238
|
parameterTypes,
|
|
239
|
+
thisParameterType,
|
|
212
240
|
returnType,
|
|
213
241
|
parameterModes,
|
|
214
242
|
typeParameters,
|
|
@@ -450,11 +478,24 @@ export const createTypeSystem = (config) => {
|
|
|
450
478
|
* Look up a member on a structural (object) type.
|
|
451
479
|
*/
|
|
452
480
|
const lookupStructuralMember = (type, memberName, site) => {
|
|
481
|
+
const addUndefinedToType = (t) => {
|
|
482
|
+
const undefinedType = {
|
|
483
|
+
kind: "primitiveType",
|
|
484
|
+
name: "undefined",
|
|
485
|
+
};
|
|
486
|
+
if (t.kind === "unionType") {
|
|
487
|
+
const hasUndefined = t.types.some((x) => x.kind === "primitiveType" && x.name === "undefined");
|
|
488
|
+
return hasUndefined ? t : { ...t, types: [...t.types, undefinedType] };
|
|
489
|
+
}
|
|
490
|
+
return { kind: "unionType", types: [t, undefinedType] };
|
|
491
|
+
};
|
|
453
492
|
if (type.kind === "objectType") {
|
|
454
493
|
const member = type.members.find((m) => m.name === memberName);
|
|
455
494
|
if (member) {
|
|
456
495
|
if (member.kind === "propertySignature") {
|
|
457
|
-
return member.
|
|
496
|
+
return member.isOptional
|
|
497
|
+
? addUndefinedToType(member.type)
|
|
498
|
+
: member.type;
|
|
458
499
|
}
|
|
459
500
|
// Method signature - return function type using the same parameters
|
|
460
501
|
if (member.kind === "methodSignature") {
|
|
@@ -473,7 +514,9 @@ export const createTypeSystem = (config) => {
|
|
|
473
514
|
const member = type.structuralMembers.find((m) => m.name === memberName);
|
|
474
515
|
if (member) {
|
|
475
516
|
if (member.kind === "propertySignature") {
|
|
476
|
-
return member.
|
|
517
|
+
return member.isOptional
|
|
518
|
+
? addUndefinedToType(member.type)
|
|
519
|
+
: member.type;
|
|
477
520
|
}
|
|
478
521
|
if (member.kind === "methodSignature") {
|
|
479
522
|
const funcType = {
|
|
@@ -570,6 +613,25 @@ export const createTypeSystem = (config) => {
|
|
|
570
613
|
return filtered[0];
|
|
571
614
|
return { kind: "unionType", types: filtered };
|
|
572
615
|
};
|
|
616
|
+
// tsbindgen-generated "sticky extension scope" helpers are TS-only wrappers that
|
|
617
|
+
// must erase for deterministic IR typing and call inference.
|
|
618
|
+
//
|
|
619
|
+
// Example (generated bindings for Tsonic source):
|
|
620
|
+
// import type { ExtensionMethods as __TsonicExt_Ef } from "@tsonic/efcore/Microsoft.EntityFrameworkCore.js";
|
|
621
|
+
// readonly Tenants: __TsonicExt_Ef<...>;
|
|
622
|
+
//
|
|
623
|
+
// These wrapper types have no CLR identity. For the compiler, the only meaningful
|
|
624
|
+
// runtime/CLR shape is the inner type argument.
|
|
625
|
+
const stripTsonicExtensionWrappers = (type) => {
|
|
626
|
+
if (type.kind === "referenceType") {
|
|
627
|
+
if (type.name.startsWith("__TsonicExt_") &&
|
|
628
|
+
(type.typeArguments?.length ?? 0) === 1) {
|
|
629
|
+
const inner = type.typeArguments?.[0];
|
|
630
|
+
return inner ? stripTsonicExtensionWrappers(inner) : type;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return type;
|
|
634
|
+
};
|
|
573
635
|
const unwrapAwaitedForInference = (type) => {
|
|
574
636
|
if (type.kind === "unionType") {
|
|
575
637
|
return {
|
|
@@ -602,14 +664,15 @@ export const createTypeSystem = (config) => {
|
|
|
602
664
|
* Deterministically infer an expression's type using only:
|
|
603
665
|
* - local lambda parameter environment
|
|
604
666
|
* - declaration types (typeOfDecl)
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
667
|
+
* - numeric literal lexeme rules
|
|
668
|
+
*
|
|
669
|
+
* This is intentionally small: it's used only to type lambda bodies for
|
|
670
|
+
* initializer-driven generic inference (e.g., `Enumerable.select(..., x => x * 2)`).
|
|
671
|
+
*/
|
|
610
672
|
const inferExpressionType = (expr, env) => {
|
|
611
673
|
const unwrapped = unwrapParens(expr);
|
|
612
|
-
if (ts.isAsExpression(unwrapped) ||
|
|
674
|
+
if (ts.isAsExpression(unwrapped) ||
|
|
675
|
+
ts.isTypeAssertionExpression(unwrapped)) {
|
|
613
676
|
return convertTypeNode(unwrapped.type);
|
|
614
677
|
}
|
|
615
678
|
if (ts.isNonNullExpression(unwrapped)) {
|
|
@@ -790,13 +853,13 @@ export const createTypeSystem = (config) => {
|
|
|
790
853
|
});
|
|
791
854
|
const env = new Map();
|
|
792
855
|
for (const p of parameters) {
|
|
793
|
-
if (p.pattern.kind === "identifierPattern" &&
|
|
794
|
-
p.pattern.name &&
|
|
795
|
-
p.type) {
|
|
856
|
+
if (p.pattern.kind === "identifierPattern" && p.pattern.name && p.type) {
|
|
796
857
|
env.set(p.pattern.name, p.type);
|
|
797
858
|
}
|
|
798
859
|
}
|
|
799
|
-
const explicitReturnType = "type" in unwrapped && unwrapped.type
|
|
860
|
+
const explicitReturnType = "type" in unwrapped && unwrapped.type
|
|
861
|
+
? convertTypeNode(unwrapped.type)
|
|
862
|
+
: undefined;
|
|
800
863
|
const expectedReturnType = expectedFnType?.returnType;
|
|
801
864
|
const inferredReturnType = explicitReturnType ??
|
|
802
865
|
(expectedReturnType && !containsTypeParameter(expectedReturnType)
|
|
@@ -1157,6 +1220,10 @@ export const createTypeSystem = (config) => {
|
|
|
1157
1220
|
const inferred = inferExpressionType(init, new Map());
|
|
1158
1221
|
return inferred && inferred.kind !== "unknownType" ? inferred : undefined;
|
|
1159
1222
|
}
|
|
1223
|
+
const inferred = inferExpressionType(init, new Map());
|
|
1224
|
+
if (inferred && inferred.kind !== "unknownType") {
|
|
1225
|
+
return inferred;
|
|
1226
|
+
}
|
|
1160
1227
|
return undefined;
|
|
1161
1228
|
};
|
|
1162
1229
|
const typeOfDecl = (declId) => {
|
|
@@ -1222,7 +1289,9 @@ export const createTypeSystem = (config) => {
|
|
|
1222
1289
|
const effectiveReceiver = receiver.kind === "unionType"
|
|
1223
1290
|
? (() => {
|
|
1224
1291
|
const nonNullish = receiver.types.filter((t) => t && !isNullishPrimitive(t));
|
|
1225
|
-
return nonNullish.length === 1 && nonNullish[0]
|
|
1292
|
+
return nonNullish.length === 1 && nonNullish[0]
|
|
1293
|
+
? nonNullish[0]
|
|
1294
|
+
: receiver;
|
|
1226
1295
|
})()
|
|
1227
1296
|
: receiver;
|
|
1228
1297
|
// 1. Normalize receiver to nominal form
|
|
@@ -1230,7 +1299,8 @@ export const createTypeSystem = (config) => {
|
|
|
1230
1299
|
if (!normalized) {
|
|
1231
1300
|
// Handle structural types (objectType)
|
|
1232
1301
|
if (effectiveReceiver.kind === "objectType" ||
|
|
1233
|
-
(effectiveReceiver.kind === "referenceType" &&
|
|
1302
|
+
(effectiveReceiver.kind === "referenceType" &&
|
|
1303
|
+
effectiveReceiver.structuralMembers)) {
|
|
1234
1304
|
return lookupStructuralMember(effectiveReceiver, memberName, site);
|
|
1235
1305
|
}
|
|
1236
1306
|
emitDiagnostic("TSN5203", `Cannot resolve member '${memberName}' on type`, site);
|
|
@@ -1333,7 +1403,9 @@ export const createTypeSystem = (config) => {
|
|
|
1333
1403
|
if (!first)
|
|
1334
1404
|
return undefined;
|
|
1335
1405
|
// Strip assembly qualification (", Assembly, Version=..., ...") if present.
|
|
1336
|
-
const withoutAsm = first.includes(",")
|
|
1406
|
+
const withoutAsm = first.includes(",")
|
|
1407
|
+
? (first.split(",")[0] ?? first)
|
|
1408
|
+
: first;
|
|
1337
1409
|
return withoutAsm.trim();
|
|
1338
1410
|
};
|
|
1339
1411
|
const getIndexerInfo = (receiver, _site) => {
|
|
@@ -1401,7 +1473,22 @@ export const createTypeSystem = (config) => {
|
|
|
1401
1473
|
return true;
|
|
1402
1474
|
}
|
|
1403
1475
|
// Poison/any provides no deterministic information
|
|
1404
|
-
if (argumentType.kind === "unknownType" ||
|
|
1476
|
+
if (argumentType.kind === "unknownType" ||
|
|
1477
|
+
argumentType.kind === "anyType") {
|
|
1478
|
+
return true;
|
|
1479
|
+
}
|
|
1480
|
+
// Intersection argument types: unify through each constituent.
|
|
1481
|
+
//
|
|
1482
|
+
// This is required for airplane-grade extension method typing where the receiver
|
|
1483
|
+
// often has the form `TShape & <extension markers> & <method table>`.
|
|
1484
|
+
// Generic inference must still be able to infer through the real CLR shape in the intersection.
|
|
1485
|
+
if (argumentType.kind === "intersectionType") {
|
|
1486
|
+
for (const part of argumentType.types) {
|
|
1487
|
+
if (!part)
|
|
1488
|
+
continue;
|
|
1489
|
+
if (!tryUnify(parameterType, part))
|
|
1490
|
+
return false;
|
|
1491
|
+
}
|
|
1405
1492
|
return true;
|
|
1406
1493
|
}
|
|
1407
1494
|
// Expression<TDelegate> wrapper: infer through the underlying delegate shape.
|
|
@@ -1419,12 +1506,14 @@ export const createTypeSystem = (config) => {
|
|
|
1419
1506
|
// Without this, generic methods like:
|
|
1420
1507
|
// Select<TResult>(selector: Func<TSource, TResult>)
|
|
1421
1508
|
// cannot infer TResult from a lambda argument, causing TSN5201/TSN5202.
|
|
1422
|
-
if (parameterType.kind === "referenceType" &&
|
|
1509
|
+
if (parameterType.kind === "referenceType" &&
|
|
1510
|
+
argumentType.kind === "functionType") {
|
|
1423
1511
|
const delegateFn = delegateToFunctionType(parameterType);
|
|
1424
1512
|
if (delegateFn)
|
|
1425
1513
|
return tryUnify(delegateFn, argumentType);
|
|
1426
1514
|
}
|
|
1427
|
-
if (parameterType.kind === "functionType" &&
|
|
1515
|
+
if (parameterType.kind === "functionType" &&
|
|
1516
|
+
argumentType.kind === "referenceType") {
|
|
1428
1517
|
const delegateFn = delegateToFunctionType(argumentType);
|
|
1429
1518
|
if (delegateFn)
|
|
1430
1519
|
return tryUnify(parameterType, delegateFn);
|
|
@@ -1435,14 +1524,18 @@ export const createTypeSystem = (config) => {
|
|
|
1435
1524
|
(parameterType.typeArguments?.length ?? 0) === 1 &&
|
|
1436
1525
|
argumentType.kind === "arrayType") {
|
|
1437
1526
|
const elementParam = parameterType.typeArguments?.[0];
|
|
1438
|
-
return elementParam
|
|
1527
|
+
return elementParam
|
|
1528
|
+
? tryUnify(elementParam, argumentType.elementType)
|
|
1529
|
+
: true;
|
|
1439
1530
|
}
|
|
1440
1531
|
// Union parameter type: allow deterministic inference through common nullish unions.
|
|
1441
1532
|
// Example: constructor(value: T | null) with argument of type T.
|
|
1442
1533
|
if (parameterType.kind === "unionType") {
|
|
1443
1534
|
const nonNullish = parameterType.types.filter((t) => t && !isNullishPrimitive(t));
|
|
1444
1535
|
const nullish = parameterType.types.filter((t) => t && isNullishPrimitive(t));
|
|
1445
|
-
const candidates = isNullishPrimitive(argumentType)
|
|
1536
|
+
const candidates = isNullishPrimitive(argumentType)
|
|
1537
|
+
? nullish
|
|
1538
|
+
: nonNullish;
|
|
1446
1539
|
if (candidates.length === 1) {
|
|
1447
1540
|
const only = candidates[0];
|
|
1448
1541
|
return only ? tryUnify(only, argumentType) : true;
|
|
@@ -1455,7 +1548,9 @@ export const createTypeSystem = (config) => {
|
|
|
1455
1548
|
argumentType.name === "Array" &&
|
|
1456
1549
|
(argumentType.typeArguments?.length ?? 0) === 1) {
|
|
1457
1550
|
const elementArg = argumentType.typeArguments?.[0];
|
|
1458
|
-
return elementArg
|
|
1551
|
+
return elementArg
|
|
1552
|
+
? tryUnify(parameterType.elementType, elementArg)
|
|
1553
|
+
: true;
|
|
1459
1554
|
}
|
|
1460
1555
|
// Same-kind structural unification
|
|
1461
1556
|
if (parameterType.kind !== argumentType.kind) {
|
|
@@ -1550,7 +1645,6 @@ export const createTypeSystem = (config) => {
|
|
|
1550
1645
|
}
|
|
1551
1646
|
return tryUnify(parameterType.returnType, argFn.returnType);
|
|
1552
1647
|
}
|
|
1553
|
-
case "intersectionType":
|
|
1554
1648
|
case "objectType":
|
|
1555
1649
|
case "dictionaryType":
|
|
1556
1650
|
// Conservative: only infer through these when shapes already match exactly.
|
|
@@ -1573,6 +1667,80 @@ export const createTypeSystem = (config) => {
|
|
|
1573
1667
|
}
|
|
1574
1668
|
return substitution;
|
|
1575
1669
|
};
|
|
1670
|
+
const mapEntriesEqual = (left, right) => {
|
|
1671
|
+
if (left.size !== right.size)
|
|
1672
|
+
return false;
|
|
1673
|
+
for (const [key, leftValue] of left) {
|
|
1674
|
+
const rightValue = right.get(key);
|
|
1675
|
+
if (!rightValue || !typesEqual(leftValue, rightValue))
|
|
1676
|
+
return false;
|
|
1677
|
+
}
|
|
1678
|
+
return true;
|
|
1679
|
+
};
|
|
1680
|
+
const collectExpectedReturnCandidates = (type) => {
|
|
1681
|
+
const queue = [type];
|
|
1682
|
+
const out = [];
|
|
1683
|
+
const seen = new Set();
|
|
1684
|
+
const enqueue = (candidate) => {
|
|
1685
|
+
if (!candidate)
|
|
1686
|
+
return;
|
|
1687
|
+
const key = JSON.stringify(candidate);
|
|
1688
|
+
if (seen.has(key))
|
|
1689
|
+
return;
|
|
1690
|
+
seen.add(key);
|
|
1691
|
+
queue.push(candidate);
|
|
1692
|
+
};
|
|
1693
|
+
while (queue.length > 0) {
|
|
1694
|
+
const current = queue.shift();
|
|
1695
|
+
if (!current)
|
|
1696
|
+
continue;
|
|
1697
|
+
out.push(current);
|
|
1698
|
+
if (current.kind === "unionType") {
|
|
1699
|
+
for (const member of current.types)
|
|
1700
|
+
enqueue(member);
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
if (current.kind === "referenceType" && current.typeArguments) {
|
|
1704
|
+
const typeId = current.typeId ??
|
|
1705
|
+
resolveTypeIdByName(current.resolvedClrType ?? current.name, current.typeArguments.length);
|
|
1706
|
+
if (typeId) {
|
|
1707
|
+
const entry = unifiedCatalog.getByTypeId(typeId);
|
|
1708
|
+
if (entry?.aliasedType) {
|
|
1709
|
+
const aliasSubst = new Map();
|
|
1710
|
+
const aliasTypeParams = entry.typeParameters;
|
|
1711
|
+
const aliasTypeArgs = current.typeArguments;
|
|
1712
|
+
for (let i = 0; i < Math.min(aliasTypeParams.length, aliasTypeArgs.length); i++) {
|
|
1713
|
+
const tp = aliasTypeParams[i];
|
|
1714
|
+
const ta = aliasTypeArgs[i];
|
|
1715
|
+
if (tp && ta)
|
|
1716
|
+
aliasSubst.set(tp.name, ta);
|
|
1717
|
+
}
|
|
1718
|
+
const expanded = aliasSubst.size > 0
|
|
1719
|
+
? irSubstitute(entry.aliasedType, aliasSubst)
|
|
1720
|
+
: entry.aliasedType;
|
|
1721
|
+
enqueue(expanded);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
if (current.typeArguments.length !== 1)
|
|
1725
|
+
continue;
|
|
1726
|
+
const simpleName = current.name.split(".").pop() ?? current.name;
|
|
1727
|
+
const clrName = current.resolvedClrType ?? current.name;
|
|
1728
|
+
const isAsyncWrapper = simpleName === "Promise" ||
|
|
1729
|
+
simpleName === "Task_1" ||
|
|
1730
|
+
simpleName === "Task`1" ||
|
|
1731
|
+
simpleName === "ValueTask_1" ||
|
|
1732
|
+
simpleName === "ValueTask`1" ||
|
|
1733
|
+
clrName === "System.Threading.Tasks.Task" ||
|
|
1734
|
+
clrName === "System.Threading.Tasks.ValueTask" ||
|
|
1735
|
+
clrName.startsWith("System.Threading.Tasks.Task`1") ||
|
|
1736
|
+
clrName.startsWith("System.Threading.Tasks.ValueTask`1");
|
|
1737
|
+
if (isAsyncWrapper) {
|
|
1738
|
+
enqueue(current.typeArguments[0]);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
return out;
|
|
1743
|
+
};
|
|
1576
1744
|
const containsMethodTypeParameter = (type, unresolved) => {
|
|
1577
1745
|
if (type.kind === "typeParameterType")
|
|
1578
1746
|
return unresolved.has(type.name);
|
|
@@ -1587,7 +1755,8 @@ export const createTypeSystem = (config) => {
|
|
|
1587
1755
|
}
|
|
1588
1756
|
if (type.kind === "functionType") {
|
|
1589
1757
|
const paramsContain = type.parameters.some((p) => p.type ? containsMethodTypeParameter(p.type, unresolved) : false);
|
|
1590
|
-
return paramsContain ||
|
|
1758
|
+
return (paramsContain ||
|
|
1759
|
+
containsMethodTypeParameter(type.returnType, unresolved));
|
|
1591
1760
|
}
|
|
1592
1761
|
if (type.kind === "unionType" || type.kind === "intersectionType") {
|
|
1593
1762
|
return type.types.some((t) => t ? containsMethodTypeParameter(t, unresolved) : false);
|
|
@@ -1670,7 +1839,7 @@ export const createTypeSystem = (config) => {
|
|
|
1670
1839
|
return score;
|
|
1671
1840
|
};
|
|
1672
1841
|
const tryResolveCallFromUnifiedCatalog = (declaringTypeTsName, declaringMemberName, query) => {
|
|
1673
|
-
const { argumentCount, receiverType, explicitTypeArgs, argTypes
|
|
1842
|
+
const { argumentCount, receiverType, explicitTypeArgs, argTypes } = query;
|
|
1674
1843
|
if (!argTypes)
|
|
1675
1844
|
return undefined;
|
|
1676
1845
|
if (argTypes.length < argumentCount)
|
|
@@ -1794,7 +1963,12 @@ export const createTypeSystem = (config) => {
|
|
|
1794
1963
|
return best?.resolved;
|
|
1795
1964
|
};
|
|
1796
1965
|
const resolveCall = (query) => {
|
|
1797
|
-
const { sigId, argumentCount, receiverType, explicitTypeArgs, argTypes, site, } = query;
|
|
1966
|
+
const { sigId, argumentCount, receiverType, explicitTypeArgs, argTypes, expectedReturnType, site, } = query;
|
|
1967
|
+
// Extension method scopes are modeled as TS-only wrapper types (e.g. __TsonicExt_Ef<T>).
|
|
1968
|
+
// They must erase to their underlying CLR shapes for deterministic call inference.
|
|
1969
|
+
const effectiveReceiverType = receiverType
|
|
1970
|
+
? stripTsonicExtensionWrappers(receiverType)
|
|
1971
|
+
: undefined;
|
|
1798
1972
|
// 1. Load raw signature (cached)
|
|
1799
1973
|
const rawSig = getRawSignature(sigId);
|
|
1800
1974
|
if (!rawSig) {
|
|
@@ -1810,15 +1984,19 @@ export const createTypeSystem = (config) => {
|
|
|
1810
1984
|
}
|
|
1811
1985
|
// 2. Start with raw types
|
|
1812
1986
|
let workingParams = [...rawSig.parameterTypes];
|
|
1987
|
+
let workingThisParam = rawSig.thisParameterType;
|
|
1813
1988
|
let workingReturn = rawSig.returnType;
|
|
1814
1989
|
let workingPredicate = rawSig.typePredicate;
|
|
1815
1990
|
// 3. Compute receiver substitution (class type params)
|
|
1816
|
-
if (
|
|
1991
|
+
if (effectiveReceiverType &&
|
|
1817
1992
|
rawSig.declaringTypeTsName &&
|
|
1818
1993
|
rawSig.declaringMemberName) {
|
|
1819
|
-
const receiverSubst = computeReceiverSubstitution(
|
|
1994
|
+
const receiverSubst = computeReceiverSubstitution(effectiveReceiverType, rawSig.declaringTypeTsName, rawSig.declaringMemberName);
|
|
1820
1995
|
if (receiverSubst && receiverSubst.size > 0) {
|
|
1821
1996
|
workingParams = workingParams.map((p) => p ? irSubstitute(p, receiverSubst) : undefined);
|
|
1997
|
+
if (workingThisParam) {
|
|
1998
|
+
workingThisParam = irSubstitute(workingThisParam, receiverSubst);
|
|
1999
|
+
}
|
|
1822
2000
|
workingReturn = irSubstitute(workingReturn, receiverSubst);
|
|
1823
2001
|
if (workingPredicate) {
|
|
1824
2002
|
workingPredicate =
|
|
@@ -1849,9 +2027,38 @@ export const createTypeSystem = (config) => {
|
|
|
1849
2027
|
}
|
|
1850
2028
|
}
|
|
1851
2029
|
// Source 2: Deterministic argument-driven unification
|
|
1852
|
-
|
|
2030
|
+
// 2a) Receiver-driven unification via TS `this:` parameter
|
|
2031
|
+
//
|
|
2032
|
+
// Method-table extension typing represents the receiver as an explicit `this:` parameter
|
|
2033
|
+
// in the `.d.ts` signature. Generic methods like:
|
|
2034
|
+
// ToArrayAsync<T>(this: IQueryable<T>, ...): Task<T[]>
|
|
2035
|
+
// must infer T from the receiver even when there are ZERO call arguments.
|
|
2036
|
+
//
|
|
2037
|
+
// This is airplane-grade determinism: we anchor inference to the selected TS signature’s
|
|
2038
|
+
// `this:` type and the IR receiver type (not TS structural tricks).
|
|
2039
|
+
if (effectiveReceiverType && workingThisParam) {
|
|
2040
|
+
const receiverParamForInference = callSubst.size > 0
|
|
2041
|
+
? irSubstitute(workingThisParam, callSubst)
|
|
2042
|
+
: workingThisParam;
|
|
2043
|
+
const inferredFromReceiver = inferMethodTypeArgsFromArguments(methodTypeParams, [receiverParamForInference], [effectiveReceiverType]);
|
|
2044
|
+
if (inferredFromReceiver) {
|
|
2045
|
+
for (const [name, inferredType] of inferredFromReceiver) {
|
|
2046
|
+
const existing = callSubst.get(name);
|
|
2047
|
+
if (existing) {
|
|
2048
|
+
if (!typesEqual(existing, inferredType)) {
|
|
2049
|
+
emitDiagnostic("TSN5202", `Conflicting type argument inference for '${name}' (receiver)`, site);
|
|
2050
|
+
return poisonedCall(argumentCount, diagnostics.slice());
|
|
2051
|
+
}
|
|
2052
|
+
continue;
|
|
2053
|
+
}
|
|
2054
|
+
callSubst.set(name, inferredType);
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
// 2b) Argument-driven unification (run even when argTypes is empty).
|
|
2059
|
+
if (argTypes) {
|
|
1853
2060
|
const paramsForInference = callSubst.size > 0
|
|
1854
|
-
? workingParams.map((p) =>
|
|
2061
|
+
? workingParams.map((p) => p ? irSubstitute(p, callSubst) : undefined)
|
|
1855
2062
|
: workingParams;
|
|
1856
2063
|
const inferred = inferMethodTypeArgsFromArguments(methodTypeParams, paramsForInference, argTypes);
|
|
1857
2064
|
if (!inferred) {
|
|
@@ -1870,7 +2077,52 @@ export const createTypeSystem = (config) => {
|
|
|
1870
2077
|
callSubst.set(name, inferredType);
|
|
1871
2078
|
}
|
|
1872
2079
|
}
|
|
1873
|
-
// Source 3:
|
|
2080
|
+
// Source 3: Contextual expected return type from the call site.
|
|
2081
|
+
// This handles generic APIs where method type parameters appear only in
|
|
2082
|
+
// the return position (or where argument inference is intentionally weak).
|
|
2083
|
+
if (expectedReturnType) {
|
|
2084
|
+
const returnForInference = callSubst.size > 0
|
|
2085
|
+
? irSubstitute(workingReturn, callSubst)
|
|
2086
|
+
: workingReturn;
|
|
2087
|
+
const expectedCandidates = collectExpectedReturnCandidates(expectedReturnType);
|
|
2088
|
+
let matched;
|
|
2089
|
+
for (const candidate of expectedCandidates) {
|
|
2090
|
+
const inferred = inferMethodTypeArgsFromArguments(methodTypeParams, [returnForInference], [candidate]);
|
|
2091
|
+
if (!inferred || inferred.size === 0)
|
|
2092
|
+
continue;
|
|
2093
|
+
let conflictsWithExisting = false;
|
|
2094
|
+
for (const [name, inferredType] of inferred) {
|
|
2095
|
+
const existing = callSubst.get(name);
|
|
2096
|
+
if (existing && !typesEqual(existing, inferredType)) {
|
|
2097
|
+
conflictsWithExisting = true;
|
|
2098
|
+
break;
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
if (conflictsWithExisting)
|
|
2102
|
+
continue;
|
|
2103
|
+
if (matched && !mapEntriesEqual(matched, inferred)) {
|
|
2104
|
+
// Ambiguous contextual-return inference: ignore this source and
|
|
2105
|
+
// rely on explicit/argument/default inference only.
|
|
2106
|
+
matched = undefined;
|
|
2107
|
+
break;
|
|
2108
|
+
}
|
|
2109
|
+
matched = inferred;
|
|
2110
|
+
}
|
|
2111
|
+
if (matched) {
|
|
2112
|
+
for (const [name, inferredType] of matched) {
|
|
2113
|
+
const existing = callSubst.get(name);
|
|
2114
|
+
if (existing) {
|
|
2115
|
+
if (!typesEqual(existing, inferredType)) {
|
|
2116
|
+
emitDiagnostic("TSN5202", `Conflicting type argument inference for '${name}' (expected return context)`, site);
|
|
2117
|
+
return poisonedCall(argumentCount, diagnostics.slice());
|
|
2118
|
+
}
|
|
2119
|
+
continue;
|
|
2120
|
+
}
|
|
2121
|
+
callSubst.set(name, inferredType);
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
// Source 4: Default type parameters
|
|
1874
2126
|
for (const tp of methodTypeParams) {
|
|
1875
2127
|
if (!callSubst.has(tp.name) && tp.defaultType) {
|
|
1876
2128
|
callSubst.set(tp.name, tp.defaultType);
|
|
@@ -1897,7 +2149,8 @@ export const createTypeSystem = (config) => {
|
|
|
1897
2149
|
const unresolved = new Set(methodTypeParams
|
|
1898
2150
|
.map((tp) => tp.name)
|
|
1899
2151
|
.filter((name) => !callSubst.has(name)));
|
|
1900
|
-
if (unresolved.size > 0 &&
|
|
2152
|
+
if (unresolved.size > 0 &&
|
|
2153
|
+
containsMethodTypeParameter(workingReturn, unresolved)) {
|
|
1901
2154
|
const fallback = argTypes && rawSig.declaringTypeTsName && rawSig.declaringMemberName
|
|
1902
2155
|
? tryResolveCallFromUnifiedCatalog(rawSig.declaringTypeTsName, rawSig.declaringMemberName, query)
|
|
1903
2156
|
: undefined;
|
|
@@ -2237,7 +2490,10 @@ export const createTypeSystem = (config) => {
|
|
|
2237
2490
|
*/
|
|
2238
2491
|
const expandAwaitedUtility = (type) => {
|
|
2239
2492
|
if (type.kind === "unionType") {
|
|
2240
|
-
return {
|
|
2493
|
+
return {
|
|
2494
|
+
kind: "unionType",
|
|
2495
|
+
types: type.types.map((t) => expandAwaitedUtility(t)),
|
|
2496
|
+
};
|
|
2241
2497
|
}
|
|
2242
2498
|
// Check for Promise<T>
|
|
2243
2499
|
if (type.kind === "referenceType" &&
|