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