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