@tsonic/frontend 0.0.61 → 0.0.63

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 (466) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/dependency-graph.d.ts +1 -1
  3. package/dist/dependency-graph.d.ts.map +1 -1
  4. package/dist/dependency-graph.js +1 -1
  5. package/dist/dependency-graph.js.map +1 -1
  6. package/dist/dotnet-metadata.d.ts +0 -12
  7. package/dist/dotnet-metadata.d.ts.map +1 -1
  8. package/dist/dotnet-metadata.js +3 -25
  9. package/dist/dotnet-metadata.js.map +1 -1
  10. package/dist/dotnet-metadata.test.js.map +1 -1
  11. package/dist/generic-function-values.d.ts +11 -0
  12. package/dist/generic-function-values.d.ts.map +1 -0
  13. package/dist/generic-function-values.js +243 -0
  14. package/dist/generic-function-values.js.map +1 -0
  15. package/dist/generic-function-values.test.d.ts +2 -0
  16. package/dist/generic-function-values.test.d.ts.map +1 -0
  17. package/dist/generic-function-values.test.js +256 -0
  18. package/dist/generic-function-values.test.js.map +1 -0
  19. package/dist/graph/extraction/imports.d.ts +5 -0
  20. package/dist/graph/extraction/imports.d.ts.map +1 -1
  21. package/dist/graph/extraction/imports.js +30 -0
  22. package/dist/graph/extraction/imports.js.map +1 -1
  23. package/dist/graph/extraction/index.d.ts +1 -1
  24. package/dist/graph/extraction/index.d.ts.map +1 -1
  25. package/dist/graph/extraction/index.js +1 -1
  26. package/dist/graph/extraction/index.js.map +1 -1
  27. package/dist/graph/extraction/orchestrator.d.ts.map +1 -1
  28. package/dist/graph/extraction/orchestrator.js +16 -2
  29. package/dist/graph/extraction/orchestrator.js.map +1 -1
  30. package/dist/graph/extraction.d.ts +1 -1
  31. package/dist/graph/extraction.d.ts.map +1 -1
  32. package/dist/graph/extraction.js +1 -1
  33. package/dist/graph/extraction.js.map +1 -1
  34. package/dist/ir/binding/binding-factory.d.ts +17 -0
  35. package/dist/ir/binding/binding-factory.d.ts.map +1 -0
  36. package/dist/ir/binding/binding-factory.js +765 -0
  37. package/dist/ir/binding/binding-factory.js.map +1 -0
  38. package/dist/ir/binding/binding-helpers.d.ts +90 -0
  39. package/dist/ir/binding/binding-helpers.d.ts.map +1 -0
  40. package/dist/ir/binding/binding-helpers.js +387 -0
  41. package/dist/ir/binding/binding-helpers.js.map +1 -0
  42. package/dist/ir/binding/binding-types.d.ts +203 -0
  43. package/dist/ir/binding/binding-types.d.ts.map +1 -0
  44. package/dist/ir/binding/binding-types.js +9 -0
  45. package/dist/ir/binding/binding-types.js.map +1 -0
  46. package/dist/ir/binding/index.d.ts +4 -151
  47. package/dist/ir/binding/index.d.ts.map +1 -1
  48. package/dist/ir/binding/index.js +3 -1124
  49. package/dist/ir/binding/index.js.map +1 -1
  50. package/dist/ir/binding-resolution.test.js +4 -1
  51. package/dist/ir/binding-resolution.test.js.map +1 -1
  52. package/dist/ir/bindings-disambiguation.test.js.map +1 -1
  53. package/dist/ir/builder/imports.d.ts.map +1 -1
  54. package/dist/ir/builder/imports.js +91 -5
  55. package/dist/ir/builder/imports.js.map +1 -1
  56. package/dist/ir/builder.test.js +456 -24
  57. package/dist/ir/builder.test.js.map +1 -1
  58. package/dist/ir/converters/anonymous-synthesis.d.ts +3 -3
  59. package/dist/ir/converters/anonymous-synthesis.d.ts.map +1 -1
  60. package/dist/ir/converters/anonymous-synthesis.js +45 -8
  61. package/dist/ir/converters/anonymous-synthesis.js.map +1 -1
  62. package/dist/ir/converters/expressions/access/access-converter.d.ts +14 -0
  63. package/dist/ir/converters/expressions/access/access-converter.d.ts.map +1 -0
  64. package/dist/ir/converters/expressions/access/access-converter.js +141 -0
  65. package/dist/ir/converters/expressions/access/access-converter.js.map +1 -0
  66. package/dist/ir/converters/expressions/access/binding-resolution.d.ts +35 -0
  67. package/dist/ir/converters/expressions/access/binding-resolution.d.ts.map +1 -0
  68. package/dist/ir/converters/expressions/access/binding-resolution.js +384 -0
  69. package/dist/ir/converters/expressions/access/binding-resolution.js.map +1 -0
  70. package/dist/ir/converters/expressions/access/member-resolution.d.ts +67 -0
  71. package/dist/ir/converters/expressions/access/member-resolution.d.ts.map +1 -0
  72. package/dist/ir/converters/expressions/access/member-resolution.js +262 -0
  73. package/dist/ir/converters/expressions/access/member-resolution.js.map +1 -0
  74. package/dist/ir/converters/expressions/access.d.ts +1 -7
  75. package/dist/ir/converters/expressions/access.d.ts.map +1 -1
  76. package/dist/ir/converters/expressions/access.js +1 -720
  77. package/dist/ir/converters/expressions/access.js.map +1 -1
  78. package/dist/ir/converters/expressions/calls/call-converter.d.ts +23 -0
  79. package/dist/ir/converters/expressions/calls/call-converter.d.ts.map +1 -0
  80. package/dist/ir/converters/expressions/calls/call-converter.js +526 -0
  81. package/dist/ir/converters/expressions/calls/call-converter.js.map +1 -0
  82. package/dist/ir/converters/expressions/calls/call-site-analysis.d.ts +53 -0
  83. package/dist/ir/converters/expressions/calls/call-site-analysis.d.ts.map +1 -0
  84. package/dist/ir/converters/expressions/calls/call-site-analysis.js +554 -0
  85. package/dist/ir/converters/expressions/calls/call-site-analysis.js.map +1 -0
  86. package/dist/ir/converters/expressions/calls/new-converter.d.ts +21 -0
  87. package/dist/ir/converters/expressions/calls/new-converter.d.ts.map +1 -0
  88. package/dist/ir/converters/expressions/calls/new-converter.js +182 -0
  89. package/dist/ir/converters/expressions/calls/new-converter.js.map +1 -0
  90. package/dist/ir/converters/expressions/calls.d.ts +2 -28
  91. package/dist/ir/converters/expressions/calls.d.ts.map +1 -1
  92. package/dist/ir/converters/expressions/calls.js +2 -953
  93. package/dist/ir/converters/expressions/calls.js.map +1 -1
  94. package/dist/ir/converters/expressions/collections.d.ts.map +1 -1
  95. package/dist/ir/converters/expressions/collections.js +56 -28
  96. package/dist/ir/converters/expressions/collections.js.map +1 -1
  97. package/dist/ir/converters/expressions/functions.js +3 -3
  98. package/dist/ir/converters/expressions/functions.js.map +1 -1
  99. package/dist/ir/converters/expressions/helpers.d.ts.map +1 -1
  100. package/dist/ir/converters/expressions/helpers.js +1 -0
  101. package/dist/ir/converters/expressions/helpers.js.map +1 -1
  102. package/dist/ir/converters/expressions/operators.d.ts.map +1 -1
  103. package/dist/ir/converters/expressions/operators.js +1 -1
  104. package/dist/ir/converters/expressions/operators.js.map +1 -1
  105. package/dist/ir/converters/expressions/other.d.ts.map +1 -1
  106. package/dist/ir/converters/expressions/other.js +17 -2
  107. package/dist/ir/converters/expressions/other.js.map +1 -1
  108. package/dist/ir/converters/flow-narrowing.d.ts.map +1 -1
  109. package/dist/ir/converters/flow-narrowing.js +3 -2
  110. package/dist/ir/converters/flow-narrowing.js.map +1 -1
  111. package/dist/ir/converters/statements/control/loops.d.ts.map +1 -1
  112. package/dist/ir/converters/statements/control/loops.js +8 -2
  113. package/dist/ir/converters/statements/control/loops.js.map +1 -1
  114. package/dist/ir/converters/statements/declarations/classes/constructors.d.ts.map +1 -1
  115. package/dist/ir/converters/statements/declarations/classes/constructors.js.map +1 -1
  116. package/dist/ir/converters/statements/declarations/classes/methods.d.ts.map +1 -1
  117. package/dist/ir/converters/statements/declarations/classes/methods.js +71 -23
  118. package/dist/ir/converters/statements/declarations/classes/methods.js.map +1 -1
  119. package/dist/ir/converters/statements/declarations/classes/orchestrator.d.ts.map +1 -1
  120. package/dist/ir/converters/statements/declarations/classes/orchestrator.js +10 -4
  121. package/dist/ir/converters/statements/declarations/classes/orchestrator.js.map +1 -1
  122. package/dist/ir/converters/statements/declarations/classes/override-detection.d.ts.map +1 -1
  123. package/dist/ir/converters/statements/declarations/classes/override-detection.js +5 -1
  124. package/dist/ir/converters/statements/declarations/classes/override-detection.js.map +1 -1
  125. package/dist/ir/converters/statements/declarations/classes/properties.d.ts.map +1 -1
  126. package/dist/ir/converters/statements/declarations/classes/properties.js +2 -1
  127. package/dist/ir/converters/statements/declarations/classes/properties.js.map +1 -1
  128. package/dist/ir/converters/statements/declarations/type-aliases.js +1 -1
  129. package/dist/ir/converters/statements/declarations/type-aliases.js.map +1 -1
  130. package/dist/ir/converters/statements/declarations/variables.d.ts +2 -2
  131. package/dist/ir/converters/statements/declarations/variables.d.ts.map +1 -1
  132. package/dist/ir/converters/statements/declarations/variables.js +290 -3
  133. package/dist/ir/converters/statements/declarations/variables.js.map +1 -1
  134. package/dist/ir/converters/statements/helpers.d.ts.map +1 -1
  135. package/dist/ir/converters/statements/helpers.js +10 -2
  136. package/dist/ir/converters/statements/helpers.js.map +1 -1
  137. package/dist/ir/converters/type-env.d.ts.map +1 -1
  138. package/dist/ir/converters/type-env.js.map +1 -1
  139. package/dist/ir/expression-converter.d.ts +0 -1
  140. package/dist/ir/expression-converter.d.ts.map +1 -1
  141. package/dist/ir/expression-converter.js +25 -4
  142. package/dist/ir/expression-converter.js.map +1 -1
  143. package/dist/ir/field-marker.test.js.map +1 -1
  144. package/dist/ir/generic-function-value-lowering.test.d.ts +2 -0
  145. package/dist/ir/generic-function-value-lowering.test.d.ts.map +1 -0
  146. package/dist/ir/generic-function-value-lowering.test.js +312 -0
  147. package/dist/ir/generic-function-value-lowering.test.js.map +1 -0
  148. package/dist/ir/generic-validator.d.ts +3 -4
  149. package/dist/ir/generic-validator.d.ts.map +1 -1
  150. package/dist/ir/generic-validator.js +3 -35
  151. package/dist/ir/generic-validator.js.map +1 -1
  152. package/dist/ir/program-context.d.ts +7 -0
  153. package/dist/ir/program-context.d.ts.map +1 -1
  154. package/dist/ir/program-context.js +7 -2
  155. package/dist/ir/program-context.js.map +1 -1
  156. package/dist/ir/statement-converter.d.ts +0 -2
  157. package/dist/ir/statement-converter.d.ts.map +1 -1
  158. package/dist/ir/statement-converter.js +0 -3
  159. package/dist/ir/statement-converter.js.map +1 -1
  160. package/dist/ir/type-system/internal/handle-types.d.ts +16 -16
  161. package/dist/ir/type-system/internal/handle-types.d.ts.map +1 -1
  162. package/dist/ir/type-system/internal/nominal-env.d.ts +0 -2
  163. package/dist/ir/type-system/internal/nominal-env.d.ts.map +1 -1
  164. package/dist/ir/type-system/internal/nominal-env.js +2 -6
  165. package/dist/ir/type-system/internal/nominal-env.js.map +1 -1
  166. package/dist/ir/type-system/internal/type-converter/converter.d.ts +3 -1
  167. package/dist/ir/type-system/internal/type-converter/converter.d.ts.map +1 -1
  168. package/dist/ir/type-system/internal/type-converter/converter.js +3 -1
  169. package/dist/ir/type-system/internal/type-converter/converter.js.map +1 -1
  170. package/dist/ir/type-system/internal/type-converter/objects.js +7 -1
  171. package/dist/ir/type-system/internal/type-converter/objects.js.map +1 -1
  172. package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts +0 -2
  173. package/dist/ir/type-system/internal/type-converter/orchestrator.d.ts.map +1 -1
  174. package/dist/ir/type-system/internal/type-converter/orchestrator.js +318 -24
  175. package/dist/ir/type-system/internal/type-converter/orchestrator.js.map +1 -1
  176. package/dist/ir/type-system/internal/type-converter/orchestrator.test.d.ts +2 -0
  177. package/dist/ir/type-system/internal/type-converter/orchestrator.test.d.ts.map +1 -0
  178. package/dist/ir/type-system/internal/type-converter/orchestrator.test.js +265 -0
  179. package/dist/ir/type-system/internal/type-converter/orchestrator.test.js.map +1 -0
  180. package/dist/ir/type-system/internal/type-converter/primitives.d.ts.map +1 -1
  181. package/dist/ir/type-system/internal/type-converter/primitives.js +5 -0
  182. package/dist/ir/type-system/internal/type-converter/primitives.js.map +1 -1
  183. package/dist/ir/type-system/internal/type-converter/references.d.ts.map +1 -1
  184. package/dist/ir/type-system/internal/type-converter/references.js +172 -26
  185. package/dist/ir/type-system/internal/type-converter/references.js.map +1 -1
  186. package/dist/ir/type-system/internal/type-converter/utility-types.d.ts.map +1 -1
  187. package/dist/ir/type-system/internal/type-converter/utility-types.js +154 -4
  188. package/dist/ir/type-system/internal/type-converter/utility-types.js.map +1 -1
  189. package/dist/ir/type-system/internal/type-converter/utility-types.test.js +91 -1
  190. package/dist/ir/type-system/internal/type-converter/utility-types.test.js.map +1 -1
  191. package/dist/ir/type-system/internal/type-registry.d.ts +1 -1
  192. package/dist/ir/type-system/internal/type-registry.d.ts.map +1 -1
  193. package/dist/ir/type-system/internal/type-registry.js +15 -11
  194. package/dist/ir/type-system/internal/type-registry.js.map +1 -1
  195. package/dist/ir/type-system/internal/universe/alias-table.d.ts +0 -14
  196. package/dist/ir/type-system/internal/universe/alias-table.d.ts.map +1 -1
  197. package/dist/ir/type-system/internal/universe/alias-table.js +0 -17
  198. package/dist/ir/type-system/internal/universe/alias-table.js.map +1 -1
  199. package/dist/ir/type-system/internal/universe/clr-catalog.d.ts +3 -0
  200. package/dist/ir/type-system/internal/universe/clr-catalog.d.ts.map +1 -1
  201. package/dist/ir/type-system/internal/universe/clr-catalog.js +4 -1027
  202. package/dist/ir/type-system/internal/universe/clr-catalog.js.map +1 -1
  203. package/dist/ir/type-system/internal/universe/clr-entry-converter.d.ts +51 -0
  204. package/dist/ir/type-system/internal/universe/clr-entry-converter.d.ts.map +1 -0
  205. package/dist/ir/type-system/internal/universe/clr-entry-converter.js +657 -0
  206. package/dist/ir/type-system/internal/universe/clr-entry-converter.js.map +1 -0
  207. package/dist/ir/type-system/internal/universe/clr-type-parser.d.ts +52 -0
  208. package/dist/ir/type-system/internal/universe/clr-type-parser.d.ts.map +1 -0
  209. package/dist/ir/type-system/internal/universe/clr-type-parser.js +415 -0
  210. package/dist/ir/type-system/internal/universe/clr-type-parser.js.map +1 -0
  211. package/dist/ir/type-system/internal/universe/index.d.ts +1 -1
  212. package/dist/ir/type-system/internal/universe/index.d.ts.map +1 -1
  213. package/dist/ir/type-system/internal/universe/index.js +1 -3
  214. package/dist/ir/type-system/internal/universe/index.js.map +1 -1
  215. package/dist/ir/type-system/internal/universe/source-catalog.js +3 -1
  216. package/dist/ir/type-system/internal/universe/source-catalog.js.map +1 -1
  217. package/dist/ir/type-system/internal/universe/types.d.ts +7 -0
  218. package/dist/ir/type-system/internal/universe/types.d.ts.map +1 -1
  219. package/dist/ir/type-system/internal/universe/types.js.map +1 -1
  220. package/dist/ir/type-system/internal/universe/unified-universe.d.ts.map +1 -1
  221. package/dist/ir/type-system/internal/universe/unified-universe.js +16 -1
  222. package/dist/ir/type-system/internal/universe/unified-universe.js.map +1 -1
  223. package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts +2 -0
  224. package/dist/ir/type-system/internal/universe/unified-universe.test.d.ts.map +1 -0
  225. package/dist/ir/type-system/internal/universe/unified-universe.test.js +89 -0
  226. package/dist/ir/type-system/internal/universe/unified-universe.test.js.map +1 -0
  227. package/dist/ir/type-system/type-system-call-resolution.d.ts +69 -0
  228. package/dist/ir/type-system/type-system-call-resolution.d.ts.map +1 -0
  229. package/dist/ir/type-system/type-system-call-resolution.js +1121 -0
  230. package/dist/ir/type-system/type-system-call-resolution.js.map +1 -0
  231. package/dist/ir/type-system/type-system-inference.d.ts +98 -0
  232. package/dist/ir/type-system/type-system-inference.d.ts.map +1 -0
  233. package/dist/ir/type-system/type-system-inference.js +1083 -0
  234. package/dist/ir/type-system/type-system-inference.js.map +1 -0
  235. package/dist/ir/type-system/type-system-relations.d.ts +15 -0
  236. package/dist/ir/type-system/type-system-relations.d.ts.map +1 -0
  237. package/dist/ir/type-system/type-system-relations.js +152 -0
  238. package/dist/ir/type-system/type-system-relations.js.map +1 -0
  239. package/dist/ir/type-system/type-system-state.d.ts +436 -0
  240. package/dist/ir/type-system/type-system-state.d.ts.map +1 -0
  241. package/dist/ir/type-system/type-system-state.js +212 -0
  242. package/dist/ir/type-system/type-system-state.js.map +1 -0
  243. package/dist/ir/type-system/type-system-utilities.d.ts +56 -0
  244. package/dist/ir/type-system/type-system-utilities.d.ts.map +1 -0
  245. package/dist/ir/type-system/type-system-utilities.js +373 -0
  246. package/dist/ir/type-system/type-system-utilities.js.map +1 -0
  247. package/dist/ir/type-system/type-system.d.ts +17 -350
  248. package/dist/ir/type-system/type-system.d.ts.map +1 -1
  249. package/dist/ir/type-system/type-system.js +67 -2764
  250. package/dist/ir/type-system/type-system.js.map +1 -1
  251. package/dist/ir/types/index.d.ts +1 -0
  252. package/dist/ir/types/index.d.ts.map +1 -1
  253. package/dist/ir/types/index.js +1 -0
  254. package/dist/ir/types/index.js.map +1 -1
  255. package/dist/ir/types/ir-substitution.js +1 -1
  256. package/dist/ir/types/ir-substitution.js.map +1 -1
  257. package/dist/ir/types/ir-types.d.ts.map +1 -1
  258. package/dist/ir/types/module.d.ts +11 -0
  259. package/dist/ir/types/module.d.ts.map +1 -1
  260. package/dist/ir/types/statements.d.ts +1 -1
  261. package/dist/ir/types/type-ops.d.ts +9 -0
  262. package/dist/ir/types/type-ops.d.ts.map +1 -0
  263. package/dist/ir/types/type-ops.js +134 -0
  264. package/dist/ir/types/type-ops.js.map +1 -0
  265. package/dist/ir/types/type-ops.test.d.ts +2 -0
  266. package/dist/ir/types/type-ops.test.d.ts.map +1 -0
  267. package/dist/ir/types/type-ops.test.js +73 -0
  268. package/dist/ir/types/type-ops.test.js.map +1 -0
  269. package/dist/ir/validation/anonymous-type-lowering-pass.d.ts.map +1 -1
  270. package/dist/ir/validation/anonymous-type-lowering-pass.js +101 -49
  271. package/dist/ir/validation/anonymous-type-lowering-pass.js.map +1 -1
  272. package/dist/ir/validation/arrow-return-finalization-pass.js +13 -3
  273. package/dist/ir/validation/arrow-return-finalization-pass.js.map +1 -1
  274. package/dist/ir/validation/attribute-collection/arg-extractor.d.ts +58 -0
  275. package/dist/ir/validation/attribute-collection/arg-extractor.d.ts.map +1 -0
  276. package/dist/ir/validation/attribute-collection/arg-extractor.js +284 -0
  277. package/dist/ir/validation/attribute-collection/arg-extractor.js.map +1 -0
  278. package/dist/ir/validation/attribute-collection/marker-parser.d.ts +28 -0
  279. package/dist/ir/validation/attribute-collection/marker-parser.d.ts.map +1 -0
  280. package/dist/ir/validation/attribute-collection/marker-parser.js +404 -0
  281. package/dist/ir/validation/attribute-collection/marker-parser.js.map +1 -0
  282. package/dist/ir/validation/attribute-collection/orchestrator.d.ts +28 -0
  283. package/dist/ir/validation/attribute-collection/orchestrator.d.ts.map +1 -0
  284. package/dist/ir/validation/attribute-collection/orchestrator.js +332 -0
  285. package/dist/ir/validation/attribute-collection/orchestrator.js.map +1 -0
  286. package/dist/ir/validation/attribute-collection-pass.d.ts +1 -23
  287. package/dist/ir/validation/attribute-collection-pass.d.ts.map +1 -1
  288. package/dist/ir/validation/attribute-collection-pass.js +1 -953
  289. package/dist/ir/validation/attribute-collection-pass.js.map +1 -1
  290. package/dist/ir/validation/attribute-collection-pass.test.js +42 -19
  291. package/dist/ir/validation/attribute-collection-pass.test.js.map +1 -1
  292. package/dist/ir/validation/char-validation-pass.d.ts.map +1 -1
  293. package/dist/ir/validation/char-validation-pass.js +6 -3
  294. package/dist/ir/validation/char-validation-pass.js.map +1 -1
  295. package/dist/ir/validation/numeric-coercion-pass.d.ts.map +1 -1
  296. package/dist/ir/validation/numeric-coercion-pass.js.map +1 -1
  297. package/dist/ir/validation/numeric-invariants.test.js +46 -0
  298. package/dist/ir/validation/numeric-invariants.test.js.map +1 -1
  299. package/dist/ir/validation/numeric-proof-pass.d.ts.map +1 -1
  300. package/dist/ir/validation/numeric-proof-pass.js +68 -1
  301. package/dist/ir/validation/numeric-proof-pass.js.map +1 -1
  302. package/dist/ir/validation/rest-type-synthesis-pass.js +1 -1
  303. package/dist/ir/validation/rest-type-synthesis-pass.js.map +1 -1
  304. package/dist/ir/validation/soundness-gate.d.ts.map +1 -1
  305. package/dist/ir/validation/soundness-gate.js +8 -5
  306. package/dist/ir/validation/soundness-gate.js.map +1 -1
  307. package/dist/ir/validation/soundness-gate.test.js +158 -0
  308. package/dist/ir/validation/soundness-gate.test.js.map +1 -1
  309. package/dist/ir/validation/yield-lowering-pass.d.ts +11 -5
  310. package/dist/ir/validation/yield-lowering-pass.d.ts.map +1 -1
  311. package/dist/ir/validation/yield-lowering-pass.js +942 -48
  312. package/dist/ir/validation/yield-lowering-pass.js.map +1 -1
  313. package/dist/ir/validation/yield-lowering-pass.test.js +1333 -127
  314. package/dist/ir/validation/yield-lowering-pass.test.js.map +1 -1
  315. package/dist/program/binding-loader.d.ts +37 -0
  316. package/dist/program/binding-loader.d.ts.map +1 -0
  317. package/dist/program/binding-loader.js +155 -0
  318. package/dist/program/binding-loader.js.map +1 -0
  319. package/dist/program/binding-registry.d.ts +106 -0
  320. package/dist/program/binding-registry.d.ts.map +1 -0
  321. package/dist/program/binding-registry.js +590 -0
  322. package/dist/program/binding-registry.js.map +1 -0
  323. package/dist/program/binding-types.d.ts +166 -0
  324. package/dist/program/binding-types.d.ts.map +1 -0
  325. package/dist/program/binding-types.js +57 -0
  326. package/dist/program/binding-types.js.map +1 -0
  327. package/dist/program/bindings.d.ts +6 -271
  328. package/dist/program/bindings.d.ts.map +1 -1
  329. package/dist/program/bindings.js +7 -781
  330. package/dist/program/bindings.js.map +1 -1
  331. package/dist/program/clr-bindings-discovery.d.ts +19 -0
  332. package/dist/program/clr-bindings-discovery.d.ts.map +1 -0
  333. package/dist/program/clr-bindings-discovery.js +150 -0
  334. package/dist/program/clr-bindings-discovery.js.map +1 -0
  335. package/dist/program/clr-bindings-discovery.test.d.ts +2 -0
  336. package/dist/program/clr-bindings-discovery.test.d.ts.map +1 -0
  337. package/dist/program/clr-bindings-discovery.test.js +119 -0
  338. package/dist/program/clr-bindings-discovery.test.js.map +1 -0
  339. package/dist/program/creation.d.ts.map +1 -1
  340. package/dist/program/creation.js +2 -1
  341. package/dist/program/creation.js.map +1 -1
  342. package/dist/program/creation.test.js.map +1 -1
  343. package/dist/program/dependency-graph.d.ts +2 -2
  344. package/dist/program/dependency-graph.d.ts.map +1 -1
  345. package/dist/program/dependency-graph.js +26 -42
  346. package/dist/program/dependency-graph.js.map +1 -1
  347. package/dist/resolver/clr-bindings-resolver.d.ts +0 -1
  348. package/dist/resolver/clr-bindings-resolver.d.ts.map +1 -1
  349. package/dist/resolver/clr-bindings-resolver.js +22 -30
  350. package/dist/resolver/clr-bindings-resolver.js.map +1 -1
  351. package/dist/resolver/clr-bindings-resolver.test.js +0 -27
  352. package/dist/resolver/clr-bindings-resolver.test.js.map +1 -1
  353. package/dist/resolver/import-resolution.d.ts +1 -1
  354. package/dist/resolver/import-resolution.d.ts.map +1 -1
  355. package/dist/resolver/import-resolution.js +2 -7
  356. package/dist/resolver/import-resolution.js.map +1 -1
  357. package/dist/resolver/namespace.d.ts.map +1 -1
  358. package/dist/resolver/namespace.js +1 -3
  359. package/dist/resolver/namespace.js.map +1 -1
  360. package/dist/resolver/naming.d.ts.map +1 -1
  361. package/dist/resolver/naming.js +1 -0
  362. package/dist/resolver/naming.js.map +1 -1
  363. package/dist/tsbindgen/names.d.ts.map +1 -1
  364. package/dist/tsbindgen/names.js +4 -2
  365. package/dist/tsbindgen/names.js.map +1 -1
  366. package/dist/types/diagnostic.d.ts +1 -1
  367. package/dist/types/diagnostic.d.ts.map +1 -1
  368. package/dist/types/diagnostic.js.map +1 -1
  369. package/dist/validation/core-intrinsics.d.ts.map +1 -1
  370. package/dist/validation/core-intrinsics.js +3 -1
  371. package/dist/validation/core-intrinsics.js.map +1 -1
  372. package/dist/validation/extension-methods.d.ts.map +1 -1
  373. package/dist/validation/extension-methods.js.map +1 -1
  374. package/dist/validation/features.d.ts.map +1 -1
  375. package/dist/validation/features.js +38 -13
  376. package/dist/validation/features.js.map +1 -1
  377. package/dist/validation/features.test.d.ts +2 -0
  378. package/dist/validation/features.test.d.ts.map +1 -0
  379. package/dist/validation/features.test.js +273 -0
  380. package/dist/validation/features.test.js.map +1 -0
  381. package/dist/validation/generics.d.ts +1 -1
  382. package/dist/validation/generics.d.ts.map +1 -1
  383. package/dist/validation/generics.js +2 -26
  384. package/dist/validation/generics.js.map +1 -1
  385. package/dist/validation/imports.d.ts.map +1 -1
  386. package/dist/validation/imports.js +2 -1
  387. package/dist/validation/imports.js.map +1 -1
  388. package/dist/validation/imports.test.d.ts +2 -0
  389. package/dist/validation/imports.test.d.ts.map +1 -0
  390. package/dist/validation/imports.test.js +112 -0
  391. package/dist/validation/imports.test.js.map +1 -0
  392. package/dist/validation/static-safety.d.ts +6 -6
  393. package/dist/validation/static-safety.d.ts.map +1 -1
  394. package/dist/validation/static-safety.js +163 -94
  395. package/dist/validation/static-safety.js.map +1 -1
  396. package/dist/validation/unsupported-utility-types.d.ts +3 -3
  397. package/dist/validation/unsupported-utility-types.d.ts.map +1 -1
  398. package/dist/validation/unsupported-utility-types.js +4 -7
  399. package/dist/validation/unsupported-utility-types.js.map +1 -1
  400. package/dist/validator.maximus.test.d.ts +2 -0
  401. package/dist/validator.maximus.test.d.ts.map +1 -0
  402. package/dist/validator.maximus.test.js +1214 -0
  403. package/dist/validator.maximus.test.js.map +1 -0
  404. package/dist/validator.test.js +152 -18
  405. package/dist/validator.test.js.map +1 -1
  406. package/package.json +1 -1
  407. package/dist/ir/converters/statements/declarations/registry.d.ts +0 -96
  408. package/dist/ir/converters/statements/declarations/registry.d.ts.map +0 -1
  409. package/dist/ir/converters/statements/declarations/registry.js +0 -130
  410. package/dist/ir/converters/statements/declarations/registry.js.map +0 -1
  411. package/dist/ir/this-parameter-inference.test.d.ts +0 -13
  412. package/dist/ir/this-parameter-inference.test.d.ts.map +0 -1
  413. package/dist/ir/this-parameter-inference.test.js +0 -165
  414. package/dist/ir/this-parameter-inference.test.js.map +0 -1
  415. package/dist/metadata/bindings-loader.d.ts +0 -41
  416. package/dist/metadata/bindings-loader.d.ts.map +0 -1
  417. package/dist/metadata/bindings-loader.js +0 -308
  418. package/dist/metadata/bindings-loader.js.map +0 -1
  419. package/dist/metadata/bindings-loader.test.d.ts +0 -5
  420. package/dist/metadata/bindings-loader.test.d.ts.map +0 -1
  421. package/dist/metadata/bindings-loader.test.js +0 -117
  422. package/dist/metadata/bindings-loader.test.js.map +0 -1
  423. package/dist/metadata/index.d.ts +0 -8
  424. package/dist/metadata/index.d.ts.map +0 -1
  425. package/dist/metadata/index.js +0 -7
  426. package/dist/metadata/index.js.map +0 -1
  427. package/dist/metadata/library-loader.d.ts +0 -42
  428. package/dist/metadata/library-loader.d.ts.map +0 -1
  429. package/dist/metadata/library-loader.js +0 -126
  430. package/dist/metadata/library-loader.js.map +0 -1
  431. package/dist/metadata/loader.d.ts +0 -26
  432. package/dist/metadata/loader.d.ts.map +0 -1
  433. package/dist/metadata/loader.js +0 -333
  434. package/dist/metadata/loader.js.map +0 -1
  435. package/dist/metadata/loader.test.d.ts +0 -5
  436. package/dist/metadata/loader.test.d.ts.map +0 -1
  437. package/dist/metadata/loader.test.js +0 -119
  438. package/dist/metadata/loader.test.js.map +0 -1
  439. package/dist/resolver/naming-policy.d.ts +0 -20
  440. package/dist/resolver/naming-policy.d.ts.map +0 -1
  441. package/dist/resolver/naming-policy.js +0 -40
  442. package/dist/resolver/naming-policy.js.map +0 -1
  443. package/dist/types/bindings.d.ts +0 -153
  444. package/dist/types/bindings.d.ts.map +0 -1
  445. package/dist/types/bindings.js +0 -14
  446. package/dist/types/bindings.js.map +0 -1
  447. package/dist/types/metadata.d.ts +0 -196
  448. package/dist/types/metadata.d.ts.map +0 -1
  449. package/dist/types/metadata.js +0 -10
  450. package/dist/types/metadata.js.map +0 -1
  451. package/dist/types/nested-types.d.ts +0 -111
  452. package/dist/types/nested-types.d.ts.map +0 -1
  453. package/dist/types/nested-types.js +0 -176
  454. package/dist/types/nested-types.js.map +0 -1
  455. package/dist/types/nested-types.test.d.ts +0 -5
  456. package/dist/types/nested-types.test.d.ts.map +0 -1
  457. package/dist/types/nested-types.test.js +0 -135
  458. package/dist/types/nested-types.test.js.map +0 -1
  459. package/dist/types/ref-parameters.d.ts +0 -123
  460. package/dist/types/ref-parameters.d.ts.map +0 -1
  461. package/dist/types/ref-parameters.js +0 -203
  462. package/dist/types/ref-parameters.js.map +0 -1
  463. package/dist/types/ref-parameters.test.d.ts +0 -5
  464. package/dist/types/ref-parameters.test.d.ts.map +0 -1
  465. package/dist/types/ref-parameters.test.js +0 -147
  466. package/dist/types/ref-parameters.test.js.map +0 -1
@@ -10,57 +10,30 @@
10
10
  * - INV-1: No convertType/getHandleRegistry outside TypeAuthority
11
11
  * - INV-2: Deterministic type sources only
12
12
  * - INV-3: Poison-on-missing-types (return unknownType + emit diagnostic)
13
- */
14
- import * as ts from "typescript";
15
- import { substituteIrType as irSubstitute, } from "../types/ir-substitution.js";
16
- import { inferNumericKindFromRaw } from "../types/numeric-helpers.js";
17
- import { getBinaryResultKind, TSONIC_TO_NUMERIC_KIND, } from "../types/numeric-kind.js";
18
- // ═══════════════════════════════════════════════════════════════════════════
19
- // BUILTIN NOMINAL MAPPING
20
- // ═══════════════════════════════════════════════════════════════════════════
21
- /**
22
- * Mapping from primitive type names to their nominal type names.
23
13
  *
24
- * Used by typeOfMember to look up members on primitives.
25
- * e.g., `"hello".length` String.length
14
+ * DAG position: orchestrator imports all split modules, constructs state,
15
+ * returns TypeAuthority with functions bound to shared state.
26
16
  */
27
- export const BUILTIN_NOMINALS = {
28
- string: "String",
29
- number: "Number",
30
- boolean: "Boolean",
31
- bigint: "BigInt",
32
- symbol: "Symbol",
33
- };
17
+ export { BUILTIN_NOMINALS, poisonedCall } from "./type-system-state.js";
18
+ // Import split module functions
19
+ import { substitute as relSubstitute, instantiate as relInstantiate, isAssignableTo as relIsAssignableTo, typesEqual as relTypesEqual, containsTypeParameter as relContainsTypeParameter, } from "./type-system-relations.js";
20
+ import { resolveCall as crResolveCall, delegateToFunctionType as crDelegateToFunctionType, } from "./type-system-call-resolution.js";
21
+ import { typeOfDecl as infTypeOfDecl, typeOfMember as infTypeOfMember, getIndexerInfo as infGetIndexerInfo, typeOfMemberId as infTypeOfMemberId, getFQNameOfDecl as infGetFQNameOfDecl, isTypeDecl as infIsTypeDecl, isInterfaceDecl as infIsInterfaceDecl, isTypeAliasToObjectLiteral as infIsTypeAliasToObjectLiteral, signatureHasConditionalReturn as infSignatureHasConditionalReturn, signatureHasVariadicTypeParams as infSignatureHasVariadicTypeParams, declHasTypeAnnotation as infDeclHasTypeAnnotation, checkTsClassMemberOverride as infCheckTsClassMemberOverride, hasTypeParameters as infHasTypeParameters, typeFromSyntax as infTypeFromSyntax, } from "./type-system-inference.js";
22
+ import { expandUtility as utExpandUtility } from "./type-system-utilities.js";
34
23
  // ═══════════════════════════════════════════════════════════════════════════
35
- // POISON VALUES
24
+ // TYPESYSTEM FACTORY — Orchestrator
36
25
  // ═══════════════════════════════════════════════════════════════════════════
37
- /** Poison type for undeterminable types */
38
- export const unknownType = { kind: "unknownType" };
39
- /** Poison type for impossible types */
40
- export const neverType = { kind: "neverType" };
41
- /** Void type for functions with no return */
42
- export const voidType = { kind: "voidType" };
43
- /**
44
- * Create a poisoned ResolvedCall with correct arity.
45
- *
46
- * CRITICAL (Alice's spec): Empty arrays are ILLEGAL.
47
- * Poisoned results must have correct arity so callers cannot
48
- * detect failure via `length === 0` and fall back to legacy.
49
- *
50
- * @param arity Number of parameters/arguments (from CallQuery.argumentCount)
51
- * @param diagnostics Diagnostics explaining why resolution failed
52
- */
53
- export const poisonedCall = (arity, diagnostics) => ({
54
- parameterTypes: Array(arity).fill(unknownType),
55
- parameterModes: Array(arity).fill("value"),
56
- returnType: unknownType,
57
- diagnostics,
58
- });
59
26
  /**
60
27
  * Create a TypeSystem instance with internal caches.
61
28
  *
62
29
  * This is the single factory for TypeSystem. All type queries go through
63
30
  * the returned TypeSystem instance.
31
+ *
32
+ * Constructs the shared TypeSystemState and delegates to split modules:
33
+ * - type-system-relations.ts: substitute, instantiate, isAssignableTo, typesEqual, containsTypeParameter
34
+ * - type-system-call-resolution.ts: resolveCall, delegateToFunctionType, convertTypeNode
35
+ * - type-system-inference.ts: typeOfDecl, typeOfMember, getIndexerInfo, and declaration queries
36
+ * - type-system-utilities.ts: expandUtility
64
37
  */
65
38
  export const createTypeSystem = (config) => {
66
39
  const { handleRegistry, typeRegistry, nominalEnv, convertTypeNode: convertTypeNodeRaw, unifiedCatalog, aliasTable, resolveIdentifier, resolveCallSignature, resolveConstructorSignature, } = config;
@@ -96,2733 +69,63 @@ export const createTypeSystem = (config) => {
96
69
  */
97
70
  const diagnostics = [];
98
71
  // ─────────────────────────────────────────────────────────────────────────
99
- // DIAGNOSTIC HELPERS
100
- // ─────────────────────────────────────────────────────────────────────────
101
- const emitDiagnostic = (code, message, site) => {
102
- const location = site?.file !== undefined &&
103
- site?.line !== undefined &&
104
- site?.column !== undefined
105
- ? {
106
- file: site.file,
107
- line: site.line,
108
- column: site.column,
109
- length: 1, // Default length
110
- }
111
- : undefined;
112
- diagnostics.push({
113
- code,
114
- severity: "error",
115
- message,
116
- location,
117
- });
118
- };
119
- // ─────────────────────────────────────────────────────────────────────────
120
- // CACHE KEY HELPERS
121
- // ─────────────────────────────────────────────────────────────────────────
122
- /**
123
- * Create a cache key for member type lookup.
124
- */
125
- const makeMemberCacheKey = (fqName, memberName, typeArgs) => {
126
- if (typeArgs && typeArgs.length > 0) {
127
- return `${fqName}:${memberName}:${JSON.stringify(typeArgs)}`;
128
- }
129
- return `${fqName}:${memberName}`;
130
- };
131
- /**
132
- * Create a cache key for nominal lookup.
133
- */
134
- const makeNominalLookupKey = (fqName, typeArgs, memberName) => {
135
- return `${fqName}:${JSON.stringify(typeArgs)}:${memberName}`;
136
- };
137
- // Helper to check if type is null/undefined primitive
138
- const isNullishPrimitive = (t) => {
139
- return (t.kind === "primitiveType" &&
140
- (t.name === "null" || t.name === "undefined"));
141
- };
142
- // Use makeNominalLookupKey to suppress unused warning
143
- void makeNominalLookupKey;
144
- // ─────────────────────────────────────────────────────────────────────────
145
- // RAW SIGNATURE EXTRACTION
146
- // ─────────────────────────────────────────────────────────────────────────
147
- /**
148
- * Get or compute raw signature info from SignatureId.
149
- * Caches the result for subsequent calls.
150
- */
151
- const getRawSignature = (sigId) => {
152
- const cached = signatureRawCache.get(sigId.id);
153
- if (cached)
154
- return cached;
155
- const sigInfo = handleRegistry.getSignature(sigId);
156
- if (!sigInfo)
157
- return undefined;
158
- // Convert parameter types from TypeNodes to IrTypes
159
- const parameterTypes = sigInfo.parameters.map((p) => (p.typeNode ? convertTypeNode(p.typeNode) : undefined));
160
- // Convert a TypeScript `this:` parameter type (if present) to an IrType.
161
- const thisParameterType = (() => {
162
- const n = sigInfo.thisTypeNode;
163
- return n ? convertTypeNode(n) : undefined;
164
- })();
165
- // Extract parameter modes
166
- const parameterModes = sigInfo.parameters.map((p) => p.mode ?? "value");
167
- // Extract parameter names
168
- const parameterNames = sigInfo.parameters.map((p) => p.name);
169
- // Extract type parameters
170
- const typeParameters = (sigInfo.typeParameters ?? []).map((tp) => ({
171
- name: tp.name,
172
- constraint: tp.constraintNode
173
- ? convertTypeNode(tp.constraintNode)
174
- : undefined,
175
- defaultType: tp.defaultNode ? convertTypeNode(tp.defaultNode) : undefined,
176
- }));
177
- const isConstructor = sigInfo.declaringMemberName === "constructor";
178
- // Convert return type
179
- const returnType = (() => {
180
- if (sigInfo.returnTypeNode)
181
- return convertTypeNode(sigInfo.returnTypeNode);
182
- // Class constructor declarations do not have return type annotations in TS syntax.
183
- // Deterministically synthesize the constructed instance type using the declaring
184
- // identity captured in Binding and the (class) type parameters captured for the
185
- // constructor signature.
186
- if (isConstructor && sigInfo.declaringTypeTsName) {
187
- const typeArguments = typeParameters.map((tp) => ({
188
- kind: "typeParameterType",
189
- name: tp.name,
190
- }));
191
- return {
192
- kind: "referenceType",
193
- name: sigInfo.declaringTypeTsName,
194
- ...(typeArguments.length > 0 ? { typeArguments } : {}),
195
- };
196
- }
197
- return voidType;
198
- })();
199
- // Extract type predicate (already extracted in Binding at registration time)
200
- let typePredicate;
201
- if (sigInfo.typePredicate) {
202
- const pred = sigInfo.typePredicate;
203
- const targetType = convertTypeNode(pred.targetTypeNode);
204
- if (pred.kind === "param") {
205
- typePredicate = {
206
- kind: "param",
207
- parameterIndex: pred.parameterIndex,
208
- targetType,
209
- };
210
- }
211
- else {
212
- typePredicate = {
213
- kind: "this",
214
- targetType,
215
- };
216
- }
217
- }
218
- const rawSig = {
219
- parameterTypes,
220
- thisParameterType,
221
- returnType,
222
- parameterModes,
223
- typeParameters,
224
- parameterNames,
225
- typePredicate,
226
- declaringTypeTsName: sigInfo.declaringTypeTsName,
227
- declaringMemberName: sigInfo.declaringMemberName,
228
- };
229
- signatureRawCache.set(sigId.id, rawSig);
230
- return rawSig;
231
- };
232
- // ─────────────────────────────────────────────────────────────────────────
233
- // STEP 5: TYPESYSTEM ALGORITHM IMPLEMENTATIONS
234
- // ─────────────────────────────────────────────────────────────────────────
235
- /**
236
- * Resolve a surface name to a canonical TypeId.
237
- *
238
- * Order:
239
- * 1) AliasTable (primitives/globals/System.* canonicalization)
240
- * 2) UnifiedTypeCatalog by tsName
241
- * 3) UnifiedTypeCatalog by clrName
242
- *
243
- * IMPORTANT (airplane-grade):
244
- * Resolution must be arity-aware when type arguments are present. Facade
245
- * types often omit the `_N` generic arity suffix (e.g. `IList<T>` is a
246
- * facade over `IList_1<T>`). When `arity` is provided and the direct
247
- * resolution doesn't match, we deterministically try `<name>_<arity>`.
248
- */
249
- const resolveTypeIdByName = (name, arity) => {
250
- const direct = aliasTable.get(name) ??
251
- unifiedCatalog.resolveTsName(name) ??
252
- unifiedCatalog.resolveClrName(name);
253
- if (arity === undefined)
254
- return direct;
255
- if (direct) {
256
- const directArity = unifiedCatalog.getTypeParameters(direct).length;
257
- if (directArity === arity)
258
- return direct;
259
- }
260
- // Facade name without arity suffix → try tsbindgen's structural encoding.
261
- if (arity > 0) {
262
- const suffixed = `${name}_${arity}`;
263
- const candidate = aliasTable.get(suffixed) ??
264
- unifiedCatalog.resolveTsName(suffixed) ??
265
- unifiedCatalog.resolveClrName(suffixed);
266
- if (candidate) {
267
- const candidateArity = unifiedCatalog.getTypeParameters(candidate).length;
268
- if (candidateArity === arity)
269
- return candidate;
270
- }
271
- }
272
- return undefined;
273
- };
274
- /**
275
- * Attach canonical TypeIds to IR types where possible.
276
- *
277
- * This keeps nominal identity stable throughout the pipeline and enables
278
- * emit-time resolution without relying on string name matching.
279
- */
280
- const attachParameterTypeIds = (p) => ({
281
- ...p,
282
- type: p.type ? attachTypeIds(p.type) : undefined,
283
- });
284
- const attachTypeParameterTypeIds = (tp) => ({
285
- ...tp,
286
- constraint: tp.constraint ? attachTypeIds(tp.constraint) : undefined,
287
- default: tp.default ? attachTypeIds(tp.default) : undefined,
288
- structuralMembers: tp.structuralMembers?.map(attachInterfaceMemberTypeIds),
289
- });
290
- const attachInterfaceMemberTypeIds = (m) => {
291
- if (m.kind === "propertySignature") {
292
- return { ...m, type: attachTypeIds(m.type) };
293
- }
294
- return {
295
- ...m,
296
- typeParameters: m.typeParameters?.map(attachTypeParameterTypeIds),
297
- parameters: m.parameters.map(attachParameterTypeIds),
298
- returnType: m.returnType ? attachTypeIds(m.returnType) : undefined,
299
- };
300
- };
301
- const attachTypeIds = (type) => {
302
- switch (type.kind) {
303
- case "referenceType": {
304
- const typeId = type.typeId ??
305
- resolveTypeIdByName(type.resolvedClrType ?? type.name, type.typeArguments?.length);
306
- return {
307
- ...type,
308
- ...(type.typeArguments
309
- ? { typeArguments: type.typeArguments.map(attachTypeIds) }
310
- : {}),
311
- ...(type.structuralMembers
312
- ? {
313
- structuralMembers: type.structuralMembers.map(attachInterfaceMemberTypeIds),
314
- }
315
- : {}),
316
- ...(typeId ? { typeId } : {}),
317
- };
318
- }
319
- case "arrayType":
320
- return { ...type, elementType: attachTypeIds(type.elementType) };
321
- case "tupleType":
322
- return {
323
- ...type,
324
- elementTypes: type.elementTypes.map(attachTypeIds),
325
- };
326
- case "functionType":
327
- return {
328
- ...type,
329
- parameters: type.parameters.map(attachParameterTypeIds),
330
- returnType: attachTypeIds(type.returnType),
331
- };
332
- case "objectType":
333
- return {
334
- ...type,
335
- members: type.members.map(attachInterfaceMemberTypeIds),
336
- };
337
- case "dictionaryType":
338
- return {
339
- ...type,
340
- keyType: attachTypeIds(type.keyType),
341
- valueType: attachTypeIds(type.valueType),
342
- };
343
- case "unionType":
344
- case "intersectionType":
345
- return { ...type, types: type.types.map(attachTypeIds) };
346
- default:
347
- return type;
348
- }
349
- };
350
- /**
351
- * Deterministic type syntax conversion with canonical TypeId attachment.
352
- *
353
- * The underlying converter is syntax-only; this wrapper re-attaches the
354
- * nominal identity from the UnifiedUniverse so downstream passes (including
355
- * the emitter) can resolve CLR types without re-driving a parallel lookup.
356
- */
357
- const convertTypeNode = (node) => {
358
- return attachTypeIds(convertTypeNodeRaw(node));
359
- };
360
- /**
361
- * Normalize a receiver type to nominal form for member lookup.
362
- *
363
- * Phase 6: Returns TypeId + typeArgs for TypeId-based NominalEnv.
364
- *
365
- * ALICE'S RULE R3: Primitive-to-nominal bridging is part of TypeSystem.
366
- */
367
- const normalizeToNominal = (type) => {
368
- if (type.kind === "referenceType") {
369
- const arity = type.typeArguments?.length;
370
- const typeId = type.typeId ??
371
- (type.resolvedClrType
372
- ? resolveTypeIdByName(type.resolvedClrType, arity)
373
- : undefined) ??
374
- resolveTypeIdByName(type.name, arity);
375
- if (!typeId)
376
- return undefined;
377
- return { typeId, typeArgs: type.typeArguments ?? [] };
378
- }
379
- if (type.kind === "primitiveType") {
380
- const typeId = resolveTypeIdByName(type.name, 0);
381
- if (!typeId)
382
- return undefined;
383
- return { typeId, typeArgs: [] };
384
- }
385
- if (type.kind === "arrayType") {
386
- const arrayTypeId = resolveTypeIdByName("Array", 1);
387
- if (!arrayTypeId)
388
- return undefined;
389
- return { typeId: arrayTypeId, typeArgs: [type.elementType] };
390
- }
391
- return undefined;
392
- };
393
- /**
394
- * Convert a nominal CLR delegate type to an IrFunctionType by reading its Invoke signature.
395
- *
396
- * This is used for deterministic lambda typing when the expected type is a delegate
397
- * (e.g., custom delegates from CLR metadata).
398
- */
399
- const delegateToFunctionType = (type) => {
400
- // Expression<TDelegate> wrapper: treat as its underlying delegate type for
401
- // deterministic lambda contextual typing.
402
- //
403
- // This models C#'s implicit lambda conversion to Expression<Func<...>>:
404
- // the TypeScript surface uses Expression<TDelegate>, but lambdas should be
405
- // typed against the delegate shape.
406
- if (type.kind === "referenceType" &&
407
- type.name === "Expression_1" &&
408
- (type.typeArguments?.length ?? 0) === 1) {
409
- const inner = type.typeArguments?.[0];
410
- if (!inner)
411
- return undefined;
412
- if (inner.kind === "functionType")
413
- return inner;
414
- return delegateToFunctionType(inner);
415
- }
416
- const normalized = normalizeToNominal(type);
417
- if (!normalized)
418
- return undefined;
419
- const entry = unifiedCatalog.getByTypeId(normalized.typeId);
420
- if (!entry || entry.kind !== "delegate")
421
- return undefined;
422
- const invokeMember = unifiedCatalog.getMember(normalized.typeId, "Invoke") ??
423
- unifiedCatalog.getMember(normalized.typeId, "invoke");
424
- const invokeSig = invokeMember?.signatures?.[0];
425
- if (!invokeSig)
426
- return undefined;
427
- const typeParams = unifiedCatalog.getTypeParameters(normalized.typeId);
428
- const subst = new Map();
429
- for (let i = 0; i < Math.min(typeParams.length, normalized.typeArgs.length); i++) {
430
- const tp = typeParams[i];
431
- const arg = normalized.typeArgs[i];
432
- if (tp && arg)
433
- subst.set(tp.name, arg);
434
- }
435
- const substitute = (t) => subst.size > 0 ? irSubstitute(t, subst) : t;
436
- const parameters = invokeSig.parameters.map((p) => {
437
- const paramType = substitute(p.type);
438
- return {
439
- kind: "parameter",
440
- pattern: {
441
- kind: "identifierPattern",
442
- name: p.name,
443
- ...(paramType ? { type: paramType } : {}),
444
- },
445
- type: paramType,
446
- initializer: undefined,
447
- isOptional: p.isOptional,
448
- isRest: p.isRest,
449
- passing: p.mode,
450
- };
451
- });
452
- return {
453
- kind: "functionType",
454
- parameters,
455
- returnType: substitute(invokeSig.returnType),
456
- };
457
- };
458
- /**
459
- * Look up a member on a structural (object) type.
460
- */
461
- const lookupStructuralMember = (type, memberName, site) => {
462
- if (type.kind === "objectType") {
463
- const member = type.members.find((m) => m.name === memberName);
464
- if (member) {
465
- if (member.kind === "propertySignature") {
466
- return member.type;
467
- }
468
- // Method signature - return function type using the same parameters
469
- if (member.kind === "methodSignature") {
470
- const funcType = {
471
- kind: "functionType",
472
- parameters: member.parameters,
473
- returnType: member.returnType ?? voidType,
474
- };
475
- return funcType;
476
- }
477
- }
478
- }
479
- if (type.kind === "referenceType" &&
480
- type.structuralMembers &&
481
- type.structuralMembers.length > 0) {
482
- const member = type.structuralMembers.find((m) => m.name === memberName);
483
- if (member) {
484
- if (member.kind === "propertySignature") {
485
- return member.type;
486
- }
487
- if (member.kind === "methodSignature") {
488
- const funcType = {
489
- kind: "functionType",
490
- parameters: member.parameters,
491
- returnType: member.returnType ?? voidType,
492
- };
493
- return funcType;
494
- }
495
- }
496
- }
497
- emitDiagnostic("TSN5203", `Member '${memberName}' not found on structural type`, site);
498
- return unknownType;
499
- };
500
- /**
501
- * Compute receiver substitution for a method call.
502
- *
503
- * Given a receiver type (e.g., Array<string>) and a declaring type's TS name,
504
- * computes the substitution map for class type parameters.
505
- *
506
- * Phase 6: Uses TypeId-based NominalEnv.getInstantiation().
507
- */
508
- const computeReceiverSubstitution = (receiverType, declaringTypeTsName, _declaringMemberName) => {
509
- const normalized = normalizeToNominal(receiverType);
510
- if (!normalized)
511
- return undefined;
512
- const declaringTypeId = resolveTypeIdByName(declaringTypeTsName);
513
- if (!declaringTypeId)
514
- return undefined;
515
- return nominalEnv.getInstantiation(normalized.typeId, normalized.typeArgs, declaringTypeId);
516
- };
517
- // ─────────────────────────────────────────────────────────────────────────
518
- // typeOfDecl — Get declared type of a declaration
519
- // ─────────────────────────────────────────────────────────────────────────
520
- /**
521
- * Derive IrType from NumericKind (deterministic, no TypeScript).
522
- * Mirrors the logic in literals.ts deriveTypeFromNumericIntent.
523
- */
524
- const deriveTypeFromNumericKind = (kind) => {
525
- if (kind === "Int32")
526
- return { kind: "referenceType", name: "int" };
527
- if (kind === "Int64")
528
- return { kind: "referenceType", name: "long" };
529
- if (kind === "Double")
530
- return { kind: "primitiveType", name: "number" };
531
- if (kind === "Single")
532
- return { kind: "referenceType", name: "float" };
533
- if (kind === "Byte")
534
- return { kind: "referenceType", name: "byte" };
535
- if (kind === "Int16")
536
- return { kind: "referenceType", name: "short" };
537
- if (kind === "UInt32")
538
- return { kind: "referenceType", name: "uint" };
539
- if (kind === "UInt64")
540
- return { kind: "referenceType", name: "ulong" };
541
- if (kind === "UInt16")
542
- return { kind: "referenceType", name: "ushort" };
543
- if (kind === "SByte")
544
- return { kind: "referenceType", name: "sbyte" };
545
- // Default to double for unknown
546
- return { kind: "primitiveType", name: "number" };
547
- };
548
- const unwrapParens = (expr) => {
549
- let current = expr;
550
- while (ts.isParenthesizedExpression(current)) {
551
- current = current.expression;
552
- }
553
- return current;
554
- };
555
- const isLambdaExpression = (expr) => {
556
- const unwrapped = unwrapParens(expr);
557
- return ts.isArrowFunction(unwrapped) || ts.isFunctionExpression(unwrapped);
558
- };
559
- const getNumericKindFromIrType = (type) => {
560
- if (type.kind === "primitiveType" && type.name === "number")
561
- return "Double";
562
- if (type.kind === "primitiveType") {
563
- return TSONIC_TO_NUMERIC_KIND.get(type.name);
564
- }
565
- if (type.kind === "referenceType") {
566
- return TSONIC_TO_NUMERIC_KIND.get(type.name);
567
- }
568
- return undefined;
569
- };
570
- const stripNullishForInference = (type) => {
571
- if (isNullishPrimitive(type))
572
- return undefined;
573
- if (type.kind !== "unionType")
574
- return type;
575
- const filtered = type.types.filter((t) => !isNullishPrimitive(t));
576
- if (filtered.length === 0)
577
- return undefined;
578
- if (filtered.length === 1 && filtered[0])
579
- return filtered[0];
580
- return { kind: "unionType", types: filtered };
581
- };
582
- const unwrapAwaitedForInference = (type) => {
583
- if (type.kind === "unionType") {
584
- return {
585
- kind: "unionType",
586
- types: type.types.map((t) => (t ? unwrapAwaitedForInference(t) : t)),
587
- };
588
- }
589
- if (type.kind === "referenceType" &&
590
- (type.name === "Promise" || type.name === "PromiseLike")) {
591
- const inner = type.typeArguments?.[0];
592
- if (inner)
593
- return unwrapAwaitedForInference(inner);
594
- }
595
- if (type.kind === "referenceType") {
596
- const clrName = type.typeId?.clrName;
597
- if (clrName === "System.Threading.Tasks.Task" ||
598
- clrName === "System.Threading.Tasks.ValueTask") {
599
- return voidType;
600
- }
601
- if (clrName?.startsWith("System.Threading.Tasks.Task`") ||
602
- clrName?.startsWith("System.Threading.Tasks.ValueTask`")) {
603
- const inner = type.typeArguments?.[0];
604
- if (inner)
605
- return unwrapAwaitedForInference(inner);
606
- }
607
- }
608
- return type;
609
- };
610
- /**
611
- * Deterministically infer an expression's type using only:
612
- * - local lambda parameter environment
613
- * - declaration types (typeOfDecl)
614
- * - numeric literal lexeme rules
615
- *
616
- * This is intentionally small: it's used only to type lambda bodies for
617
- * initializer-driven generic inference (e.g., `Enumerable.select(..., x => x * 2)`).
618
- */
619
- const inferExpressionType = (expr, env) => {
620
- const unwrapped = unwrapParens(expr);
621
- if (ts.isAsExpression(unwrapped) ||
622
- ts.isTypeAssertionExpression(unwrapped)) {
623
- return convertTypeNode(unwrapped.type);
624
- }
625
- if (ts.isNonNullExpression(unwrapped)) {
626
- const inner = inferExpressionType(unwrapped.expression, env);
627
- if (!inner || inner.kind === "unknownType")
628
- return undefined;
629
- return stripNullishForInference(inner);
630
- }
631
- if (ts.isAwaitExpression(unwrapped)) {
632
- const inner = inferExpressionType(unwrapped.expression, env);
633
- if (!inner || inner.kind === "unknownType")
634
- return undefined;
635
- return unwrapAwaitedForInference(inner);
636
- }
637
- if (ts.isCallExpression(unwrapped)) {
638
- return tryInferReturnTypeFromCallExpression(unwrapped, env);
639
- }
640
- if (ts.isNewExpression(unwrapped)) {
641
- const sigId = resolveConstructorSignature(unwrapped);
642
- if (!sigId)
643
- return undefined;
644
- const explicitTypeArgs = unwrapped.typeArguments && unwrapped.typeArguments.length > 0
645
- ? unwrapped.typeArguments.map((ta) => convertTypeNode(ta))
646
- : undefined;
647
- const argumentCount = unwrapped.arguments?.length ?? 0;
648
- const argTypesWorking = Array(argumentCount).fill(undefined);
649
- const args = unwrapped.arguments ?? [];
650
- for (let i = 0; i < args.length; i++) {
651
- const arg = args[i];
652
- if (!arg)
653
- continue;
654
- if (ts.isSpreadElement(arg))
655
- continue;
656
- if (isLambdaExpression(arg))
657
- continue;
658
- const t = inferExpressionType(arg, env);
659
- if (t && t.kind !== "unknownType") {
660
- argTypesWorking[i] = t;
661
- }
662
- }
663
- const resolved = resolveCall({
664
- sigId,
665
- argumentCount,
666
- explicitTypeArgs,
667
- argTypes: argTypesWorking,
668
- });
669
- return resolved.returnType.kind === "unknownType"
670
- ? undefined
671
- : resolved.returnType;
672
- }
673
- if (ts.isPropertyAccessExpression(unwrapped)) {
674
- const receiverType = inferExpressionType(unwrapped.expression, env);
675
- if (!receiverType || receiverType.kind === "unknownType")
676
- return undefined;
677
- const memberType = typeOfMember(receiverType, {
678
- kind: "byName",
679
- name: unwrapped.name.text,
680
- });
681
- return memberType.kind === "unknownType" ? undefined : memberType;
682
- }
683
- if (ts.isElementAccessExpression(unwrapped)) {
684
- const objectType = inferExpressionType(unwrapped.expression, env);
685
- if (!objectType || objectType.kind === "unknownType")
686
- return undefined;
687
- if (objectType.kind === "arrayType") {
688
- return objectType.elementType;
689
- }
690
- if (objectType.kind === "dictionaryType") {
691
- return objectType.valueType;
692
- }
693
- if (objectType.kind === "primitiveType" && objectType.name === "string") {
694
- return { kind: "primitiveType", name: "string" };
695
- }
696
- if (objectType.kind === "referenceType") {
697
- return getIndexerInfo(objectType)?.valueType;
698
- }
699
- return undefined;
700
- }
701
- if (ts.isIdentifier(unwrapped)) {
702
- const fromEnv = env.get(unwrapped.text);
703
- if (fromEnv)
704
- return fromEnv;
705
- const declId = resolveIdentifier(unwrapped);
706
- if (!declId)
707
- return undefined;
708
- const t = typeOfDecl(declId);
709
- return t.kind === "unknownType" ? undefined : t;
710
- }
711
- if (ts.isNumericLiteral(unwrapped)) {
712
- const numericKind = inferNumericKindFromRaw(unwrapped.getText());
713
- return deriveTypeFromNumericKind(numericKind);
714
- }
715
- if (ts.isStringLiteral(unwrapped)) {
716
- return { kind: "primitiveType", name: "string" };
717
- }
718
- if (ts.isNoSubstitutionTemplateLiteral(unwrapped) ||
719
- ts.isTemplateExpression(unwrapped)) {
720
- return { kind: "primitiveType", name: "string" };
721
- }
722
- if (unwrapped.kind === ts.SyntaxKind.TrueKeyword ||
723
- unwrapped.kind === ts.SyntaxKind.FalseKeyword) {
724
- return { kind: "primitiveType", name: "boolean" };
725
- }
726
- if (ts.isPrefixUnaryExpression(unwrapped)) {
727
- if (unwrapped.operator === ts.SyntaxKind.ExclamationToken) {
728
- return { kind: "primitiveType", name: "boolean" };
729
- }
730
- return inferExpressionType(unwrapped.operand, env);
731
- }
732
- if (ts.isBinaryExpression(unwrapped)) {
733
- const op = unwrapped.operatorToken.kind;
734
- // Comparisons / equality always return boolean.
735
- if (op === ts.SyntaxKind.EqualsEqualsToken ||
736
- op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
737
- op === ts.SyntaxKind.ExclamationEqualsToken ||
738
- op === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
739
- op === ts.SyntaxKind.LessThanToken ||
740
- op === ts.SyntaxKind.LessThanEqualsToken ||
741
- op === ts.SyntaxKind.GreaterThanToken ||
742
- op === ts.SyntaxKind.GreaterThanEqualsToken) {
743
- return { kind: "primitiveType", name: "boolean" };
744
- }
745
- if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
746
- op === ts.SyntaxKind.BarBarToken) {
747
- return { kind: "primitiveType", name: "boolean" };
748
- }
749
- if (op === ts.SyntaxKind.PlusToken ||
750
- op === ts.SyntaxKind.MinusToken ||
751
- op === ts.SyntaxKind.AsteriskToken ||
752
- op === ts.SyntaxKind.SlashToken ||
753
- op === ts.SyntaxKind.PercentToken) {
754
- const leftType = inferExpressionType(unwrapped.left, env);
755
- const rightType = inferExpressionType(unwrapped.right, env);
756
- if (!leftType || !rightType)
757
- return undefined;
758
- // String concatenation
759
- if (op === ts.SyntaxKind.PlusToken &&
760
- ((leftType.kind === "primitiveType" && leftType.name === "string") ||
761
- (rightType.kind === "primitiveType" && rightType.name === "string"))) {
762
- return { kind: "primitiveType", name: "string" };
763
- }
764
- const leftKind = getNumericKindFromIrType(leftType);
765
- const rightKind = getNumericKindFromIrType(rightType);
766
- if (!leftKind || !rightKind)
767
- return undefined;
768
- return deriveTypeFromNumericKind(getBinaryResultKind(leftKind, rightKind));
769
- }
770
- }
771
- return undefined;
772
- };
773
- const inferLambdaType = (expr, expectedType) => {
774
- const unwrapped = unwrapParens(expr);
775
- if (!ts.isArrowFunction(unwrapped) && !ts.isFunctionExpression(unwrapped)) {
776
- return undefined;
777
- }
778
- const expectedFnType = expectedType?.kind === "functionType"
779
- ? expectedType
780
- : expectedType
781
- ? delegateToFunctionType(expectedType)
782
- : undefined;
783
- const parameters = unwrapped.parameters.map((p, index) => {
784
- const name = ts.isIdentifier(p.name) ? p.name.text : `arg${index}`;
785
- const paramType = p.type
786
- ? convertTypeNode(p.type)
787
- : expectedFnType?.parameters[index]?.type;
788
- return {
789
- kind: "parameter",
790
- pattern: {
791
- kind: "identifierPattern",
792
- name,
793
- },
794
- type: paramType,
795
- initializer: undefined,
796
- isOptional: !!p.questionToken,
797
- isRest: !!p.dotDotDotToken,
798
- passing: "value",
799
- };
800
- });
801
- const env = new Map();
802
- for (const p of parameters) {
803
- if (p.pattern.kind === "identifierPattern" && p.pattern.name && p.type) {
804
- env.set(p.pattern.name, p.type);
805
- }
806
- }
807
- const explicitReturnType = "type" in unwrapped && unwrapped.type
808
- ? convertTypeNode(unwrapped.type)
809
- : undefined;
810
- const expectedReturnType = expectedFnType?.returnType;
811
- const inferredReturnType = explicitReturnType ??
812
- (expectedReturnType && !containsTypeParameter(expectedReturnType)
813
- ? expectedReturnType
814
- : undefined) ??
815
- (() => {
816
- if (ts.isBlock(unwrapped.body)) {
817
- const returns = [];
818
- const visit = (n) => {
819
- if (ts.isFunctionLike(n) && n !== unwrapped)
820
- return;
821
- if (ts.isReturnStatement(n) && n.expression) {
822
- returns.push(n.expression);
823
- }
824
- n.forEachChild(visit);
825
- };
826
- unwrapped.body.forEachChild(visit);
827
- if (returns.length === 0)
828
- return { kind: "voidType" };
829
- const first = inferExpressionType(returns[0], env);
830
- if (!first)
831
- return undefined;
832
- for (let i = 1; i < returns.length; i++) {
833
- const t = inferExpressionType(returns[i], env);
834
- if (!t || !typesEqual(t, first))
835
- return undefined;
836
- }
837
- return first;
838
- }
839
- return inferExpressionType(unwrapped.body, env);
840
- })();
841
- if (!inferredReturnType)
842
- return undefined;
843
- return {
844
- kind: "functionType",
845
- parameters,
846
- returnType: inferredReturnType,
847
- };
848
- };
849
- /**
850
- * Try to infer type from a variable declaration's literal initializer.
851
- *
852
- * DETERMINISM: Uses the raw lexeme form of the literal, not TS computed types.
853
- * Only handles simple literal initializers:
854
- * - Numeric literals → inferred via inferNumericKindFromRaw
855
- * - String literals → primitiveType("string")
856
- * - Boolean literals → primitiveType("boolean")
857
- *
858
- * Returns undefined if the initializer is not a simple literal.
859
- */
860
- const tryInferTypeFromLiteralInitializer = (declNode) => {
861
- // TypeScript's VariableDeclaration has an `initializer` property
862
- const decl = declNode;
863
- // Must have an initializer
864
- if (!decl.initializer)
865
- return undefined;
866
- const init = decl.initializer;
867
- if (init.kind === ts.SyntaxKind.NumericLiteral && init.getText) {
868
- const raw = init.getText();
869
- const numericKind = inferNumericKindFromRaw(raw);
870
- return deriveTypeFromNumericKind(numericKind);
871
- }
872
- if (init.kind === ts.SyntaxKind.StringLiteral) {
873
- return { kind: "primitiveType", name: "string" };
874
- }
875
- if (init.kind === ts.SyntaxKind.NoSubstitutionTemplateLiteral ||
876
- init.kind === ts.SyntaxKind.TemplateExpression) {
877
- return { kind: "primitiveType", name: "string" };
878
- }
879
- if (init.kind === ts.SyntaxKind.TrueKeyword ||
880
- init.kind === ts.SyntaxKind.FalseKeyword) {
881
- return { kind: "primitiveType", name: "boolean" };
882
- }
883
- // Not a simple literal - cannot infer
884
- return undefined;
885
- };
886
- /**
887
- * Try to infer type from a variable declaration's initializer using only
888
- * deterministic sources (declarations + explicit syntax).
889
- *
890
- * Handles:
891
- * - simple literals (delegates to tryInferTypeFromLiteralInitializer)
892
- * - call expressions where the callee has an explicit declared return type
893
- * - new expressions with explicit type arguments (or best-effort nominal type)
894
- * - identifier initializers (propagate deterministically)
895
- */
896
- const tryInferReturnTypeFromCallExpression = (call, env) => {
897
- const sigId = resolveCallSignature(call);
898
- if (!sigId)
899
- return undefined;
900
- const explicitTypeArgs = call.typeArguments && call.typeArguments.length > 0
901
- ? call.typeArguments.map((ta) => convertTypeNode(ta))
902
- : undefined;
903
- const receiverType = (() => {
904
- if (!ts.isPropertyAccessExpression(call.expression))
905
- return undefined;
906
- const receiverExpr = call.expression.expression;
907
- const receiver = inferExpressionType(receiverExpr, env);
908
- return receiver && receiver.kind !== "unknownType" ? receiver : undefined;
909
- })();
910
- const argumentCount = call.arguments.length;
911
- // Two-pass: resolve once to get expected parameter types, then infer non-lambda args,
912
- // then infer lambda arg types (from expected types + body), then final resolve.
913
- const initialResolved = resolveCall({
914
- sigId,
915
- argumentCount,
916
- receiverType,
917
- explicitTypeArgs,
918
- });
919
- const initialParameterTypes = initialResolved.parameterTypes;
920
- const argTypesWorking = Array(argumentCount).fill(undefined);
921
- for (let index = 0; index < call.arguments.length; index++) {
922
- const arg = call.arguments[index];
923
- if (!arg)
924
- continue;
925
- if (ts.isSpreadElement(arg))
926
- continue;
927
- if (isLambdaExpression(arg))
928
- continue;
929
- if (ts.isNumericLiteral(arg)) {
930
- const numericKind = inferNumericKindFromRaw(arg.getText());
931
- argTypesWorking[index] = deriveTypeFromNumericKind(numericKind);
932
- continue;
933
- }
934
- if (ts.isStringLiteral(arg)) {
935
- argTypesWorking[index] = { kind: "primitiveType", name: "string" };
936
- continue;
937
- }
938
- if (arg.kind === ts.SyntaxKind.TrueKeyword ||
939
- arg.kind === ts.SyntaxKind.FalseKeyword) {
940
- argTypesWorking[index] = {
941
- kind: "primitiveType",
942
- name: "boolean",
943
- };
944
- continue;
945
- }
946
- if (ts.isIdentifier(arg)) {
947
- const argDeclId = resolveIdentifier(arg);
948
- if (!argDeclId)
949
- continue;
950
- const t = typeOfDecl(argDeclId);
951
- if (t.kind !== "unknownType") {
952
- argTypesWorking[index] = t;
953
- }
954
- continue;
955
- }
956
- if (ts.isCallExpression(arg)) {
957
- const t = tryInferReturnTypeFromCallExpression(arg, env);
958
- if (t) {
959
- argTypesWorking[index] = t;
960
- }
961
- continue;
962
- }
963
- if (ts.isNewExpression(arg)) {
964
- const nestedSigId = resolveConstructorSignature(arg);
965
- if (!nestedSigId)
966
- continue;
967
- const nestedExplicitTypeArgs = arg.typeArguments && arg.typeArguments.length > 0
968
- ? arg.typeArguments.map((ta) => convertTypeNode(ta))
969
- : undefined;
970
- const nestedResolved = resolveCall({
971
- sigId: nestedSigId,
972
- argumentCount: arg.arguments?.length ?? 0,
973
- explicitTypeArgs: nestedExplicitTypeArgs,
974
- });
975
- if (nestedResolved.returnType.kind !== "unknownType") {
976
- argTypesWorking[index] = nestedResolved.returnType;
977
- }
978
- continue;
979
- }
980
- // Fallback: infer from a small deterministic expression set (identifiers, literals,
981
- // arithmetic, nested member/index access, calls, etc).
982
- const t = inferExpressionType(arg, env);
983
- if (t && t.kind !== "unknownType") {
984
- argTypesWorking[index] = t;
985
- continue;
986
- }
987
- }
988
- const lambdaContextResolved = resolveCall({
989
- sigId,
990
- argumentCount,
991
- receiverType,
992
- explicitTypeArgs,
993
- argTypes: argTypesWorking,
994
- });
995
- const parameterTypesForLambdaContext = lambdaContextResolved.parameterTypes ?? initialParameterTypes;
996
- for (let index = 0; index < call.arguments.length; index++) {
997
- const arg = call.arguments[index];
998
- if (!arg)
999
- continue;
1000
- if (ts.isSpreadElement(arg))
1001
- continue;
1002
- if (!isLambdaExpression(arg))
1003
- continue;
1004
- const expectedType = parameterTypesForLambdaContext[index];
1005
- const lambdaType = inferLambdaType(arg, expectedType);
1006
- if (lambdaType) {
1007
- argTypesWorking[index] = lambdaType;
1008
- }
1009
- }
1010
- const finalResolved = resolveCall({
1011
- sigId,
1012
- argumentCount,
1013
- receiverType,
1014
- explicitTypeArgs,
1015
- argTypes: argTypesWorking,
1016
- });
1017
- return finalResolved.returnType.kind === "unknownType"
1018
- ? undefined
1019
- : finalResolved.returnType;
1020
- };
1021
- const tryInferTypeFromInitializer = (declNode) => {
1022
- const literalType = tryInferTypeFromLiteralInitializer(declNode);
1023
- if (literalType)
1024
- return literalType;
1025
- if (!declNode || typeof declNode !== "object")
1026
- return undefined;
1027
- const node = declNode;
1028
- if (!ts.isVariableDeclaration(node))
1029
- return undefined;
1030
- let init = node.initializer;
1031
- if (!init)
1032
- return undefined;
1033
- while (ts.isParenthesizedExpression(init)) {
1034
- init = init.expression;
1035
- }
1036
- // Explicit type assertions are deterministic sources for variable typing.
1037
- // This supports patterns like:
1038
- // const xs = numbers as unknown as LinqSeq<int>;
1039
- // where the user intentionally supplies the type at the assertion site.
1040
- if (ts.isAsExpression(init) || ts.isTypeAssertionExpression(init)) {
1041
- return convertTypeNode(init.type);
1042
- }
1043
- if (ts.isNonNullExpression(init)) {
1044
- const inner = inferExpressionType(init.expression, new Map());
1045
- if (!inner || inner.kind === "unknownType")
1046
- return undefined;
1047
- return stripNullishForInference(inner);
1048
- }
1049
- if (ts.isAwaitExpression(init)) {
1050
- const inner = inferExpressionType(init.expression, new Map());
1051
- if (!inner || inner.kind === "unknownType")
1052
- return undefined;
1053
- return unwrapAwaitedForInference(inner);
1054
- }
1055
- if (ts.isCallExpression(init)) {
1056
- return tryInferReturnTypeFromCallExpression(init, new Map());
1057
- }
1058
- if (ts.isArrayLiteralExpression(init)) {
1059
- // Deterministic array literal typing for variable declarations:
1060
- // infer `T[]` only when all element types are deterministically known and equal.
1061
- const elementTypes = [];
1062
- const emptyEnv = new Map();
1063
- for (const el of init.elements) {
1064
- if (ts.isOmittedExpression(el)) {
1065
- return undefined;
1066
- }
1067
- if (ts.isSpreadElement(el)) {
1068
- return undefined;
1069
- }
1070
- const t = inferExpressionType(el, emptyEnv);
1071
- if (!t || t.kind === "unknownType") {
1072
- return undefined;
1073
- }
1074
- elementTypes.push(t);
1075
- }
1076
- if (elementTypes.length === 0)
1077
- return undefined;
1078
- const first = elementTypes[0];
1079
- if (first && elementTypes.every((t) => typesEqual(t, first))) {
1080
- return { kind: "arrayType", elementType: first };
1081
- }
1082
- return undefined;
1083
- }
1084
- // Phase 15: NewExpression branch - use constructor signature with argTypes
1085
- if (ts.isNewExpression(init)) {
1086
- const sigId = resolveConstructorSignature(init);
1087
- if (!sigId)
1088
- return undefined;
1089
- const explicitTypeArgs = init.typeArguments && init.typeArguments.length > 0
1090
- ? init.typeArguments.map((ta) => convertTypeNode(ta))
1091
- : undefined;
1092
- // Derive argTypes conservatively from syntax (same pattern as CallExpression)
1093
- const args = init.arguments ?? [];
1094
- const argTypes = args.map((arg) => {
1095
- if (ts.isSpreadElement(arg))
1096
- return undefined;
1097
- if (ts.isNumericLiteral(arg)) {
1098
- const numericKind = inferNumericKindFromRaw(arg.getText());
1099
- return deriveTypeFromNumericKind(numericKind);
1100
- }
1101
- if (ts.isStringLiteral(arg)) {
1102
- return { kind: "primitiveType", name: "string" };
1103
- }
1104
- if (arg.kind === ts.SyntaxKind.TrueKeyword ||
1105
- arg.kind === ts.SyntaxKind.FalseKeyword) {
1106
- return { kind: "primitiveType", name: "boolean" };
1107
- }
1108
- if (ts.isIdentifier(arg)) {
1109
- const argDeclId = resolveIdentifier(arg);
1110
- if (!argDeclId)
1111
- return undefined;
1112
- const t = typeOfDecl(argDeclId);
1113
- return t.kind === "unknownType" ? undefined : t;
1114
- }
1115
- // Recursive handling for nested new expressions
1116
- if (ts.isNewExpression(arg)) {
1117
- const nestedSigId = resolveConstructorSignature(arg);
1118
- if (!nestedSigId)
1119
- return undefined;
1120
- const nestedExplicitTypeArgs = arg.typeArguments && arg.typeArguments.length > 0
1121
- ? arg.typeArguments.map((ta) => convertTypeNode(ta))
1122
- : undefined;
1123
- const nestedResolved = resolveCall({
1124
- sigId: nestedSigId,
1125
- argumentCount: arg.arguments?.length ?? 0,
1126
- explicitTypeArgs: nestedExplicitTypeArgs,
1127
- });
1128
- return nestedResolved.returnType.kind === "unknownType"
1129
- ? undefined
1130
- : nestedResolved.returnType;
1131
- }
1132
- return undefined;
1133
- });
1134
- // Resolve constructor call with argTypes for inference
1135
- const resolved = resolveCall({
1136
- sigId,
1137
- argumentCount: args.length,
1138
- explicitTypeArgs,
1139
- argTypes,
1140
- });
1141
- return resolved.returnType.kind === "unknownType"
1142
- ? undefined
1143
- : resolved.returnType;
1144
- }
1145
- if (ts.isIdentifier(init)) {
1146
- const sourceDeclId = resolveIdentifier(init);
1147
- if (!sourceDeclId)
1148
- return undefined;
1149
- const sourceType = typeOfDecl(sourceDeclId);
1150
- return sourceType.kind === "unknownType" ? undefined : sourceType;
1151
- }
1152
- // Property access: const output = response.outputStream
1153
- // DETERMINISTIC: Infer via TypeSystem member lookup on a deterministically typed receiver.
1154
- if (ts.isPropertyAccessExpression(init)) {
1155
- const receiverType = inferExpressionType(init.expression, new Map());
1156
- if (!receiverType || receiverType.kind === "unknownType")
1157
- return undefined;
1158
- const memberType = typeOfMember(receiverType, {
1159
- kind: "byName",
1160
- name: init.name.text,
1161
- });
1162
- return memberType.kind === "unknownType" ? undefined : memberType;
1163
- }
1164
- // Element access: const first = items[0]
1165
- // DETERMINISTIC: Infer element type from a deterministically typed receiver.
1166
- if (ts.isElementAccessExpression(init)) {
1167
- const inferred = inferExpressionType(init, new Map());
1168
- return inferred && inferred.kind !== "unknownType" ? inferred : undefined;
1169
- }
1170
- return undefined;
1171
- };
1172
- const typeOfDecl = (declId) => {
1173
- // Check cache first
1174
- const cached = declTypeCache.get(declId.id);
1175
- if (cached)
1176
- return cached;
1177
- const declInfo = handleRegistry.getDecl(declId);
1178
- if (!declInfo) {
1179
- emitDiagnostic("TSN5203", "Cannot resolve declaration");
1180
- const result = unknownType;
1181
- declTypeCache.set(declId.id, result);
1182
- return result;
1183
- }
1184
- let result;
1185
- if (declInfo.typeNode) {
1186
- // Explicit type annotation - convert to IR
1187
- result = convertTypeNode(declInfo.typeNode);
1188
- }
1189
- else if (declInfo.kind === "class" ||
1190
- declInfo.kind === "interface" ||
1191
- declInfo.kind === "enum") {
1192
- // Class/interface/enum - return reference type
1193
- result = {
1194
- kind: "referenceType",
1195
- name: declInfo.fqName ?? "unknown",
1196
- };
1197
- }
1198
- else if (declInfo.kind === "function") {
1199
- // Function without type annotation - need to build function type from signature
1200
- // For now, return unknownType as we need the signature ID
1201
- emitDiagnostic("TSN5201", `Function '${declInfo.fqName ?? "unknown"}' requires explicit return type`);
1202
- result = unknownType;
1203
- }
1204
- else if (declInfo.kind === "variable" && declInfo.declNode) {
1205
- // Variable without type annotation - infer from deterministic initializer
1206
- const inferred = tryInferTypeFromInitializer(declInfo.declNode);
1207
- if (inferred) {
1208
- result = inferred;
1209
- }
1210
- else {
1211
- // Not a simple literal - require explicit type annotation
1212
- emitDiagnostic("TSN5201", `Declaration requires explicit type annotation`);
1213
- result = unknownType;
1214
- }
1215
- }
1216
- else {
1217
- // Parameter or other declaration without type annotation
1218
- emitDiagnostic("TSN5201", `Declaration requires explicit type annotation`);
1219
- result = unknownType;
1220
- }
1221
- declTypeCache.set(declId.id, result);
1222
- return result;
1223
- };
1224
- // ─────────────────────────────────────────────────────────────────────────
1225
- // typeOfMember — Get declared type of a member (with inheritance substitution)
1226
- // ─────────────────────────────────────────────────────────────────────────
1227
- const typeOfMember = (receiver, member, site) => {
1228
- const memberName = member.kind === "byName" ? member.name : "unknown"; // MemberId.name not defined yet
1229
- // Common nullish unions (T | undefined | null) should behave like T for member lookup.
1230
- // This preserves deterministic typing for patterns like:
1231
- // const url = request.url; if (!url) return; url.absolutePath
1232
- const effectiveReceiver = receiver.kind === "unionType"
1233
- ? (() => {
1234
- const nonNullish = receiver.types.filter((t) => t && !isNullishPrimitive(t));
1235
- return nonNullish.length === 1 && nonNullish[0]
1236
- ? nonNullish[0]
1237
- : receiver;
1238
- })()
1239
- : receiver;
1240
- // 1. Normalize receiver to nominal form
1241
- const normalized = normalizeToNominal(effectiveReceiver);
1242
- if (!normalized) {
1243
- // Handle structural types (objectType)
1244
- if (effectiveReceiver.kind === "objectType" ||
1245
- (effectiveReceiver.kind === "referenceType" &&
1246
- effectiveReceiver.structuralMembers)) {
1247
- return lookupStructuralMember(effectiveReceiver, memberName, site);
1248
- }
1249
- emitDiagnostic("TSN5203", `Cannot resolve member '${memberName}' on type`, site);
1250
- return unknownType;
1251
- }
1252
- // 2. Check cache (use clrName as key for compatibility)
1253
- const cacheKey = makeMemberCacheKey(normalized.typeId.stableId, memberName, normalized.typeArgs);
1254
- const cached = memberDeclaredTypeCache.get(cacheKey);
1255
- if (cached)
1256
- return cached;
1257
- // 3. Use NominalEnv to find declaring type + substitution (Phase 6: TypeId-based)
1258
- const lookupResult = nominalEnv.findMemberDeclaringType(normalized.typeId, normalized.typeArgs, memberName);
1259
- // 4a. If NominalEnv found the member, get its declared type from Universe
1260
- if (lookupResult) {
1261
- const memberEntry = unifiedCatalog.getMember(lookupResult.declaringTypeId, memberName);
1262
- // Property/field member: return its declared type.
1263
- const memberType = memberEntry?.type;
1264
- if (memberType) {
1265
- const result = irSubstitute(memberType, lookupResult.substitution);
1266
- memberDeclaredTypeCache.set(cacheKey, result);
1267
- return result;
1268
- }
1269
- // Method member: materialize a callable function type from the first signature.
1270
- // Call resolution (resolveCall) uses SignatureId for overload selection; this
1271
- // type is used only to keep member access expressions deterministic.
1272
- const firstSig = memberEntry?.signatures?.[0];
1273
- if (firstSig) {
1274
- const funcType = {
1275
- kind: "functionType",
1276
- parameters: firstSig.parameters.map((p) => ({
1277
- kind: "parameter",
1278
- pattern: {
1279
- kind: "identifierPattern",
1280
- name: p.name,
1281
- },
1282
- type: p.type,
1283
- initializer: undefined,
1284
- isOptional: p.isOptional,
1285
- isRest: p.isRest,
1286
- passing: p.mode,
1287
- })),
1288
- returnType: firstSig.returnType,
1289
- };
1290
- const result = irSubstitute(funcType, lookupResult.substitution);
1291
- memberDeclaredTypeCache.set(cacheKey, result);
1292
- return result;
1293
- }
1294
- }
1295
- // 5. Member not found anywhere
1296
- emitDiagnostic("TSN5203", `Member '${memberName}' not found`, site);
1297
- return unknownType;
1298
- };
1299
- const parseIndexerKeyClrType = (stableId) => {
1300
- const memberSep = stableId.indexOf("::");
1301
- if (memberSep < 0)
1302
- return undefined;
1303
- const bracketStart = stableId.indexOf("[", memberSep);
1304
- if (bracketStart < 0)
1305
- return undefined;
1306
- let depth = 0;
1307
- let bracketEnd = -1;
1308
- for (let i = bracketStart; i < stableId.length; i++) {
1309
- const ch = stableId[i];
1310
- if (ch === "[")
1311
- depth++;
1312
- if (ch === "]") {
1313
- depth--;
1314
- if (depth === 0) {
1315
- bracketEnd = i;
1316
- break;
1317
- }
1318
- }
1319
- }
1320
- if (bracketEnd < 0)
1321
- return undefined;
1322
- const rawParams = stableId.slice(bracketStart + 1, bracketEnd);
1323
- // Split on top-level commas to support nested generic types.
1324
- const splitTopLevel = (value) => {
1325
- const parts = [];
1326
- let start = 0;
1327
- let bracketDepth = 0;
1328
- for (let i = 0; i < value.length; i++) {
1329
- const c = value[i];
1330
- if (c === "[")
1331
- bracketDepth++;
1332
- else if (c === "]" && bracketDepth > 0)
1333
- bracketDepth--;
1334
- else if (c === "," && bracketDepth === 0) {
1335
- parts.push(value.slice(start, i).trim());
1336
- start = i + 1;
1337
- }
1338
- }
1339
- parts.push(value.slice(start).trim());
1340
- return parts.filter((p) => p.length > 0);
1341
- };
1342
- const params = splitTopLevel(rawParams);
1343
- if (params.length !== 1)
1344
- return undefined;
1345
- const first = params[0];
1346
- if (!first)
1347
- return undefined;
1348
- // Strip assembly qualification (", Assembly, Version=..., ...") if present.
1349
- const withoutAsm = first.includes(",")
1350
- ? (first.split(",")[0] ?? first)
1351
- : first;
1352
- return withoutAsm.trim();
1353
- };
1354
- const getIndexerInfo = (receiver, _site) => {
1355
- const normalized = normalizeToNominal(receiver);
1356
- if (!normalized)
1357
- return undefined;
1358
- // Walk inheritance chain to find the first indexer property.
1359
- const chain = nominalEnv.getInheritanceChain(normalized.typeId);
1360
- for (const typeId of chain) {
1361
- const members = unifiedCatalog.getMembers(typeId);
1362
- const indexers = Array.from(members.values()).filter((m) => m.memberKind === "property" && m.isIndexer);
1363
- if (indexers.length === 0)
1364
- continue;
1365
- if (indexers.length > 1)
1366
- return undefined;
1367
- const indexer = indexers[0];
1368
- if (!indexer?.type)
1369
- return undefined;
1370
- const keyClrType = parseIndexerKeyClrType(indexer.stableId);
1371
- if (!keyClrType)
1372
- return undefined;
1373
- const inst = nominalEnv.getInstantiation(normalized.typeId, normalized.typeArgs, typeId);
1374
- const valueType = inst && inst.size > 0
1375
- ? irSubstitute(indexer.type, inst)
1376
- : indexer.type;
1377
- return { keyClrType, valueType };
1378
- }
1379
- return undefined;
1380
- };
1381
- // ─────────────────────────────────────────────────────────────────────────
1382
- // resolveCall — THE HEART OF DETERMINISM
1383
- // Resolve a call site: returns fully instantiated param/return types + modes
1384
- // ─────────────────────────────────────────────────────────────────────────
1385
- /**
1386
- * Deterministically infer method type parameters from argument types.
1387
- *
1388
- * This is intentionally conservative: it only infers when it can unify
1389
- * parameter and argument shapes without ambiguity.
1390
- */
1391
- const inferMethodTypeArgsFromArguments = (methodTypeParams, parameterTypes, argTypes) => {
1392
- if (methodTypeParams.length === 0)
1393
- return new Map();
1394
- const methodTypeParamNames = new Set(methodTypeParams.map((p) => p.name));
1395
- const substitution = new Map();
1396
- const tryUnify = (parameterType, argumentType) => {
1397
- // Method type parameter position: infer directly
1398
- if (parameterType.kind === "typeParameterType") {
1399
- if (!methodTypeParamNames.has(parameterType.name)) {
1400
- // Not a method type parameter (could be outer generic) — ignore
1401
- return true;
1402
- }
1403
- const existing = substitution.get(parameterType.name);
1404
- if (existing) {
1405
- // A self-mapping like `B -> B` can be produced when a lambda argument was typed
1406
- // contextually from the unresolved expected signature. This provides no real
1407
- // inference signal and must not block later concrete inference.
1408
- if (existing.kind === "typeParameterType" &&
1409
- existing.name === parameterType.name) {
1410
- substitution.set(parameterType.name, argumentType);
1411
- return true;
1412
- }
1413
- return typesEqual(existing, argumentType);
1414
- }
1415
- substitution.set(parameterType.name, argumentType);
1416
- return true;
1417
- }
1418
- // Poison/any provides no deterministic information
1419
- if (argumentType.kind === "unknownType" ||
1420
- argumentType.kind === "anyType") {
1421
- return true;
1422
- }
1423
- // Intersection argument types: unify through each constituent.
1424
- //
1425
- // This is required for airplane-grade extension method typing where the receiver
1426
- // often has the form `TShape & <extension markers> & <method table>`.
1427
- // Generic inference must still be able to infer through the real CLR shape in the intersection.
1428
- if (argumentType.kind === "intersectionType") {
1429
- for (const part of argumentType.types) {
1430
- if (!part)
1431
- continue;
1432
- if (!tryUnify(parameterType, part))
1433
- return false;
1434
- }
1435
- return true;
1436
- }
1437
- // Expression<TDelegate> wrapper: infer through the underlying delegate shape.
1438
- // This is required for Queryable APIs that use Expression<Func<...>>.
1439
- if (parameterType.kind === "referenceType" &&
1440
- parameterType.name === "Expression_1" &&
1441
- (parameterType.typeArguments?.length ?? 0) === 1) {
1442
- const inner = parameterType.typeArguments?.[0];
1443
- return inner ? tryUnify(inner, argumentType) : true;
1444
- }
1445
- // Delegate unification: allow deterministic inference through the delegate's
1446
- // Invoke signature when a lambda (functionType) is passed to a CLR delegate
1447
- // parameter (Func/Action/custom delegates).
1448
- //
1449
- // Without this, generic methods like:
1450
- // Select<TResult>(selector: Func<TSource, TResult>)
1451
- // cannot infer TResult from a lambda argument, causing TSN5201/TSN5202.
1452
- if (parameterType.kind === "referenceType" &&
1453
- argumentType.kind === "functionType") {
1454
- const delegateFn = delegateToFunctionType(parameterType);
1455
- if (delegateFn)
1456
- return tryUnify(delegateFn, argumentType);
1457
- }
1458
- if (parameterType.kind === "functionType" &&
1459
- argumentType.kind === "referenceType") {
1460
- const delegateFn = delegateToFunctionType(argumentType);
1461
- if (delegateFn)
1462
- return tryUnify(parameterType, delegateFn);
1463
- }
1464
- // Array<T> ↔ T[] unification
1465
- if (parameterType.kind === "referenceType" &&
1466
- parameterType.name === "Array" &&
1467
- (parameterType.typeArguments?.length ?? 0) === 1 &&
1468
- argumentType.kind === "arrayType") {
1469
- const elementParam = parameterType.typeArguments?.[0];
1470
- return elementParam
1471
- ? tryUnify(elementParam, argumentType.elementType)
1472
- : true;
1473
- }
1474
- // Union parameter type: allow deterministic inference through common nullish unions.
1475
- // Example: constructor(value: T | null) with argument of type T.
1476
- if (parameterType.kind === "unionType") {
1477
- const nonNullish = parameterType.types.filter((t) => t && !isNullishPrimitive(t));
1478
- const nullish = parameterType.types.filter((t) => t && isNullishPrimitive(t));
1479
- const candidates = isNullishPrimitive(argumentType)
1480
- ? nullish
1481
- : nonNullish;
1482
- if (candidates.length === 1) {
1483
- const only = candidates[0];
1484
- return only ? tryUnify(only, argumentType) : true;
1485
- }
1486
- // Conservative: ambiguous unions provide no deterministic signal.
1487
- return true;
1488
- }
1489
- if (parameterType.kind === "arrayType" &&
1490
- argumentType.kind === "referenceType" &&
1491
- argumentType.name === "Array" &&
1492
- (argumentType.typeArguments?.length ?? 0) === 1) {
1493
- const elementArg = argumentType.typeArguments?.[0];
1494
- return elementArg
1495
- ? tryUnify(parameterType.elementType, elementArg)
1496
- : true;
1497
- }
1498
- // Same-kind structural unification
1499
- if (parameterType.kind !== argumentType.kind) {
1500
- // Type mismatch provides no deterministic inference signal.
1501
- return true;
1502
- }
1503
- switch (parameterType.kind) {
1504
- case "primitiveType":
1505
- return true;
1506
- case "literalType":
1507
- return true;
1508
- case "referenceType": {
1509
- const argRef = argumentType;
1510
- const sameNominal = (() => {
1511
- if (parameterType.typeId && argRef.typeId) {
1512
- return parameterType.typeId.stableId === argRef.typeId.stableId;
1513
- }
1514
- return parameterType.name === argRef.name;
1515
- })();
1516
- // Direct generic unification when the nominals match
1517
- if (sameNominal) {
1518
- const paramArgs = parameterType.typeArguments ?? [];
1519
- const argArgs = argRef.typeArguments ?? [];
1520
- if (paramArgs.length !== argArgs.length)
1521
- return true;
1522
- for (let i = 0; i < paramArgs.length; i++) {
1523
- const pa = paramArgs[i];
1524
- const aa = argArgs[i];
1525
- if (!pa || !aa)
1526
- continue;
1527
- if (!tryUnify(pa, aa))
1528
- return false;
1529
- }
1530
- return true;
1531
- }
1532
- // Inheritance/interface unification: allow argumentType to flow through
1533
- // its inheritance chain to the parameter type (e.g., List<T> → IEnumerable<T>).
1534
- const paramNominal = normalizeToNominal(parameterType);
1535
- const argNominal = normalizeToNominal(argRef);
1536
- if (paramNominal && argNominal) {
1537
- const inst = nominalEnv.getInstantiation(argNominal.typeId, argNominal.typeArgs, paramNominal.typeId);
1538
- if (inst) {
1539
- const targetTypeParams = unifiedCatalog.getTypeParameters(paramNominal.typeId);
1540
- const instantiatedArgs = targetTypeParams.map((tp) => inst.get(tp.name));
1541
- const paramArgs = parameterType.typeArguments ?? [];
1542
- if (instantiatedArgs.every((t) => t !== undefined) &&
1543
- paramArgs.length === instantiatedArgs.length) {
1544
- for (let i = 0; i < paramArgs.length; i++) {
1545
- const pa = paramArgs[i];
1546
- const aa = instantiatedArgs[i];
1547
- if (!pa || !aa)
1548
- continue;
1549
- if (!tryUnify(pa, aa))
1550
- return false;
1551
- }
1552
- }
1553
- }
1554
- }
1555
- return true;
1556
- }
1557
- case "arrayType":
1558
- return tryUnify(parameterType.elementType, argumentType.elementType);
1559
- case "tupleType": {
1560
- const argTuple = argumentType;
1561
- if (parameterType.elementTypes.length !== argTuple.elementTypes.length) {
1562
- return true;
1563
- }
1564
- for (let i = 0; i < parameterType.elementTypes.length; i++) {
1565
- const pe = parameterType.elementTypes[i];
1566
- const ae = argTuple.elementTypes[i];
1567
- if (!pe || !ae)
1568
- continue;
1569
- if (!tryUnify(pe, ae))
1570
- return false;
1571
- }
1572
- return true;
1573
- }
1574
- case "functionType": {
1575
- const argFn = argumentType;
1576
- if (parameterType.parameters.length !== argFn.parameters.length) {
1577
- return true;
1578
- }
1579
- for (let i = 0; i < parameterType.parameters.length; i++) {
1580
- const pp = parameterType.parameters[i];
1581
- const ap = argFn.parameters[i];
1582
- const pt = pp?.type;
1583
- const at = ap?.type;
1584
- if (pt && at) {
1585
- if (!tryUnify(pt, at))
1586
- return false;
1587
- }
1588
- }
1589
- return tryUnify(parameterType.returnType, argFn.returnType);
1590
- }
1591
- case "objectType":
1592
- case "dictionaryType":
1593
- // Conservative: only infer through these when shapes already match exactly.
1594
- return true;
1595
- case "voidType":
1596
- case "neverType":
1597
- return true;
1598
- default:
1599
- return true;
1600
- }
1601
- };
1602
- const pairs = Math.min(parameterTypes.length, argTypes.length);
1603
- for (let i = 0; i < pairs; i++) {
1604
- const paramType = parameterTypes[i];
1605
- const argType = argTypes[i];
1606
- if (!paramType || !argType)
1607
- continue;
1608
- if (!tryUnify(paramType, argType))
1609
- return undefined;
1610
- }
1611
- return substitution;
1612
- };
1613
- const containsMethodTypeParameter = (type, unresolved) => {
1614
- if (type.kind === "typeParameterType")
1615
- return unresolved.has(type.name);
1616
- if (type.kind === "referenceType") {
1617
- return (type.typeArguments ?? []).some((t) => t ? containsMethodTypeParameter(t, unresolved) : false);
1618
- }
1619
- if (type.kind === "arrayType") {
1620
- return containsMethodTypeParameter(type.elementType, unresolved);
1621
- }
1622
- if (type.kind === "tupleType") {
1623
- return type.elementTypes.some((t) => t ? containsMethodTypeParameter(t, unresolved) : false);
1624
- }
1625
- if (type.kind === "functionType") {
1626
- const paramsContain = type.parameters.some((p) => p.type ? containsMethodTypeParameter(p.type, unresolved) : false);
1627
- return (paramsContain ||
1628
- containsMethodTypeParameter(type.returnType, unresolved));
1629
- }
1630
- if (type.kind === "unionType" || type.kind === "intersectionType") {
1631
- return type.types.some((t) => t ? containsMethodTypeParameter(t, unresolved) : false);
1632
- }
1633
- if (type.kind === "objectType") {
1634
- return type.members.some((m) => {
1635
- if (m.kind === "propertySignature") {
1636
- return containsMethodTypeParameter(m.type, unresolved);
1637
- }
1638
- if (m.kind === "methodSignature") {
1639
- const paramsContain = m.parameters.some((p) => p.type ? containsMethodTypeParameter(p.type, unresolved) : false);
1640
- return (paramsContain ||
1641
- (m.returnType
1642
- ? containsMethodTypeParameter(m.returnType, unresolved)
1643
- : false));
1644
- }
1645
- return false;
1646
- });
1647
- }
1648
- return false;
1649
- };
1650
- const normalizeCatalogTsName = (name) => {
1651
- if (name.endsWith("$instance"))
1652
- return name.slice(0, -"$instance".length);
1653
- if (name.startsWith("__") && name.endsWith("$views")) {
1654
- return name.slice("__".length, -"$views".length);
1655
- }
1656
- return name;
1657
- };
1658
- const isArityCompatible = (signature, argumentCount) => {
1659
- const params = signature.parameters;
1660
- if (params.length === 0)
1661
- return argumentCount === 0;
1662
- // Rest parameter can absorb any extra args.
1663
- const restIndex = params.findIndex((p) => p.isRest);
1664
- if (restIndex >= 0) {
1665
- // Only support `...rest` in the last position.
1666
- if (restIndex !== params.length - 1)
1667
- return false;
1668
- // Must supply all non-rest parameters.
1669
- if (argumentCount < restIndex)
1670
- return false;
1671
- return true;
1672
- }
1673
- // Too many args for non-rest signature.
1674
- if (argumentCount > params.length)
1675
- return false;
1676
- // Missing args must correspond to optional parameters.
1677
- for (let i = argumentCount; i < params.length; i++) {
1678
- const p = params[i];
1679
- if (!p || !p.isOptional)
1680
- return false;
1681
- }
1682
- return true;
1683
- };
1684
- const scoreSignatureMatch = (parameterTypes, argTypes, argumentCount) => {
1685
- let score = 0;
1686
- const pairs = Math.min(argumentCount, parameterTypes.length, argTypes.length);
1687
- for (let i = 0; i < pairs; i++) {
1688
- const pt = parameterTypes[i];
1689
- const at = argTypes[i];
1690
- if (!pt || !at)
1691
- continue;
1692
- if (typesEqual(pt, at)) {
1693
- score += 3;
1694
- continue;
1695
- }
1696
- const pNom = normalizeToNominal(pt);
1697
- const aNom = normalizeToNominal(at);
1698
- if (!pNom || !aNom)
1699
- continue;
1700
- if (pNom.typeId.stableId === aNom.typeId.stableId) {
1701
- score += 2;
1702
- continue;
1703
- }
1704
- const inst = nominalEnv.getInstantiation(aNom.typeId, aNom.typeArgs, pNom.typeId);
1705
- if (inst)
1706
- score += 1;
1707
- }
1708
- return score;
1709
- };
1710
- const tryResolveCallFromUnifiedCatalog = (declaringTypeTsName, declaringMemberName, query) => {
1711
- const { argumentCount, receiverType, explicitTypeArgs, argTypes } = query;
1712
- if (!argTypes)
1713
- return undefined;
1714
- if (argTypes.length < argumentCount)
1715
- return undefined;
1716
- for (let i = 0; i < argumentCount; i++) {
1717
- if (!argTypes[i])
1718
- return undefined;
1719
- }
1720
- const catalogTypeName = normalizeCatalogTsName(declaringTypeTsName);
1721
- const declaringTypeId = resolveTypeIdByName(catalogTypeName);
1722
- if (!declaringTypeId)
1723
- return undefined;
1724
- const entry = unifiedCatalog.getByTypeId(declaringTypeId);
1725
- if (!entry || entry.origin !== "assembly")
1726
- return undefined;
1727
- const member = unifiedCatalog.getMember(declaringTypeId, declaringMemberName);
1728
- const candidates = member?.signatures;
1729
- if (!candidates || candidates.length === 0)
1730
- return undefined;
1731
- const resolveCandidate = (signature) => {
1732
- if (!isArityCompatible(signature, argumentCount))
1733
- return undefined;
1734
- let workingParams = signature.parameters.map((p) => p.type);
1735
- let workingReturn = signature.returnType;
1736
- // Receiver substitution (class type params) for instance calls.
1737
- if (receiverType) {
1738
- const receiverSubst = computeReceiverSubstitution(receiverType, catalogTypeName, declaringMemberName);
1739
- if (receiverSubst && receiverSubst.size > 0) {
1740
- workingParams = workingParams.map((p) => irSubstitute(p, receiverSubst));
1741
- workingReturn = irSubstitute(workingReturn, receiverSubst);
1742
- }
1743
- }
1744
- // Method type parameter substitution.
1745
- const methodTypeParams = signature.typeParameters.map((tp) => ({
1746
- name: tp.name,
1747
- constraint: tp.constraint,
1748
- defaultType: tp.defaultType,
1749
- }));
1750
- if (methodTypeParams.length > 0) {
1751
- const callSubst = new Map();
1752
- if (explicitTypeArgs) {
1753
- for (let i = 0; i < Math.min(explicitTypeArgs.length, methodTypeParams.length); i++) {
1754
- const param = methodTypeParams[i];
1755
- const arg = explicitTypeArgs[i];
1756
- if (param && arg) {
1757
- callSubst.set(param.name, arg);
1758
- }
1759
- }
1760
- }
1761
- const paramsForInference = callSubst.size > 0
1762
- ? workingParams.map((p) => irSubstitute(p, callSubst))
1763
- : workingParams;
1764
- const inferred = inferMethodTypeArgsFromArguments(methodTypeParams, paramsForInference, argTypes);
1765
- if (!inferred)
1766
- return undefined;
1767
- for (const [name, inferredType] of inferred) {
1768
- const existing = callSubst.get(name);
1769
- if (existing) {
1770
- if (!typesEqual(existing, inferredType))
1771
- return undefined;
1772
- continue;
1773
- }
1774
- callSubst.set(name, inferredType);
1775
- }
1776
- for (const tp of methodTypeParams) {
1777
- if (!callSubst.has(tp.name) && tp.defaultType) {
1778
- callSubst.set(tp.name, tp.defaultType);
1779
- }
1780
- }
1781
- if (callSubst.size > 0) {
1782
- workingParams = workingParams.map((p) => irSubstitute(p, callSubst));
1783
- workingReturn = irSubstitute(workingReturn, callSubst);
1784
- }
1785
- const unresolved = new Set(methodTypeParams
1786
- .map((tp) => tp.name)
1787
- .filter((name) => !callSubst.has(name)));
1788
- if (unresolved.size > 0 &&
1789
- containsMethodTypeParameter(workingReturn, unresolved)) {
1790
- return undefined;
1791
- }
1792
- }
1793
- return {
1794
- parameterTypes: workingParams,
1795
- parameterModes: signature.parameters.map((p) => p.mode),
1796
- returnType: workingReturn,
1797
- typePredicate: undefined,
1798
- diagnostics: [],
1799
- };
1800
- };
1801
- let best;
1802
- for (const sig of candidates) {
1803
- const resolved = resolveCandidate(sig);
1804
- if (!resolved)
1805
- continue;
1806
- if (resolved.returnType.kind === "unknownType")
1807
- continue;
1808
- const candidate = {
1809
- resolved,
1810
- score: scoreSignatureMatch(resolved.parameterTypes, argTypes, argumentCount),
1811
- typeParamCount: sig.typeParameters.length,
1812
- parameterCount: sig.parameters.length,
1813
- stableId: sig.stableId,
1814
- };
1815
- if (!best) {
1816
- best = candidate;
1817
- continue;
1818
- }
1819
- const better = candidate.score > best.score ||
1820
- (candidate.score === best.score &&
1821
- candidate.typeParamCount < best.typeParamCount) ||
1822
- (candidate.score === best.score &&
1823
- candidate.typeParamCount === best.typeParamCount &&
1824
- candidate.parameterCount < best.parameterCount) ||
1825
- (candidate.score === best.score &&
1826
- candidate.typeParamCount === best.typeParamCount &&
1827
- candidate.parameterCount === best.parameterCount &&
1828
- candidate.stableId < best.stableId);
1829
- if (better)
1830
- best = candidate;
1831
- }
1832
- return best?.resolved;
1833
- };
1834
- const resolveCall = (query) => {
1835
- const { sigId, argumentCount, receiverType, explicitTypeArgs, argTypes, site, } = query;
1836
- // 1. Load raw signature (cached)
1837
- const rawSig = getRawSignature(sigId);
1838
- if (!rawSig) {
1839
- // BINDING CONTRACT VIOLATION (Alice's spec): If Binding returned a
1840
- // SignatureId, HandleRegistry.getSignature(sigId) MUST succeed.
1841
- // This indicates a bug in Binding, not a normal runtime condition.
1842
- //
1843
- // However, we cannot throw during normal compilation as it would
1844
- // crash the compiler. Instead, emit diagnostic and return poisoned
1845
- // result with correct arity.
1846
- emitDiagnostic("TSN5203", `Cannot resolve signature (Binding contract violation: ID ${sigId.id} not in HandleRegistry)`, site);
1847
- return poisonedCall(argumentCount, diagnostics.slice());
1848
- }
1849
- // 2. Start with raw types
1850
- let workingParams = [...rawSig.parameterTypes];
1851
- let workingThisParam = rawSig.thisParameterType;
1852
- let workingReturn = rawSig.returnType;
1853
- let workingPredicate = rawSig.typePredicate;
1854
- // 3. Compute receiver substitution (class type params)
1855
- if (receiverType &&
1856
- rawSig.declaringTypeTsName &&
1857
- rawSig.declaringMemberName) {
1858
- const receiverSubst = computeReceiverSubstitution(receiverType, rawSig.declaringTypeTsName, rawSig.declaringMemberName);
1859
- if (receiverSubst && receiverSubst.size > 0) {
1860
- workingParams = workingParams.map((p) => p ? irSubstitute(p, receiverSubst) : undefined);
1861
- if (workingThisParam) {
1862
- workingThisParam = irSubstitute(workingThisParam, receiverSubst);
1863
- }
1864
- workingReturn = irSubstitute(workingReturn, receiverSubst);
1865
- if (workingPredicate) {
1866
- workingPredicate =
1867
- workingPredicate.kind === "param"
1868
- ? {
1869
- ...workingPredicate,
1870
- targetType: irSubstitute(workingPredicate.targetType, receiverSubst),
1871
- }
1872
- : {
1873
- ...workingPredicate,
1874
- targetType: irSubstitute(workingPredicate.targetType, receiverSubst),
1875
- };
1876
- }
1877
- }
1878
- }
1879
- // 4. Compute call substitution (method type params)
1880
- const methodTypeParams = rawSig.typeParameters;
1881
- if (methodTypeParams.length > 0) {
1882
- const callSubst = new Map();
1883
- // Source 1: Explicit type args from call syntax
1884
- if (explicitTypeArgs) {
1885
- for (let i = 0; i < Math.min(explicitTypeArgs.length, methodTypeParams.length); i++) {
1886
- const param = methodTypeParams[i];
1887
- const arg = explicitTypeArgs[i];
1888
- if (param && arg) {
1889
- callSubst.set(param.name, arg);
1890
- }
1891
- }
1892
- }
1893
- // Source 2: Deterministic argument-driven unification
1894
- // 2a) Receiver-driven unification via TS `this:` parameter
1895
- //
1896
- // Method-table extension typing represents the receiver as an explicit `this:` parameter
1897
- // in the `.d.ts` signature. Generic methods like:
1898
- // ToArrayAsync<T>(this: IQueryable<T>, ...): Task<T[]>
1899
- // must infer T from the receiver even when there are ZERO call arguments.
1900
- //
1901
- // This is airplane-grade determinism: we anchor inference to the selected TS signature’s
1902
- // `this:` type and the IR receiver type (not TS structural tricks).
1903
- if (receiverType && workingThisParam) {
1904
- const receiverParamForInference = callSubst.size > 0
1905
- ? irSubstitute(workingThisParam, callSubst)
1906
- : workingThisParam;
1907
- const inferredFromReceiver = inferMethodTypeArgsFromArguments(methodTypeParams, [receiverParamForInference], [receiverType]);
1908
- if (inferredFromReceiver) {
1909
- for (const [name, inferredType] of inferredFromReceiver) {
1910
- const existing = callSubst.get(name);
1911
- if (existing) {
1912
- if (!typesEqual(existing, inferredType)) {
1913
- emitDiagnostic("TSN5202", `Conflicting type argument inference for '${name}' (receiver)`, site);
1914
- return poisonedCall(argumentCount, diagnostics.slice());
1915
- }
1916
- continue;
1917
- }
1918
- callSubst.set(name, inferredType);
1919
- }
1920
- }
1921
- }
1922
- // 2b) Argument-driven unification (run even when argTypes is empty).
1923
- if (argTypes) {
1924
- const paramsForInference = callSubst.size > 0
1925
- ? workingParams.map((p) => p ? irSubstitute(p, callSubst) : undefined)
1926
- : workingParams;
1927
- const inferred = inferMethodTypeArgsFromArguments(methodTypeParams, paramsForInference, argTypes);
1928
- if (!inferred) {
1929
- emitDiagnostic("TSN5202", "Type arguments cannot be inferred deterministically from arguments", site);
1930
- return poisonedCall(argumentCount, diagnostics.slice());
1931
- }
1932
- for (const [name, inferredType] of inferred) {
1933
- const existing = callSubst.get(name);
1934
- if (existing) {
1935
- if (!typesEqual(existing, inferredType)) {
1936
- emitDiagnostic("TSN5202", `Conflicting type argument inference for '${name}'`, site);
1937
- return poisonedCall(argumentCount, diagnostics.slice());
1938
- }
1939
- continue;
1940
- }
1941
- callSubst.set(name, inferredType);
1942
- }
1943
- }
1944
- // Source 3: Default type parameters
1945
- for (const tp of methodTypeParams) {
1946
- if (!callSubst.has(tp.name) && tp.defaultType) {
1947
- callSubst.set(tp.name, tp.defaultType);
1948
- }
1949
- }
1950
- // Apply call substitution
1951
- if (callSubst.size > 0) {
1952
- workingParams = workingParams.map((p) => p ? irSubstitute(p, callSubst) : undefined);
1953
- workingReturn = irSubstitute(workingReturn, callSubst);
1954
- if (workingPredicate) {
1955
- workingPredicate =
1956
- workingPredicate.kind === "param"
1957
- ? {
1958
- ...workingPredicate,
1959
- targetType: irSubstitute(workingPredicate.targetType, callSubst),
1960
- }
1961
- : {
1962
- ...workingPredicate,
1963
- targetType: irSubstitute(workingPredicate.targetType, callSubst),
1964
- };
1965
- }
1966
- }
1967
- // Check for unresolved method type parameters (after explicit/arg/default inference)
1968
- const unresolved = new Set(methodTypeParams
1969
- .map((tp) => tp.name)
1970
- .filter((name) => !callSubst.has(name)));
1971
- if (unresolved.size > 0 &&
1972
- containsMethodTypeParameter(workingReturn, unresolved)) {
1973
- const fallback = argTypes && rawSig.declaringTypeTsName && rawSig.declaringMemberName
1974
- ? tryResolveCallFromUnifiedCatalog(rawSig.declaringTypeTsName, rawSig.declaringMemberName, query)
1975
- : undefined;
1976
- if (fallback) {
1977
- return fallback;
1978
- }
1979
- emitDiagnostic("TSN5202", "Return type contains unresolved type parameters - explicit type arguments required", site);
1980
- workingReturn = unknownType;
1981
- }
1982
- }
1983
- const resolved = {
1984
- parameterTypes: workingParams,
1985
- parameterModes: rawSig.parameterModes,
1986
- returnType: workingReturn,
1987
- typePredicate: workingPredicate,
1988
- diagnostics: [],
1989
- };
1990
- // CLR overload correction (airplane-grade determinism):
1991
- //
1992
- // TypeScript cannot always select the correct overload for CLR APIs because some
1993
- // Tsonic surface types intentionally erase to TS primitives (e.g., `char` is `string`
1994
- // in @tsonic/core for TSC compatibility). This can cause TS to resolve calls like
1995
- // Console.writeLine("Hello") to a `char` overload, which is semantically invalid.
1996
- //
1997
- // When we have full argument types, and the call targets an assembly-origin type,
1998
- // prefer the best matching overload from the UnifiedTypeCatalog if it scores higher
1999
- // than the TS-selected signature.
2000
- if (!resolved.typePredicate &&
2001
- argTypes &&
2002
- rawSig.declaringTypeTsName &&
2003
- rawSig.declaringMemberName) {
2004
- const hasAllArgTypes = argTypes.length >= argumentCount &&
2005
- Array.from({ length: argumentCount }, (_, i) => argTypes[i]).every((t) => t !== undefined);
2006
- if (hasAllArgTypes) {
2007
- const catalogResolved = tryResolveCallFromUnifiedCatalog(rawSig.declaringTypeTsName, rawSig.declaringMemberName, query);
2008
- if (catalogResolved) {
2009
- const currentScore = scoreSignatureMatch(resolved.parameterTypes, argTypes, argumentCount);
2010
- const catalogScore = scoreSignatureMatch(catalogResolved.parameterTypes, argTypes, argumentCount);
2011
- if (catalogScore > currentScore) {
2012
- return catalogResolved;
2013
- }
2014
- }
2015
- }
2016
- }
2017
- return resolved;
2018
- };
2019
- // ─────────────────────────────────────────────────────────────────────────
2020
- // expandUtility — Utility type expansion (Step 8)
2021
- //
2022
- // Implements all 13 utility types with deterministic constraints:
2023
- // - Partial/Required/Readonly: T must be object-like
2024
- // - Pick/Omit: K must be string literal union (finite keys)
2025
- // - ReturnType/Parameters: F must be function type
2026
- // - NonNullable: Works on any type
2027
- // - Exclude/Extract: Works on any types
2028
- // - Awaited: Recursive on Promise<T>, Task<T>, ValueTask<T>
2029
- // - Record: K must be finite literal union (string/number infinite → dictionary)
2030
- // ─────────────────────────────────────────────────────────────────────────
2031
- const expandUtility = (name, args, site) => {
2032
- const firstArg = args[0];
2033
- if (!firstArg) {
2034
- emitDiagnostic("TSN7414", `Utility type '${name}' requires a type argument`, site);
2035
- return unknownType;
2036
- }
2037
- // Check if first arg contains type parameters (cannot expand)
2038
- if (containsTypeParameter(firstArg)) {
2039
- // Return unknownType - cannot expand utility types with type parameters
2040
- return unknownType;
2041
- }
2042
- switch (name) {
2043
- case "NonNullable":
2044
- return expandNonNullableUtility(firstArg);
2045
- case "Partial":
2046
- return expandMappedUtility(firstArg, "optional", site);
2047
- case "Required":
2048
- return expandMappedUtility(firstArg, "required", site);
2049
- case "Readonly":
2050
- return expandMappedUtility(firstArg, "readonly", site);
2051
- case "Pick": {
2052
- const keysArg = args[1];
2053
- if (!keysArg) {
2054
- emitDiagnostic("TSN7414", `Pick requires two type arguments`, site);
2055
- return unknownType;
2056
- }
2057
- return expandPickOmitUtility(firstArg, keysArg, true, site);
2058
- }
2059
- case "Omit": {
2060
- const keysArg = args[1];
2061
- if (!keysArg) {
2062
- emitDiagnostic("TSN7414", `Omit requires two type arguments`, site);
2063
- return unknownType;
2064
- }
2065
- return expandPickOmitUtility(firstArg, keysArg, false, site);
2066
- }
2067
- case "ReturnType":
2068
- return expandReturnTypeUtility(firstArg, site);
2069
- case "Parameters":
2070
- return expandParametersUtility(firstArg, site);
2071
- case "Exclude": {
2072
- const excludeArg = args[1];
2073
- if (!excludeArg) {
2074
- emitDiagnostic("TSN7414", `Exclude requires two type arguments`, site);
2075
- return unknownType;
2076
- }
2077
- return expandExcludeExtractUtility(firstArg, excludeArg, false);
2078
- }
2079
- case "Extract": {
2080
- const extractArg = args[1];
2081
- if (!extractArg) {
2082
- emitDiagnostic("TSN7414", `Extract requires two type arguments`, site);
2083
- return unknownType;
2084
- }
2085
- return expandExcludeExtractUtility(firstArg, extractArg, true);
2086
- }
2087
- case "Awaited":
2088
- return expandAwaitedUtility(firstArg);
2089
- case "Record": {
2090
- const valueArg = args[1];
2091
- if (!valueArg) {
2092
- emitDiagnostic("TSN7414", `Record requires two type arguments`, site);
2093
- return unknownType;
2094
- }
2095
- return expandRecordUtility(firstArg, valueArg, site);
2096
- }
2097
- default:
2098
- emitDiagnostic("TSN7414", `Utility type '${name}' is not supported`, site);
2099
- return unknownType;
2100
- }
2101
- };
2102
- // ─────────────────────────────────────────────────────────────────────────
2103
- // Utility Type Helper Functions
2104
- // ─────────────────────────────────────────────────────────────────────────
2105
- /**
2106
- * Expand NonNullable<T>: Filter out null and undefined from union
2107
- */
2108
- const expandNonNullableUtility = (type) => {
2109
- // Direct null/undefined
2110
- if (isNullishPrimitive(type)) {
2111
- return neverType;
2112
- }
2113
- // Not a union - return as-is
2114
- if (type.kind !== "unionType") {
2115
- return type;
2116
- }
2117
- // Filter out null and undefined from union
2118
- const filtered = type.types.filter((t) => !isNullishPrimitive(t));
2119
- if (filtered.length === 0) {
2120
- return neverType;
2121
- }
2122
- if (filtered.length === 1 && filtered[0]) {
2123
- return filtered[0];
2124
- }
2125
- return { kind: "unionType", types: filtered };
2126
- };
2127
- /**
2128
- * Expand Partial/Required/Readonly<T>: Mapped type transformation
2129
- */
2130
- const expandMappedUtility = (type, mode, site) => {
2131
- // Must be object-like
2132
- if (type.kind !== "objectType") {
2133
- // For reference types, we need structural members
2134
- if (type.kind === "referenceType") {
2135
- // Try to get structural members from type
2136
- const members = getStructuralMembersForType(type);
2137
- if (members.length === 0) {
2138
- emitDiagnostic("TSN7414", `${mode === "optional" ? "Partial" : mode === "required" ? "Required" : "Readonly"} requires a concrete object type`, site);
2139
- return unknownType;
2140
- }
2141
- // Transform the members
2142
- return {
2143
- kind: "objectType",
2144
- members: transformMembers(members, mode),
2145
- };
2146
- }
2147
- emitDiagnostic("TSN7414", `${mode === "optional" ? "Partial" : mode === "required" ? "Required" : "Readonly"} requires an object type`, site);
2148
- return unknownType;
2149
- }
2150
- return {
2151
- kind: "objectType",
2152
- members: transformMembers(type.members, mode),
2153
- };
2154
- };
2155
- /**
2156
- * Transform members for Partial/Required/Readonly
2157
- */
2158
- const transformMembers = (members, mode) => {
2159
- return members.map((m) => {
2160
- if (m.kind === "propertySignature") {
2161
- return {
2162
- ...m,
2163
- isOptional: mode === "optional"
2164
- ? true
2165
- : mode === "required"
2166
- ? false
2167
- : m.isOptional,
2168
- isReadonly: mode === "readonly" ? true : m.isReadonly,
2169
- };
2170
- }
2171
- return m;
2172
- });
2173
- };
2174
- /**
2175
- * Get structural members for a reference type
2176
- */
2177
- const getStructuralMembersForType = (type) => {
2178
- if (type.structuralMembers) {
2179
- return type.structuralMembers;
2180
- }
2181
- // Try to look up in registry
2182
- const fqName = typeRegistry.getFQName(type.name);
2183
- const entry = fqName
2184
- ? typeRegistry.resolveNominal(fqName)
2185
- : typeRegistry.resolveBySimpleName(type.name);
2186
- if (!entry)
2187
- return [];
2188
- // Convert registry members to IR members
2189
- const members = [];
2190
- entry.members.forEach((info, name) => {
2191
- if (info.kind === "property" && info.type) {
2192
- members.push({
2193
- kind: "propertySignature",
2194
- name,
2195
- type: info.type,
2196
- isOptional: info.isOptional,
2197
- isReadonly: info.isReadonly,
2198
- });
2199
- }
2200
- });
2201
- return members;
2202
- };
2203
- /**
2204
- * Expand Pick/Omit<T, K>: Filter members by keys
2205
- */
2206
- const expandPickOmitUtility = (type, keysType, isPick, site) => {
2207
- // Extract literal keys from keysType
2208
- const keys = extractLiteralKeys(keysType);
2209
- if (keys === null) {
2210
- emitDiagnostic("TSN7414", `${isPick ? "Pick" : "Omit"} requires literal string keys`, site);
2211
- return unknownType;
2212
- }
2213
- // Get members from type
2214
- let members;
2215
- if (type.kind === "objectType") {
2216
- members = type.members;
2217
- }
2218
- else if (type.kind === "referenceType") {
2219
- members = getStructuralMembersForType(type);
2220
- }
2221
- else {
2222
- emitDiagnostic("TSN7414", `${isPick ? "Pick" : "Omit"} requires an object type`, site);
2223
- return unknownType;
2224
- }
2225
- // Filter members
2226
- const filtered = members.filter((m) => {
2227
- const include = isPick ? keys.has(m.name) : !keys.has(m.name);
2228
- return include;
2229
- });
2230
- return { kind: "objectType", members: filtered };
2231
- };
2232
- /**
2233
- * Extract literal keys from a type (string literals or union of string literals)
2234
- */
2235
- const extractLiteralKeys = (type) => {
2236
- if (type.kind === "literalType" && typeof type.value === "string") {
2237
- return new Set([type.value]);
2238
- }
2239
- if (type.kind === "unionType") {
2240
- const keys = new Set();
2241
- for (const t of type.types) {
2242
- if (t.kind === "literalType" && typeof t.value === "string") {
2243
- keys.add(t.value);
2244
- }
2245
- else if (t.kind === "literalType" && typeof t.value === "number") {
2246
- keys.add(String(t.value));
2247
- }
2248
- else {
2249
- return null; // Non-literal in union
2250
- }
2251
- }
2252
- return keys;
2253
- }
2254
- return null;
2255
- };
2256
- /**
2257
- * Expand ReturnType<F>: Extract return type from function type
2258
- */
2259
- const expandReturnTypeUtility = (type, site) => {
2260
- if (type.kind === "functionType") {
2261
- return type.returnType ?? voidType;
2262
- }
2263
- emitDiagnostic("TSN7414", `ReturnType requires a function type argument`, site);
2264
- return unknownType;
2265
- };
2266
- /**
2267
- * Expand Parameters<F>: Extract parameters as tuple from function type
2268
- */
2269
- const expandParametersUtility = (type, site) => {
2270
- if (type.kind === "functionType") {
2271
- const elementTypes = type.parameters.map((p) => p.type ?? { kind: "anyType" });
2272
- return { kind: "tupleType", elementTypes };
2273
- }
2274
- emitDiagnostic("TSN7414", `Parameters requires a function type argument`, site);
2275
- return unknownType;
2276
- };
2277
- /**
2278
- * Expand Exclude<T, U> or Extract<T, U>
2279
- */
2280
- const expandExcludeExtractUtility = (tType, uType, isExtract) => {
2281
- // If T is not a union, check if it matches U
2282
- if (tType.kind !== "unionType") {
2283
- const matches = typesEqual(tType, uType) ||
2284
- (uType.kind === "unionType" &&
2285
- uType.types.some((u) => typesEqual(tType, u)));
2286
- if (isExtract) {
2287
- return matches ? tType : neverType;
2288
- }
2289
- else {
2290
- return matches ? neverType : tType;
2291
- }
2292
- }
2293
- // T is a union - filter its constituents
2294
- const uTypes = uType.kind === "unionType" ? uType.types : [uType];
2295
- const filtered = tType.types.filter((t) => {
2296
- const matches = uTypes.some((u) => typesEqual(t, u));
2297
- return isExtract ? matches : !matches;
2298
- });
2299
- if (filtered.length === 0) {
2300
- return neverType;
2301
- }
2302
- if (filtered.length === 1 && filtered[0]) {
2303
- return filtered[0];
2304
- }
2305
- return { kind: "unionType", types: filtered };
2306
- };
2307
- /**
2308
- * Expand Awaited<T>: Unwrap Promise / Task / ValueTask types recursively.
2309
- */
2310
- const expandAwaitedUtility = (type) => {
2311
- if (type.kind === "unionType") {
2312
- return {
2313
- kind: "unionType",
2314
- types: type.types.map((t) => expandAwaitedUtility(t)),
2315
- };
2316
- }
2317
- // Check for Promise<T>
2318
- if (type.kind === "referenceType" &&
2319
- (type.name === "Promise" || type.name === "PromiseLike")) {
2320
- const innerType = type.typeArguments?.[0];
2321
- if (innerType) {
2322
- // Recursively unwrap
2323
- return expandAwaitedUtility(innerType);
2324
- }
2325
- }
2326
- // CLR awaitables: Task / ValueTask
2327
- if (type.kind === "referenceType") {
2328
- const clrName = type.typeId?.clrName;
2329
- // Non-generic: await Task / await ValueTask => void
2330
- if (clrName === "System.Threading.Tasks.Task" ||
2331
- clrName === "System.Threading.Tasks.ValueTask") {
2332
- return voidType;
2333
- }
2334
- // Generic: await Task<T> / await ValueTask<T> => T (recursively)
2335
- if (clrName?.startsWith("System.Threading.Tasks.Task`") ||
2336
- clrName?.startsWith("System.Threading.Tasks.ValueTask`")) {
2337
- const innerType = type.typeArguments?.[0];
2338
- if (innerType)
2339
- return expandAwaitedUtility(innerType);
2340
- }
2341
- }
2342
- // Not an awaitable - return as-is
2343
- return type;
2344
- };
2345
- /**
2346
- * Expand Record<K, V>: Create object type from literal keys
2347
- */
2348
- const expandRecordUtility = (keyType, valueType, site) => {
2349
- // Check if K is a finite set of literal keys
2350
- const keys = extractLiteralKeys(keyType);
2351
- if (keys === null) {
2352
- // Non-finite key type - cannot expand to object, use dictionary instead
2353
- // Return unknownType to signal that caller should use dictionaryType
2354
- emitDiagnostic("TSN7414", `Record with non-literal keys cannot be expanded to object type`, site);
2355
- return unknownType;
2356
- }
2357
- // Build object type with a property for each key
2358
- const members = Array.from(keys).map((key) => ({
2359
- kind: "propertySignature",
2360
- name: key,
2361
- type: valueType,
2362
- isOptional: false,
2363
- isReadonly: false,
2364
- }));
2365
- return { kind: "objectType", members };
2366
- };
2367
- // ─────────────────────────────────────────────────────────────────────────
2368
- // substitute — Delegate to ir-substitution
2369
- // ─────────────────────────────────────────────────────────────────────────
2370
- const substitute = (type, subst) => {
2371
- // Convert TypeSubstitutionMap to IrSubstitutionMap if needed
2372
- // (they're the same type, just different naming)
2373
- return irSubstitute(type, subst);
2374
- };
2375
- // ─────────────────────────────────────────────────────────────────────────
2376
- // instantiate — Instantiate a generic type with type arguments
2377
- // ─────────────────────────────────────────────────────────────────────────
2378
- const instantiate = (typeName, typeArgs, site) => {
2379
- // Look up the type in registry
2380
- const fqName = typeRegistry.getFQName(typeName);
2381
- const entry = fqName
2382
- ? typeRegistry.resolveNominal(fqName)
2383
- : typeRegistry.resolveBySimpleName(typeName);
2384
- if (!entry) {
2385
- emitDiagnostic("TSN5203", `Cannot resolve type '${typeName}'`, site);
2386
- return unknownType;
2387
- }
2388
- // Build substitution map from type parameters to arguments
2389
- const subst = new Map();
2390
- const typeParams = entry.typeParameters;
2391
- for (let i = 0; i < Math.min(typeParams.length, typeArgs.length); i++) {
2392
- const param = typeParams[i];
2393
- const arg = typeArgs[i];
2394
- if (param && arg) {
2395
- subst.set(param.name, arg);
2396
- }
2397
- }
2398
- // Return instantiated reference type
2399
- const result = {
2400
- kind: "referenceType",
2401
- name: entry.name,
2402
- typeArguments: typeArgs.length > 0 ? [...typeArgs] : undefined,
2403
- };
2404
- return result;
2405
- };
2406
- // ─────────────────────────────────────────────────────────────────────────
2407
- // isAssignableTo — Conservative subtype check
2408
- // ─────────────────────────────────────────────────────────────────────────
2409
- const isAssignableTo = (source, target) => {
2410
- // Same type - always assignable
2411
- if (typesEqual(source, target))
2412
- return true;
2413
- // any is assignable to anything, anything is assignable to any
2414
- if (source.kind === "anyType" || target.kind === "anyType")
2415
- return true;
2416
- // never is assignable to anything
2417
- if (source.kind === "neverType")
2418
- return true;
2419
- // undefined/null assignability (represented as primitiveType with name "null"/"undefined")
2420
- if (isNullishPrimitive(source)) {
2421
- // Assignable to union containing undefined/null
2422
- if (target.kind === "unionType") {
2423
- return target.types.some((t) => t.kind === "primitiveType" && t.name === source.name);
2424
- }
2425
- return false;
2426
- }
2427
- // Primitives - same primitive type
2428
- if (source.kind === "primitiveType" && target.kind === "primitiveType") {
2429
- return source.name === target.name;
2430
- }
2431
- // Union source - all members must be assignable
2432
- if (source.kind === "unionType") {
2433
- return source.types.every((t) => isAssignableTo(t, target));
2434
- }
2435
- // Union target - source must be assignable to at least one member
2436
- if (target.kind === "unionType") {
2437
- return target.types.some((t) => isAssignableTo(source, t));
2438
- }
2439
- // Array types
2440
- if (source.kind === "arrayType" && target.kind === "arrayType") {
2441
- return isAssignableTo(source.elementType, target.elementType);
2442
- }
2443
- // Reference types - check nominal compatibility via TypeId
2444
- if (source.kind === "referenceType" && target.kind === "referenceType") {
2445
- const sourceNominal = normalizeToNominal(source);
2446
- const targetNominal = normalizeToNominal(target);
2447
- if (!sourceNominal || !targetNominal)
2448
- return false;
2449
- if (sourceNominal.typeId.stableId === targetNominal.typeId.stableId) {
2450
- const sourceArgs = sourceNominal.typeArgs;
2451
- const targetArgs = targetNominal.typeArgs;
2452
- if (sourceArgs.length !== targetArgs.length)
2453
- return false;
2454
- return sourceArgs.every((sa, i) => {
2455
- const ta = targetArgs[i];
2456
- return ta ? typesEqual(sa, ta) : false;
2457
- });
2458
- }
2459
- const chain = nominalEnv.getInheritanceChain(sourceNominal.typeId);
2460
- return chain.some((t) => t.stableId === targetNominal.typeId.stableId);
2461
- }
2462
- // Conservative - return false if unsure
2463
- return false;
2464
- };
2465
- // ─────────────────────────────────────────────────────────────────────────
2466
- // typesEqual — Structural equality check
2467
- // ─────────────────────────────────────────────────────────────────────────
2468
- const typesEqual = (a, b) => {
2469
- if (a.kind !== b.kind)
2470
- return false;
2471
- switch (a.kind) {
2472
- case "primitiveType":
2473
- return b.kind === "primitiveType" && a.name === b.name;
2474
- case "referenceType": {
2475
- if (b.kind !== "referenceType")
2476
- return false;
2477
- if (a.name !== b.name)
2478
- return false;
2479
- const aArgs = a.typeArguments ?? [];
2480
- const bArgs = b.typeArguments ?? [];
2481
- if (aArgs.length !== bArgs.length)
2482
- return false;
2483
- return aArgs.every((arg, i) => {
2484
- const bArg = bArgs[i];
2485
- return bArg ? typesEqual(arg, bArg) : false;
2486
- });
2487
- }
2488
- case "arrayType":
2489
- return (b.kind === "arrayType" &&
2490
- typesEqual(a.elementType, b.elementType));
2491
- case "tupleType": {
2492
- if (b.kind !== "tupleType")
2493
- return false;
2494
- const bTyped = b;
2495
- if (a.elementTypes.length !== bTyped.elementTypes.length)
2496
- return false;
2497
- return a.elementTypes.every((el, i) => {
2498
- const bEl = bTyped.elementTypes[i];
2499
- return bEl ? typesEqual(el, bEl) : false;
2500
- });
2501
- }
2502
- case "unionType":
2503
- case "intersectionType": {
2504
- if (b.kind !== a.kind)
2505
- return false;
2506
- const bTyped = b;
2507
- if (a.types.length !== bTyped.types.length)
2508
- return false;
2509
- // Order-independent comparison for unions/intersections
2510
- return a.types.every((at) => bTyped.types.some((bt) => typesEqual(at, bt)));
2511
- }
2512
- case "functionType": {
2513
- if (b.kind !== "functionType")
2514
- return false;
2515
- const bTyped = b;
2516
- if (a.parameters.length !== bTyped.parameters.length)
2517
- return false;
2518
- const paramsEqual = a.parameters.every((ap, i) => {
2519
- const bp = bTyped.parameters[i];
2520
- if (!bp)
2521
- return false;
2522
- if (ap.type && bp.type)
2523
- return typesEqual(ap.type, bp.type);
2524
- return !ap.type && !bp.type;
2525
- });
2526
- if (!paramsEqual)
2527
- return false;
2528
- if (a.returnType && bTyped.returnType) {
2529
- return typesEqual(a.returnType, bTyped.returnType);
2530
- }
2531
- return !a.returnType && !bTyped.returnType;
2532
- }
2533
- case "typeParameterType":
2534
- return (b.kind === "typeParameterType" && a.name === b.name);
2535
- case "literalType":
2536
- return b.kind === "literalType" && a.value === b.value;
2537
- case "voidType":
2538
- case "neverType":
2539
- case "unknownType":
2540
- case "anyType":
2541
- return a.kind === b.kind;
2542
- default:
2543
- // For other types, fall back to JSON comparison
2544
- return JSON.stringify(a) === JSON.stringify(b);
2545
- }
2546
- };
2547
- // ─────────────────────────────────────────────────────────────────────────
2548
- // containsTypeParameter — Check if type contains unresolved type params
2549
- // ─────────────────────────────────────────────────────────────────────────
2550
- const containsTypeParameter = (type) => {
2551
- if (type.kind === "typeParameterType")
2552
- return true;
2553
- if (type.kind === "referenceType") {
2554
- return (type.typeArguments ?? []).some(containsTypeParameter);
2555
- }
2556
- if (type.kind === "arrayType") {
2557
- return containsTypeParameter(type.elementType);
2558
- }
2559
- if (type.kind === "functionType") {
2560
- const paramsContain = type.parameters.some((p) => p.type && containsTypeParameter(p.type));
2561
- const returnContains = type.returnType && containsTypeParameter(type.returnType);
2562
- return paramsContain || !!returnContains;
2563
- }
2564
- if (type.kind === "unionType" || type.kind === "intersectionType") {
2565
- return type.types.some(containsTypeParameter);
2566
- }
2567
- if (type.kind === "tupleType") {
2568
- return type.elementTypes.some(containsTypeParameter);
2569
- }
2570
- if (type.kind === "objectType") {
2571
- return type.members.some((m) => {
2572
- if (m.kind === "propertySignature") {
2573
- return containsTypeParameter(m.type);
2574
- }
2575
- if (m.kind === "methodSignature") {
2576
- const paramsContain = m.parameters.some((p) => p.type && containsTypeParameter(p.type));
2577
- const returnContains = m.returnType && containsTypeParameter(m.returnType);
2578
- return paramsContain || !!returnContains;
2579
- }
2580
- return false;
2581
- });
2582
- }
2583
- return false;
2584
- };
2585
- const getDiagnostics = () => {
2586
- return diagnostics.slice();
2587
- };
2588
- const clearDiagnostics = () => {
2589
- diagnostics.length = 0;
2590
- };
2591
- // ─────────────────────────────────────────────────────────────────────────
2592
- // hasTypeParameters — Check if declaration has type parameters
2593
- // ─────────────────────────────────────────────────────────────────────────
2594
- const hasTypeParameters = (declId) => {
2595
- const declInfo = handleRegistry.getDecl(declId);
2596
- if (!declInfo?.declNode)
2597
- return false;
2598
- // Check the declaration node for type parameters
2599
- // We need to import ts to check for type parameter declarations
2600
- // Access the declNode as any to check for typeParameters property
2601
- const declNode = declInfo.declNode;
2602
- return !!(declNode.typeParameters && declNode.typeParameters.length > 0);
2603
- };
2604
- // ─────────────────────────────────────────────────────────────────────────
2605
- // typeOfMemberId — Get type of member by handle
2606
- // ─────────────────────────────────────────────────────────────────────────
2607
- const typeOfMemberId = (memberId) => {
2608
- const memberInfo = handleRegistry.getMember(memberId);
2609
- if (!memberInfo) {
2610
- return unknownType;
2611
- }
2612
- // If the member has a type node, convert it
2613
- if (memberInfo.typeNode) {
2614
- return convertTypeNode(memberInfo.typeNode);
2615
- }
2616
- // Otherwise, attempt to recover type deterministically from the member declaration.
2617
- // This is required for namespace imports (`import * as X`) where members are
2618
- // function declarations / const declarations (no typeNode captured by Binding).
2619
- const decl = memberInfo.declNode;
2620
- if (decl) {
2621
- if (ts.isFunctionDeclaration(decl)) {
2622
- // Determinism: require explicit parameter + return annotations.
2623
- if (!decl.type)
2624
- return unknownType;
2625
- if (decl.parameters.some((p) => p.type === undefined))
2626
- return unknownType;
2627
- const parameters = decl.parameters.map((p) => ({
2628
- kind: "parameter",
2629
- pattern: {
2630
- kind: "identifierPattern",
2631
- name: ts.isIdentifier(p.name) ? p.name.text : "param",
2632
- },
2633
- type: p.type ? convertTypeNode(p.type) : undefined,
2634
- initializer: undefined,
2635
- isOptional: !!p.questionToken || !!p.initializer,
2636
- isRest: !!p.dotDotDotToken,
2637
- passing: "value",
2638
- }));
2639
- const returnType = convertTypeNode(decl.type);
2640
- const fnType = {
2641
- kind: "functionType",
2642
- parameters,
2643
- returnType,
2644
- };
2645
- return fnType;
2646
- }
2647
- if (ts.isVariableDeclaration(decl)) {
2648
- if (decl.type)
2649
- return convertTypeNode(decl.type);
2650
- const inferred = tryInferTypeFromInitializer(decl);
2651
- return inferred ?? unknownType;
2652
- }
2653
- }
2654
- return unknownType;
2655
- };
2656
- // ─────────────────────────────────────────────────────────────────────────
2657
- // getFQNameOfDecl — Get fully-qualified name of declaration
2658
- // ─────────────────────────────────────────────────────────────────────────
2659
- const getFQNameOfDecl = (declId) => {
2660
- const declInfo = handleRegistry.getDecl(declId);
2661
- return declInfo?.fqName;
2662
- };
2663
- // ─────────────────────────────────────────────────────────────────────────
2664
- // isTypeDecl — Check if declaration is a type
2665
- // ─────────────────────────────────────────────────────────────────────────
2666
- const isTypeDecl = (declId) => {
2667
- const declInfo = handleRegistry.getDecl(declId);
2668
- if (!declInfo)
2669
- return false;
2670
- const typeKinds = [
2671
- "interface",
2672
- "class",
2673
- "typeAlias",
2674
- "enum",
2675
- ];
2676
- return typeKinds.includes(declInfo.kind);
2677
- };
2678
- // ─────────────────────────────────────────────────────────────────────────
2679
- // isInterfaceDecl — Check if declaration is an interface
2680
- // ─────────────────────────────────────────────────────────────────────────
2681
- const isInterfaceDecl = (declId) => {
2682
- const declInfo = handleRegistry.getDecl(declId);
2683
- return declInfo?.kind === "interface";
2684
- };
2685
- // ─────────────────────────────────────────────────────────────────────────
2686
- // isTypeAliasToObjectLiteral — Check if type alias points to object literal
2687
- // ─────────────────────────────────────────────────────────────────────────
2688
- const isTypeAliasToObjectLiteral = (declId) => {
2689
- const declInfo = handleRegistry.getDecl(declId);
2690
- if (!declInfo || declInfo.kind !== "typeAlias")
2691
- return false;
2692
- // Check if the typeNode is a type literal node
2693
- // We need to access the declNode to get the type alias declaration
2694
- const declNode = declInfo.declNode;
2695
- if (!declNode?.type)
2696
- return false;
2697
- return declNode.type.kind === ts.SyntaxKind.TypeLiteral;
2698
- };
2699
- // Suppress unused variable warning for nominalMemberLookupCache
2700
- // Will be used for more advanced caching in future
2701
- void nominalMemberLookupCache;
2702
- // ─────────────────────────────────────────────────────────────────────────
2703
- // signatureHasConditionalReturn — Check for conditional return type
2704
- // ─────────────────────────────────────────────────────────────────────────
2705
- const signatureHasConditionalReturn = (sigId) => {
2706
- const sigInfo = handleRegistry.getSignature(sigId);
2707
- if (!sigInfo)
2708
- return false;
2709
- const returnTypeNode = sigInfo.returnTypeNode;
2710
- if (!returnTypeNode)
2711
- return false;
2712
- return returnTypeNode.kind === ts.SyntaxKind.ConditionalType;
2713
- };
2714
- // ─────────────────────────────────────────────────────────────────────────
2715
- // signatureHasVariadicTypeParams — Check for variadic type parameters
2716
- // ─────────────────────────────────────────────────────────────────────────
2717
- const signatureHasVariadicTypeParams = (sigId) => {
2718
- const sigInfo = handleRegistry.getSignature(sigId);
2719
- if (!sigInfo)
2720
- return false;
2721
- if (!sigInfo.typeParameters)
2722
- return false;
2723
- for (const typeParam of sigInfo.typeParameters) {
2724
- const constraintNode = typeParam.constraintNode;
2725
- if (!constraintNode)
2726
- continue;
2727
- // Check if constraint is an array type (variadic pattern: T extends unknown[])
2728
- if (constraintNode.kind === ts.SyntaxKind.ArrayType) {
2729
- const elementType = constraintNode.elementType;
2730
- if (!elementType)
2731
- continue;
2732
- // Check for unknown[] or any[] constraint
2733
- if (elementType.kind === ts.SyntaxKind.UnknownKeyword ||
2734
- elementType.kind === ts.SyntaxKind.AnyKeyword) {
2735
- return true;
2736
- }
2737
- // Also check for type reference to "unknown" or "any"
2738
- const typeName = elementType.typeName?.text;
2739
- if (typeName === "unknown" || typeName === "any") {
2740
- return true;
2741
- }
2742
- }
2743
- }
2744
- return false;
2745
- };
2746
- // ─────────────────────────────────────────────────────────────────────────
2747
- // declHasTypeAnnotation — Check if declaration has explicit type
2748
- // ─────────────────────────────────────────────────────────────────────────
2749
- const declHasTypeAnnotation = (declId) => {
2750
- const declInfo = handleRegistry.getDecl(declId);
2751
- return declInfo?.typeNode !== undefined;
2752
- };
2753
- // ─────────────────────────────────────────────────────────────────────────
2754
- // checkTsClassMemberOverride — Check if member can be overridden
2755
- // ─────────────────────────────────────────────────────────────────────────
2756
- /**
2757
- * Check if a class member overrides a base class member.
2758
- *
2759
- * ALICE'S SPEC: Uses captured ClassMemberNames (pure data) from Binding.
2760
- * No TS AST inspection, no SyntaxKind numbers. TS-version safe.
2761
- */
2762
- const checkTsClassMemberOverride = (declId, memberName, memberKind) => {
2763
- const declInfo = handleRegistry.getDecl(declId);
2764
- const members = declInfo?.classMemberNames;
2765
- // No class member info available
2766
- if (!members) {
2767
- return { isOverride: false, isShadow: false };
2768
- }
2769
- // Check if base class has this member
2770
- const has = memberKind === "method"
2771
- ? members.methods.has(memberName)
2772
- : members.properties.has(memberName);
2773
- // In TypeScript, all methods can be overridden (no `final` keyword)
2774
- return has
2775
- ? { isOverride: true, isShadow: false }
2776
- : { isOverride: false, isShadow: false };
2777
- };
2778
- // ─────────────────────────────────────────────────────────────────────────
2779
- // typeFromSyntax — Convert captured type syntax to IrType
2780
- // ─────────────────────────────────────────────────────────────────────────
2781
- /**
2782
- * Convert a captured type syntax to IrType.
2783
- *
2784
- * This method takes a TypeSyntaxId handle (opaque to caller) and looks up
2785
- * the captured TypeNode in the HandleRegistry, then converts it.
2786
- *
2787
- * ALICE'S SPEC (Phase 2): TypeSystem receives opaque handles, not ts.TypeNode.
2788
- */
2789
- const typeFromSyntax = (typeSyntaxId) => {
2790
- const syntaxInfo = handleRegistry.getTypeSyntax(typeSyntaxId);
2791
- if (!syntaxInfo) {
2792
- // Invalid handle - return unknownType
2793
- return { kind: "unknownType" };
2794
- }
2795
- // Phase 5: convertTypeNode accepts unknown, cast is inside type-system/internal
2796
- return convertTypeNode(syntaxInfo.typeNode);
72
+ // SHARED STATE — DI container for all split functions
73
+ // ─────────────────────────────────────────────────────────────────────────
74
+ const state = {
75
+ handleRegistry,
76
+ typeRegistry,
77
+ nominalEnv,
78
+ convertTypeNodeRaw,
79
+ unifiedCatalog,
80
+ aliasTable,
81
+ resolveIdentifier,
82
+ resolveCallSignature,
83
+ resolveConstructorSignature,
84
+ declTypeCache,
85
+ memberDeclaredTypeCache,
86
+ signatureRawCache,
87
+ nominalMemberLookupCache,
88
+ diagnostics,
2797
89
  };
2798
90
  // ─────────────────────────────────────────────────────────────────────────
2799
91
  // RETURN TYPESYSTEM INSTANCE
2800
92
  // ─────────────────────────────────────────────────────────────────────────
2801
93
  return {
2802
- typeFromSyntax,
2803
- typeOfDecl,
2804
- typeOfMember,
2805
- getIndexerInfo,
2806
- typeOfMemberId,
2807
- getFQNameOfDecl,
2808
- isTypeDecl,
2809
- isInterfaceDecl,
2810
- isTypeAliasToObjectLiteral,
2811
- signatureHasConditionalReturn,
2812
- signatureHasVariadicTypeParams,
2813
- declHasTypeAnnotation,
2814
- checkTsClassMemberOverride,
2815
- resolveCall,
2816
- delegateToFunctionType,
2817
- expandUtility,
2818
- substitute,
2819
- instantiate,
2820
- isAssignableTo,
2821
- typesEqual,
2822
- containsTypeParameter,
2823
- hasTypeParameters,
2824
- getDiagnostics,
2825
- clearDiagnostics,
94
+ // Type syntax conversion (inference module)
95
+ typeFromSyntax: (typeSyntaxId) => infTypeFromSyntax(state, typeSyntaxId),
96
+ // Declaration types (inference module)
97
+ typeOfDecl: (declId) => infTypeOfDecl(state, declId),
98
+ // Member types (inference module)
99
+ typeOfMember: (receiver, member, site) => infTypeOfMember(state, receiver, member, site),
100
+ getIndexerInfo: (receiver, site) => infGetIndexerInfo(state, receiver, site),
101
+ // Call resolution (call-resolution module)
102
+ resolveCall: (query) => crResolveCall(state, query),
103
+ delegateToFunctionType: (type) => crDelegateToFunctionType(state, type),
104
+ // Utility type expansion (utilities module)
105
+ expandUtility: (name, args, site) => utExpandUtility(state, name, args, site),
106
+ // Substitution & instantiation (relations module)
107
+ substitute: (type, subst) => relSubstitute(type, subst),
108
+ instantiate: (typeName, typeArgs, site) => relInstantiate(state, typeName, typeArgs, site),
109
+ // Type relations (relations module)
110
+ isAssignableTo: (source, target) => relIsAssignableTo(state, source, target),
111
+ typesEqual: (a, b) => relTypesEqual(a, b),
112
+ containsTypeParameter: (type) => relContainsTypeParameter(type),
113
+ // Declaration inspection (inference module)
114
+ hasTypeParameters: (declId) => infHasTypeParameters(state, declId),
115
+ typeOfMemberId: (memberId) => infTypeOfMemberId(state, memberId),
116
+ getFQNameOfDecl: (declId) => infGetFQNameOfDecl(state, declId),
117
+ isTypeDecl: (declId) => infIsTypeDecl(state, declId),
118
+ isInterfaceDecl: (declId) => infIsInterfaceDecl(state, declId),
119
+ isTypeAliasToObjectLiteral: (declId) => infIsTypeAliasToObjectLiteral(state, declId),
120
+ signatureHasConditionalReturn: (sigId) => infSignatureHasConditionalReturn(state, sigId),
121
+ signatureHasVariadicTypeParams: (sigId) => infSignatureHasVariadicTypeParams(state, sigId),
122
+ declHasTypeAnnotation: (declId) => infDeclHasTypeAnnotation(state, declId),
123
+ checkTsClassMemberOverride: (declId, memberName, memberKind) => infCheckTsClassMemberOverride(state, declId, memberName, memberKind),
124
+ // Diagnostics
125
+ getDiagnostics: () => diagnostics.slice(),
126
+ clearDiagnostics: () => {
127
+ diagnostics.length = 0;
128
+ },
2826
129
  };
2827
130
  };
2828
131
  //# sourceMappingURL=type-system.js.map