@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.
Files changed (185) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/dotnet-metadata.d.ts.map +1 -1
  3. package/dist/dotnet-metadata.js +3 -1
  4. package/dist/dotnet-metadata.js.map +1 -1
  5. package/dist/dotnet-metadata.test.js.map +1 -1
  6. package/dist/ir/binding/index.d.ts +24 -0
  7. package/dist/ir/binding/index.d.ts.map +1 -1
  8. package/dist/ir/binding/index.js +51 -7
  9. package/dist/ir/binding/index.js.map +1 -1
  10. package/dist/ir/binding-resolution.test.js +4 -1
  11. package/dist/ir/binding-resolution.test.js.map +1 -1
  12. package/dist/ir/bindings-disambiguation.test.js.map +1 -1
  13. package/dist/ir/builder/imports.d.ts.map +1 -1
  14. package/dist/ir/builder/imports.js +91 -5
  15. package/dist/ir/builder/imports.js.map +1 -1
  16. package/dist/ir/builder.test.js +233 -24
  17. package/dist/ir/builder.test.js.map +1 -1
  18. package/dist/ir/converters/expressions/access.d.ts.map +1 -1
  19. package/dist/ir/converters/expressions/access.js +94 -11
  20. package/dist/ir/converters/expressions/access.js.map +1 -1
  21. package/dist/ir/converters/expressions/calls.d.ts +1 -1
  22. package/dist/ir/converters/expressions/calls.d.ts.map +1 -1
  23. package/dist/ir/converters/expressions/calls.js +398 -7
  24. package/dist/ir/converters/expressions/calls.js.map +1 -1
  25. package/dist/ir/converters/expressions/collections.d.ts.map +1 -1
  26. package/dist/ir/converters/expressions/collections.js +19 -22
  27. package/dist/ir/converters/expressions/collections.js.map +1 -1
  28. package/dist/ir/converters/expressions/functions.js +2 -2
  29. package/dist/ir/converters/expressions/functions.js.map +1 -1
  30. package/dist/ir/converters/expressions/operators.d.ts.map +1 -1
  31. package/dist/ir/converters/expressions/operators.js +1 -1
  32. package/dist/ir/converters/expressions/operators.js.map +1 -1
  33. package/dist/ir/converters/expressions/other.d.ts.map +1 -1
  34. package/dist/ir/converters/expressions/other.js +16 -2
  35. package/dist/ir/converters/expressions/other.js.map +1 -1
  36. package/dist/ir/converters/flow-narrowing.d.ts.map +1 -1
  37. package/dist/ir/converters/flow-narrowing.js.map +1 -1
  38. package/dist/ir/converters/statements/control/loops.d.ts.map +1 -1
  39. package/dist/ir/converters/statements/control/loops.js +8 -2
  40. package/dist/ir/converters/statements/control/loops.js.map +1 -1
  41. package/dist/ir/converters/statements/declarations/classes/constructors.d.ts.map +1 -1
  42. package/dist/ir/converters/statements/declarations/classes/constructors.js.map +1 -1
  43. package/dist/ir/converters/statements/declarations/classes/methods.d.ts.map +1 -1
  44. package/dist/ir/converters/statements/declarations/classes/methods.js +70 -22
  45. package/dist/ir/converters/statements/declarations/classes/methods.js.map +1 -1
  46. package/dist/ir/converters/statements/declarations/classes/orchestrator.d.ts.map +1 -1
  47. package/dist/ir/converters/statements/declarations/classes/orchestrator.js +10 -4
  48. package/dist/ir/converters/statements/declarations/classes/orchestrator.js.map +1 -1
  49. package/dist/ir/converters/statements/declarations/classes/override-detection.d.ts.map +1 -1
  50. package/dist/ir/converters/statements/declarations/classes/override-detection.js +5 -1
  51. package/dist/ir/converters/statements/declarations/classes/override-detection.js.map +1 -1
  52. package/dist/ir/converters/statements/declarations/classes/properties.d.ts.map +1 -1
  53. package/dist/ir/converters/statements/declarations/classes/properties.js +2 -1
  54. package/dist/ir/converters/statements/declarations/classes/properties.js.map +1 -1
  55. package/dist/ir/converters/statements/declarations/variables.d.ts.map +1 -1
  56. package/dist/ir/converters/statements/declarations/variables.js +1 -1
  57. package/dist/ir/converters/statements/declarations/variables.js.map +1 -1
  58. package/dist/ir/converters/statements/helpers.d.ts.map +1 -1
  59. package/dist/ir/converters/statements/helpers.js +10 -2
  60. package/dist/ir/converters/statements/helpers.js.map +1 -1
  61. package/dist/ir/converters/type-env.d.ts.map +1 -1
  62. package/dist/ir/converters/type-env.js.map +1 -1
  63. package/dist/ir/expression-converter.d.ts.map +1 -1
  64. package/dist/ir/expression-converter.js +25 -2
  65. package/dist/ir/expression-converter.js.map +1 -1
  66. package/dist/ir/field-marker.test.js.map +1 -1
  67. package/dist/ir/program-context.d.ts.map +1 -1
  68. package/dist/ir/program-context.js +6 -2
  69. package/dist/ir/program-context.js.map +1 -1
  70. package/dist/ir/this-parameter-inference-rewrap.test.d.ts +14 -0
  71. package/dist/ir/this-parameter-inference-rewrap.test.d.ts.map +1 -0
  72. package/dist/ir/this-parameter-inference-rewrap.test.js +110 -0
  73. package/dist/ir/this-parameter-inference-rewrap.test.js.map +1 -0
  74. package/dist/ir/this-parameter-inference.test.d.ts +13 -0
  75. package/dist/ir/this-parameter-inference.test.d.ts.map +1 -0
  76. package/dist/ir/this-parameter-inference.test.js +165 -0
  77. package/dist/ir/this-parameter-inference.test.js.map +1 -0
  78. package/dist/ir/type-system/internal/handle-types.d.ts +2 -0
  79. package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
  80. package/dist/ir/type-system/internal/nominal-env.d.ts.map +1 -1
  81. package/dist/ir/type-system/internal/nominal-env.js.map +1 -1
  82. package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts.map +1 -1
  83. package/dist/ir/type-system/internal/type-converter/orchestrator.js +3 -1
  84. package/dist/ir/type-system/internal/type-converter/orchestrator.js.map +1 -1
  85. package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
  86. package/dist/ir/type-system/internal/type-converter/references.js +204 -2
  87. package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
  88. package/dist/ir/type-system/internal/type-converter/utility-types.d.ts.map +1 -1
  89. package/dist/ir/type-system/internal/type-converter/utility-types.js +9 -4
  90. package/dist/ir/type-system/internal/type-converter/utility-types.js.map +1 -1
  91. package/dist/ir/type-system/internal/type-registry.d.ts.map +1 -1
  92. package/dist/ir/type-system/internal/type-registry.js +8 -4
  93. package/dist/ir/type-system/internal/type-registry.js.map +1 -1
  94. package/dist/ir/type-system/internal/universe/clr-catalog.d.ts.map +1 -1
  95. package/dist/ir/type-system/internal/universe/clr-catalog.js +27 -10
  96. package/dist/ir/type-system/internal/universe/clr-catalog.js.map +1 -1
  97. package/dist/ir/type-system/internal/universe/source-catalog.js +3 -1
  98. package/dist/ir/type-system/internal/universe/source-catalog.js.map +1 -1
  99. package/dist/ir/type-system/internal/universe/types.d.ts +7 -0
  100. package/dist/ir/type-system/internal/universe/types.d.ts.map +1 -1
  101. package/dist/ir/type-system/internal/universe/types.js.map +1 -1
  102. package/dist/ir/type-system/internal/universe/unified-universe.d.ts.map +1 -1
  103. package/dist/ir/type-system/internal/universe/unified-universe.js +16 -1
  104. package/dist/ir/type-system/internal/universe/unified-universe.js.map +1 -1
  105. package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts +2 -0
  106. package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts.map +1 -0
  107. package/dist/ir/type-system/internal/universe/unified-universe.test.js +87 -0
  108. package/dist/ir/type-system/internal/universe/unified-universe.test.js.map +1 -0
  109. package/dist/ir/type-system/type-system.d.ts +12 -0
  110. package/dist/ir/type-system/type-system.d.ts.map +1 -1
  111. package/dist/ir/type-system/type-system.js +291 -35
  112. package/dist/ir/type-system/type-system.js.map +1 -1
  113. package/dist/ir/types/ir-types.d.ts.map +1 -1
  114. package/dist/ir/types/module.d.ts +11 -0
  115. package/dist/ir/types/module.d.ts.map +1 -1
  116. package/dist/ir/validation/anonymous-type-lowering-pass.d.ts.map +1 -1
  117. package/dist/ir/validation/anonymous-type-lowering-pass.js +101 -49
  118. package/dist/ir/validation/anonymous-type-lowering-pass.js.map +1 -1
  119. package/dist/ir/validation/arrow-return-finalization-pass.js +13 -3
  120. package/dist/ir/validation/arrow-return-finalization-pass.js.map +1 -1
  121. package/dist/ir/validation/attribute-collection-pass.d.ts.map +1 -1
  122. package/dist/ir/validation/attribute-collection-pass.js +11 -3
  123. package/dist/ir/validation/attribute-collection-pass.js.map +1 -1
  124. package/dist/ir/validation/attribute-collection-pass.test.js +30 -13
  125. package/dist/ir/validation/attribute-collection-pass.test.js.map +1 -1
  126. package/dist/ir/validation/char-validation-pass.d.ts.map +1 -1
  127. package/dist/ir/validation/char-validation-pass.js +6 -3
  128. package/dist/ir/validation/char-validation-pass.js.map +1 -1
  129. package/dist/ir/validation/numeric-coercion-pass.d.ts.map +1 -1
  130. package/dist/ir/validation/numeric-coercion-pass.js.map +1 -1
  131. package/dist/ir/validation/numeric-invariants.test.js +46 -0
  132. package/dist/ir/validation/numeric-invariants.test.js.map +1 -1
  133. package/dist/ir/validation/numeric-proof-pass.d.ts.map +1 -1
  134. package/dist/ir/validation/numeric-proof-pass.js +68 -1
  135. package/dist/ir/validation/numeric-proof-pass.js.map +1 -1
  136. package/dist/ir/validation/rest-type-synthesis-pass.js +1 -1
  137. package/dist/ir/validation/rest-type-synthesis-pass.js.map +1 -1
  138. package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
  139. package/dist/ir/validation/soundness-gate.js +6 -4
  140. package/dist/ir/validation/soundness-gate.js.map +1 -1
  141. package/dist/ir/validation/soundness-gate.test.js +89 -0
  142. package/dist/ir/validation/soundness-gate.test.js.map +1 -1
  143. package/dist/program/bindings.d.ts +7 -0
  144. package/dist/program/bindings.d.ts.map +1 -1
  145. package/dist/program/bindings.js +17 -6
  146. package/dist/program/bindings.js.map +1 -1
  147. package/dist/program/clr-bindings-discovery.d.ts +19 -0
  148. package/dist/program/clr-bindings-discovery.d.ts.map +1 -0
  149. package/dist/program/clr-bindings-discovery.js +150 -0
  150. package/dist/program/clr-bindings-discovery.js.map +1 -0
  151. package/dist/program/clr-bindings-discovery.test.d.ts +2 -0
  152. package/dist/program/clr-bindings-discovery.test.d.ts.map +1 -0
  153. package/dist/program/clr-bindings-discovery.test.js +119 -0
  154. package/dist/program/clr-bindings-discovery.test.js.map +1 -0
  155. package/dist/program/creation.d.ts.map +1 -1
  156. package/dist/program/creation.js +2 -1
  157. package/dist/program/creation.js.map +1 -1
  158. package/dist/program/creation.test.js.map +1 -1
  159. package/dist/program/dependency-graph.d.ts +2 -2
  160. package/dist/program/dependency-graph.d.ts.map +1 -1
  161. package/dist/program/dependency-graph.js +26 -42
  162. package/dist/program/dependency-graph.js.map +1 -1
  163. package/dist/resolver/clr-bindings-resolver.d.ts.map +1 -1
  164. package/dist/resolver/clr-bindings-resolver.js +3 -1
  165. package/dist/resolver/clr-bindings-resolver.js.map +1 -1
  166. package/dist/resolver/clr-bindings-resolver.test.js.map +1 -1
  167. package/dist/resolver/namespace.d.ts.map +1 -1
  168. package/dist/resolver/namespace.js +1 -3
  169. package/dist/resolver/namespace.js.map +1 -1
  170. package/dist/tsbindgen/names.d.ts.map +1 -1
  171. package/dist/tsbindgen/names.js +4 -2
  172. package/dist/tsbindgen/names.js.map +1 -1
  173. package/dist/validation/core-intrinsics.d.ts.map +1 -1
  174. package/dist/validation/core-intrinsics.js +3 -1
  175. package/dist/validation/core-intrinsics.js.map +1 -1
  176. package/dist/validation/extension-methods.d.ts.map +1 -1
  177. package/dist/validation/extension-methods.js.map +1 -1
  178. package/dist/validation/generics.d.ts.map +1 -1
  179. package/dist/validation/generics.js +1 -1
  180. package/dist/validation/generics.js.map +1 -1
  181. package/dist/validation/static-safety.d.ts.map +1 -1
  182. package/dist/validation/static-safety.js +17 -2
  183. package/dist/validation/static-safety.js.map +1 -1
  184. package/dist/validator.test.js.map +1 -1
  185. 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) => (p.typeNode ? convertTypeNode(p.typeNode) : undefined));
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) => ({ kind: "typeParameterType", name: tp.name }));
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.type;
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.type;
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
- * - numeric literal lexeme rules
606
- *
607
- * This is intentionally small: it's used only to type lambda bodies for
608
- * initializer-driven generic inference (e.g., `Enumerable.select(..., x => x * 2)`).
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) || ts.isTypeAssertionExpression(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 ? convertTypeNode(unwrapped.type) : undefined;
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] ? nonNullish[0] : receiver;
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" && effectiveReceiver.structuralMembers)) {
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(",") ? (first.split(",")[0] ?? first) : first;
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" || argumentType.kind === "anyType") {
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" && argumentType.kind === "functionType") {
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" && argumentType.kind === "referenceType") {
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 ? tryUnify(elementParam, argumentType.elementType) : true;
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) ? nullish : nonNullish;
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 ? tryUnify(parameterType.elementType, elementArg) : true;
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 || containsMethodTypeParameter(type.returnType, unresolved);
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, } = query;
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 (receiverType &&
1991
+ if (effectiveReceiverType &&
1817
1992
  rawSig.declaringTypeTsName &&
1818
1993
  rawSig.declaringMemberName) {
1819
- const receiverSubst = computeReceiverSubstitution(receiverType, rawSig.declaringTypeTsName, rawSig.declaringMemberName);
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
- if (argTypes && argTypes.length > 0) {
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) => (p ? irSubstitute(p, callSubst) : undefined))
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: Default type parameters
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 && containsMethodTypeParameter(workingReturn, unresolved)) {
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 { kind: "unionType", types: type.types.map((t) => expandAwaitedUtility(t)) };
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" &&