@geastack/compiler 1.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/LICENSE +202 -0
- package/README.md +149 -0
- package/dist/cli-analyze.d.ts +1 -0
- package/dist/cli-analyze.js +61 -0
- package/dist/cli-coverage.d.ts +1 -0
- package/dist/cli-coverage.js +329 -0
- package/dist/cli-emit.d.ts +10 -0
- package/dist/cli-emit.js +398 -0
- package/dist/cli-module-graph.d.ts +18 -0
- package/dist/cli-module-graph.js +123 -0
- package/dist/cli-package-source.d.ts +5 -0
- package/dist/cli-package-source.js +116 -0
- package/dist/cli-project.d.ts +2 -0
- package/dist/cli-project.js +60 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +199 -0
- package/dist/compiler.d.ts +228 -0
- package/dist/compiler.js +1029 -0
- package/dist/conversion/algebra.d.ts +218 -0
- package/dist/conversion/algebra.js +155 -0
- package/dist/conversion/build.d.ts +67 -0
- package/dist/conversion/build.js +1378 -0
- package/dist/conversion/derive.d.ts +37 -0
- package/dist/conversion/derive.js +260 -0
- package/dist/conversion/graph-validation.d.ts +8 -0
- package/dist/conversion/graph-validation.js +97 -0
- package/dist/conversion/native-callable-adapter.d.ts +13 -0
- package/dist/conversion/native-callable-adapter.js +53 -0
- package/dist/conversion/native-class-reference.d.ts +12 -0
- package/dist/conversion/native-class-reference.js +39 -0
- package/dist/conversion/native-payload-transport.d.ts +25 -0
- package/dist/conversion/native-payload-transport.js +33 -0
- package/dist/conversion/native-selection.d.ts +49 -0
- package/dist/conversion/native-selection.js +135 -0
- package/dist/conversion/native-sum.d.ts +42 -0
- package/dist/conversion/native-sum.js +115 -0
- package/dist/conversion/nodes.d.ts +55 -0
- package/dist/conversion/nodes.js +91 -0
- package/dist/conversion/operand-view.d.ts +14 -0
- package/dist/conversion/operand-view.js +20 -0
- package/dist/conversion/record-view.d.ts +157 -0
- package/dist/conversion/record-view.js +273 -0
- package/dist/conversion/registry.d.ts +217 -0
- package/dist/conversion/registry.js +1 -0
- package/dist/diagnostics/model.d.ts +76 -0
- package/dist/diagnostics/model.js +60 -0
- package/dist/diagnostics/sweep.d.ts +31 -0
- package/dist/diagnostics/sweep.js +112 -0
- package/dist/identity/ids.d.ts +179 -0
- package/dist/identity/ids.js +212 -0
- package/dist/ir/absent-class-arm.d.ts +48 -0
- package/dist/ir/absent-class-arm.js +157 -0
- package/dist/ir/borrow-effects.d.ts +23 -0
- package/dist/ir/borrow-effects.js +151 -0
- package/dist/ir/borrowed-call-arguments.d.ts +40 -0
- package/dist/ir/borrowed-call-arguments.js +117 -0
- package/dist/ir/build.d.ts +168 -0
- package/dist/ir/build.js +459 -0
- package/dist/ir/call-dispatch.d.ts +38 -0
- package/dist/ir/call-dispatch.js +502 -0
- package/dist/ir/call-entry.d.ts +142 -0
- package/dist/ir/call-entry.js +386 -0
- package/dist/ir/callable-class-flow.d.ts +27 -0
- package/dist/ir/callable-class-flow.js +1386 -0
- package/dist/ir/callable-field-slots.d.ts +22 -0
- package/dist/ir/callable-field-slots.js +166 -0
- package/dist/ir/callable-identity-demand.d.ts +52 -0
- package/dist/ir/callable-identity-demand.js +460 -0
- package/dist/ir/callable-member-candidates.d.ts +9 -0
- package/dist/ir/callable-member-candidates.js +39 -0
- package/dist/ir/callable-records.d.ts +21 -0
- package/dist/ir/callable-records.js +411 -0
- package/dist/ir/captures.d.ts +26 -0
- package/dist/ir/captures.js +335 -0
- package/dist/ir/certificate.d.ts +45 -0
- package/dist/ir/certificate.js +47 -0
- package/dist/ir/certify/carrier-keys.d.ts +73 -0
- package/dist/ir/certify/carrier-keys.js +221 -0
- package/dist/ir/certify/function-source.d.ts +4 -0
- package/dist/ir/certify/function-source.js +28 -0
- package/dist/ir/certify/has-property-key.d.ts +88 -0
- package/dist/ir/certify/has-property-key.js +116 -0
- package/dist/ir/certify/instanceof-key.d.ts +24 -0
- package/dist/ir/certify/instanceof-key.js +35 -0
- package/dist/ir/certify/property-access-keys.d.ts +172 -0
- package/dist/ir/certify/property-access-keys.js +291 -0
- package/dist/ir/certify/property-access.d.ts +3 -0
- package/dist/ir/certify/property-access.js +597 -0
- package/dist/ir/certify/runtime-helper.d.ts +3 -0
- package/dist/ir/certify/runtime-helper.js +326 -0
- package/dist/ir/certify/typeof-operand.d.ts +14 -0
- package/dist/ir/certify/typeof-operand.js +16 -0
- package/dist/ir/certify.d.ts +123 -0
- package/dist/ir/certify.js +481 -0
- package/dist/ir/class-evaluation.d.ts +26 -0
- package/dist/ir/class-evaluation.js +50 -0
- package/dist/ir/class-static-fields.d.ts +60 -0
- package/dist/ir/class-static-fields.js +108 -0
- package/dist/ir/construct-entry.d.ts +26 -0
- package/dist/ir/construct-entry.js +117 -0
- package/dist/ir/dead-values.d.ts +90 -0
- package/dist/ir/dead-values.js +184 -0
- package/dist/ir/deferral.d.ts +99 -0
- package/dist/ir/deferral.js +409 -0
- package/dist/ir/dense-loops.d.ts +230 -0
- package/dist/ir/dense-loops.js +697 -0
- package/dist/ir/dominance.d.ts +82 -0
- package/dist/ir/dominance.js +268 -0
- package/dist/ir/emission-representations.d.ts +71 -0
- package/dist/ir/emission-representations.js +350 -0
- package/dist/ir/facts.d.ts +218 -0
- package/dist/ir/facts.js +181 -0
- package/dist/ir/fixed-data-definition.d.ts +19 -0
- package/dist/ir/fixed-data-definition.js +49 -0
- package/dist/ir/generator-split.d.ts +38 -0
- package/dist/ir/generator-split.js +329 -0
- package/dist/ir/hoist.d.ts +55 -0
- package/dist/ir/hoist.js +375 -0
- package/dist/ir/instantiation.d.ts +61 -0
- package/dist/ir/instantiation.js +137 -0
- package/dist/ir/integer-storage.d.ts +170 -0
- package/dist/ir/integer-storage.js +822 -0
- package/dist/ir/integers.d.ts +161 -0
- package/dist/ir/integers.js +539 -0
- package/dist/ir/integrity-restrictions.d.ts +50 -0
- package/dist/ir/integrity-restrictions.js +118 -0
- package/dist/ir/local-iterators.d.ts +4 -0
- package/dist/ir/local-iterators.js +27 -0
- package/dist/ir/lower-allocation.d.ts +4 -0
- package/dist/ir/lower-allocation.js +325 -0
- package/dist/ir/lower-completion.d.ts +15 -0
- package/dist/ir/lower-completion.js +25 -0
- package/dist/ir/lower-destructuring.d.ts +5 -0
- package/dist/ir/lower-destructuring.js +693 -0
- package/dist/ir/lower-element.d.ts +29 -0
- package/dist/ir/lower-element.js +111 -0
- package/dist/ir/lower-exceptions.d.ts +47 -0
- package/dist/ir/lower-exceptions.js +92 -0
- package/dist/ir/lower-flow.d.ts +137 -0
- package/dist/ir/lower-flow.js +600 -0
- package/dist/ir/lower-graph.d.ts +218 -0
- package/dist/ir/lower-graph.js +687 -0
- package/dist/ir/lower-invocation.d.ts +4 -0
- package/dist/ir/lower-invocation.js +514 -0
- package/dist/ir/lower-narrow.d.ts +53 -0
- package/dist/ir/lower-narrow.js +320 -0
- package/dist/ir/lower-operands.d.ts +272 -0
- package/dist/ir/lower-operands.js +461 -0
- package/dist/ir/lower-property.d.ts +21 -0
- package/dist/ir/lower-property.js +132 -0
- package/dist/ir/lower-protocol.d.ts +11 -0
- package/dist/ir/lower-protocol.js +118 -0
- package/dist/ir/lower-short-circuit.d.ts +41 -0
- package/dist/ir/lower-short-circuit.js +63 -0
- package/dist/ir/lower.d.ts +82 -0
- package/dist/ir/lower.js +1346 -0
- package/dist/ir/model.d.ts +1474 -0
- package/dist/ir/model.js +6 -0
- package/dist/ir/native-absent-property.d.ts +3 -0
- package/dist/ir/native-absent-property.js +13 -0
- package/dist/ir/native-array-transport.d.ts +7 -0
- package/dist/ir/native-array-transport.js +46 -0
- package/dist/ir/native-callable-bind.d.ts +9 -0
- package/dist/ir/native-callable-bind.js +30 -0
- package/dist/ir/native-carrier-predicate.d.ts +34 -0
- package/dist/ir/native-carrier-predicate.js +49 -0
- package/dist/ir/native-class-accessor.d.ts +18 -0
- package/dist/ir/native-class-accessor.js +52 -0
- package/dist/ir/native-class-construction.d.ts +16 -0
- package/dist/ir/native-class-construction.js +71 -0
- package/dist/ir/native-class-initialization.d.ts +15 -0
- package/dist/ir/native-class-initialization.js +56 -0
- package/dist/ir/native-class-origins.d.ts +13 -0
- package/dist/ir/native-class-origins.js +237 -0
- package/dist/ir/native-dictionary-transport.d.ts +6 -0
- package/dist/ir/native-dictionary-transport.js +37 -0
- package/dist/ir/native-enumeration.d.ts +14 -0
- package/dist/ir/native-enumeration.js +26 -0
- package/dist/ir/native-equality.d.ts +10 -0
- package/dist/ir/native-equality.js +18 -0
- package/dist/ir/native-field-owner.d.ts +37 -0
- package/dist/ir/native-field-owner.js +183 -0
- package/dist/ir/native-fixed-layout.d.ts +41 -0
- package/dist/ir/native-fixed-layout.js +232 -0
- package/dist/ir/native-host-construction.d.ts +53 -0
- package/dist/ir/native-host-construction.js +62 -0
- package/dist/ir/native-key-query.d.ts +4 -0
- package/dist/ir/native-key-query.js +38 -0
- package/dist/ir/native-merge-transport.d.ts +25 -0
- package/dist/ir/native-merge-transport.js +71 -0
- package/dist/ir/native-record-index-transport.d.ts +11 -0
- package/dist/ir/native-record-index-transport.js +34 -0
- package/dist/ir/native-record-index.d.ts +12 -0
- package/dist/ir/native-record-index.js +27 -0
- package/dist/ir/native-reflect-field.d.ts +5 -0
- package/dist/ir/native-reflect-field.js +33 -0
- package/dist/ir/native-sequence-transport.d.ts +7 -0
- package/dist/ir/native-sequence-transport.js +53 -0
- package/dist/ir/numeric-intrinsics.d.ts +13 -0
- package/dist/ir/numeric-intrinsics.js +57 -0
- package/dist/ir/object-value-conversions.d.ts +20 -0
- package/dist/ir/object-value-conversions.js +50 -0
- package/dist/ir/physical-class-reflection.d.ts +9 -0
- package/dist/ir/physical-class-reflection.js +57 -0
- package/dist/ir/presence-proof.d.ts +42 -0
- package/dist/ir/presence-proof.js +490 -0
- package/dist/ir/program-facts.d.ts +106 -0
- package/dist/ir/program-facts.js +319 -0
- package/dist/ir/proven-branches.d.ts +16 -0
- package/dist/ir/proven-branches.js +219 -0
- package/dist/ir/queries.d.ts +41 -0
- package/dist/ir/queries.js +213 -0
- package/dist/ir/reflection-demand.d.ts +64 -0
- package/dist/ir/reflection-demand.js +1394 -0
- package/dist/ir/refusal.d.ts +43 -0
- package/dist/ir/refusal.js +28 -0
- package/dist/ir/shake.d.ts +37 -0
- package/dist/ir/shake.js +1078 -0
- package/dist/ir/static-callables.d.ts +11 -0
- package/dist/ir/static-callables.js +163 -0
- package/dist/ir/string-layout-reuse.d.ts +13 -0
- package/dist/ir/string-layout-reuse.js +39 -0
- package/dist/ir/string-length-reuse.d.ts +8 -0
- package/dist/ir/string-length-reuse.js +47 -0
- package/dist/ir/transfer.d.ts +78 -0
- package/dist/ir/transfer.js +270 -0
- package/dist/ir/type-query-results.d.ts +25 -0
- package/dist/ir/type-query-results.js +96 -0
- package/dist/ir/typed-property-access.d.ts +100 -0
- package/dist/ir/typed-property-access.js +161 -0
- package/dist/ir/verify.d.ts +19 -0
- package/dist/ir/verify.js +355 -0
- package/dist/plugins/apple/constructors.d.ts +112 -0
- package/dist/plugins/apple/constructors.js +217 -0
- package/dist/plugins/apple/host.d.ts +181 -0
- package/dist/plugins/apple/host.js +262 -0
- package/dist/plugins/apple/jsx.d.ts +2 -0
- package/dist/plugins/apple/jsx.js +293 -0
- package/dist/plugins/apple/members.d.ts +16 -0
- package/dist/plugins/apple/members.js +190 -0
- package/dist/plugins/apple/plugin.d.ts +2 -0
- package/dist/plugins/apple/plugin.js +156 -0
- package/dist/plugins/gea/component-classes.d.ts +25 -0
- package/dist/plugins/gea/component-classes.js +162 -0
- package/dist/plugins/gea/component-inline.d.ts +13 -0
- package/dist/plugins/gea/component-inline.js +532 -0
- package/dist/plugins/gea/constructors.d.ts +23 -0
- package/dist/plugins/gea/constructors.js +100 -0
- package/dist/plugins/gea/contract.d.ts +150 -0
- package/dist/plugins/gea/contract.js +195 -0
- package/dist/plugins/gea/element-ref.d.ts +31 -0
- package/dist/plugins/gea/element-ref.js +45 -0
- package/dist/plugins/gea/host.d.ts +520 -0
- package/dist/plugins/gea/host.js +762 -0
- package/dist/plugins/gea/lower.d.ts +6 -0
- package/dist/plugins/gea/lower.js +195 -0
- package/dist/plugins/gea/members.d.ts +22 -0
- package/dist/plugins/gea/members.js +221 -0
- package/dist/plugins/gea/plugin.d.ts +22 -0
- package/dist/plugins/gea/plugin.js +307 -0
- package/dist/plugins/gea/prelude.d.ts +78 -0
- package/dist/plugins/gea/prelude.js +153 -0
- package/dist/plugins/gea/producer.d.ts +5 -0
- package/dist/plugins/gea/producer.js +52 -0
- package/dist/plugins/gea/reactive-slots.d.ts +49 -0
- package/dist/plugins/gea/reactive-slots.js +578 -0
- package/dist/plugins/gea/render-bridge.d.ts +6 -0
- package/dist/plugins/gea/render-bridge.js +281 -0
- package/dist/plugins/gea/slots.d.ts +15 -0
- package/dist/plugins/gea/slots.js +36 -0
- package/dist/plugins/gea/template-analysis.d.ts +151 -0
- package/dist/plugins/gea/template-analysis.js +346 -0
- package/dist/plugins/gea/user-agent-styles.d.ts +9 -0
- package/dist/plugins/gea/user-agent-styles.js +94 -0
- package/dist/plugins/installed.d.ts +19 -0
- package/dist/plugins/installed.js +21 -0
- package/dist/plugins/load.d.ts +7 -0
- package/dist/plugins/load.js +207 -0
- package/dist/plugins/model.d.ts +735 -0
- package/dist/plugins/model.js +47 -0
- package/dist/plugins/webgl/host.d.ts +77 -0
- package/dist/plugins/webgl/host.js +162 -0
- package/dist/plugins/webgl/plugin.d.ts +40 -0
- package/dist/plugins/webgl/plugin.js +99 -0
- package/dist/preflight/obligations.d.ts +206 -0
- package/dist/preflight/obligations.js +36 -0
- package/dist/preflight/report.d.ts +20 -0
- package/dist/preflight/report.js +61 -0
- package/dist/preflight/run.d.ts +39 -0
- package/dist/preflight/run.js +403 -0
- package/dist/project-preparation.d.ts +33 -0
- package/dist/project-preparation.js +314 -0
- package/dist/projection/abi.d.ts +82 -0
- package/dist/projection/abi.js +349 -0
- package/dist/projection/apply-arguments.d.ts +12 -0
- package/dist/projection/apply-arguments.js +20 -0
- package/dist/projection/bindings.d.ts +250 -0
- package/dist/projection/bindings.js +340 -0
- package/dist/projection/callee.d.ts +196 -0
- package/dist/projection/callee.js +444 -0
- package/dist/projection/class-property-presence.d.ts +28 -0
- package/dist/projection/class-property-presence.js +58 -0
- package/dist/projection/class-prototype.d.ts +5 -0
- package/dist/projection/class-prototype.js +23 -0
- package/dist/projection/class-storage.d.ts +26 -0
- package/dist/projection/class-storage.js +236 -0
- package/dist/projection/classes.d.ts +283 -0
- package/dist/projection/classes.js +944 -0
- package/dist/projection/coercions.d.ts +20 -0
- package/dist/projection/coercions.js +33 -0
- package/dist/projection/dispatch.d.ts +167 -0
- package/dist/projection/dispatch.js +379 -0
- package/dist/projection/fields.d.ts +123 -0
- package/dist/projection/fields.js +383 -0
- package/dist/projection/instance-test.d.ts +78 -0
- package/dist/projection/instance-test.js +156 -0
- package/dist/projection/slots.d.ts +146 -0
- package/dist/projection/slots.js +663 -0
- package/dist/projection/synthesized-abi.d.ts +61 -0
- package/dist/projection/synthesized-abi.js +94 -0
- package/dist/representation/array-index.d.ts +14 -0
- package/dist/representation/array-index.js +17 -0
- package/dist/representation/callable-object.d.ts +3 -0
- package/dist/representation/callable-object.js +6 -0
- package/dist/representation/collections.d.ts +84 -0
- package/dist/representation/collections.js +139 -0
- package/dist/representation/derive.d.ts +159 -0
- package/dist/representation/derive.js +2546 -0
- package/dist/representation/difference.d.ts +30 -0
- package/dist/representation/difference.js +240 -0
- package/dist/representation/field-descriptor-policy.d.ts +19 -0
- package/dist/representation/field-descriptor-policy.js +39 -0
- package/dist/representation/function-constructor.d.ts +13 -0
- package/dist/representation/function-constructor.js +9 -0
- package/dist/representation/host-abi.d.ts +32 -0
- package/dist/representation/host-abi.js +97 -0
- package/dist/representation/host-templates.d.ts +67 -0
- package/dist/representation/host-templates.js +94 -0
- package/dist/representation/intersection.d.ts +84 -0
- package/dist/representation/intersection.js +149 -0
- package/dist/representation/literal-destination.d.ts +43 -0
- package/dist/representation/literal-destination.js +133 -0
- package/dist/representation/merge.d.ts +18 -0
- package/dist/representation/merge.js +83 -0
- package/dist/representation/model.d.ts +1160 -0
- package/dist/representation/model.js +1019 -0
- package/dist/representation/numeric-index.d.ts +13 -0
- package/dist/representation/numeric-index.js +29 -0
- package/dist/representation/object-shape.d.ts +109 -0
- package/dist/representation/object-shape.js +123 -0
- package/dist/representation/optional.d.ts +12 -0
- package/dist/representation/optional.js +87 -0
- package/dist/representation/plan.d.ts +60 -0
- package/dist/representation/plan.js +78 -0
- package/dist/representation/policies.d.ts +589 -0
- package/dist/representation/policies.js +107 -0
- package/dist/representation/primitive-domain.d.ts +1 -0
- package/dist/representation/primitive-domain.js +1 -0
- package/dist/representation/primitives.d.ts +44 -0
- package/dist/representation/primitives.js +78 -0
- package/dist/representation/publish.d.ts +49 -0
- package/dist/representation/publish.js +648 -0
- package/dist/representation/record-fields.d.ts +96 -0
- package/dist/representation/record-fields.js +116 -0
- package/dist/representation/template-object.d.ts +11 -0
- package/dist/representation/template-object.js +26 -0
- package/dist/representation/union.d.ts +30 -0
- package/dist/representation/union.js +324 -0
- package/dist/representation/value-records.d.ts +3 -0
- package/dist/representation/value-records.js +307 -0
- package/dist/representation/verify.d.ts +17 -0
- package/dist/representation/verify.js +221 -0
- package/dist/semantics/alias-this-field-declaration-transform.d.ts +4 -0
- package/dist/semantics/alias-this-field-declaration-transform.js +207 -0
- package/dist/semantics/ambient-type-realization-transform.d.ts +62 -0
- package/dist/semantics/ambient-type-realization-transform.js +168 -0
- package/dist/semantics/ambient.d.ts +24 -0
- package/dist/semantics/ambient.js +119 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.d.ts +4 -0
- package/dist/semantics/borrowed-builtin-call-bind-source-transform.js +341 -0
- package/dist/semantics/callable-origins.d.ts +46 -0
- package/dist/semantics/callable-origins.js +354 -0
- package/dist/semantics/class-alias.d.ts +7 -0
- package/dist/semantics/class-alias.js +37 -0
- package/dist/semantics/class-heritage.d.ts +34 -0
- package/dist/semantics/class-heritage.js +104 -0
- package/dist/semantics/commonjs-wrapper.d.ts +69 -0
- package/dist/semantics/commonjs-wrapper.js +231 -0
- package/dist/semantics/constructor-slot-subclasses.d.ts +28 -0
- package/dist/semantics/constructor-slot-subclasses.js +112 -0
- package/dist/semantics/declaration-overlay-transform.d.ts +35 -0
- package/dist/semantics/declaration-overlay-transform.js +2157 -0
- package/dist/semantics/define-property-source-transform.d.ts +4 -0
- package/dist/semantics/define-property-source-transform.js +437 -0
- package/dist/semantics/diagnostic-source-preparation.d.ts +24 -0
- package/dist/semantics/diagnostic-source-preparation.js +82 -0
- package/dist/semantics/documentation-ranges.d.ts +22 -0
- package/dist/semantics/documentation-ranges.js +36 -0
- package/dist/semantics/dynamic-fallback.d.ts +86 -0
- package/dist/semantics/dynamic-fallback.js +249 -0
- package/dist/semantics/frontend-timing.d.ts +6 -0
- package/dist/semantics/frontend-timing.js +35 -0
- package/dist/semantics/frontend.d.ts +504 -0
- package/dist/semantics/frontend.js +1157 -0
- package/dist/semantics/host-declaration-provenance.d.ts +11 -0
- package/dist/semantics/host-declaration-provenance.js +18 -0
- package/dist/semantics/host-methods.d.ts +24 -0
- package/dist/semantics/host-methods.js +74 -0
- package/dist/semantics/host-protocols.d.ts +429 -0
- package/dist/semantics/host-protocols.js +1501 -0
- package/dist/semantics/inherited-accessor.d.ts +7 -0
- package/dist/semantics/inherited-accessor.js +48 -0
- package/dist/semantics/interface-families.d.ts +70 -0
- package/dist/semantics/interface-families.js +180 -0
- package/dist/semantics/interface-implementors.d.ts +53 -0
- package/dist/semantics/interface-implementors.js +87 -0
- package/dist/semantics/jsdoc-namepath-transform.d.ts +4 -0
- package/dist/semantics/jsdoc-namepath-transform.js +85 -0
- package/dist/semantics/model/coverage.d.ts +68 -0
- package/dist/semantics/model/coverage.js +73 -0
- package/dist/semantics/model/edges.d.ts +103 -0
- package/dist/semantics/model/edges.js +20 -0
- package/dist/semantics/model/graph.d.ts +55 -0
- package/dist/semantics/model/graph.js +129 -0
- package/dist/semantics/model/operands.d.ts +159 -0
- package/dist/semantics/model/operands.js +26 -0
- package/dist/semantics/model/operations.d.ts +496 -0
- package/dist/semantics/model/operations.js +2 -0
- package/dist/semantics/model/primitive-domain.d.ts +26 -0
- package/dist/semantics/model/primitive-domain.js +38 -0
- package/dist/semantics/model/selected-signature.d.ts +261 -0
- package/dist/semantics/model/selected-signature.js +55 -0
- package/dist/semantics/model/structural-type-table.d.ts +93 -0
- package/dist/semantics/model/structural-type-table.js +237 -0
- package/dist/semantics/model/structural-types.d.ts +367 -0
- package/dist/semantics/model/structural-types.js +200 -0
- package/dist/semantics/module-resolution.d.ts +23 -0
- package/dist/semantics/module-resolution.js +227 -0
- package/dist/semantics/new-callee-class-tag-source-transform.d.ts +4 -0
- package/dist/semantics/new-callee-class-tag-source-transform.js +64 -0
- package/dist/semantics/node-project.d.ts +13 -0
- package/dist/semantics/node-project.js +107 -0
- package/dist/semantics/node-source-hooks.d.ts +1 -0
- package/dist/semantics/node-source-hooks.js +63 -0
- package/dist/semantics/normalize/absent-globals.d.ts +143 -0
- package/dist/semantics/normalize/absent-globals.js +191 -0
- package/dist/semantics/normalize/arguments-objects.d.ts +43 -0
- package/dist/semantics/normalize/arguments-objects.js +60 -0
- package/dist/semantics/normalize/asserted-arm-absence.d.ts +28 -0
- package/dist/semantics/normalize/asserted-arm-absence.js +61 -0
- package/dist/semantics/normalize/assignment-patterns.d.ts +70 -0
- package/dist/semantics/normalize/assignment-patterns.js +147 -0
- package/dist/semantics/normalize/bag-absence.d.ts +8 -0
- package/dist/semantics/normalize/bag-absence.js +42 -0
- package/dist/semantics/normalize/binding-fixpoint.d.ts +36 -0
- package/dist/semantics/normalize/binding-fixpoint.js +140 -0
- package/dist/semantics/normalize/callback-parameter-contracts.d.ts +16 -0
- package/dist/semantics/normalize/callback-parameter-contracts.js +91 -0
- package/dist/semantics/normalize/cells/agreement.d.ts +46 -0
- package/dist/semantics/normalize/cells/agreement.js +34 -0
- package/dist/semantics/normalize/cells/candidates.d.ts +17 -0
- package/dist/semantics/normalize/cells/candidates.js +35 -0
- package/dist/semantics/normalize/cells/facts.d.ts +19 -0
- package/dist/semantics/normalize/cells/facts.js +90 -0
- package/dist/semantics/normalize/cells/index.d.ts +10 -0
- package/dist/semantics/normalize/cells/index.js +6 -0
- package/dist/semantics/normalize/cells/model.d.ts +98 -0
- package/dist/semantics/normalize/cells/model.js +2 -0
- package/dist/semantics/normalize/cells/policies/bag.d.ts +44 -0
- package/dist/semantics/normalize/cells/policies/bag.js +114 -0
- package/dist/semantics/normalize/cells/policies/collection.d.ts +42 -0
- package/dist/semantics/normalize/cells/policies/collection.js +218 -0
- package/dist/semantics/normalize/cells/policies/field.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/field.js +40 -0
- package/dist/semantics/normalize/cells/policies/index.d.ts +49 -0
- package/dist/semantics/normalize/cells/policies/index.js +58 -0
- package/dist/semantics/normalize/cells/policies/local.d.ts +18 -0
- package/dist/semantics/normalize/cells/policies/local.js +37 -0
- package/dist/semantics/normalize/cells/policies/parameter.d.ts +28 -0
- package/dist/semantics/normalize/cells/policies/parameter.js +39 -0
- package/dist/semantics/normalize/cells/policies/return.d.ts +26 -0
- package/dist/semantics/normalize/cells/policies/return.js +45 -0
- package/dist/semantics/normalize/cells/policies/shared.d.ts +33 -0
- package/dist/semantics/normalize/cells/policies/shared.js +45 -0
- package/dist/semantics/normalize/cells/policy.d.ts +72 -0
- package/dist/semantics/normalize/cells/policy.js +18 -0
- package/dist/semantics/normalize/cells/registry.d.ts +14 -0
- package/dist/semantics/normalize/cells/registry.js +17 -0
- package/dist/semantics/normalize/census-refusal.d.ts +62 -0
- package/dist/semantics/normalize/census-refusal.js +27 -0
- package/dist/semantics/normalize/census.d.ts +109 -0
- package/dist/semantics/normalize/census.js +667 -0
- package/dist/semantics/normalize/collection-bindings.d.ts +278 -0
- package/dist/semantics/normalize/collection-bindings.js +677 -0
- package/dist/semantics/normalize/commonjs-module-record.d.ts +21 -0
- package/dist/semantics/normalize/commonjs-module-record.js +289 -0
- package/dist/semantics/normalize/commonjs-require.d.ts +13 -0
- package/dist/semantics/normalize/commonjs-require.js +1527 -0
- package/dist/semantics/normalize/contribution.d.ts +63 -0
- package/dist/semantics/normalize/contribution.js +172 -0
- package/dist/semantics/normalize/dead-typeof-guards.d.ts +64 -0
- package/dist/semantics/normalize/dead-typeof-guards.js +152 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.d.ts +57 -0
- package/dist/semantics/normalize/deferred-intrinsic-protocols.js +109 -0
- package/dist/semantics/normalize/derived-expression-type.d.ts +1070 -0
- package/dist/semantics/normalize/derived-expression-type.js +3463 -0
- package/dist/semantics/normalize/evaluation-order.d.ts +16 -0
- package/dist/semantics/normalize/evaluation-order.js +37 -0
- package/dist/semantics/normalize/field-bindings.d.ts +167 -0
- package/dist/semantics/normalize/field-bindings.js +1125 -0
- package/dist/semantics/normalize/flow/array-element-continuation.d.ts +27 -0
- package/dist/semantics/normalize/flow/array-element-continuation.js +1452 -0
- package/dist/semantics/normalize/flow/callable-array-origins.d.ts +42 -0
- package/dist/semantics/normalize/flow/callable-array-origins.js +318 -0
- package/dist/semantics/normalize/flow/callable-completions.d.ts +45 -0
- package/dist/semantics/normalize/flow/callable-completions.js +82 -0
- package/dist/semantics/normalize/flow/callable-reach.d.ts +237 -0
- package/dist/semantics/normalize/flow/callable-reach.js +7174 -0
- package/dist/semantics/normalize/flow/class-family-member-read.d.ts +16 -0
- package/dist/semantics/normalize/flow/class-family-member-read.js +992 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.d.ts +21 -0
- package/dist/semantics/normalize/flow/collection-value-continuation.js +192 -0
- package/dist/semantics/normalize/flow/component-solver.d.ts +199 -0
- package/dist/semantics/normalize/flow/component-solver.js +587 -0
- package/dist/semantics/normalize/flow/computed-key-set.d.ts +84 -0
- package/dist/semantics/normalize/flow/computed-key-set.js +660 -0
- package/dist/semantics/normalize/flow/export-importers.d.ts +24 -0
- package/dist/semantics/normalize/flow/export-importers.js +269 -0
- package/dist/semantics/normalize/flow/host-text-sink.d.ts +25 -0
- package/dist/semantics/normalize/flow/host-text-sink.js +87 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.d.ts +84 -0
- package/dist/semantics/normalize/flow/intrinsic-array-callback-frames.js +180 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.d.ts +35 -0
- package/dist/semantics/normalize/flow/intrinsic-data-definition.js +140 -0
- package/dist/semantics/normalize/flow/invocation-facts.d.ts +98 -0
- package/dist/semantics/normalize/flow/invocation-facts.js +257 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.d.ts +122 -0
- package/dist/semantics/normalize/flow/member-call-forwarding.js +835 -0
- package/dist/semantics/normalize/flow/model.d.ts +357 -0
- package/dist/semantics/normalize/flow/model.js +177 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.d.ts +24 -0
- package/dist/semantics/normalize/flow/native-collection-protocol.js +252 -0
- package/dist/semantics/normalize/flow/node-path-token.d.ts +3 -0
- package/dist/semantics/normalize/flow/node-path-token.js +53 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.d.ts +11 -0
- package/dist/semantics/normalize/flow/object-binding-continuation.js +42 -0
- package/dist/semantics/normalize/flow/origin-authority.d.ts +56 -0
- package/dist/semantics/normalize/flow/origin-authority.js +2 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.d.ts +35 -0
- package/dist/semantics/normalize/flow/owned-class-receivers.js +191 -0
- package/dist/semantics/normalize/flow/parameter-values.d.ts +27 -0
- package/dist/semantics/normalize/flow/parameter-values.js +251 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.d.ts +66 -0
- package/dist/semantics/normalize/flow/proof-hypotheses.js +162 -0
- package/dist/semantics/normalize/flow/record-alias-closure.d.ts +27 -0
- package/dist/semantics/normalize/flow/record-alias-closure.js +298 -0
- package/dist/semantics/normalize/flow/seeded-origins.d.ts +43 -0
- package/dist/semantics/normalize/flow/seeded-origins.js +54 -0
- package/dist/semantics/normalize/flow/source-class-data.d.ts +132 -0
- package/dist/semantics/normalize/flow/source-class-data.js +838 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.d.ts +13 -0
- package/dist/semantics/normalize/flow/source-class-instanceof.js +37 -0
- package/dist/semantics/normalize/flow/source-class-static-data.d.ts +16 -0
- package/dist/semantics/normalize/flow/source-class-static-data.js +47 -0
- package/dist/semantics/normalize/flow/source-construction-frames.d.ts +12 -0
- package/dist/semantics/normalize/flow/source-construction-frames.js +118 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.d.ts +34 -0
- package/dist/semantics/normalize/flow/source-invocation-frame-layout.js +78 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.d.ts +37 -0
- package/dist/semantics/normalize/flow/source-invocation-receiver.js +95 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.d.ts +23 -0
- package/dist/semantics/normalize/flow/source-prototype-method-identity.js +81 -0
- package/dist/semantics/normalize/flow/source-record-data.d.ts +29 -0
- package/dist/semantics/normalize/flow/source-record-data.js +626 -0
- package/dist/semantics/normalize/flow/source-value-session.d.ts +77 -0
- package/dist/semantics/normalize/flow/source-value-session.js +3089 -0
- package/dist/semantics/normalize/flow/targets.d.ts +118 -0
- package/dist/semantics/normalize/flow/targets.js +405 -0
- package/dist/semantics/normalize/flow/value-flow.d.ts +36 -0
- package/dist/semantics/normalize/flow/value-flow.js +823 -0
- package/dist/semantics/normalize/flow/value-provenance.d.ts +31 -0
- package/dist/semantics/normalize/flow/value-provenance.js +112 -0
- package/dist/semantics/normalize/gating.d.ts +51 -0
- package/dist/semantics/normalize/gating.js +560 -0
- package/dist/semantics/normalize/generic-function-choice.d.ts +31 -0
- package/dist/semantics/normalize/generic-function-choice.js +115 -0
- package/dist/semantics/normalize/global-host-mutations.d.ts +51 -0
- package/dist/semantics/normalize/global-host-mutations.js +5989 -0
- package/dist/semantics/normalize/host-effect-contracts.d.ts +77 -0
- package/dist/semantics/normalize/host-effect-contracts.js +143 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.d.ts +38 -0
- package/dist/semantics/normalize/host-mutation-computed-keys.js +26 -0
- package/dist/semantics/normalize/host-mutation-key-reader.d.ts +66 -0
- package/dist/semantics/normalize/host-mutation-key-reader.js +192 -0
- package/dist/semantics/normalize/host-mutation-keys.d.ts +114 -0
- package/dist/semantics/normalize/host-mutation-keys.js +183 -0
- package/dist/semantics/normalize/identities.d.ts +172 -0
- package/dist/semantics/normalize/identities.js +426 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.d.ts +97 -0
- package/dist/semantics/normalize/implicit-arguments-tuple.js +197 -0
- package/dist/semantics/normalize/implicit-arguments.d.ts +11 -0
- package/dist/semantics/normalize/implicit-arguments.js +39 -0
- package/dist/semantics/normalize/instantiation.d.ts +73 -0
- package/dist/semantics/normalize/instantiation.js +399 -0
- package/dist/semantics/normalize/intrinsic-property-call.d.ts +18 -0
- package/dist/semantics/normalize/intrinsic-property-call.js +69 -0
- package/dist/semantics/normalize/intrinsic-prototype.d.ts +41 -0
- package/dist/semantics/normalize/intrinsic-prototype.js +87 -0
- package/dist/semantics/normalize/intrinsic-static-member.d.ts +14 -0
- package/dist/semantics/normalize/intrinsic-static-member.js +23 -0
- package/dist/semantics/normalize/jsdoc-type-names.d.ts +32 -0
- package/dist/semantics/normalize/jsdoc-type-names.js +512 -0
- package/dist/semantics/normalize/keyof.d.ts +32 -0
- package/dist/semantics/normalize/keyof.js +110 -0
- package/dist/semantics/normalize/local-bindings.d.ts +176 -0
- package/dist/semantics/normalize/local-bindings.js +1826 -0
- package/dist/semantics/normalize/logical-result-type.d.ts +16 -0
- package/dist/semantics/normalize/logical-result-type.js +102 -0
- package/dist/semantics/normalize/namespace-paths.d.ts +57 -0
- package/dist/semantics/normalize/namespace-paths.js +108 -0
- package/dist/semantics/normalize/normalize.d.ts +57 -0
- package/dist/semantics/normalize/normalize.js +68 -0
- package/dist/semantics/normalize/object-bag-bindings.d.ts +305 -0
- package/dist/semantics/normalize/object-bag-bindings.js +1290 -0
- package/dist/semantics/normalize/omitted-stated-parameter.d.ts +53 -0
- package/dist/semantics/normalize/omitted-stated-parameter.js +59 -0
- package/dist/semantics/normalize/open-type-form.d.ts +10 -0
- package/dist/semantics/normalize/open-type-form.js +32 -0
- package/dist/semantics/normalize/parameter-bindings.d.ts +361 -0
- package/dist/semantics/normalize/parameter-bindings.js +3339 -0
- package/dist/semantics/normalize/parameter-slot.d.ts +264 -0
- package/dist/semantics/normalize/parameter-slot.js +491 -0
- package/dist/semantics/normalize/physical-overload-result.d.ts +77 -0
- package/dist/semantics/normalize/physical-overload-result.js +99 -0
- package/dist/semantics/normalize/primitive-property-absence.d.ts +12 -0
- package/dist/semantics/normalize/primitive-property-absence.js +60 -0
- package/dist/semantics/normalize/producer-context.d.ts +376 -0
- package/dist/semantics/normalize/producer-context.js +1 -0
- package/dist/semantics/normalize/producers/allocations.d.ts +3 -0
- package/dist/semantics/normalize/producers/allocations.js +863 -0
- package/dist/semantics/normalize/producers/binding-kind.d.ts +37 -0
- package/dist/semantics/normalize/producers/binding-kind.js +36 -0
- package/dist/semantics/normalize/producers/bindings.d.ts +85 -0
- package/dist/semantics/normalize/producers/bindings.js +710 -0
- package/dist/semantics/normalize/producers/boundary.d.ts +34 -0
- package/dist/semantics/normalize/producers/boundary.js +123 -0
- package/dist/semantics/normalize/producers/class-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/class-lifecycle.js +902 -0
- package/dist/semantics/normalize/producers/computations.d.ts +3 -0
- package/dist/semantics/normalize/producers/computations.js +613 -0
- package/dist/semantics/normalize/producers/control-loops.d.ts +30 -0
- package/dist/semantics/normalize/producers/control-loops.js +91 -0
- package/dist/semantics/normalize/producers/control.d.ts +30 -0
- package/dist/semantics/normalize/producers/control.js +923 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.d.ts +3 -0
- package/dist/semantics/normalize/producers/declaration-lifecycle.js +390 -0
- package/dist/semantics/normalize/producers/destructuring.d.ts +45 -0
- package/dist/semantics/normalize/producers/destructuring.js +1180 -0
- package/dist/semantics/normalize/producers/dynamic-language.d.ts +3 -0
- package/dist/semantics/normalize/producers/dynamic-language.js +70 -0
- package/dist/semantics/normalize/producers/erasure.d.ts +51 -0
- package/dist/semantics/normalize/producers/erasure.js +90 -0
- package/dist/semantics/normalize/producers/installed.d.ts +3 -0
- package/dist/semantics/normalize/producers/installed.js +55 -0
- package/dist/semantics/normalize/producers/invocations.d.ts +35 -0
- package/dist/semantics/normalize/producers/invocations.js +1796 -0
- package/dist/semantics/normalize/producers/iteration-yield.d.ts +59 -0
- package/dist/semantics/normalize/producers/iteration-yield.js +235 -0
- package/dist/semantics/normalize/producers/jsx.d.ts +3 -0
- package/dist/semantics/normalize/producers/jsx.js +360 -0
- package/dist/semantics/normalize/producers/mint.d.ts +39 -0
- package/dist/semantics/normalize/producers/mint.js +44 -0
- package/dist/semantics/normalize/producers/nullish.d.ts +16 -0
- package/dist/semantics/normalize/producers/nullish.js +27 -0
- package/dist/semantics/normalize/producers/object-assignment.d.ts +8 -0
- package/dist/semantics/normalize/producers/object-assignment.js +204 -0
- package/dist/semantics/normalize/producers/object-tag.d.ts +9 -0
- package/dist/semantics/normalize/producers/object-tag.js +119 -0
- package/dist/semantics/normalize/producers/optional-chain.d.ts +44 -0
- package/dist/semantics/normalize/producers/optional-chain.js +75 -0
- package/dist/semantics/normalize/producers/properties.d.ts +21 -0
- package/dist/semantics/normalize/producers/properties.js +1053 -0
- package/dist/semantics/normalize/producers/protocol.d.ts +67 -0
- package/dist/semantics/normalize/producers/protocol.js +695 -0
- package/dist/semantics/normalize/producers/references.d.ts +53 -0
- package/dist/semantics/normalize/producers/references.js +1027 -0
- package/dist/semantics/normalize/producers/shared.d.ts +561 -0
- package/dist/semantics/normalize/producers/shared.js +1683 -0
- package/dist/semantics/normalize/producers/spread-arguments.d.ts +72 -0
- package/dist/semantics/normalize/producers/spread-arguments.js +375 -0
- package/dist/semantics/normalize/producers/tagged-template.d.ts +5 -0
- package/dist/semantics/normalize/producers/tagged-template.js +307 -0
- package/dist/semantics/normalize/producers/tuple-spread.d.ts +189 -0
- package/dist/semantics/normalize/producers/tuple-spread.js +279 -0
- package/dist/semantics/normalize/property-key-domain.d.ts +36 -0
- package/dist/semantics/normalize/property-key-domain.js +150 -0
- package/dist/semantics/normalize/reachability.d.ts +189 -0
- package/dist/semantics/normalize/reachability.js +1057 -0
- package/dist/semantics/normalize/reassigned-bindings.d.ts +13 -0
- package/dist/semantics/normalize/reassigned-bindings.js +41 -0
- package/dist/semantics/normalize/record-storage-families.d.ts +11 -0
- package/dist/semantics/normalize/record-storage-families.js +109 -0
- package/dist/semantics/normalize/return-bindings.d.ts +260 -0
- package/dist/semantics/normalize/return-bindings.js +1311 -0
- package/dist/semantics/normalize/return-paths.d.ts +2 -0
- package/dist/semantics/normalize/return-paths.js +28 -0
- package/dist/semantics/normalize/script-global-redefinition.d.ts +44 -0
- package/dist/semantics/normalize/script-global-redefinition.js +75 -0
- package/dist/semantics/normalize/specialization.d.ts +201 -0
- package/dist/semantics/normalize/specialization.js +1824 -0
- package/dist/semantics/normalize/structural-array-element.d.ts +176 -0
- package/dist/semantics/normalize/structural-array-element.js +700 -0
- package/dist/semantics/normalize/structural-array-read.d.ts +13 -0
- package/dist/semantics/normalize/structural-array-read.js +124 -0
- package/dist/semantics/normalize/structural-callable.d.ts +12 -0
- package/dist/semantics/normalize/structural-callable.js +82 -0
- package/dist/semantics/normalize/structural-creation-order.d.ts +32 -0
- package/dist/semantics/normalize/structural-creation-order.js +111 -0
- package/dist/semantics/normalize/structural-declarations.d.ts +395 -0
- package/dist/semantics/normalize/structural-declarations.js +968 -0
- package/dist/semantics/normalize/structural-declared-body.d.ts +25 -0
- package/dist/semantics/normalize/structural-declared-body.js +147 -0
- package/dist/semantics/normalize/structural-generics.d.ts +56 -0
- package/dist/semantics/normalize/structural-generics.js +120 -0
- package/dist/semantics/normalize/structural-indexed-access.d.ts +11 -0
- package/dist/semantics/normalize/structural-indexed-access.js +126 -0
- package/dist/semantics/normalize/structural-instantiated-member.d.ts +64 -0
- package/dist/semantics/normalize/structural-instantiated-member.js +407 -0
- package/dist/semantics/normalize/structural-joins.d.ts +44 -0
- package/dist/semantics/normalize/structural-joins.js +143 -0
- package/dist/semantics/normalize/structural-layout-relevance.d.ts +29 -0
- package/dist/semantics/normalize/structural-layout-relevance.js +391 -0
- package/dist/semantics/normalize/structural-layout-type.d.ts +11 -0
- package/dist/semantics/normalize/structural-layout-type.js +1468 -0
- package/dist/semantics/normalize/structural-leaves.d.ts +49 -0
- package/dist/semantics/normalize/structural-leaves.js +125 -0
- package/dist/semantics/normalize/structural-local-union.d.ts +13 -0
- package/dist/semantics/normalize/structural-local-union.js +133 -0
- package/dist/semantics/normalize/structural-members.d.ts +26 -0
- package/dist/semantics/normalize/structural-members.js +84 -0
- package/dist/semantics/normalize/structural-mutable-method.d.ts +15 -0
- package/dist/semantics/normalize/structural-mutable-method.js +109 -0
- package/dist/semantics/normalize/structural-parts.d.ts +131 -0
- package/dist/semantics/normalize/structural-parts.js +737 -0
- package/dist/semantics/normalize/structural-receiver.d.ts +66 -0
- package/dist/semantics/normalize/structural-receiver.js +551 -0
- package/dist/semantics/normalize/structural-rules.d.ts +112 -0
- package/dist/semantics/normalize/structural-rules.js +93 -0
- package/dist/semantics/normalize/structural-self-reference.d.ts +150 -0
- package/dist/semantics/normalize/structural-self-reference.js +494 -0
- package/dist/semantics/normalize/structural.d.ts +202 -0
- package/dist/semantics/normalize/structural.js +4218 -0
- package/dist/semantics/normalize/unreduced-type-form.d.ts +41 -0
- package/dist/semantics/normalize/unreduced-type-form.js +53 -0
- package/dist/semantics/normalize/unresolvable-names.d.ts +56 -0
- package/dist/semantics/normalize/unresolvable-names.js +140 -0
- package/dist/semantics/package-sources.d.ts +16 -0
- package/dist/semantics/package-sources.js +365 -0
- package/dist/semantics/program.d.ts +151 -0
- package/dist/semantics/program.js +667 -0
- package/dist/semantics/prototype-install-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-install-source-transform.js +341 -0
- package/dist/semantics/prototype-object-class-source-transform.d.ts +4 -0
- package/dist/semantics/prototype-object-class-source-transform.js +525 -0
- package/dist/semantics/prototype-reparenting.d.ts +50 -0
- package/dist/semantics/prototype-reparenting.js +317 -0
- package/dist/semantics/stable-checker.d.ts +10 -0
- package/dist/semantics/stable-checker.js +148 -0
- package/dist/semantics/subclass-member-overlay-transform.d.ts +35 -0
- package/dist/semantics/subclass-member-overlay-transform.js +1418 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.d.ts +4 -0
- package/dist/semantics/symbol-keyed-expando-source-transform.js +66 -0
- package/dist/semantics/this-constructor-source-transform.d.ts +4 -0
- package/dist/semantics/this-constructor-source-transform.js +122 -0
- package/dist/semantics/uninstantiable-classes.d.ts +22 -0
- package/dist/semantics/uninstantiable-classes.js +75 -0
- package/dist/targets/cpp/balanced-units.d.ts +3 -0
- package/dist/targets/cpp/balanced-units.js +58 -0
- package/dist/targets/cpp/borrowed-call-entry.d.ts +30 -0
- package/dist/targets/cpp/borrowed-call-entry.js +68 -0
- package/dist/targets/cpp/captures.d.ts +68 -0
- package/dist/targets/cpp/captures.js +269 -0
- package/dist/targets/cpp/class-layout.d.ts +313 -0
- package/dist/targets/cpp/class-layout.js +483 -0
- package/dist/targets/cpp/class-properties/computed-method-value.d.ts +25 -0
- package/dist/targets/cpp/class-properties/computed-method-value.js +22 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.d.ts +216 -0
- package/dist/targets/cpp/class-properties/emit-class-properties.js +917 -0
- package/dist/targets/cpp/class-properties/native-prototype.d.ts +11 -0
- package/dist/targets/cpp/class-properties/native-prototype.js +101 -0
- package/dist/targets/cpp/class-ref-transport.d.ts +12 -0
- package/dist/targets/cpp/class-ref-transport.js +32 -0
- package/dist/targets/cpp/conversions.d.ts +3 -0
- package/dist/targets/cpp/conversions.js +2027 -0
- package/dist/targets/cpp/deferral-safety.d.ts +82 -0
- package/dist/targets/cpp/deferral-safety.js +86 -0
- package/dist/targets/cpp/direct-call-receivers.d.ts +37 -0
- package/dist/targets/cpp/direct-call-receivers.js +79 -0
- package/dist/targets/cpp/document.d.ts +74 -0
- package/dist/targets/cpp/document.js +106 -0
- package/dist/targets/cpp/emit-allocation.d.ts +60 -0
- package/dist/targets/cpp/emit-allocation.js +573 -0
- package/dist/targets/cpp/emit-arrays.d.ts +119 -0
- package/dist/targets/cpp/emit-arrays.js +1047 -0
- package/dist/targets/cpp/emit-binding-reference.d.ts +17 -0
- package/dist/targets/cpp/emit-binding-reference.js +120 -0
- package/dist/targets/cpp/emit-bindings.d.ts +158 -0
- package/dist/targets/cpp/emit-bindings.js +769 -0
- package/dist/targets/cpp/emit-buffers.d.ts +156 -0
- package/dist/targets/cpp/emit-buffers.js +573 -0
- package/dist/targets/cpp/emit-callable.d.ts +230 -0
- package/dist/targets/cpp/emit-callable.js +2154 -0
- package/dist/targets/cpp/emit-carrier-members.d.ts +406 -0
- package/dist/targets/cpp/emit-carrier-members.js +1224 -0
- package/dist/targets/cpp/emit-coercion.d.ts +26 -0
- package/dist/targets/cpp/emit-coercion.js +39 -0
- package/dist/targets/cpp/emit-context.d.ts +1882 -0
- package/dist/targets/cpp/emit-context.js +904 -0
- package/dist/targets/cpp/emit-dynamic-properties.d.ts +174 -0
- package/dist/targets/cpp/emit-dynamic-properties.js +1249 -0
- package/dist/targets/cpp/emit-equality.d.ts +39 -0
- package/dist/targets/cpp/emit-equality.js +472 -0
- package/dist/targets/cpp/emit-exceptions.d.ts +104 -0
- package/dist/targets/cpp/emit-exceptions.js +513 -0
- package/dist/targets/cpp/emit-field-owner.d.ts +4 -0
- package/dist/targets/cpp/emit-field-owner.js +27 -0
- package/dist/targets/cpp/emit-in.d.ts +31 -0
- package/dist/targets/cpp/emit-in.js +426 -0
- package/dist/targets/cpp/emit-instanceof.d.ts +19 -0
- package/dist/targets/cpp/emit-instanceof.js +601 -0
- package/dist/targets/cpp/emit-integers.d.ts +68 -0
- package/dist/targets/cpp/emit-integers.js +184 -0
- package/dist/targets/cpp/emit-iterator.d.ts +100 -0
- package/dist/targets/cpp/emit-iterator.js +1137 -0
- package/dist/targets/cpp/emit-json.d.ts +73 -0
- package/dist/targets/cpp/emit-json.js +823 -0
- package/dist/targets/cpp/emit-jsx.d.ts +74 -0
- package/dist/targets/cpp/emit-jsx.js +806 -0
- package/dist/targets/cpp/emit-mixed-binary.d.ts +51 -0
- package/dist/targets/cpp/emit-mixed-binary.js +60 -0
- package/dist/targets/cpp/emit-namespaces.d.ts +101 -0
- package/dist/targets/cpp/emit-namespaces.js +133 -0
- package/dist/targets/cpp/emit-narrowing.d.ts +738 -0
- package/dist/targets/cpp/emit-narrowing.js +3967 -0
- package/dist/targets/cpp/emit-native-equality.d.ts +3 -0
- package/dist/targets/cpp/emit-native-equality.js +14 -0
- package/dist/targets/cpp/emit-native-selection.d.ts +5 -0
- package/dist/targets/cpp/emit-native-selection.js +37 -0
- package/dist/targets/cpp/emit-object-tag.d.ts +4 -0
- package/dist/targets/cpp/emit-object-tag.js +108 -0
- package/dist/targets/cpp/emit-owned-record.d.ts +2 -0
- package/dist/targets/cpp/emit-owned-record.js +15 -0
- package/dist/targets/cpp/emit-presence.d.ts +78 -0
- package/dist/targets/cpp/emit-presence.js +376 -0
- package/dist/targets/cpp/emit-properties.d.ts +105 -0
- package/dist/targets/cpp/emit-properties.js +1640 -0
- package/dist/targets/cpp/emit-record-view.d.ts +20 -0
- package/dist/targets/cpp/emit-record-view.js +354 -0
- package/dist/targets/cpp/emit-return.d.ts +5 -0
- package/dist/targets/cpp/emit-return.js +237 -0
- package/dist/targets/cpp/emit-sum-widening.d.ts +10 -0
- package/dist/targets/cpp/emit-sum-widening.js +69 -0
- package/dist/targets/cpp/emit-tonumber.d.ts +38 -0
- package/dist/targets/cpp/emit-tonumber.js +177 -0
- package/dist/targets/cpp/emit-tostring.d.ts +92 -0
- package/dist/targets/cpp/emit-tostring.js +556 -0
- package/dist/targets/cpp/emit-typeof.d.ts +49 -0
- package/dist/targets/cpp/emit-typeof.js +317 -0
- package/dist/targets/cpp/emit-union-properties.d.ts +181 -0
- package/dist/targets/cpp/emit-union-properties.js +1281 -0
- package/dist/targets/cpp/emit.d.ts +45 -0
- package/dist/targets/cpp/emit.js +2225 -0
- package/dist/targets/cpp/error-types.d.ts +4 -0
- package/dist/targets/cpp/error-types.js +11 -0
- package/dist/targets/cpp/function-source-reads.d.ts +72 -0
- package/dist/targets/cpp/function-source-reads.js +148 -0
- package/dist/targets/cpp/host/atomics.d.ts +25 -0
- package/dist/targets/cpp/host/atomics.js +63 -0
- package/dist/targets/cpp/host/core-globals.d.ts +108 -0
- package/dist/targets/cpp/host/core-globals.js +158 -0
- package/dist/targets/cpp/host/dynamic-argument-members.d.ts +42 -0
- package/dist/targets/cpp/host/dynamic-argument-members.js +61 -0
- package/dist/targets/cpp/host/emit-host-arity.d.ts +139 -0
- package/dist/targets/cpp/host/emit-host-arity.js +232 -0
- package/dist/targets/cpp/host/emit-host-invoke.d.ts +91 -0
- package/dist/targets/cpp/host/emit-host-invoke.js +1105 -0
- package/dist/targets/cpp/host/emit-host-object.d.ts +55 -0
- package/dist/targets/cpp/host/emit-host-object.js +2206 -0
- package/dist/targets/cpp/host/emit-host-properties.d.ts +69 -0
- package/dist/targets/cpp/host/emit-host-properties.js +533 -0
- package/dist/targets/cpp/host/emit-host-reflect.d.ts +4 -0
- package/dist/targets/cpp/host/emit-host-reflect.js +180 -0
- package/dist/targets/cpp/host/emit-host-value.d.ts +120 -0
- package/dist/targets/cpp/host/emit-host-value.js +392 -0
- package/dist/targets/cpp/host/host-members.d.ts +505 -0
- package/dist/targets/cpp/host/host-members.js +819 -0
- package/dist/targets/cpp/host/host-method-aliases.d.ts +30 -0
- package/dist/targets/cpp/host/host-method-aliases.js +76 -0
- package/dist/targets/cpp/host/native-protocols.d.ts +47 -0
- package/dist/targets/cpp/host/native-protocols.js +183 -0
- package/dist/targets/cpp/host/object-protocol.d.ts +351 -0
- package/dist/targets/cpp/host/object-protocol.js +671 -0
- package/dist/targets/cpp/host-namespace-reads.d.ts +83 -0
- package/dist/targets/cpp/host-namespace-reads.js +113 -0
- package/dist/targets/cpp/manifest/capabilities.d.ts +39 -0
- package/dist/targets/cpp/manifest/capabilities.js +1484 -0
- package/dist/targets/cpp/manifest.d.ts +23 -0
- package/dist/targets/cpp/manifest.js +113 -0
- package/dist/targets/cpp/native-error-base.d.ts +38 -0
- package/dist/targets/cpp/native-error-base.js +74 -0
- package/dist/targets/cpp/native-narrowing-transport.d.ts +12 -0
- package/dist/targets/cpp/native-narrowing-transport.js +151 -0
- package/dist/targets/cpp/native-selection-helpers.d.ts +11 -0
- package/dist/targets/cpp/native-selection-helpers.js +46 -0
- package/dist/targets/cpp/native-symbol-keys.d.ts +8 -0
- package/dist/targets/cpp/native-symbol-keys.js +34 -0
- package/dist/targets/cpp/ownership.d.ts +43 -0
- package/dist/targets/cpp/ownership.js +38 -0
- package/dist/targets/cpp/owning-conversion-input.d.ts +14 -0
- package/dist/targets/cpp/owning-conversion-input.js +12 -0
- package/dist/targets/cpp/property-read-claims.d.ts +62 -0
- package/dist/targets/cpp/property-read-claims.js +23 -0
- package/dist/targets/cpp/property-store-claims.d.ts +62 -0
- package/dist/targets/cpp/property-store-claims.js +26 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.d.ts +111 -0
- package/dist/targets/cpp/prototype/emit-prototype-array.js +602 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.d.ts +133 -0
- package/dist/targets/cpp/prototype/emit-prototype-date.js +515 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.d.ts +13 -0
- package/dist/targets/cpp/prototype/emit-prototype-error.js +54 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.d.ts +34 -0
- package/dist/targets/cpp/prototype/emit-prototype-invoke.js +1003 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.d.ts +47 -0
- package/dist/targets/cpp/prototype/emit-prototype-iterator.js +250 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.d.ts +46 -0
- package/dist/targets/cpp/prototype/emit-prototype-promise.js +143 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.d.ts +335 -0
- package/dist/targets/cpp/prototype/emit-prototype-regexp.js +853 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.d.ts +42 -0
- package/dist/targets/cpp/prototype/emit-prototype-string.js +252 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.d.ts +25 -0
- package/dist/targets/cpp/prototype/prototype-method-reads.js +182 -0
- package/dist/targets/cpp/reactive-dependencies.d.ts +140 -0
- package/dist/targets/cpp/reactive-dependencies.js +432 -0
- package/dist/targets/cpp/reactive-origins.d.ts +44 -0
- package/dist/targets/cpp/reactive-origins.js +82 -0
- package/dist/targets/cpp/records.d.ts +277 -0
- package/dist/targets/cpp/records.js +2427 -0
- package/dist/targets/cpp/recursive-containers.d.ts +43 -0
- package/dist/targets/cpp/recursive-containers.js +144 -0
- package/dist/targets/cpp/regexp-types.d.ts +56 -0
- package/dist/targets/cpp/regexp-types.js +59 -0
- package/dist/targets/cpp/substrate.d.ts +125 -0
- package/dist/targets/cpp/substrate.js +12 -0
- package/dist/targets/cpp/translation-unit.d.ts +219 -0
- package/dist/targets/cpp/translation-unit.js +2063 -0
- package/dist/targets/cpp/types.d.ts +280 -0
- package/dist/targets/cpp/types.js +1135 -0
- package/dist/targets/cpp/virtual-methods.d.ts +95 -0
- package/dist/targets/cpp/virtual-methods.js +264 -0
- package/package.json +95 -0
- package/src/targets/cpp/runtime/gea_dynamic_proxy.h +824 -0
- package/src/targets/cpp/runtime/gea_eval.h +1376 -0
- package/src/targets/cpp/runtime/gea_native_class_prototype.h +44 -0
- package/src/targets/cpp/runtime/gea_runtime.h +29222 -0
- package/src/targets/cpp/runtime/gea_runtime_builtins.cpp +55 -0
|
@@ -0,0 +1,4218 @@
|
|
|
1
|
+
import ts from 'typescript';
|
|
2
|
+
import { prepareStructuralRules, structuralDisagreementsEnabled } from './structural-rules.js';
|
|
3
|
+
import { recordStorageFamilies } from './record-storage-families.js';
|
|
4
|
+
import { emptyDeclaredMemberCensus } from './structural-declarations.js';
|
|
5
|
+
import { createLocalUnionResolver } from './structural-local-union.js';
|
|
6
|
+
import { createMutableMethodResolver } from './structural-mutable-method.js';
|
|
7
|
+
import { structuralArrayReadAt } from './structural-array-read.js';
|
|
8
|
+
import { enclosingArgumentsFunction, implicitArgumentsSlotOf, isArgumentsObjectIdentifier } from './implicit-arguments.js';
|
|
9
|
+
import { createStructuralCallResultResolver, createStructuralConstructResultResolver } from './structural-callable.js';
|
|
10
|
+
import { genericFunctionChoiceMembersOf, genericSourceFunctionDeclarationOf } from './generic-function-choice.js';
|
|
11
|
+
import { accessorSignatureOf, constructorImplementationSignatureOf, implementationSignatureOf, modifierOnlyMappedSourceOf, optionalMethodSignatureOf, declaredValueTypeOf, physicalInitializerTypeOf, physicalOverloadTypeAt, physicalStringObjectTypeAt } from './structural-declarations.js';
|
|
12
|
+
import { createKeyofResolver } from './keyof.js';
|
|
13
|
+
import { constructorInstalledMemberDeclarationsOf } from './flow/source-class-data.js';
|
|
14
|
+
import { arityAdmittedSignature, arrayPredicateNarrowedElementTypeOf, impliedPatternTargetOf, isGlobalObjectInterface, isStandardInterfaceType, isUnusableEvidence, widestOf } from './derived-expression-type.js';
|
|
15
|
+
import { createLeafKeying, literalFor, primitiveFor, symbolKeyDeclarationOf } from './structural-leaves.js';
|
|
16
|
+
import { unwrapErasedExpression } from './producers/erasure.js';
|
|
17
|
+
import { createStructuralParts, selfReferentialCallableShapeOf } from './structural-parts.js';
|
|
18
|
+
import { bodyReadsThis, createReceiverResolver } from './structural-receiver.js';
|
|
19
|
+
import { createMemberRules } from './structural-members.js';
|
|
20
|
+
import { emptyAbsentGlobalCensus } from './absent-globals.js';
|
|
21
|
+
import { createLayoutTypeResolver } from './structural-layout-type.js';
|
|
22
|
+
import { emptyParameterBindingCensus } from './parameter-bindings.js';
|
|
23
|
+
import { emptyCollectionBindingCensus } from './collection-bindings.js';
|
|
24
|
+
import { bagShapeOfType, bagShapeTypeAt, emptyObjectBagCensus } from './object-bag-bindings.js';
|
|
25
|
+
import { indexedAccessMemberTypes } from './structural-indexed-access.js';
|
|
26
|
+
import { joinedCallableOf, joinedIndexUnionOf } from './structural-joins.js';
|
|
27
|
+
import { creationOrderedProperties } from './structural-creation-order.js';
|
|
28
|
+
import { collectionMemberResultTypeAt, contextualArrayConstructTypeAt, inferredArrayElementAt, statedCollectionTypeAt, inferredCollectionTypeArgumentsAt, unstatedNeverArray } from './structural-array-element.js';
|
|
29
|
+
import { createDeclaredBodyResolver } from './structural-declared-body.js';
|
|
30
|
+
import { emptyInstantiationCensus } from './instantiation.js';
|
|
31
|
+
import { emptySpecializationCensus } from './specialization.js';
|
|
32
|
+
import { createTypeParameterSubstitution } from './structural-generics.js';
|
|
33
|
+
import { layoutRelevantParameterIndices } from './structural-layout-relevance.js';
|
|
34
|
+
import { rootSpecialization } from './identities.js';
|
|
35
|
+
import { emptyInterfaceFamilyCensus } from '../interface-families.js';
|
|
36
|
+
import { createInstantiatedMembers } from './structural-instantiated-member.js';
|
|
37
|
+
import { createAliasRecurrence, isSelfReferentialSignal, createViewIndependentRecurrence, selfReferentialKeyOf, selfReferentialShapeOf, selfReferentialSignal } from './structural-self-reference.js';
|
|
38
|
+
import { restParameterArrayElementAt, restParameterUnionOfTuplesElementAt, censusRestElementAt, impliedPatternArrayElementAt } from './parameter-slot.js';
|
|
39
|
+
import { physicalGeneratorOverloadResultAt } from './physical-overload-result.js';
|
|
40
|
+
import { arrayAssignmentPatternSourceExpression, arrayAssignmentTargetOf } from './assignment-patterns.js';
|
|
41
|
+
import { emptyCommonJsModuleRecordCensus } from './commonjs-module-record.js';
|
|
42
|
+
/**
|
|
43
|
+
* The TYPE PARAMETER a reference actually holds, where the checker answered
|
|
44
|
+
* with its base constraint instead.
|
|
45
|
+
*
|
|
46
|
+
* `getTypeAtLocation` on a reference to a `T`-typed binding does not answer
|
|
47
|
+
* `T`. TypeScript computes an APPARENT type for the reference so member
|
|
48
|
+
* lookups and narrowing have a concrete shape to work against, and for an
|
|
49
|
+
* unnarrowed generic that apparent type is the parameter's base constraint --
|
|
50
|
+
* `object` inside hono's `json = <T extends JSONValue | {} | InvalidJSONValue>
|
|
51
|
+
* (object: T) => ... JSON.stringify(object)` reads back as the whole
|
|
52
|
+
* constraint union.
|
|
53
|
+
*
|
|
54
|
+
* That is an ERASURE of the monomorphization, and it disagrees with the cell:
|
|
55
|
+
* the parameter's own declaration is typed `T`, which this copy substitutes to
|
|
56
|
+
* what the call bound, so the binding held `{ hello: string }` while every
|
|
57
|
+
* read of it published the constraint. A `binding-read-conversion` from a
|
|
58
|
+
* record to a ten-armed union is not a conversion any backend should install
|
|
59
|
+
* -- the two carriers describe one value, and only one of them is the value's
|
|
60
|
+
* type.
|
|
61
|
+
*
|
|
62
|
+
* Answered only when the checker's type IS the constraint, object-identical.
|
|
63
|
+
* A reference the flow analysis genuinely narrowed (`typeof object ===
|
|
64
|
+
* 'string'`) reaches a different type, and that narrowing is real.
|
|
65
|
+
*/
|
|
66
|
+
const constraintErasedParameterAt = (checker, node) => {
|
|
67
|
+
if (!ts.isIdentifier(node))
|
|
68
|
+
return null;
|
|
69
|
+
const declaration = checker.getSymbolAtLocation(node)?.valueDeclaration;
|
|
70
|
+
if (!declaration)
|
|
71
|
+
return null;
|
|
72
|
+
if (!ts.isParameter(declaration) && !ts.isVariableDeclaration(declaration))
|
|
73
|
+
return null;
|
|
74
|
+
if (declaration.name === node)
|
|
75
|
+
return null;
|
|
76
|
+
const declared = checker.getTypeAtLocation(declaration);
|
|
77
|
+
if ((declared.flags & ts.TypeFlags.TypeParameter) === 0)
|
|
78
|
+
return null;
|
|
79
|
+
return checker.getBaseConstraintOfType(declared) === checker.getTypeAtLocation(node) ? declared : null;
|
|
80
|
+
};
|
|
81
|
+
export const createStructuralMapper = (checker, identities, table, instantiations = emptyInstantiationCensus, specializations = emptySpecializationCensus, parameters = emptyParameterBindingCensus, absent = emptyAbsentGlobalCensus, collections = emptyCollectionBindingCensus, bags = emptyObjectBagCensus, flow, families = emptyInterfaceFamilyCensus, moduleRecords = emptyCommonJsModuleRecordCensus, declaredMembers = emptyDeclaredMemberCensus, isIntrinsicDescriptorCall = () => false) => {
|
|
82
|
+
const storageTypeOf = recordStorageFamilies(checker, flow, parameters);
|
|
83
|
+
// One disagreement list for the WHOLE mapper, for the same reason the caches
|
|
84
|
+
// below are shared: two rules answering for one node is a fact about the rule
|
|
85
|
+
// set, and a per-view list would report it once per copy that asked.
|
|
86
|
+
const disagreements = [];
|
|
87
|
+
// One recurrence stack for the WHOLE mapper: the unfolding it folds crosses specialization views.
|
|
88
|
+
const aliasRecurrence = createAliasRecurrence(checker);
|
|
89
|
+
// One table cache for the WHOLE mapper, for the same reason: a copy's member
|
|
90
|
+
// types are a property of the copy, and every view that passes through it
|
|
91
|
+
// asks the same question.
|
|
92
|
+
const instantiatedMembersFor = createInstantiatedMembers(checker, specializations);
|
|
93
|
+
// And one recurrence key for every view-independent cycle, for the same reason.
|
|
94
|
+
const viewIndependentKeyOf = createViewIndependentRecurrence(checker);
|
|
95
|
+
// The ids those cycles settled on, for every view: a view that enters the
|
|
96
|
+
// same cycle at another member (`State` where the first entered at
|
|
97
|
+
// `State[]`) closes it through these instead of interning a second copy.
|
|
98
|
+
const sharedCompleted = new Map();
|
|
99
|
+
// Every generic class's copies, for every view: a class's copies are the
|
|
100
|
+
// program's, not a view's, and their fillings are closed types, so both
|
|
101
|
+
// answers are the same from every view. `classCopyKeys` is what
|
|
102
|
+
// `classCopies` publishes to the deriver.
|
|
103
|
+
const classCopyKeys = new Map();
|
|
104
|
+
const views = new Map();
|
|
105
|
+
const mapperFor = (path, bindingPath = path) => {
|
|
106
|
+
// Keyed by the copy, owner included, never by the ordinals alone: `copyKeyOf` (identities.ts) says why.
|
|
107
|
+
// Both paths are in the key: two views differing only in what they BIND
|
|
108
|
+
// are two different answers, and sharing one memo hands the second
|
|
109
|
+
// whichever the first settled.
|
|
110
|
+
const key = `${identities.copyKeyOf(path)}|${identities.copyKeyOf(bindingPath)}`;
|
|
111
|
+
const cached = views.get(key);
|
|
112
|
+
if (cached)
|
|
113
|
+
return cached;
|
|
114
|
+
const built = buildMapper(checker, identities.forSpecialization(path), table, instantiations, specializations, path, bindingPath, mapperFor, parameters, absent, collections, bags, flow, storageTypeOf, families, moduleRecords, declaredMembers, isIntrinsicDescriptorCall, aliasRecurrence, instantiatedMembersFor(bindingPath), viewIndependentKeyOf, sharedCompleted, classCopyKeys, disagreements);
|
|
115
|
+
views.set(key, built);
|
|
116
|
+
return built;
|
|
117
|
+
};
|
|
118
|
+
return mapperFor(rootSpecialization);
|
|
119
|
+
};
|
|
120
|
+
const buildMapper = (checker, identities, table, instantiations, specializations, path, bindingPath, mapperFor, parameters, absent, collections, bags, flow, storageTypeOf, families, moduleRecords, declaredMembers, isIntrinsicDescriptorCall, aliasRecurrence, instantiatedMembers, viewIndependentKeyOf, sharedCompleted, classCopyKeys, disagreements) => {
|
|
121
|
+
const { boundByPath, bindingOf: censusBindingOf, substituteTypeParameter } = createTypeParameterSubstitution(identities, instantiations, specializations, bindingPath);
|
|
122
|
+
// A type under translation must resolve to its anchor rather than recursing:
|
|
123
|
+
// `interface Node { next: Node }` would otherwise never terminate.
|
|
124
|
+
const inProgress = new Map();
|
|
125
|
+
const completed = new Map();
|
|
126
|
+
/** Self-reference with no declared name to anchor on -- a recursive type alias. See `structural-self-reference.ts`. */
|
|
127
|
+
const walking = new Set();
|
|
128
|
+
const selfReferential = new Set();
|
|
129
|
+
/**
|
|
130
|
+
* Every memo an in-flight attempt has written, so an unwind can take them
|
|
131
|
+
* back. A stale citation, not a missing one: an unwound frame's memos are
|
|
132
|
+
* keyed by checker type and survive, and the shapes behind them were interned
|
|
133
|
+
* with the ABANDONED anchor inside -- so the retry's correct answer sits in
|
|
134
|
+
* the table unused while the first attempt's conclusion outranks it. lib.dom's
|
|
135
|
+
* `window` is the standing case (`Window & typeof globalThis`, `Window`
|
|
136
|
+
* abandoned partway through): mentioning it at all selected a carrier
|
|
137
|
+
* containing `unresolved(...)`. `null` when nothing is in flight.
|
|
138
|
+
*/
|
|
139
|
+
let journal = null;
|
|
140
|
+
const selfReferentialKeys = new Map();
|
|
141
|
+
const unresolved = (reason, fallback) => table.intern({ kind: 'unresolved', reason, ...(fallback ? { fallback } : {}) });
|
|
142
|
+
const { keyOfSymbol } = createLeafKeying(identities, checker);
|
|
143
|
+
const { implicitReceiverOf, declaredMemberSignatureOf } = createReceiverResolver(checker, (node) => layoutTypeAt(node), declaredMembers);
|
|
144
|
+
/**
|
|
145
|
+
* The object half of a `T[K]`, resolved the way this copy resolves a bare `T`.
|
|
146
|
+
*
|
|
147
|
+
* The `TypeParameter` branch of `translate` answers a parameter in three
|
|
148
|
+
* steps -- what this copy binds, what the program-wide census binds, and the
|
|
149
|
+
* author's own DEFAULT -- and only the first of those reached here, so a
|
|
150
|
+
* parameter answered by either of the other two carried a `T[K]` that had
|
|
151
|
+
* nothing left to refuse with. hono's `class Hono<E extends Env = Env, ...>`
|
|
152
|
+
* is the case: nothing writes `Hono<Something>`, so every `E['Bindings']` in
|
|
153
|
+
* `hono-base.ts` and `context.ts` -- 96 obligations, the file's largest
|
|
154
|
+
* single cluster -- asked about a parameter whose answer is its default,
|
|
155
|
+
* `Env`, and got the refusal instead.
|
|
156
|
+
*
|
|
157
|
+
* The default is the language's own substitution, not a guess: a reference
|
|
158
|
+
* that omits the argument IS the default, and the checker has already typed
|
|
159
|
+
* every such reference that way. Answering `T[K]` with anything else would
|
|
160
|
+
* put this layer and the checker into disagreement about one expression.
|
|
161
|
+
*
|
|
162
|
+
* A fourth step is NOT here but at the access itself
|
|
163
|
+
* (`memberTypesThroughBound`): the declared upper bound. It belongs there
|
|
164
|
+
* rather than here because the same rule answers a case this function's
|
|
165
|
+
* shape cannot see -- an object type that is not a parameter at all.
|
|
166
|
+
*/
|
|
167
|
+
const resolvedObjectType = (objectType) => {
|
|
168
|
+
const substituted = substituteTypeParameter(objectType);
|
|
169
|
+
if (substituted !== objectType)
|
|
170
|
+
return substituted;
|
|
171
|
+
if ((objectType.flags & ts.TypeFlags.TypeParameter) === 0)
|
|
172
|
+
return objectType;
|
|
173
|
+
const symbol = objectType.getSymbol();
|
|
174
|
+
const declaration = symbol ? identities.declarationOfSymbol(symbol) : null;
|
|
175
|
+
if (!declaration || !ts.isTypeParameterDeclaration(declaration) || !declaration.default)
|
|
176
|
+
return objectType;
|
|
177
|
+
// The instantiated default where the checker has one -- see the type-parameter
|
|
178
|
+
// branch of `translate` below for why the declaration node alone is wrong.
|
|
179
|
+
return checker.getDefaultFromTypeParameter(objectType) ?? checker.getTypeFromTypeNode(declaration.default);
|
|
180
|
+
};
|
|
181
|
+
/**
|
|
182
|
+
* `T & {}` with `T := A | B | undefined` is `(A & {}) | (B & {}) |
|
|
183
|
+
* (undefined & {})`, which is `A | B`.
|
|
184
|
+
*
|
|
185
|
+
* TypeScript distributes an intersection over its union members when it
|
|
186
|
+
* BUILDS one (`getIntersectionType`), so the checker never hands this
|
|
187
|
+
* mapper an intersection with a union member of its own -- until a copy
|
|
188
|
+
* substitutes a union for the type parameter the checker left in place.
|
|
189
|
+
* tsc's `assertIsDefined<T>(value: T)` and `cast<TOut extends TIn, TIn>`
|
|
190
|
+
* narrow `value` to `T & {}`, and every copy bound to a union read an
|
|
191
|
+
* intersection with a union member, which no record layout can hold: ~400
|
|
192
|
+
* rows of "no primitive for an intersection whose member is not a record
|
|
193
|
+
* shape" on the tsc self-compile. This is the checker's own reduction,
|
|
194
|
+
* applied after substitution: distribute, drop `unknown` and the empty
|
|
195
|
+
* object type (both intersect as identity), and reduce a product that pairs
|
|
196
|
+
* an absence with anything else, or two primitives of different domains, to
|
|
197
|
+
* `never`, which the union then drops. Only an UNNAMED intersection
|
|
198
|
+
* distributes: a declared one keeps its name as its layout anchor.
|
|
199
|
+
*/
|
|
200
|
+
// A recursive declaration is deliberately visible by id before its shape
|
|
201
|
+
// exists. It is an atomic member until the frame that reserved it completes
|
|
202
|
+
// it; inspecting it here violates the table's anchor protocol, while
|
|
203
|
+
// retaining its id in each distributed product preserves the recurrence.
|
|
204
|
+
const closedShapeAt = (id) => (table.isOpen(id) ? null : table.get(id).shape);
|
|
205
|
+
const distributedIntersectionOf = (members) => {
|
|
206
|
+
if (!members.some((member) => closedShapeAt(member)?.kind === 'union'))
|
|
207
|
+
return null;
|
|
208
|
+
let products = [[]];
|
|
209
|
+
for (const member of members) {
|
|
210
|
+
const shape = closedShapeAt(member);
|
|
211
|
+
const choices = shape?.kind === 'union' ? shape.members : [member];
|
|
212
|
+
products = products.flatMap((product) => choices.map((choice) => [...product, choice]));
|
|
213
|
+
if (products.length > 512)
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const arms = [];
|
|
217
|
+
for (const product of products) {
|
|
218
|
+
const arm = reducedIntersectionOf(product);
|
|
219
|
+
if (arm !== null && !arms.includes(arm))
|
|
220
|
+
arms.push(arm);
|
|
221
|
+
}
|
|
222
|
+
const only = arms[0];
|
|
223
|
+
if (only === undefined)
|
|
224
|
+
return typeOf(checker.getNeverType());
|
|
225
|
+
return arms.length === 1 ? only : table.intern({ kind: 'union', members: arms });
|
|
226
|
+
};
|
|
227
|
+
/** One product of the distribution, reduced as the checker reduces an intersection; `null` is `never`. */
|
|
228
|
+
const reducedIntersectionOf = (product) => {
|
|
229
|
+
const isIdentity = (shape) => (shape.kind === 'primitive' && shape.primitive === 'unknown') ||
|
|
230
|
+
(shape.kind === 'object' && shape.members.length === 0 && shape.index.length === 0);
|
|
231
|
+
const kept = [...new Set(product)].filter((member) => {
|
|
232
|
+
const shape = closedShapeAt(member);
|
|
233
|
+
return shape === null || !isIdentity(shape);
|
|
234
|
+
});
|
|
235
|
+
const first = product[0];
|
|
236
|
+
if (kept.length === 0)
|
|
237
|
+
return first ?? null;
|
|
238
|
+
const domains = kept.map((member) => {
|
|
239
|
+
const shape = closedShapeAt(member);
|
|
240
|
+
if (shape === null)
|
|
241
|
+
return null;
|
|
242
|
+
if (shape.kind === 'primitive')
|
|
243
|
+
return shape.primitive;
|
|
244
|
+
if (shape.kind === 'literal')
|
|
245
|
+
return shape.primitive;
|
|
246
|
+
return null;
|
|
247
|
+
});
|
|
248
|
+
if (domains.includes('never'))
|
|
249
|
+
return null;
|
|
250
|
+
const primitives = new Set(domains.flatMap((domain) => (domain === null ? [] : [domain])));
|
|
251
|
+
if (primitives.size > 1)
|
|
252
|
+
return null;
|
|
253
|
+
const absent = [...primitives].some((domain) => domain === 'undefined' || domain === 'null' || domain === 'void');
|
|
254
|
+
if (absent && kept.length > 1)
|
|
255
|
+
return null;
|
|
256
|
+
const only = kept[0];
|
|
257
|
+
if (kept.length === 1 && only !== undefined)
|
|
258
|
+
return only;
|
|
259
|
+
if (kept.some((member) => closedShapeAt(member)?.kind === 'union'))
|
|
260
|
+
return distributedIntersectionOf(kept);
|
|
261
|
+
return table.intern({ kind: 'intersection', members: kept, declaration: null, resolved: null });
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* The index half of `T[K]`, resolved the way `resolvedObjectType` resolves
|
|
265
|
+
* the object half: the copy's binding first, then the parameter's own
|
|
266
|
+
* constraint. `readPackageJsonField<K extends MatchingKeys<PackageJson,
|
|
267
|
+
* string | undefined>>(json, fieldName: K): PackageJson[K]` (tsc's
|
|
268
|
+
* moduleNameResolver.ts) is the shape -- the OBJECT is a plain interface
|
|
269
|
+
* and only the index is a parameter, which the object-side substitution
|
|
270
|
+
* alone never touched, so every copy refused "an indexed access whose
|
|
271
|
+
* object type is still a type parameter" for an access whose object type
|
|
272
|
+
* never was one. A copy bound to `"types"` reads `PackageJson["types"]`;
|
|
273
|
+
* the value-use copy reads the constraint, the checker-evaluated union of
|
|
274
|
+
* the matching keys, which `keysOf` enumerates as it does any literal
|
|
275
|
+
* union. A union index is left as written for the same enumerator.
|
|
276
|
+
*/
|
|
277
|
+
const resolvedIndexType = (indexType) => {
|
|
278
|
+
const substituted = substituteTypeParameter(indexType);
|
|
279
|
+
if (substituted !== indexType)
|
|
280
|
+
return substituted;
|
|
281
|
+
if ((indexType.flags & ts.TypeFlags.TypeParameter) === 0)
|
|
282
|
+
return indexType;
|
|
283
|
+
const bound = checker.getBaseConstraintOfType(indexType);
|
|
284
|
+
return bound && bound !== indexType ? bound : indexType;
|
|
285
|
+
};
|
|
286
|
+
/**
|
|
287
|
+
* Whether a type is, or contains, a form the checker left DEFERRED -- a
|
|
288
|
+
* conditional it could not evaluate, an unresolved indexed access, a
|
|
289
|
+
* substitution. Such a type's base constraint is a fallback rather than a
|
|
290
|
+
* statement, which is the distinction `memberTypesThroughBound` turns on.
|
|
291
|
+
*/
|
|
292
|
+
const carriesDeferredForm = (type, depth = 0) => {
|
|
293
|
+
if (depth > 8)
|
|
294
|
+
return false;
|
|
295
|
+
const deferred = ts.TypeFlags.Conditional | ts.TypeFlags.IndexedAccess | ts.TypeFlags.Substitution;
|
|
296
|
+
if ((type.flags & deferred) !== 0)
|
|
297
|
+
return true;
|
|
298
|
+
if (type.isUnion() || type.isIntersection())
|
|
299
|
+
return type.types.some((part) => carriesDeferredForm(part, depth + 1));
|
|
300
|
+
return false;
|
|
301
|
+
};
|
|
302
|
+
/**
|
|
303
|
+
* `T[K]`'s member types read off `T`'s declared UPPER BOUND, for the object
|
|
304
|
+
* types whose own shape cannot answer.
|
|
305
|
+
*
|
|
306
|
+
* A bound is information, not its absence. `E extends Env` states that every
|
|
307
|
+
* `E` this program can produce is an `Env`, so every `E['Bindings']` is one
|
|
308
|
+
* of `Env['Bindings']`'s own members -- and answering with those is
|
|
309
|
+
* answering with a type every instantiation's value satisfies, which is
|
|
310
|
+
* exactly what a storage carrier has to be. The alternative was a bottom
|
|
311
|
+
* carrier, which is not a cell at all.
|
|
312
|
+
*
|
|
313
|
+
* The case that forced it is not a naked parameter, which is why this is not
|
|
314
|
+
* inside `resolvedObjectType`. hono's router chain substitutes `E` with a
|
|
315
|
+
* growing INTERSECTION -- `IfAnyThenEmptyObject<E extends Env ? Env extends
|
|
316
|
+
* E ? {} : E : E> & IfAnyThenEmptyObject<E2 ...> & {}`, one arm per `.get()`
|
|
317
|
+
* in the program -- because every route returns a `Hono` whose environment
|
|
318
|
+
* merges the last one's. Substitution resolves `E` to that intersection
|
|
319
|
+
* perfectly well; what cannot answer `['Bindings']` is the intersection,
|
|
320
|
+
* whose constituents are CONDITIONAL types the checker leaves deferred while
|
|
321
|
+
* `E` is generic. Its base constraint is `{}`, the environment hono's own
|
|
322
|
+
* `BlankEnv` states, and `{}` declares no `Bindings` -- so the access is
|
|
323
|
+
* `undefined`, which is what `indexedAccessMemberTypes` already answers for
|
|
324
|
+
* a missing key on a real object type.
|
|
325
|
+
*
|
|
326
|
+
* `getBaseConstraintOfType` rather than `getConstraintOfType`: a constraint
|
|
327
|
+
* can itself be a type parameter (`<A, B extends A>`), and a carrier needs
|
|
328
|
+
* the bound that is no longer one. A type with no constraint answers
|
|
329
|
+
* `undefined` and the caller keeps its refusal -- nothing was stated, so
|
|
330
|
+
* there is nothing to resolve against. `any`/`unknown` as the bound keeps it
|
|
331
|
+
* too: those are answered above, where the object type itself is the top
|
|
332
|
+
* type, and reaching them through a bound would turn "nothing is stated"
|
|
333
|
+
* into a claim about members.
|
|
334
|
+
*/
|
|
335
|
+
const memberTypesThroughBound = (objectType, indexType) => {
|
|
336
|
+
const bound = checker.getBaseConstraintOfType(objectType);
|
|
337
|
+
if (!bound || bound === objectType)
|
|
338
|
+
return null;
|
|
339
|
+
if ((bound.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0)
|
|
340
|
+
return null;
|
|
341
|
+
// An EMPTY bound over a DEFERRED type states nothing, and must not be read
|
|
342
|
+
// as stating absence. `indexedAccessMemberTypes` answers a missing key with
|
|
343
|
+
// `undefined` -- the language's own answer, and the right one for a real
|
|
344
|
+
// object type that genuinely declares no such member. `{}` arrived at as
|
|
345
|
+
// the constraint of a conditional the checker could not evaluate is a
|
|
346
|
+
// different fact wearing the same shape: it is TypeScript's fallback, not
|
|
347
|
+
// the author's claim. hono's `env: E['Bindings'] = {}` is where the two
|
|
348
|
+
// part company -- in the copy whose object type is the router chain's
|
|
349
|
+
// intersection of deferred conditionals, absence would carrier the field as
|
|
350
|
+
// `undefined`, a cell that provably cannot hold the initializer written on
|
|
351
|
+
// the very same line. `unknown` is what is actually known there, and it is
|
|
352
|
+
// a cell.
|
|
353
|
+
if (carriesDeferredForm(objectType) && bound.getProperties().length === 0 && checker.getIndexInfosOfType(bound).length === 0) {
|
|
354
|
+
return [checker.getUnknownType()];
|
|
355
|
+
}
|
|
356
|
+
return indexedAccessMemberTypes(checker, bound, indexType);
|
|
357
|
+
};
|
|
358
|
+
// `getMinArgumentCount` is checker-internal. The public answer is the count of
|
|
359
|
+
// leading parameters the call site must supply: everything before the first
|
|
360
|
+
// optional, defaulted, or rest parameter.
|
|
361
|
+
const { signatureOf, memberOf, indexesOf, tupleElementsOf } = createStructuralParts({
|
|
362
|
+
parameters,
|
|
363
|
+
checker,
|
|
364
|
+
identities,
|
|
365
|
+
typeOf: (type) => typeOf(type),
|
|
366
|
+
parameterOverrideAt: (parameter) => refusedArrayParameterTypeAt(parameter) ?? prototypeObjectParameterTypeAt(parameter),
|
|
367
|
+
implicitReceiverOf,
|
|
368
|
+
declaredMemberSignatureOf,
|
|
369
|
+
declaredMembers,
|
|
370
|
+
keyOfSymbol,
|
|
371
|
+
// Same wrap the body-side rest-parameter reference below performs
|
|
372
|
+
// (`table.intern({ kind: 'array', element: typeOf(restElement), ... })`)
|
|
373
|
+
// exposed to `structural-parts.ts`'s `parameterOf`, which has no `table`
|
|
374
|
+
// of its own -- see `StructuralPartsInput.internArray`'s doc.
|
|
375
|
+
internArray: (element) => table.intern({ kind: 'array', element, readonly: false, extension: [] }),
|
|
376
|
+
internUnion: (members) => table.intern({ kind: 'union', members }),
|
|
377
|
+
// So `memberOf` can close the same keyed-collection-field gap `typeAt`
|
|
378
|
+
// closes for every other node shape naming the same cell -- see
|
|
379
|
+
// `StructuralPartsInput.collections`'s own doc.
|
|
380
|
+
collections,
|
|
381
|
+
table,
|
|
382
|
+
// The bag census the collection value slot needs -- see
|
|
383
|
+
// `StructuralPartsInput.bags`.
|
|
384
|
+
bags
|
|
385
|
+
});
|
|
386
|
+
const { keeperFor } = createMemberRules(identities);
|
|
387
|
+
/**
|
|
388
|
+
* The shape of a type the LANGUAGE indexes -- a tuple or an Array -- or
|
|
389
|
+
* `null` for anything else.
|
|
390
|
+
*
|
|
391
|
+
* Factored out because there are two places a type can be shaped, and only
|
|
392
|
+
* one of them used to ask this. `Array<T>`'s own members mention
|
|
393
|
+
* `Array<T>` (`concat`, `slice`, `filter` all return one), so an array
|
|
394
|
+
* reached mid-walk is SELF-REFERENTIAL, and the self-referential branch
|
|
395
|
+
* anchored it and then handed it to `buildDeclaredShape` -- which builds
|
|
396
|
+
* the interface's data-only projection, `{ length, [Symbol.unscopables],
|
|
397
|
+
* [number]: T }` with every method dropped. `remember` then cached that
|
|
398
|
+
* against the very `ts.Type` the array branch below owns, so every later
|
|
399
|
+
* mention of the same array got the projection too, and the array branch
|
|
400
|
+
* was never reached again.
|
|
401
|
+
*
|
|
402
|
+
* Reached that way, `Object3D[]` carried as a `native-record-ref`:
|
|
403
|
+
* CubeCamera's `const [ cameraPX, ... ] = cameras` asked for a
|
|
404
|
+
* `destructuring:array-pattern:native-record-ref` helper no manifest
|
|
405
|
+
* claims or should. Measured on the three.js app, 34 shapes and 52 selected
|
|
406
|
+
* carriers were Array projections of this kind, against 4258 honest
|
|
407
|
+
* `array-object` carriers -- an ordering leak, not a systemic
|
|
408
|
+
* misclassification, which is exactly why it survived: most arrays are
|
|
409
|
+
* reached from a position that asks the array branch first.
|
|
410
|
+
*
|
|
411
|
+
* `readonly` is `false` for the array case, as it has always effectively
|
|
412
|
+
* been: the old expression was `isArrayLikeType(type) && !isArrayType(type)`
|
|
413
|
+
* evaluated INSIDE an `isArrayType` branch, so it could not be anything
|
|
414
|
+
* else. A `readonly T[]` is `ReadonlyArray<T>`, which `isArrayType` answers
|
|
415
|
+
* `false` for and which reaches neither this helper nor that branch.
|
|
416
|
+
*/
|
|
417
|
+
const indexedShapeOf = (type) => {
|
|
418
|
+
if (checker.isTupleType(type)) {
|
|
419
|
+
const reference = type;
|
|
420
|
+
return { kind: 'tuple', elements: tupleElementsOf(reference), readonly: reference.target.readonly };
|
|
421
|
+
}
|
|
422
|
+
if (!checker.isArrayType(type))
|
|
423
|
+
return null;
|
|
424
|
+
const element = checker.getTypeArguments(type)[0];
|
|
425
|
+
if (!element)
|
|
426
|
+
return { kind: 'unresolved', reason: 'array type without an element type argument' };
|
|
427
|
+
return { kind: 'array', element: typeOf(element), readonly: false, extension: [] };
|
|
428
|
+
};
|
|
429
|
+
/**
|
|
430
|
+
* Whether an interface's heritage reaches the standard `Array` or
|
|
431
|
+
* `ReadonlyArray`, through any chain of source interfaces.
|
|
432
|
+
*/
|
|
433
|
+
const reachesStandardArray = (target, anchor, visited) => {
|
|
434
|
+
if (visited.has(target))
|
|
435
|
+
return null;
|
|
436
|
+
visited.add(target);
|
|
437
|
+
for (const base of checker.getBaseTypes(target)) {
|
|
438
|
+
if (isStandardInterfaceType(checker, anchor, 'Array', base))
|
|
439
|
+
return 'array';
|
|
440
|
+
if (isStandardInterfaceType(checker, anchor, 'ReadonlyArray', base))
|
|
441
|
+
return 'readonly-array';
|
|
442
|
+
// `ConcatArray<T>` is the third spelling of the same object, not a
|
|
443
|
+
// separate shape -- see `arrayHeritageShapeOf`'s own note on why it is
|
|
444
|
+
// recognized directly rather than through heritage.
|
|
445
|
+
if (isStandardInterfaceType(checker, anchor, 'ConcatArray', base))
|
|
446
|
+
return 'readonly-array';
|
|
447
|
+
const baseTarget = base.target ?? base;
|
|
448
|
+
if (!(baseTarget.objectFlags & ts.ObjectFlags.Interface))
|
|
449
|
+
continue;
|
|
450
|
+
const reached = reachesStandardArray(baseTarget, anchor, visited);
|
|
451
|
+
if (reached)
|
|
452
|
+
return reached;
|
|
453
|
+
}
|
|
454
|
+
return null;
|
|
455
|
+
};
|
|
456
|
+
/** Whether a property is one the standard `Array`/`ReadonlyArray` interfaces themselves declare. */
|
|
457
|
+
const isStandardArrayMember = (property) => (property.declarations ?? []).some((declaration) => {
|
|
458
|
+
const owner = declaration.parent;
|
|
459
|
+
return (ts.isInterfaceDeclaration(owner) &&
|
|
460
|
+
owner.getSourceFile().isDeclarationFile &&
|
|
461
|
+
(owner.name.text === 'Array' || owner.name.text === 'ReadonlyArray' || owner.name.text === 'ConcatArray'));
|
|
462
|
+
});
|
|
463
|
+
/**
|
|
464
|
+
* A BRAND on an array-extending interface -- `" __sortedArrayBrand": any`
|
|
465
|
+
* (TypeScript's `SortedReadonlyArray<T>`) -- names no storage: its type
|
|
466
|
+
* admits no value a program could write, and its name is spelled to be
|
|
467
|
+
* unwritable. The object deriver's `isVacuousBrand` makes the same call for
|
|
468
|
+
* intersections; here the member is simply not part of the extension.
|
|
469
|
+
*/
|
|
470
|
+
const isArrayBrandMember = (property, location) => {
|
|
471
|
+
const name = property.getName();
|
|
472
|
+
if (!(name.startsWith(' ') || name.startsWith('__')))
|
|
473
|
+
return false;
|
|
474
|
+
const flags = checker.getTypeOfSymbolAtLocation(property, location).flags;
|
|
475
|
+
return (flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never | ts.TypeFlags.UniqueESSymbol)) !== 0;
|
|
476
|
+
};
|
|
477
|
+
/**
|
|
478
|
+
* An interface whose heritage reaches the standard `Array`/`ReadonlyArray`
|
|
479
|
+
* -- TypeScript's own `NodeArray<T> extends ReadonlyArray<T>,
|
|
480
|
+
* ReadonlyTextRange` -- is an ARRAY with extra fields, not an object that
|
|
481
|
+
* happens to carry the array's members as storage. Enumerated as an object
|
|
482
|
+
* it interned `map<U>`, `filter<S>` and the rest as fields whose type
|
|
483
|
+
* parameters no copy ever binds (230 "type parameter ... reached
|
|
484
|
+
* representation without monomorphization" rows on the tsc self-compile,
|
|
485
|
+
* one shape), and the deriver laid out a record for a value every consumer
|
|
486
|
+
* indexes and iterates.
|
|
487
|
+
*
|
|
488
|
+
* The element is the INSTANTIATED number-index type, so `NodeArray<T>` read
|
|
489
|
+
* inside a generic copy still resolves `T` through that copy exactly as
|
|
490
|
+
* `T[]` does. The extension is the interface's own data members -- every
|
|
491
|
+
* property the array interfaces do not themselves declare, so a second base
|
|
492
|
+
* (`ReadonlyTextRange`'s `pos`/`end`) contributes too -- minus brand
|
|
493
|
+
* members, which state nothing storable. `readonly` stays `false` for the
|
|
494
|
+
* same reason `indexedShapeOf` keeps it so: `Array` and `ReadonlyArray`
|
|
495
|
+
* heritage must intern to ONE shape, since `MutableNodeArray<T>` and
|
|
496
|
+
* `NodeArray<T>` are the same object under two spellings.
|
|
497
|
+
*/
|
|
498
|
+
const arrayHeritageShapeOf = (type, location) => {
|
|
499
|
+
if (!(type.flags & ts.TypeFlags.Object))
|
|
500
|
+
return null;
|
|
501
|
+
const object = type;
|
|
502
|
+
const target = object.objectFlags & ts.ObjectFlags.Reference ? type.target : object;
|
|
503
|
+
if (!(target.objectFlags & ts.ObjectFlags.Interface))
|
|
504
|
+
return null;
|
|
505
|
+
// `ConcatArray<T>` is the one standard array interface that reaches
|
|
506
|
+
// neither `Array` nor `ReadonlyArray` through heritage: `lib.es5.d.ts`
|
|
507
|
+
// declares it standalone, with `readonly length`, `readonly [n: number]:
|
|
508
|
+
// T`, `join` and `slice`, and `Array<T>`/`ReadonlyArray<T>`/every tuple
|
|
509
|
+
// satisfy it structurally. It is a SPELLING of the array object, not an
|
|
510
|
+
// object that happens to carry an array's members, and it is where every
|
|
511
|
+
// `Array.prototype.concat(...items: ConcatArray<T>[])` argument lands --
|
|
512
|
+
// so deriving it as a record made `a.concat(b)` refuse the rest pack it
|
|
513
|
+
// had just built (`conversion:array-object(E)->native-record-ref`), for
|
|
514
|
+
// every element type, in every program. hono's `RegExpRouter`
|
|
515
|
+
// (`Object.keys(a).concat(Object.keys(b))`) and its trie router
|
|
516
|
+
// (`tempNodes.concat(shifted)`) are the two that named it.
|
|
517
|
+
if (!reachesStandardArray(target, location, new Set()) &&
|
|
518
|
+
!isStandardInterfaceType(checker, location, 'ConcatArray', type))
|
|
519
|
+
return null;
|
|
520
|
+
const element = checker.getIndexTypeOfType(type, ts.IndexKind.Number);
|
|
521
|
+
if (!element)
|
|
522
|
+
return null;
|
|
523
|
+
const extension = [];
|
|
524
|
+
for (const property of creationOrderedProperties(checker, type, parameters)) {
|
|
525
|
+
if (isStandardArrayMember(property) || isArrayBrandMember(property, location))
|
|
526
|
+
continue;
|
|
527
|
+
const member = memberOf(property, location);
|
|
528
|
+
if (member)
|
|
529
|
+
extension.push(member);
|
|
530
|
+
}
|
|
531
|
+
return { kind: 'array', element: typeOf(element), readonly: false, extension };
|
|
532
|
+
};
|
|
533
|
+
const objectShapeOf = (type, location, members = 'all') => {
|
|
534
|
+
const properties = creationOrderedProperties(checker, type, parameters);
|
|
535
|
+
const kept = members === 'all' ? properties : properties.filter(keeperFor(properties, members));
|
|
536
|
+
const mapped = kept.flatMap((property) => {
|
|
537
|
+
const member = memberOf(property, location);
|
|
538
|
+
return member ? [member] : [];
|
|
539
|
+
});
|
|
540
|
+
const indexes = [...indexesOf(type)];
|
|
541
|
+
if (location && ts.isObjectLiteralExpression(location) && members === 'all') {
|
|
542
|
+
const runtimeMembers = mapped.filter((member) => {
|
|
543
|
+
if (member.key.kind !== 'symbol' || member.accessor !== null)
|
|
544
|
+
return false;
|
|
545
|
+
const keyDeclarationId = member.key.declaration;
|
|
546
|
+
const property = kept.find((candidate) => {
|
|
547
|
+
const keyDeclaration = symbolKeyDeclarationOf(checker, identities, candidate);
|
|
548
|
+
return keyDeclaration !== null && identities.declarationIdOf(keyDeclaration) === keyDeclarationId;
|
|
549
|
+
});
|
|
550
|
+
const declarations = property?.declarations;
|
|
551
|
+
return !!declarations?.length && declarations.every(ts.isPropertyAssignment) && !declarations[0].getSourceFile().isDeclarationFile;
|
|
552
|
+
});
|
|
553
|
+
if (runtimeMembers.length) {
|
|
554
|
+
const existing = indexes.findIndex((index) => index.key === 'symbol');
|
|
555
|
+
const prior = existing < 0 ? undefined : indexes[existing];
|
|
556
|
+
const values = [...new Set([...runtimeMembers.map((member) => member.type), ...(prior ? [prior.value] : [])])];
|
|
557
|
+
const value = values.length === 1 ? values[0] : table.intern({ kind: 'union', members: values });
|
|
558
|
+
const index = {
|
|
559
|
+
key: 'symbol',
|
|
560
|
+
value,
|
|
561
|
+
readonly: false,
|
|
562
|
+
runtimeMembers: runtimeMembers.flatMap((member) => (member.key.kind === 'symbol' ? [member.key.declaration] : [])),
|
|
563
|
+
finite: prior === undefined
|
|
564
|
+
};
|
|
565
|
+
if (existing < 0)
|
|
566
|
+
indexes.push(index);
|
|
567
|
+
else
|
|
568
|
+
indexes[existing] = index;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
return {
|
|
572
|
+
kind: 'object',
|
|
573
|
+
members: mapped,
|
|
574
|
+
index: indexes,
|
|
575
|
+
membersDropped: kept.length !== properties.length
|
|
576
|
+
};
|
|
577
|
+
};
|
|
578
|
+
/**
|
|
579
|
+
* The structure a declared name stands for.
|
|
580
|
+
*
|
|
581
|
+
* A name without a body is a name the later layers cannot lay out, so the body
|
|
582
|
+
* is interned here while the nominal identity is still anchored -- a member
|
|
583
|
+
* that refers back to the declaration resolves to the anchor instead of
|
|
584
|
+
* re-entering translation.
|
|
585
|
+
*/
|
|
586
|
+
/**
|
|
587
|
+
* The storage a class instance owns.
|
|
588
|
+
*
|
|
589
|
+
* Only `Property` members: a method and an accessor live on the prototype, so
|
|
590
|
+
* putting either in the instance's structure would claim per-instance storage
|
|
591
|
+
* the language does not allocate, and every instance would carry a copy of
|
|
592
|
+
* every method. A field that happens to hold a function (`onClick = () => {}`)
|
|
593
|
+
* *is* per-instance storage, and the symbol flags are what tell the two apart
|
|
594
|
+
* -- not the type of the value they hold.
|
|
595
|
+
*/
|
|
596
|
+
const classInstanceBodyOf = (type, location) => {
|
|
597
|
+
// A class declared in a declaration file is enumerated like any other. Its
|
|
598
|
+
// *fields* are data, and a subclass this program does define inherits them
|
|
599
|
+
// -- refusing the layout would leave that subclass with no carrier at all.
|
|
600
|
+
// What the program genuinely cannot do with such a class is construct one or
|
|
601
|
+
// call one of its methods, and both of those refuse where they happen: the
|
|
602
|
+
// construction has no body to run, and a method key resolves to no callable.
|
|
603
|
+
const shape = objectShapeOf(type, location, 'data-only');
|
|
604
|
+
// `objectShapeOf` walks `type.getProperties()` -- the checker's OWN
|
|
605
|
+
// member table -- which is blind to a field installed only through a
|
|
606
|
+
// `const _this = this` alias (`source-class-data.ts`'s
|
|
607
|
+
// `constructorInstalledMemberWritesOf` says why the checker never learns
|
|
608
|
+
// one). Without this, such a field got no struct member at all, and every
|
|
609
|
+
// read/write of it fell back to the fully dynamic `gea_readOwnField`/
|
|
610
|
+
// `gea_writeOwnField` expando protocol -- the closure PROOF for a call
|
|
611
|
+
// reached through it could still certify (that fallback fixed the flow-
|
|
612
|
+
// index side, in `source-class-data.ts`), but the emitted storage stayed
|
|
613
|
+
// boxed. `flow` is only absent for a handful of callers that never had a
|
|
614
|
+
// constructor-function/class-alias question to ask in the first place
|
|
615
|
+
// (see `buildMapper`'s `flow?: ValueFlowIndex`); `ts.isClassLike` matches
|
|
616
|
+
// this function's one call site, gated the same way at `declaredAnchorOf`.
|
|
617
|
+
if (flow && ts.isClassLike(location) && shape.kind === 'object') {
|
|
618
|
+
const installed = constructorInstalledMemberDeclarationsOf(flow, location);
|
|
619
|
+
if (installed.size > 0) {
|
|
620
|
+
const existing = new Set(shape.members.flatMap((member) => (member.key.kind === 'string' ? [member.key.value] : [])));
|
|
621
|
+
const extra = [];
|
|
622
|
+
for (const [key, declarations] of installed) {
|
|
623
|
+
if (existing.has(key))
|
|
624
|
+
continue;
|
|
625
|
+
const values = [...new Set(declarations.map((declaration) => typeOf(checker.getTypeAtLocation(declaration.right))))];
|
|
626
|
+
extra.push({
|
|
627
|
+
key: { kind: 'string', value: key },
|
|
628
|
+
type: values.length === 1 ? values[0] : table.intern({ kind: 'union', members: values }),
|
|
629
|
+
optional: false,
|
|
630
|
+
readonly: false,
|
|
631
|
+
accessor: null
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
if (extra.length > 0)
|
|
635
|
+
return table.intern({ ...shape, members: [...shape.members, ...extra] });
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return table.intern(shape);
|
|
639
|
+
};
|
|
640
|
+
const { declaredBodyOf } = createDeclaredBodyResolver({ table, typeOf, signatureOf, objectShapeOf, arrayHeritageShapeOf });
|
|
641
|
+
const declaredAnchorOf = (type) => {
|
|
642
|
+
// `type Img = { imageId: number; describe(): number }` -- a type alias to
|
|
643
|
+
// an anonymous object-literal type -- has its OWN symbol answer the
|
|
644
|
+
// anonymous `__type` symbol pointing at the `TypeLiteral` node, not the
|
|
645
|
+
// `TypeAliasDeclaration`, because that is genuinely what `type.getSymbol()`
|
|
646
|
+
// returns for an alias to an object literal type (verified against the
|
|
647
|
+
// checker directly). The `?? type.aliasSymbol` fallback below therefore
|
|
648
|
+
// never fires for this one specific shape, and `Img` never gets the
|
|
649
|
+
// `declared` nominal anchor an `interface Img {...}` gets for the
|
|
650
|
+
// identical body -- two spellings of the same kind of declaration ending
|
|
651
|
+
// up with two different identity treatments. Preferring `aliasSymbol`
|
|
652
|
+
// whenever the own symbol resolves to a `TypeLiteral` (rather than always
|
|
653
|
+
// preferring it, which would wrongly re-route `type X = SomeInterface`
|
|
654
|
+
// away from `SomeInterface`'s own, already-correct anchor) makes `Img`
|
|
655
|
+
// resolve through the alias exactly like `interface Img` does, without
|
|
656
|
+
// changing any other declared type's resolution.
|
|
657
|
+
//
|
|
658
|
+
// ⛔ A MAPPED type is deliberately NOT treated as anonymous here, and this
|
|
659
|
+
// was measured both ways. `Record<K, V>` is `type Record<K, T> = { [P in
|
|
660
|
+
// K]: T }`, so an instantiation's own symbol answers the anonymous
|
|
661
|
+
// `__type` of that `MappedTypeNode` rather than the `TypeAliasDeclaration`
|
|
662
|
+
// -- which means a type recursing THROUGH a mapped alias has no
|
|
663
|
+
// declaration to break the cycle on, and hono's `class Node { #children:
|
|
664
|
+
// Record<string, Node> }` (`router/reg-exp-router/node.ts`) refuses as `a
|
|
665
|
+
// self-referential type of this shape is not modelled`. Routing such a
|
|
666
|
+
// type through the ALIAS instead does fix that, and it costs
|
|
667
|
+
// `examples/weather` its whole certificate: with the alias as the anchor,
|
|
668
|
+
// a host-bound member reached through a mapped type demands
|
|
669
|
+
// `native-boundary:__type@1`, a protocol nothing registers. Net on hono
|
|
670
|
+
// once `router/reg-exp-router` stopped being reachable at all (see
|
|
671
|
+
// `reachability.ts`'s type-only import rule) it was WORSE by two
|
|
672
|
+
// obligations as well, so there is nothing left on the other side of the
|
|
673
|
+
// trade. A cycle through a mapped alias needs `selfReferentialShapeOf` to
|
|
674
|
+
// model that shape, not a second nominal anchor for it -- which is what it
|
|
675
|
+
// now does: its dictionary case closes `Record<string, Node>` on the
|
|
676
|
+
// anchor the retry already reserved, leaving this decision untouched.
|
|
677
|
+
const ownSymbol = type.getSymbol();
|
|
678
|
+
const ownDeclaration = ownSymbol ? identities.declarationOfSymbol(ownSymbol) : null;
|
|
679
|
+
const anonymous = ownDeclaration !== null && (ts.isTypeLiteralNode(ownDeclaration) || ts.isJSDocTypeLiteral(ownDeclaration));
|
|
680
|
+
const symbol = (anonymous ? type.aliasSymbol : null) ?? ownSymbol ?? type.aliasSymbol;
|
|
681
|
+
if (!symbol)
|
|
682
|
+
return null;
|
|
683
|
+
const declaration = identities.declarationOfSymbol(symbol);
|
|
684
|
+
if (!declaration)
|
|
685
|
+
return null;
|
|
686
|
+
// At the ROOT path, deliberately, and never at the copy this walk happens
|
|
687
|
+
// to be inside. `identities` is a per-copy VIEW (`identities.ts`'s
|
|
688
|
+
// `declarationIdOf: (declaration, override) => ... prefixFor(declaration,
|
|
689
|
+
// path)`), so asking it without an override mints `decl|f77|148` from a
|
|
690
|
+
// root walk and `decl|f77|148@0` from a copy's -- two nominal anchors for
|
|
691
|
+
// ONE declaration, and therefore two structural shapes, two `class-ref`
|
|
692
|
+
// carriers and two C++ struct names (`cppTypeOf` spells a class-ref as
|
|
693
|
+
// `cppClassName(representation.declaration)`).
|
|
694
|
+
//
|
|
695
|
+
// Which copy a walk was in is not part of a nominal type's identity. What
|
|
696
|
+
// IS part of it -- the instantiation's own type arguments -- is already in
|
|
697
|
+
// the anchor key below, folded through `layoutRelevantParameterIndices` so
|
|
698
|
+
// that two instantiations differing only in a phantom parameter share one
|
|
699
|
+
// physical layout. The copy path says nothing the arguments do not, and
|
|
700
|
+
// saying it twice is what split hono's `Context` and `Hono` into a
|
|
701
|
+
// root-cited half and a copy-cited half whose members only one of the two
|
|
702
|
+
// could ever find.
|
|
703
|
+
const id = identities.declarationIdOf(declaration, rootSpecialization);
|
|
704
|
+
if (ts.isClassLike(declaration)) {
|
|
705
|
+
// A class's constructor object and its instances are different values with
|
|
706
|
+
// different members; merging them loses `new` semantics entirely.
|
|
707
|
+
const isConstructorSide = type.getCallSignatures().length + type.getConstructSignatures().length > 0;
|
|
708
|
+
return { kind: isConstructorSide ? 'class-constructor' : 'class-instance', declaration: id, declarationNode: declaration };
|
|
709
|
+
}
|
|
710
|
+
// A JSDoc `@typedef {object} Node` is a declared name just as an
|
|
711
|
+
// `interface Node` is. The checker's own type for it has the synthetic
|
|
712
|
+
// JSDoc type-literal as its symbol and the typedef as `aliasSymbol`, so
|
|
713
|
+
// stopping here would re-enter the anonymous object through `Node[]` and
|
|
714
|
+
// lose the only finite native layout. The alias declaration is the stable
|
|
715
|
+
// checker identity that closes that cycle; this is declaration-kind
|
|
716
|
+
// parity, not a protocol for a particular JSDoc library.
|
|
717
|
+
if (ts.isInterfaceDeclaration(declaration) ||
|
|
718
|
+
ts.isTypeAliasDeclaration(declaration) ||
|
|
719
|
+
ts.isJSDocTypedefTag(declaration) ||
|
|
720
|
+
ts.isEnumDeclaration(declaration)) {
|
|
721
|
+
return { kind: 'declared', declaration: id, declarationNode: declaration };
|
|
722
|
+
}
|
|
723
|
+
// A pre-`class` JavaScript CONSTRUCTOR FUNCTION's instances are nominal,
|
|
724
|
+
// and named by the function: `function WebGLClipping( properties ) {
|
|
725
|
+
// this.uniform = uniform; ... }` gives TypeScript's own JS inference a
|
|
726
|
+
// construct signature whose return type it prints as `WebGLClipping`,
|
|
727
|
+
// symboled to the function declaration itself. Anchoring it here is what
|
|
728
|
+
// lets that type be SELF-REFERENTIAL, which every one of these is: the
|
|
729
|
+
// instance carries `this.setState = function ( material ) { ... }`, whose
|
|
730
|
+
// own receiver is the instance (`structural-receiver.ts`'s
|
|
731
|
+
// `jsConstructorReceiverOf`). Reached anonymously the walk collides with
|
|
732
|
+
// itself and `selfReferentialShapeOf` models no object shape with NAMED
|
|
733
|
+
// members (its dictionary case is index-only on purpose, because the
|
|
734
|
+
// retry cannot reach the location-aware member walk), so the whole
|
|
735
|
+
// instance -- every field, every method -- refuses as `a self-referential
|
|
736
|
+
// type of this shape is not modelled`; anchored, the member that refers
|
|
737
|
+
// back resolves to the anchor, exactly as a class instance's does.
|
|
738
|
+
//
|
|
739
|
+
// The INSTANCE side only. The function's own type has the same symbol, and
|
|
740
|
+
// it is not a declared name for a structure: it is the callable, whose
|
|
741
|
+
// carrier is `function-and-constructor`. The split is the one
|
|
742
|
+
// `ts.isClassLike` above makes for the identical reason -- a constructor
|
|
743
|
+
// object and its instances are different values with different members --
|
|
744
|
+
// told apart the same way, by whether the type carries a signature.
|
|
745
|
+
if (ts.isFunctionDeclaration(declaration) || ts.isFunctionExpression(declaration)) {
|
|
746
|
+
if (type.getCallSignatures().length + type.getConstructSignatures().length > 0)
|
|
747
|
+
return null;
|
|
748
|
+
return { kind: 'declared', declaration: id, declarationNode: declaration };
|
|
749
|
+
}
|
|
750
|
+
return null;
|
|
751
|
+
};
|
|
752
|
+
/**
|
|
753
|
+
* The body of a `declared`/`class-constructor`/`class-instance` anchor,
|
|
754
|
+
* once its type arguments are already in hand.
|
|
755
|
+
*
|
|
756
|
+
* Shared between the ordinary declared-anchor path (`translate`, below) and
|
|
757
|
+
* the self-referential retry (`typeOf`'s `selfReferential` branch): a class
|
|
758
|
+
* whose OWN type argument mentions the class again -- `Object3D<EventMap>`
|
|
759
|
+
* where `EventMap` describes an event carrying `Object3D<EventMap>` as its
|
|
760
|
+
* target, exactly what three.js's own `Object3DEventMap` does -- cannot
|
|
761
|
+
* compute this anchor's key up front, because the key needs the argument's
|
|
762
|
+
* structural id and deriving that id is what re-enters the class. That is a
|
|
763
|
+
* genuine cycle, not an undeclared shape: the retry mechanism already
|
|
764
|
+
* detects it and reserves an anchor before calling this, at which point
|
|
765
|
+
* `checker.getTypeArguments(...).map(typeOf)` re-entering the same class
|
|
766
|
+
* resolves through that anchor (`inProgress`) instead of recursing. Only
|
|
767
|
+
* the ordinary path's *key* depends on having the type arguments already
|
|
768
|
+
* -- the *body* this function builds does not care which path reserved its
|
|
769
|
+
* anchor.
|
|
770
|
+
*/
|
|
771
|
+
/**
|
|
772
|
+
* The one layout every interface of a family shares -- `interface-families.ts`
|
|
773
|
+
* says why the layout follows the object rather than the view. Each member
|
|
774
|
+
* is enumerated through `objectShapeOf` exactly as a lone interface's body
|
|
775
|
+
* is, then the members merge by key: a field is required only where every
|
|
776
|
+
* member of the family declares it required (an object of the family may
|
|
777
|
+
* lack it otherwise, and `memberOf`'s own rule applies -- the absence has
|
|
778
|
+
* to be in the TYPE, since that is all a field's carrier derives from), and
|
|
779
|
+
* its type is the union of what the members declare, flattened, so that
|
|
780
|
+
* `Identifier` beside `Identifier | undefined` is one three-state union and
|
|
781
|
+
* not a union nesting a union, which `union.ts` would carry as two arms of
|
|
782
|
+
* one carrier.
|
|
783
|
+
*
|
|
784
|
+
* Reserved as an ANCHOR before any member is walked: a member's own field
|
|
785
|
+
* types name family-mates (`Node.parent: Node`, `SourceFile.statements:
|
|
786
|
+
* NodeArray<Statement>`), each a declared anchor whose body is this same
|
|
787
|
+
* layout, so the walk re-enters here with the reservation made and reads
|
|
788
|
+
* the id back instead of recursing. Abandoned on an unwind for the reason
|
|
789
|
+
* `typeOfWalk` abandons its own: the retry re-reserves under the same key.
|
|
790
|
+
*/
|
|
791
|
+
const familyBodyOf = (declared) => {
|
|
792
|
+
if (declared.kind !== 'declared' || !ts.isInterfaceDeclaration(declared.declarationNode))
|
|
793
|
+
return null;
|
|
794
|
+
const family = families.familyOf(declared.declaration);
|
|
795
|
+
if (!family)
|
|
796
|
+
return null;
|
|
797
|
+
const { id, fresh } = table.anchor(`interface-family:${family.key}`);
|
|
798
|
+
if (!fresh)
|
|
799
|
+
return id;
|
|
800
|
+
let settled = false;
|
|
801
|
+
try {
|
|
802
|
+
table.complete(id, familyLayoutOf(family));
|
|
803
|
+
settled = true;
|
|
804
|
+
}
|
|
805
|
+
finally {
|
|
806
|
+
if (!settled)
|
|
807
|
+
table.abandon(id);
|
|
808
|
+
}
|
|
809
|
+
return id;
|
|
810
|
+
};
|
|
811
|
+
/**
|
|
812
|
+
* The one family member an intersection NARROWS, when that is all it does.
|
|
813
|
+
*
|
|
814
|
+
* tsc's type guards return `node is CallExpression & { expression:
|
|
815
|
+
* Identifier; arguments: [StringLiteralLike] }` and `node is
|
|
816
|
+
* BinaryExpression & { operatorToken: AssignmentOperatorToken }`
|
|
817
|
+
* (`isRequireCall`, `isAssignmentExpression`, ...): the checker narrows
|
|
818
|
+
* `node` to an intersection of a family member with an object literal
|
|
819
|
+
* type that restates some of the member's own fields more precisely. The
|
|
820
|
+
* value is the same object -- there is exactly one `Node` allocation, and
|
|
821
|
+
* the family exists so that every view of it is ONE layout -- but the
|
|
822
|
+
* intersection interned as its own shape below, whose `resolved` image is
|
|
823
|
+
* a fresh record with every field required, so every guarded read asked
|
|
824
|
+
* for `native-record-ref(family) -> record(...)`, a conversion that would
|
|
825
|
+
* copy an object the program still holds by identity (72 rows over
|
|
826
|
+
* `utilities.ts`, `checker.ts`, `utilitiesPublic.ts`).
|
|
827
|
+
*
|
|
828
|
+
* Admitted only where the intersection adds nothing to the object: every
|
|
829
|
+
* non-family member is an anonymous object literal type with no index,
|
|
830
|
+
* call or construct signature, and every property it names is a field the
|
|
831
|
+
* family already declares. A brand (`& { __x: unique symbol }`) or a new
|
|
832
|
+
* field is a different type and keeps the general path. Two family
|
|
833
|
+
* members of the same family are the same layout (`Expression &
|
|
834
|
+
* Declaration`); members of different families are not one object.
|
|
835
|
+
*/
|
|
836
|
+
const familyFieldNames = new Map();
|
|
837
|
+
const familyMemberNarrowedBy = (type) => {
|
|
838
|
+
const member = narrowedFamilyMemberOf(type);
|
|
839
|
+
return member === null ? null : typeOf(member);
|
|
840
|
+
};
|
|
841
|
+
const narrowedFamilyMemberOf = (type) => {
|
|
842
|
+
let family = null;
|
|
843
|
+
let member = null;
|
|
844
|
+
const narrowings = [];
|
|
845
|
+
for (const part of type.types) {
|
|
846
|
+
const anchor = declaredAnchorOf(part);
|
|
847
|
+
const own = anchor?.kind === 'declared' && ts.isInterfaceDeclaration(anchor.declarationNode) ? families.familyOf(anchor.declaration) : null;
|
|
848
|
+
if (own) {
|
|
849
|
+
if (family !== null && own !== family)
|
|
850
|
+
return null;
|
|
851
|
+
family = own;
|
|
852
|
+
member ??= part;
|
|
853
|
+
continue;
|
|
854
|
+
}
|
|
855
|
+
if ((part.flags & ts.TypeFlags.Object) === 0 || (part.objectFlags & ts.ObjectFlags.Anonymous) === 0)
|
|
856
|
+
return null;
|
|
857
|
+
if ((part.getSymbol()?.declarations ?? []).some((declaration) => !ts.isTypeLiteralNode(declaration)))
|
|
858
|
+
return null;
|
|
859
|
+
narrowings.push(part);
|
|
860
|
+
}
|
|
861
|
+
if (family === null || member === null)
|
|
862
|
+
return null;
|
|
863
|
+
let names = familyFieldNames.get(family.key);
|
|
864
|
+
if (!names) {
|
|
865
|
+
const collected = new Set();
|
|
866
|
+
for (const declaration of family.members) {
|
|
867
|
+
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
868
|
+
if (!symbol)
|
|
869
|
+
continue;
|
|
870
|
+
for (const property of checker.getPropertiesOfType(checker.getDeclaredTypeOfSymbol(symbol)))
|
|
871
|
+
collected.add(property.getName());
|
|
872
|
+
}
|
|
873
|
+
names = collected;
|
|
874
|
+
familyFieldNames.set(family.key, names);
|
|
875
|
+
}
|
|
876
|
+
for (const part of narrowings) {
|
|
877
|
+
if (checker.getIndexInfosOfType(part).length > 0 || part.getCallSignatures().length > 0 || part.getConstructSignatures().length > 0)
|
|
878
|
+
return null;
|
|
879
|
+
if (!checker.getPropertiesOfType(part).every((property) => names.has(property.getName())))
|
|
880
|
+
return null;
|
|
881
|
+
}
|
|
882
|
+
return member;
|
|
883
|
+
};
|
|
884
|
+
const familyLayoutOf = (family) => {
|
|
885
|
+
// An open anchor is a family-mate's (or another recursive type's) body
|
|
886
|
+
// still being built; it names one member and nothing to flatten.
|
|
887
|
+
const flatten = (id) => {
|
|
888
|
+
if (table.isOpen(id))
|
|
889
|
+
return [id];
|
|
890
|
+
const shape = table.get(id).shape;
|
|
891
|
+
return shape.kind === 'union' ? shape.members.flatMap(flatten) : [id];
|
|
892
|
+
};
|
|
893
|
+
const merged = new Map();
|
|
894
|
+
for (const member of family.members) {
|
|
895
|
+
const symbol = checker.getSymbolAtLocation(member.name);
|
|
896
|
+
if (!symbol)
|
|
897
|
+
continue;
|
|
898
|
+
const shape = objectShapeOf(checker.getDeclaredTypeOfSymbol(symbol), member, 'all');
|
|
899
|
+
if (shape.kind !== 'object')
|
|
900
|
+
continue;
|
|
901
|
+
for (const field of shape.members) {
|
|
902
|
+
if (field.accessor !== null)
|
|
903
|
+
continue;
|
|
904
|
+
const keyText = JSON.stringify(field.key);
|
|
905
|
+
const slot = merged.get(keyText) ?? { key: field.key, types: [], declaredBy: 0, requiredBy: 0, readonlyBy: 0 };
|
|
906
|
+
if (!merged.has(keyText))
|
|
907
|
+
merged.set(keyText, slot);
|
|
908
|
+
for (const part of flatten(field.type))
|
|
909
|
+
if (!slot.types.includes(part))
|
|
910
|
+
slot.types.push(part);
|
|
911
|
+
slot.declaredBy += 1;
|
|
912
|
+
if (!field.optional)
|
|
913
|
+
slot.requiredBy += 1;
|
|
914
|
+
if (field.readonly)
|
|
915
|
+
slot.readonlyBy += 1;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
const undefinedType = typeOf(checker.getUndefinedType());
|
|
919
|
+
const members = [...merged.values()].map((slot) => {
|
|
920
|
+
const optional = slot.requiredBy < family.members.length;
|
|
921
|
+
const types = optional && !slot.types.includes(undefinedType) ? [...slot.types, undefinedType] : slot.types;
|
|
922
|
+
const only = types.length === 1 ? types[0] : undefined;
|
|
923
|
+
return {
|
|
924
|
+
key: slot.key,
|
|
925
|
+
type: only ?? table.intern({ kind: 'union', members: types }),
|
|
926
|
+
optional,
|
|
927
|
+
readonly: slot.readonlyBy === slot.declaredBy,
|
|
928
|
+
accessor: null
|
|
929
|
+
};
|
|
930
|
+
});
|
|
931
|
+
return { kind: 'object', members, index: [], membersDropped: false };
|
|
932
|
+
};
|
|
933
|
+
const erasedTypeArgument = () => table.intern({ kind: 'primitive', primitive: 'any' });
|
|
934
|
+
/**
|
|
935
|
+
* The class copy this view is inside, or `null` when the view binds no copy
|
|
936
|
+
* of it.
|
|
937
|
+
*
|
|
938
|
+
* The LAST step naming the class wins, which is the precedence
|
|
939
|
+
* `createPathBinding` (structural-generics.ts) already gives the type
|
|
940
|
+
* parameters that step binds. A path can name one owner twice --
|
|
941
|
+
* `copyPathOf` appends the copy a site names onto the copy the site sits
|
|
942
|
+
* inside, so `new Box<R>(...)` written inside `Box<T>` is walked at
|
|
943
|
+
* `[Box#0, Box#1]` -- and taking the first there bound `T` from one copy
|
|
944
|
+
* while calling the other's constructor object a `Box<T>`.
|
|
945
|
+
*/
|
|
946
|
+
const copyOfClassInPath = (owner) => {
|
|
947
|
+
for (let index = bindingPath.length - 1; index >= 0; index -= 1) {
|
|
948
|
+
const step = bindingPath[index];
|
|
949
|
+
if (!step || step.owner !== owner)
|
|
950
|
+
continue;
|
|
951
|
+
const copy = specializations.specializationsOf(owner)[step.ordinal];
|
|
952
|
+
return copy ? { ordinal: copy.ordinal, arguments: copy.arguments } : null;
|
|
953
|
+
}
|
|
954
|
+
return null;
|
|
955
|
+
};
|
|
956
|
+
/**
|
|
957
|
+
* The copy of the class this view is inside, with its fillings folded
|
|
958
|
+
* through the class's layout-relevant indices exactly as the instance
|
|
959
|
+
* anchor folds a written instantiation -- the arguments the copy's
|
|
960
|
+
* constructor object is read AT. `null` when the view is inside no copy
|
|
961
|
+
* of the class. Recorded against the copy's ordinal for the deriver
|
|
962
|
+
* (`classCopies`) once the anchor is reserved, by `recordClassCopy`.
|
|
963
|
+
*/
|
|
964
|
+
const foldedCopyOf = (owner, layoutRelevant) => {
|
|
965
|
+
const copy = copyOfClassInPath(owner);
|
|
966
|
+
if (!copy)
|
|
967
|
+
return null;
|
|
968
|
+
return {
|
|
969
|
+
ordinal: copy.ordinal,
|
|
970
|
+
typeArguments: copy.arguments.map((argument, index) => layoutRelevant && !layoutRelevant.has(index) ? erasedTypeArgument() : typeOf(argument))
|
|
971
|
+
};
|
|
972
|
+
};
|
|
973
|
+
const recordClassCopy = (root, ordinal, typeArguments, constructor) => {
|
|
974
|
+
const known = classCopyKeys.get(root) ?? new Map();
|
|
975
|
+
if (!known.has(ordinal))
|
|
976
|
+
known.set(ordinal, { ordinal, typeArguments, constructor });
|
|
977
|
+
classCopyKeys.set(root, known);
|
|
978
|
+
};
|
|
979
|
+
const buildDeclaredShape = (type, declared, typeArguments) => {
|
|
980
|
+
const { kind, declaration } = declared;
|
|
981
|
+
if (kind === 'declared') {
|
|
982
|
+
return { kind, declaration, typeArguments, body: familyBodyOf(declared) ?? declaredBodyOf(type, declared.declarationNode) };
|
|
983
|
+
}
|
|
984
|
+
if (kind === 'class-constructor') {
|
|
985
|
+
// An overloaded constructor's IMPLEMENTATION declares the one frame the
|
|
986
|
+
// body runs with -- see `constructorImplementationSignatureOf`. Asked
|
|
987
|
+
// before the checker's own answer below, which is every overload and no
|
|
988
|
+
// single convention, exactly as `valueTypeAt` asks
|
|
989
|
+
// `implementationSignatureOf` before the symbol-level answer for a
|
|
990
|
+
// method's overload set.
|
|
991
|
+
const implementation = constructorImplementationSignatureOf(checker, declared.declarationNode);
|
|
992
|
+
const constructSignatures = implementation ? [implementation] : type.getConstructSignatures();
|
|
993
|
+
return {
|
|
994
|
+
kind,
|
|
995
|
+
declaration,
|
|
996
|
+
typeArguments,
|
|
997
|
+
// The constructor object's calling convention is what `new` invokes;
|
|
998
|
+
// a constructor value carrying no signature has no convention to
|
|
999
|
+
// select, and every construction fails closed.
|
|
1000
|
+
construct: constructSignatures.length > 0
|
|
1001
|
+
? table.intern({ kind: 'signature', call: [], construct: constructSignatures.map((one) => signatureOf(one)) })
|
|
1002
|
+
: null
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
// A class reached only as a field type has no constructor event to publish
|
|
1006
|
+
// its base's storage. Intern that checker-authenticated ancestry here so
|
|
1007
|
+
// the final carrier closure can resolve it without flattening inheritance.
|
|
1008
|
+
if (type.isClassOrInterface())
|
|
1009
|
+
for (const base of checker.getBaseTypes(type))
|
|
1010
|
+
typeOf(base);
|
|
1011
|
+
return { kind, declaration, typeArguments, body: classInstanceBodyOf(type, declared.declarationNode) };
|
|
1012
|
+
};
|
|
1013
|
+
// `keyof` reads its answer back out of the sealed table, so the table is the
|
|
1014
|
+
// only thing it needs from this closure -- which is why it lives on its own.
|
|
1015
|
+
const keyofOfShapeId = createKeyofResolver(table);
|
|
1016
|
+
function typeOf(type) {
|
|
1017
|
+
// Assignment-connected record views must agree before any layout is
|
|
1018
|
+
// interned, including the element reached through an array or tuple.
|
|
1019
|
+
const storage = storageTypeOf(type);
|
|
1020
|
+
if (storage !== type)
|
|
1021
|
+
return typeOf(storage);
|
|
1022
|
+
// A mapped type that changes only modifiers is its SOURCE, physically --
|
|
1023
|
+
// see `modifierOnlyMappedSourceOf`. Answered before the alias-recurrence
|
|
1024
|
+
// guard, because the point is that there is no recursion here at all:
|
|
1025
|
+
// `Mutable<T>` never was a second object for the walk to re-enter.
|
|
1026
|
+
const modifierOnly = modifierOnlyMappedSourceOf(type);
|
|
1027
|
+
if (modifierOnly)
|
|
1028
|
+
return typeOf(modifierOnly);
|
|
1029
|
+
return aliasRecurrence.within(type, () => typeOfWalk(type), foldToAncestor, (reason) => unresolved(reason));
|
|
1030
|
+
}
|
|
1031
|
+
/**
|
|
1032
|
+
* The id a recurring alias instantiation resolves to: its ancestor's, which
|
|
1033
|
+
* closes the cycle instead of unrolling it (`structural-alias-recurrence.ts`).
|
|
1034
|
+
* The cases are the three states the ancestor's own walk can be in; only the
|
|
1035
|
+
* last is new, and it reuses the retry a directly self-referential type takes.
|
|
1036
|
+
*/
|
|
1037
|
+
function foldToAncestor(ancestor) {
|
|
1038
|
+
const done = completed.get(ancestor);
|
|
1039
|
+
if (done)
|
|
1040
|
+
return done;
|
|
1041
|
+
const pending = inProgress.get(ancestor);
|
|
1042
|
+
if (pending)
|
|
1043
|
+
return pending;
|
|
1044
|
+
if (walking.has(ancestor))
|
|
1045
|
+
throw selfReferentialSignal(ancestor);
|
|
1046
|
+
return unresolved(`a recurring type alias ${ancestor.aliasSymbol?.name ?? '(unnamed)'} resolved to an ancestor whose own walk had already unwound`);
|
|
1047
|
+
}
|
|
1048
|
+
function typeOfWalk(type) {
|
|
1049
|
+
const done = completed.get(type);
|
|
1050
|
+
if (done)
|
|
1051
|
+
return done;
|
|
1052
|
+
const shared = sharedCompleted.get(type);
|
|
1053
|
+
if (shared !== undefined)
|
|
1054
|
+
return remember(type, shared);
|
|
1055
|
+
const pending = inProgress.get(type);
|
|
1056
|
+
if (pending)
|
|
1057
|
+
return pending;
|
|
1058
|
+
// Re-entered while its own walk is still running, with no anchor to resolve
|
|
1059
|
+
// to: unwind to that walk's own frame, which retries under an anchor.
|
|
1060
|
+
if (walking.has(type))
|
|
1061
|
+
throw selfReferentialSignal(type);
|
|
1062
|
+
if (selfReferential.has(type)) {
|
|
1063
|
+
// `fresh` is the table's own answer to who owns this reservation. A walk
|
|
1064
|
+
// that did not create it must not complete it and must not abandon it:
|
|
1065
|
+
// the anchor is either finished already or being built by an outer frame,
|
|
1066
|
+
// and in both cases the id alone is the whole answer here.
|
|
1067
|
+
// The ordinal is local to this mapper view, while anchors live in the
|
|
1068
|
+
// compilation-wide table. Include both view paths so unrelated recursive
|
|
1069
|
+
// types cannot reuse another view's `self-referential:0`, and an open
|
|
1070
|
+
// type translated under different bindings keeps its own layout.
|
|
1071
|
+
// -- unless no binding can reach the type at all, in which case every
|
|
1072
|
+
// view closes the cycle at one anchor (`createViewIndependentRecurrence`).
|
|
1073
|
+
const sharedKey = viewIndependentKeyOf(type);
|
|
1074
|
+
const recurrenceKey = sharedKey ?? `${identities.copyKeyOf(path)}|${identities.copyKeyOf(bindingPath)}|${selfReferentialKeyOf(selfReferentialKeys, type)}`;
|
|
1075
|
+
const { id: anchor, fresh } = table.anchor(recurrenceKey);
|
|
1076
|
+
if (!fresh)
|
|
1077
|
+
return remember(type, anchor);
|
|
1078
|
+
inProgress.set(type, anchor);
|
|
1079
|
+
walking.add(type);
|
|
1080
|
+
let settled = false;
|
|
1081
|
+
let completedShape = { kind: 'unresolved', reason: 'a self-referential type of this shape is not modelled' };
|
|
1082
|
+
try {
|
|
1083
|
+
// A declared name (class instance, class constructor, interface, type
|
|
1084
|
+
// alias) whose OWN type argument mentions it again -- see
|
|
1085
|
+
// `buildDeclaredShape`'s docstring for the concrete three.js case --
|
|
1086
|
+
// is not an anonymous cycle `selfReferentialShapeOf` needs to know a
|
|
1087
|
+
// fourth shape for: it is one of the three shapes the ordinary
|
|
1088
|
+
// declared-anchor path already builds, just reached through the one
|
|
1089
|
+
// path that cannot compute its own anchor key up front. The anchor
|
|
1090
|
+
// for `type` is already reserved above, so recomputing its type
|
|
1091
|
+
// arguments here resolves any mention of `type` itself through
|
|
1092
|
+
// `inProgress` instead of recursing.
|
|
1093
|
+
const declared = declaredAnchorOf(type);
|
|
1094
|
+
// An Array or a tuple is shaped as one HERE too, ahead of the
|
|
1095
|
+
// declared-name path -- see `indexedShapeOf`'s own comment for what
|
|
1096
|
+
// reaching this frame first used to cost. The anchor is already
|
|
1097
|
+
// reserved, so the element's own walk resolves a mention of `type`
|
|
1098
|
+
// through `inProgress` exactly as `buildDeclaredShape`'s does.
|
|
1099
|
+
const shape = bagShapeOfType(typeOf, bags, type) ??
|
|
1100
|
+
indexedShapeOf(type) ??
|
|
1101
|
+
(declared
|
|
1102
|
+
? buildDeclaredShape(type, declared, typeArgumentsOf(type).map(typeOf))
|
|
1103
|
+
: selfReferentialShapeOf(checker, type, typeOf, tupleElementsOf, indexesOf, (one) => selfReferentialCallableShapeOf(one, signatureOf)));
|
|
1104
|
+
completedShape = shape ?? completedShape;
|
|
1105
|
+
table.complete(anchor, completedShape);
|
|
1106
|
+
settled = true;
|
|
1107
|
+
}
|
|
1108
|
+
finally {
|
|
1109
|
+
walking.delete(type);
|
|
1110
|
+
inProgress.delete(type);
|
|
1111
|
+
if (!settled)
|
|
1112
|
+
table.abandon(anchor);
|
|
1113
|
+
}
|
|
1114
|
+
// A cycle another view already closed, entered here at a different
|
|
1115
|
+
// member, reaches through `sharedCompleted` a shape the table holds
|
|
1116
|
+
// under an earlier id. That shape cites nothing of this walk -- one
|
|
1117
|
+
// citing the fresh anchor could equal no earlier shape -- so the
|
|
1118
|
+
// earlier id is the answer and the anchor stays uncited: one cycle,
|
|
1119
|
+
// one set of ids, whichever member a view happened to enter at.
|
|
1120
|
+
const canonical = table.intern(completedShape);
|
|
1121
|
+
if (sharedKey !== null)
|
|
1122
|
+
sharedCompleted.set(type, canonical);
|
|
1123
|
+
return remember(type, canonical);
|
|
1124
|
+
}
|
|
1125
|
+
walking.add(type);
|
|
1126
|
+
// Only the OUTERMOST attempt journals: the frame the signal names is the
|
|
1127
|
+
// one whose retry redoes the work.
|
|
1128
|
+
const outermost = journal === null;
|
|
1129
|
+
const attempt = journal ?? [];
|
|
1130
|
+
journal = attempt;
|
|
1131
|
+
const mark = attempt.length;
|
|
1132
|
+
try {
|
|
1133
|
+
return translate(type);
|
|
1134
|
+
}
|
|
1135
|
+
catch (error) {
|
|
1136
|
+
if (!isSelfReferentialSignal(error) || error.selfReferentialType !== type)
|
|
1137
|
+
throw error;
|
|
1138
|
+
// Withdrawn before the retry: these name anchors that no longer exist.
|
|
1139
|
+
//
|
|
1140
|
+
// Deleting the `completed` memo is enough for anything this SAME walk
|
|
1141
|
+
// built by plain interning: a member id baked into its structural key,
|
|
1142
|
+
// so a shape that no longer resolves the same way mints a new id on its
|
|
1143
|
+
// own. It is not enough for a DECLARED type that finished its own build
|
|
1144
|
+
// successfully inside this failed attempt -- one that read a sibling
|
|
1145
|
+
// anchor's id while that sibling was still open (a legitimate
|
|
1146
|
+
// self-reference at the time, e.g. `MessageEvent.source` reading
|
|
1147
|
+
// `Window`'s in-progress anchor while `Window`'s own build was still
|
|
1148
|
+
// running). That declared type's OWN build never threw, so `translate`'s
|
|
1149
|
+
// finally never abandoned it; it is sitting there complete, citing an id
|
|
1150
|
+
// that is about to become an abandoned, unresolved stub. Its table KEY
|
|
1151
|
+
// has to be released too (`releaseKey`, a no-op for anything that is not
|
|
1152
|
+
// an anchor key), so the next `typeOf` call for it does not silently
|
|
1153
|
+
// reuse a shape built on a since-abandoned sibling and instead rebuilds
|
|
1154
|
+
// against whatever that sibling's retry actually resolves to.
|
|
1155
|
+
for (const remembered of attempt.slice(mark)) {
|
|
1156
|
+
const rememberedId = completed.get(remembered);
|
|
1157
|
+
completed.delete(remembered);
|
|
1158
|
+
if (rememberedId && table.citesAbandoned(rememberedId))
|
|
1159
|
+
table.releaseKey(rememberedId);
|
|
1160
|
+
}
|
|
1161
|
+
attempt.length = mark;
|
|
1162
|
+
selfReferential.add(type);
|
|
1163
|
+
}
|
|
1164
|
+
finally {
|
|
1165
|
+
walking.delete(type);
|
|
1166
|
+
if (outermost)
|
|
1167
|
+
journal = null;
|
|
1168
|
+
}
|
|
1169
|
+
// Retry inside the alias-recurrence frame that owns this walk. Calling
|
|
1170
|
+
// `typeOf` here would enter `aliasRecurrence.within` again before the
|
|
1171
|
+
// outer frame's `finally` has popped the same alias. The recurrence guard
|
|
1172
|
+
// would then find an ancestor whose failed walk has stopped walking but
|
|
1173
|
+
// whose retry has not reserved its anchor yet, and publish an unresolved
|
|
1174
|
+
// carrier instead of taking the self-referential branch above.
|
|
1175
|
+
//
|
|
1176
|
+
// The retry itself must bypass only that already-active outer guard. Every
|
|
1177
|
+
// nested type reached while rebuilding still enters through `typeOf`, so
|
|
1178
|
+
// equivalent back edges fold to the new `inProgress` anchor and a changed
|
|
1179
|
+
// alias instantiation continues to refuse fail-closed.
|
|
1180
|
+
return typeOfWalk(type);
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* A type reference's OWN type arguments.
|
|
1184
|
+
*
|
|
1185
|
+
* `checker.getTypeArguments` answers with the reference's full argument list,
|
|
1186
|
+
* and for a target that declares a `this` type -- which every class and every
|
|
1187
|
+
* interface reached through one does -- that list carries one MORE entry than
|
|
1188
|
+
* the declaration has parameters: a trailing slot holding the reference's
|
|
1189
|
+
* `this` type, threaded through as an argument that no source ever writes.
|
|
1190
|
+
*
|
|
1191
|
+
* `super.has(name)` inside `class CaseInsensitiveMap<K extends string>
|
|
1192
|
+
* extends Map<K, string>` is the case that exposed it. The `Map` reference
|
|
1193
|
+
* answers THREE arguments -- `K`, `string`, `this` -- and
|
|
1194
|
+
* `representation/collections.ts`'s arity guard then refused, correctly, a
|
|
1195
|
+
* `map` that "needs exactly 2". The guard was right and the count was wrong.
|
|
1196
|
+
*
|
|
1197
|
+
* The declaration's own parameter list is the authority on how many arguments
|
|
1198
|
+
* a reference to it has, so the answer is cut to it. Cutting rather than
|
|
1199
|
+
* asserting: a target with no `typeParameters` at all (a tuple reached
|
|
1200
|
+
* through this path, an anonymous reference) is left exactly as the checker
|
|
1201
|
+
* answered.
|
|
1202
|
+
*/
|
|
1203
|
+
const typeArgumentsOf = (type) => {
|
|
1204
|
+
const reference = type;
|
|
1205
|
+
const args = checker.getTypeArguments(reference) ?? [];
|
|
1206
|
+
const declared = reference.target?.typeParameters?.length;
|
|
1207
|
+
return declared !== undefined && args.length > declared ? args.slice(0, declared) : args;
|
|
1208
|
+
};
|
|
1209
|
+
/**
|
|
1210
|
+
* Whether an alias symbol IS one of the standard library's own type-level
|
|
1211
|
+
* operators, by name -- `null` in a program whose lib does not declare it.
|
|
1212
|
+
*
|
|
1213
|
+
* Resolved lazily and once per name, in the scope of the alias declaration
|
|
1214
|
+
* being asked about, exactly the way `host-protocols.ts`'s
|
|
1215
|
+
* `promiseDeclarationOf` resolves `Promise`: the question is "does this
|
|
1216
|
+
* alias mean the language's own operator", and `checker.resolveName` is the
|
|
1217
|
+
* public API that answers it without a use site. Resolving by name rather
|
|
1218
|
+
* than trusting the spelling is the whole point -- a program's own
|
|
1219
|
+
* `type Awaited<T> = ...` is a different operator with the same name.
|
|
1220
|
+
*/
|
|
1221
|
+
const globalAliases = new Map();
|
|
1222
|
+
const isGlobalAlias = (name, symbol, at) => {
|
|
1223
|
+
if (!globalAliases.has(name))
|
|
1224
|
+
globalAliases.set(name, checker.resolveName(name, at, ts.SymbolFlags.TypeAlias, false) ?? null);
|
|
1225
|
+
const resolved = globalAliases.get(name) ?? null;
|
|
1226
|
+
return resolved !== null && resolved === symbol;
|
|
1227
|
+
};
|
|
1228
|
+
/**
|
|
1229
|
+
* The one type-level operator argument, if this type is one of the two the
|
|
1230
|
+
* checker can still evaluate, and its own single argument.
|
|
1231
|
+
*/
|
|
1232
|
+
const operatorArgument = (type, name) => {
|
|
1233
|
+
const alias = type.aliasSymbol;
|
|
1234
|
+
const argument = type.aliasTypeArguments?.[0];
|
|
1235
|
+
if (!alias || !argument || type.aliasTypeArguments?.length !== 1)
|
|
1236
|
+
return null;
|
|
1237
|
+
const at = alias.declarations?.[0];
|
|
1238
|
+
return at && isGlobalAlias(name, alias, at) ? argument : null;
|
|
1239
|
+
};
|
|
1240
|
+
/**
|
|
1241
|
+
* This copy's filling for a type, closed as far as anything here can close it.
|
|
1242
|
+
*
|
|
1243
|
+
* Three ways, tried in order, and the third is what makes the operators
|
|
1244
|
+
* below compose. The image is the checker's own instantiation of a copy's
|
|
1245
|
+
* member type (`structural-instantiated-member.ts`); the path substitution
|
|
1246
|
+
* answers for a bare parameter a copy binds; and the recursion answers for a
|
|
1247
|
+
* parameter wrapped in one of the operators -- `NonNullable<TSchema>` closes
|
|
1248
|
+
* because `TSchema` does.
|
|
1249
|
+
*/
|
|
1250
|
+
const closedForm = (type) => {
|
|
1251
|
+
const image = instantiatedMembers.through(type);
|
|
1252
|
+
if (image)
|
|
1253
|
+
return image;
|
|
1254
|
+
const substituted = substituteTypeParameter(type);
|
|
1255
|
+
if (substituted !== type)
|
|
1256
|
+
return substituted;
|
|
1257
|
+
return reducedOperator(type);
|
|
1258
|
+
};
|
|
1259
|
+
/**
|
|
1260
|
+
* A DEFERRED `Awaited<T>` or `NonNullable<T>`, re-asked of the checker with
|
|
1261
|
+
* this copy's own filling in place of the hole.
|
|
1262
|
+
*
|
|
1263
|
+
* `await fn()` inside `withRespawn<T>(fn: () => Promise<T>)` types as
|
|
1264
|
+
* `Awaited<T>`. The checker cannot reduce `T extends PromiseLike<infer U>`
|
|
1265
|
+
* while `T` is open, so it keeps the conditional unreduced -- and a
|
|
1266
|
+
* conditional type names no structure, so everything downstream of it
|
|
1267
|
+
* refused: the await's own result, the `const` it initializes, the `return`
|
|
1268
|
+
* that publishes it. mongodb's driver is generic almost everywhere and this
|
|
1269
|
+
* was its single largest root, 616 of its mandatory obligations.
|
|
1270
|
+
*
|
|
1271
|
+
* Monomorphization has already closed the hole this walk is inside, so the
|
|
1272
|
+
* reduction is not deferred any more -- only the checker's ability to spell
|
|
1273
|
+
* it as a type is. `getAwaitedType` and `getNonNullableType` are the
|
|
1274
|
+
* checker's OWN implementations of the two operators, so handing one the
|
|
1275
|
+
* closed argument asks precisely the question that was deferred, rather than
|
|
1276
|
+
* re-deriving an answer beside the language's. Nothing is reduced when the
|
|
1277
|
+
* argument is still open, and an answer that comes back conditional again is
|
|
1278
|
+
* discarded: both leave the shape exactly as it was.
|
|
1279
|
+
*
|
|
1280
|
+
* These are the ONLY two this layer reduces, and the reason is the same for
|
|
1281
|
+
* both: the checker exposes the operator. `resolvedTrueType`/
|
|
1282
|
+
* `resolvedFalseType` on a deferred `ts.ConditionalType` are lazily populated
|
|
1283
|
+
* and read `undefined` from outside the checker, so a general "pick the
|
|
1284
|
+
* branch the closed check type satisfies" rule has no branches to pick --
|
|
1285
|
+
* measured, not assumed. `T[number]` is refused here for the mirror-image
|
|
1286
|
+
* reason: `getIndexedAccessType` is not on the public checker at all.
|
|
1287
|
+
*
|
|
1288
|
+
* `NonNullable` is NOT gated on `TypeFlags.Conditional`, and that is not an
|
|
1289
|
+
* oversight: since TypeScript 4.8 it is spelled `T & {}`, so a deferred one
|
|
1290
|
+
* arrives as an INTERSECTION. mongodb's `abstract_cursor.ts` is the case --
|
|
1291
|
+
* `transformDocument(document: NonNullable<TSchema>): Promise<NonNullable<TSchema>>`,
|
|
1292
|
+
* awaited at four sites in six copies -- and gating on the flag is what left
|
|
1293
|
+
* it unreduced while the bare `Awaited<TSchema>` beside it reduced fine.
|
|
1294
|
+
*/
|
|
1295
|
+
const reducedOperator = (type) => {
|
|
1296
|
+
const awaited = operatorArgument(type, 'Awaited');
|
|
1297
|
+
if (awaited) {
|
|
1298
|
+
const closed = closedForm(awaited);
|
|
1299
|
+
const reduced = closed ? checker.getAwaitedType(closed) : null;
|
|
1300
|
+
return reduced && (reduced.flags & ts.TypeFlags.Conditional) === 0 ? reduced : null;
|
|
1301
|
+
}
|
|
1302
|
+
const nullable = operatorArgument(type, 'NonNullable');
|
|
1303
|
+
if (nullable) {
|
|
1304
|
+
const closed = closedForm(nullable);
|
|
1305
|
+
const reduced = closed ? checker.getNonNullableType(closed) : null;
|
|
1306
|
+
return reduced && (reduced.flags & ts.TypeFlags.Conditional) === 0 ? reduced : null;
|
|
1307
|
+
}
|
|
1308
|
+
return null;
|
|
1309
|
+
};
|
|
1310
|
+
function translate(type) {
|
|
1311
|
+
// Asked BEFORE anything else, because it answers about the very type that
|
|
1312
|
+
// was handed in rather than about its parts: an open member type of a
|
|
1313
|
+
// monomorphized copy has an instantiated image, and every question below --
|
|
1314
|
+
// is it a conditional, a union, a record -- has a different answer for the
|
|
1315
|
+
// image than for the hole. See `structural-instantiated-member.ts`.
|
|
1316
|
+
const instantiated = instantiatedMembers.through(type);
|
|
1317
|
+
if (instantiated)
|
|
1318
|
+
return remember(type, typeOf(instantiated));
|
|
1319
|
+
// ⛔ BEFORE the conditional refusal below, not after it. A deferred
|
|
1320
|
+
// `Awaited<T>` IS a `ts.TypeFlags.Conditional` -- that is what the two
|
|
1321
|
+
// operators are spelled as -- so refusing every conditional first made
|
|
1322
|
+
// this line unreachable for the exact shape it exists to answer, and the
|
|
1323
|
+
// `getAwaitedType` reduction below it only ever ran for a `NonNullable`,
|
|
1324
|
+
// which since TypeScript 4.8 arrives as an INTERSECTION instead.
|
|
1325
|
+
//
|
|
1326
|
+
// `@hono/node-server`'s `readBodyWithFastPath<T>` is the case:
|
|
1327
|
+
// `Promise.resolve(fromBuffer(raw, request))` over a
|
|
1328
|
+
// `(buf, request) => T | Promise<T>` types as
|
|
1329
|
+
// `Promise<Awaited<T | Promise<T>>>`, and the copy that closed `T` got the
|
|
1330
|
+
// refusal rather than the reduction -- 54 of hono-hello's 225 roots, every
|
|
1331
|
+
// one of them a `promise(unresolved)` obligation off those two lines.
|
|
1332
|
+
//
|
|
1333
|
+
// Safe ahead of the refusal because this reads only `aliasSymbol` and
|
|
1334
|
+
// `aliasTypeArguments`, two plain fields on the type object, and calls the
|
|
1335
|
+
// checker only with an argument monomorphization has already CLOSED. What
|
|
1336
|
+
// the refusal is positioned to come before is declared-alias
|
|
1337
|
+
// NORMALIZATION further down, which asks a recursive conditional alias to
|
|
1338
|
+
// instantiate the very form it deferred -- hono's fluent environment
|
|
1339
|
+
// accumulator (`IfAnyThenEmptyObject<...>`, one alias deeper per route)
|
|
1340
|
+
// exhausted TypeScript's stack there. That alias is neither `Awaited` nor
|
|
1341
|
+
// `NonNullable`, so `operatorArgument` rejects it on the name and this
|
|
1342
|
+
// line returns before any checker call.
|
|
1343
|
+
const awaited = reducedOperator(type);
|
|
1344
|
+
if (awaited)
|
|
1345
|
+
return remember(type, typeOf(awaited));
|
|
1346
|
+
// A conditional that still exists after this copy's instantiated-member
|
|
1347
|
+
// image was asked for, and that neither operator above could reduce, is
|
|
1348
|
+
// unresolved.
|
|
1349
|
+
if (type.flags & ts.TypeFlags.Conditional)
|
|
1350
|
+
return remember(type, unresolved('an anonymous conditional type is still gated on a type parameter; monomorphization never filled it', 'erased-type-expression'));
|
|
1351
|
+
const primitive = primitiveFor(type);
|
|
1352
|
+
if (primitive)
|
|
1353
|
+
return remember(type, table.intern(primitive));
|
|
1354
|
+
const literal = literalFor(type);
|
|
1355
|
+
if (literal)
|
|
1356
|
+
return remember(type, table.intern(literal));
|
|
1357
|
+
const bag = bagShapeOfType(typeOf, bags, type);
|
|
1358
|
+
if (bag)
|
|
1359
|
+
return remember(type, table.intern(bag));
|
|
1360
|
+
// The global `Object` INTERFACE is a top type, and its layout is a
|
|
1361
|
+
// fiction.
|
|
1362
|
+
//
|
|
1363
|
+
// `Object` declares only what every value already has -- `toString`,
|
|
1364
|
+
// `valueOf`, `hasOwnProperty` -- and every non-nullish value in the
|
|
1365
|
+
// language is assignable to it, so it states nothing about what a
|
|
1366
|
+
// particular cell holds. `derived-expression-type.ts`'s
|
|
1367
|
+
// `annotationStatesNothing` has said exactly that for a long time, and
|
|
1368
|
+
// three's `@type {Object}` / `@return {Object}` tags reach this very
|
|
1369
|
+
// interface -- but only the write-discovery CENSUSES consulted it, so
|
|
1370
|
+
// this layer went on interning `Object` as a `declared` shape with a
|
|
1371
|
+
// real body, and `representation/derive.ts` went on turning that body
|
|
1372
|
+
// into a `native-record-ref` naming a struct of prototype methods. Two
|
|
1373
|
+
// authorities, one saying "states nothing" and the other emitting a
|
|
1374
|
+
// layout for it.
|
|
1375
|
+
//
|
|
1376
|
+
// Nothing can be stored in that struct. On the three.js app it was the target
|
|
1377
|
+
// of 11 of the 29 unmet conversion obligations whose pair simply has no
|
|
1378
|
+
// node -- `boolean`, an `HTMLElement` handle, an object literal and an
|
|
1379
|
+
// array of class instances all flowing into a cell typed `?Object` --
|
|
1380
|
+
// and no conversion could exist for any of them, because the target
|
|
1381
|
+
// layout was never real.
|
|
1382
|
+
//
|
|
1383
|
+
// `any` is the honest carrier, and it is the box: a genuinely dynamic
|
|
1384
|
+
// boundary, which is what `Object` is. The `ObjectConstructor` interface
|
|
1385
|
+
// -- the type of the global `Object` VALUE -- is excluded by
|
|
1386
|
+
// `isGlobalObjectInterface`'s own construct-signature test, so
|
|
1387
|
+
// `Object.keys` and friends keep their real callable shape.
|
|
1388
|
+
//
|
|
1389
|
+
// Anchored on the type's own declaration purely because `resolveName`
|
|
1390
|
+
// needs some node to resolve a GLOBAL from; which node it is cannot
|
|
1391
|
+
// change the answer, and a user interface declaring the same members
|
|
1392
|
+
// still fails the declaration-identity test.
|
|
1393
|
+
const objectAnchor = type.getSymbol()?.declarations?.[0];
|
|
1394
|
+
if (objectAnchor && isGlobalObjectInterface(checker, objectAnchor, type)) {
|
|
1395
|
+
return remember(type, table.intern({ kind: 'primitive', primitive: 'any' }));
|
|
1396
|
+
}
|
|
1397
|
+
// `IArguments` is the checker's name for the `arguments` object, and the
|
|
1398
|
+
// `arguments` object IS the phantom rest array this compiler mints for a
|
|
1399
|
+
// body that reads it (`producers/bindings.ts`'s `argumentsObjectValueAt`
|
|
1400
|
+
// binds the reference to that array). A function returning `arguments`
|
|
1401
|
+
// therefore returns that array, and typing the result by the interface's
|
|
1402
|
+
// declared layout (a record with `length` and `callee`) put a second
|
|
1403
|
+
// authority over one value: the body's return carrier said array-object,
|
|
1404
|
+
// the signature's result said native-record-ref, and the return
|
|
1405
|
+
// conversion between them cannot exist.
|
|
1406
|
+
if (objectAnchor && isStandardInterfaceType(checker, objectAnchor, 'IArguments', type)) {
|
|
1407
|
+
return remember(type, table.intern({ kind: 'array', element: table.intern({ kind: 'primitive', primitive: 'any' }), readonly: false, extension: [] }));
|
|
1408
|
+
}
|
|
1409
|
+
if (type.flags & ts.TypeFlags.UniqueESSymbol) {
|
|
1410
|
+
const symbol = type.getSymbol();
|
|
1411
|
+
const declaration = symbol ? identities.declarationOfSymbol(symbol) : null;
|
|
1412
|
+
return remember(type, declaration
|
|
1413
|
+
? table.intern({ kind: 'unique-symbol', declaration: identities.declarationIdOf(declaration) })
|
|
1414
|
+
: unresolved('unique symbol without a declaration anchor'));
|
|
1415
|
+
}
|
|
1416
|
+
// `TypeParameter` extends `Type` with no extra members, so the predicate
|
|
1417
|
+
// `this is TypeParameter` narrows the *false* branch to `never` and hides
|
|
1418
|
+
// every later check. The flag carries the same fact without that collapse.
|
|
1419
|
+
if (type.flags & ts.TypeFlags.TypeParameter) {
|
|
1420
|
+
const symbol = type.getSymbol();
|
|
1421
|
+
const declaration = symbol ? identities.declarationOfSymbol(symbol) : null;
|
|
1422
|
+
// The polymorphic `this` type is a type parameter whose symbol is the
|
|
1423
|
+
// *class*, not a `TypeParameterDeclaration`. It is not a parameter a
|
|
1424
|
+
// caller instantiates: every value it can hold is an instance of that
|
|
1425
|
+
// class, so the class instance shape is its exact answer rather than an
|
|
1426
|
+
// erasure to a constraint. Treating it as an uninstantiated parameter is
|
|
1427
|
+
// what made every unannotated `this.field` read reach representation with
|
|
1428
|
+
// no carrier at all.
|
|
1429
|
+
//
|
|
1430
|
+
// JavaScript declares the same thing without the `class` keyword.
|
|
1431
|
+
// `function Renderer(gl) { this.setMode = setMode }`, called with `new`,
|
|
1432
|
+
// is a constructor function: the binder marks its symbol
|
|
1433
|
+
// `SymbolFlags.Class` alongside `Function`, `getDeclaredTypeOfSymbol`
|
|
1434
|
+
// answers with the inferred instance type exactly as it does for a
|
|
1435
|
+
// class -- and its declaration is a `FunctionDeclaration`, so
|
|
1436
|
+
// `isClassLike` alone said no. three.js's WebGL internals are written
|
|
1437
|
+
// this way throughout, and every `this.` inside one reached
|
|
1438
|
+
// representation as an uninstantiated parameter: 151 of the three.js app's root
|
|
1439
|
+
// diagnostics. The flag is checked rather than the syntax because the
|
|
1440
|
+
// syntax is the only thing that differs.
|
|
1441
|
+
if (symbol && declaration && (ts.isClassLike(declaration) || (symbol.flags & ts.SymbolFlags.Class) !== 0)) {
|
|
1442
|
+
// Routed through the class's own declared type rather than interned
|
|
1443
|
+
// here, so the anchor that makes recursive member walks terminate is the
|
|
1444
|
+
// one shared with every other mention of the class. Interning a second
|
|
1445
|
+
// shape under the same nominal key would race that anchor's completion.
|
|
1446
|
+
return remember(type, typeOf(checker.getDeclaredTypeOfSymbol(symbol)));
|
|
1447
|
+
}
|
|
1448
|
+
if (!declaration)
|
|
1449
|
+
return remember(type, unresolved('type parameter without a declaration anchor'));
|
|
1450
|
+
// What the copy this body belongs to binds the parameter to. This is the
|
|
1451
|
+
// monomorphization: `identity<T>` compiled inside copy 0 has `T` as
|
|
1452
|
+
// `number` and inside copy 1 as `string`, and both are exact rather than
|
|
1453
|
+
// an approximation, because each copy really is a separate function in
|
|
1454
|
+
// the language.
|
|
1455
|
+
//
|
|
1456
|
+
// The program-wide census answers the remaining case: a parameter bound
|
|
1457
|
+
// once everywhere, whose owner the census did not copy -- an ambient
|
|
1458
|
+
// declaration has no body to duplicate, so there is no copy for the path
|
|
1459
|
+
// to name and the unique binding is the whole answer.
|
|
1460
|
+
//
|
|
1461
|
+
// The substitution happens here, at the one place a type parameter is
|
|
1462
|
+
// turned into a shape, rather than in the deriver. A shape is what every
|
|
1463
|
+
// later stage keys on -- carriers, conventions, layouts -- so a parameter
|
|
1464
|
+
// substituted downstream would leave the graph citing one shape and the
|
|
1465
|
+
// representation another, which is the two-authorities defect this
|
|
1466
|
+
// architecture exists to avoid.
|
|
1467
|
+
const bound = boundByPath(declaration) ?? censusBindingOf(declaration);
|
|
1468
|
+
if (bound && bound !== type)
|
|
1469
|
+
return remember(type, typeOf(bound));
|
|
1470
|
+
// A parameter nothing bound, but that the author gave a DEFAULT, is not
|
|
1471
|
+
// an uninstantiated parameter: the language substitutes the default for
|
|
1472
|
+
// every reference that omits the argument, so `class App extends
|
|
1473
|
+
// Component` really is `Component<GeaElement>` and the checker has
|
|
1474
|
+
// already typed it that way. Reading it here keeps the shape and the
|
|
1475
|
+
// checker in agreement -- without it the un-monomorphized copy of the
|
|
1476
|
+
// base carried a naked parameter into its own field layout, which the
|
|
1477
|
+
// deriver correctly refused ("field \"el\" carries unresolved(type
|
|
1478
|
+
// parameter ... reached representation without monomorphization)") and
|
|
1479
|
+
// which cost `ttf-bench` its whole emission.
|
|
1480
|
+
//
|
|
1481
|
+
// After the two bindings above on purpose: a copy that really did
|
|
1482
|
+
// substitute something must keep what it substituted, and the default is
|
|
1483
|
+
// only the answer when nothing did.
|
|
1484
|
+
//
|
|
1485
|
+
// Measured cost, stated rather than hidden: three programs that import
|
|
1486
|
+
// `three` gain ~3,400 boxed carriers, because `lib.dom`'s `E = Element`
|
|
1487
|
+
// and `lib.es5`'s `TArrayBuffer = ArrayBuffer` resolve to types no host
|
|
1488
|
+
// table claims a carrier for. None of the three compiles either way, and
|
|
1489
|
+
// before this they were the same values counted as missing primitives
|
|
1490
|
+
// rather than as boxes -- neither state is native, and the cure for both
|
|
1491
|
+
// is a carrier for `Element`, not a naked type parameter. Excluding
|
|
1492
|
+
// defaults of `any` was tried and measured: it moved the number by 32.
|
|
1493
|
+
//
|
|
1494
|
+
// The default is asked of THIS parameter, not re-typed from its
|
|
1495
|
+
// declaration node. A method's default can name the enclosing
|
|
1496
|
+
// interface's parameter -- `Promise<T>.then<TResult1 = T, ...>` -- and
|
|
1497
|
+
// reading the node `= T` in the declaration's own scope hands back
|
|
1498
|
+
// `Promise`'s open `T` even when the receiver was `Promise<Response>`
|
|
1499
|
+
// and the checker had already instantiated the default to `Response`.
|
|
1500
|
+
// That open `T` reached representation through a promise method read as
|
|
1501
|
+
// a VALUE with no call to bind it -- `@hono/node-server`'s `isPromise`
|
|
1502
|
+
// (`typeof (res as Promise<Response>).then === 'function'`) -- and the
|
|
1503
|
+
// function-value carrier `(...)->promise(unresolved)` had no emitter
|
|
1504
|
+
// recipe. `getDefaultFromTypeParameter` returns the instantiated default
|
|
1505
|
+
// where one exists and the declaration's own where it does not, so the
|
|
1506
|
+
// measured cases above are unchanged.
|
|
1507
|
+
if (ts.isTypeParameterDeclaration(declaration) && declaration.default) {
|
|
1508
|
+
const instantiated = checker.getDefaultFromTypeParameter(type) ?? checker.getTypeFromTypeNode(declaration.default);
|
|
1509
|
+
return remember(type, typeOf(instantiated));
|
|
1510
|
+
}
|
|
1511
|
+
// A parameter a CALLABLE owns, reached where no copy binds it, is that
|
|
1512
|
+
// callable used as a VALUE: a generic arrow handed to `memoizeOne`, a
|
|
1513
|
+
// generic function passed where the parameter's type is itself generic
|
|
1514
|
+
// (`emitNodeList(emit, ...)` over `EmitFunction = <T extends Node>(node:
|
|
1515
|
+
// T, ...) => void`), or the result the checker propagated such an
|
|
1516
|
+
// argument's parameters into. One closure exists at runtime for all of
|
|
1517
|
+
// those, so its type parameters have exactly one filling, the
|
|
1518
|
+
// constraint -- the same one `specialization.ts`'s `constraintBindingsOf`
|
|
1519
|
+
// mints its copy over, and the one the checker itself lands on when a
|
|
1520
|
+
// call through the value cannot infer the parameter. A class, interface
|
|
1521
|
+
// or alias parameter is not answered this way: those are copied per
|
|
1522
|
+
// instantiation and never reached unbound by a body this compiles.
|
|
1523
|
+
if (ts.isTypeParameterDeclaration(declaration) && ts.isFunctionLike(declaration.parent)) {
|
|
1524
|
+
const constraint = checker.getBaseConstraintOfType(type) ?? checker.getUnknownType();
|
|
1525
|
+
if (constraint !== type)
|
|
1526
|
+
return remember(type, typeOf(constraint));
|
|
1527
|
+
}
|
|
1528
|
+
// A parameter an interface of a FAMILY owns (`Token<TKind extends
|
|
1529
|
+
// SyntaxKind>`), reached while the family's one layout is built from
|
|
1530
|
+
// the open declaration: the layout's field is the union over every
|
|
1531
|
+
// instantiation the program will ever make, and the constraint is that
|
|
1532
|
+
// union's upper bound -- `kind: SyntaxKind`, which is what every
|
|
1533
|
+
// `Token<SyntaxKind.X>` view reads it back through anyway. The census
|
|
1534
|
+
// admits only a constrained parameter, so `unknown` is never the answer.
|
|
1535
|
+
if (ts.isTypeParameterDeclaration(declaration) && ts.isInterfaceDeclaration(declaration.parent)) {
|
|
1536
|
+
const ownerSymbol = checker.getSymbolAtLocation(declaration.parent.name);
|
|
1537
|
+
const owner = ownerSymbol ? identities.declarationOfSymbol(ownerSymbol) : null;
|
|
1538
|
+
if (owner && families.familyOf(identities.declarationIdOf(owner, rootSpecialization))) {
|
|
1539
|
+
const constraint = checker.getBaseConstraintOfType(type) ?? checker.getUnknownType();
|
|
1540
|
+
if (constraint !== type)
|
|
1541
|
+
return remember(type, typeOf(constraint));
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
return remember(type, table.intern({ kind: 'type-parameter', declaration: identities.declarationIdOf(declaration) }));
|
|
1545
|
+
}
|
|
1546
|
+
// `keyof T`. `isIndexType` is the public narrowing predicate for the flag,
|
|
1547
|
+
// matching the `isUnion`/`isTupleType` style already used below rather
|
|
1548
|
+
// than reading `.type` off the bare `Type` interface.
|
|
1549
|
+
if (type.isIndexType()) {
|
|
1550
|
+
const baseId = typeOf(type.type);
|
|
1551
|
+
let outcome;
|
|
1552
|
+
try {
|
|
1553
|
+
outcome = keyofOfShapeId(baseId);
|
|
1554
|
+
}
|
|
1555
|
+
catch {
|
|
1556
|
+
// The base is a nominal type whose own body is still being built --
|
|
1557
|
+
// `keyof` reaching back into a declaration it is itself a member of.
|
|
1558
|
+
// The sealed-table read a moment from completing cannot answer that
|
|
1559
|
+
// yet, and reading around it with a second pass would race the
|
|
1560
|
+
// anchor this same walk is in the middle of completing, so this
|
|
1561
|
+
// states the gap instead of throwing out of `typeOf` entirely.
|
|
1562
|
+
outcome = { kind: 'unmodelled', reason: `keyof of ${baseId}, whose declaration has not finished normalizing, is not modelled` };
|
|
1563
|
+
}
|
|
1564
|
+
return remember(type, outcome.kind === 'resolved' ? outcome.id : unresolved(outcome.reason));
|
|
1565
|
+
}
|
|
1566
|
+
// `T[K]`. The checker resolves every concrete indexed access before this
|
|
1567
|
+
// layer sees it, so one reaching here is the generic form -- and the
|
|
1568
|
+
// substitution this copy performs is what makes it concrete.
|
|
1569
|
+
// `structural-indexed-access.ts` states the rest.
|
|
1570
|
+
if ((type.flags & ts.TypeFlags.IndexedAccess) !== 0) {
|
|
1571
|
+
const access = type;
|
|
1572
|
+
const objectType = resolvedObjectType(access.objectType);
|
|
1573
|
+
const indexType = resolvedIndexType(access.indexType);
|
|
1574
|
+
// `any[K]` is `any` and `unknown[K]` is an error the checker already
|
|
1575
|
+
// reported -- neither is a member set to enumerate, and refusing it
|
|
1576
|
+
// reports a gap where the program declared one. hono's `Handler<E = any>`
|
|
1577
|
+
// binds `E` to `any` in one of `Context`'s copies, so `E['Bindings']`
|
|
1578
|
+
// there is the top type by the language's own rule, not a hole this
|
|
1579
|
+
// layer failed to fill. Answering with the object type itself adds no
|
|
1580
|
+
// dynamism: it IS the declared-any the program already carries.
|
|
1581
|
+
if ((objectType.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0)
|
|
1582
|
+
return remember(type, typeOf(objectType));
|
|
1583
|
+
const substituted = objectType === access.objectType && indexType === access.indexType ? null : indexedAccessMemberTypes(checker, objectType, indexType);
|
|
1584
|
+
// The bound of the type the PROGRAM WROTE is asked before the bound of
|
|
1585
|
+
// what this copy substituted into it, and the two disagree in hono's
|
|
1586
|
+
// favour of the first. `Context<E extends Env>`'s `env: E['Bindings']`
|
|
1587
|
+
// has `Env`'s own `Bindings?: Record<string, unknown>` as its bound
|
|
1588
|
+
// answer -- a dictionary that may be absent, which is what the
|
|
1589
|
+
// declaration says. The substituted intersection's bound is `{}`, which
|
|
1590
|
+
// declares no `Bindings` at all and so answers `undefined` -- and a
|
|
1591
|
+
// cell of `undefined` cannot hold that member's own `= {}` initializer.
|
|
1592
|
+
// Both are upper bounds; the tighter one is not always the truer one,
|
|
1593
|
+
// and the one the author stated outranks the one a copy produced.
|
|
1594
|
+
// A substitution that answers pure ABSENCE steps aside for the bound, and
|
|
1595
|
+
// hono's `env: E['Bindings'] = {}` is why. The copy that binds `E` to
|
|
1596
|
+
// `BlankEnv` (`{}`) really does have no `Bindings` member, so absence is
|
|
1597
|
+
// the language's own answer for a READ there -- but the field's STORAGE
|
|
1598
|
+
// was sized by the declaration, which TypeScript checked against `E`'s
|
|
1599
|
+
// constraint `Env`, where `Bindings?: Record<string, unknown>`. That is
|
|
1600
|
+
// how `= {}` on the same line is legal at all. A copy cannot shrink a
|
|
1601
|
+
// cell below what the declaration it copies admits, so the constraint's
|
|
1602
|
+
// answer outranks the copy's here, and absence survives only when no
|
|
1603
|
+
// bound has anything better to say.
|
|
1604
|
+
const statesOnlyAbsence = substituted !== null && substituted.every((member) => (member.flags & ts.TypeFlags.Undefined) !== 0);
|
|
1605
|
+
const members = (statesOnlyAbsence ? null : substituted) ??
|
|
1606
|
+
memberTypesThroughBound(access.objectType, indexType) ??
|
|
1607
|
+
memberTypesThroughBound(objectType, indexType) ??
|
|
1608
|
+
substituted;
|
|
1609
|
+
const only = members?.length === 1 ? members[0] : undefined;
|
|
1610
|
+
if (only)
|
|
1611
|
+
return remember(type, typeOf(only));
|
|
1612
|
+
if (members)
|
|
1613
|
+
return remember(type, table.intern({ kind: 'union', members: members.map(typeOf) }));
|
|
1614
|
+
return remember(type, unresolved('an indexed access whose object type is still a type parameter has no member set to resolve', 'erased-type-expression'));
|
|
1615
|
+
}
|
|
1616
|
+
if (type.isUnion()) {
|
|
1617
|
+
// A member whose bound type substitutes to `unknown`/`any` in this
|
|
1618
|
+
// copy absorbs the whole union -- `Component<RootElement = unknown>`'s
|
|
1619
|
+
// own `readonly el: RootElement | null` must collapse to bare
|
|
1620
|
+
// `unknown` for the exact same reason `unknown | null` written
|
|
1621
|
+
// directly, with no generic involved, is never a two-member union to
|
|
1622
|
+
// begin with: the checker's own union construction already performs
|
|
1623
|
+
// this simplification (`getUnionType` is not on the public
|
|
1624
|
+
// `ts.TypeChecker` surface, so it is replicated here rather than
|
|
1625
|
+
// called). Only the top type absorbs this way -- `never` is the
|
|
1626
|
+
// bottom type and a `T | never` union does not collapse the same
|
|
1627
|
+
// direction, so it is deliberately not handled here.
|
|
1628
|
+
const absorbing = type.types
|
|
1629
|
+
.map(substituteTypeParameter)
|
|
1630
|
+
.find((candidate) => candidate.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown));
|
|
1631
|
+
if (absorbing)
|
|
1632
|
+
return remember(type, typeOf(absorbing));
|
|
1633
|
+
// An arm naming a type the host says is ABSENT is not an arm this
|
|
1634
|
+
// program can ever take. `absentGlobals` already folds the VALUE
|
|
1635
|
+
// (`typeof HTMLImageElement !== 'undefined'` is `false` on a headless
|
|
1636
|
+
// ANGLE host, `absent-globals.ts`); this is the same fact asked of the
|
|
1637
|
+
// TYPE, so a union declared `HTMLImageElement | HTMLCanvasElement |
|
|
1638
|
+
// ImageData` collapses rather than demanding a carrier for a DOM class
|
|
1639
|
+
// that cannot exist here. Substituting per MEMBER rather than over the
|
|
1640
|
+
// whole union is what lets a mixed union keep the arms that are real.
|
|
1641
|
+
// `never[]` is what an EMPTY ARRAY LITERAL with no contextual type
|
|
1642
|
+
// checks as, and it is assignable to every array type -- so beside
|
|
1643
|
+
// another array-like arm it names no value the union does not already
|
|
1644
|
+
// hold, and no second carrier. `(path.match(/.../g) || [])` (hono's
|
|
1645
|
+
// pattern router) is the shape: `RegExpMatchArray | never[]`, which
|
|
1646
|
+
// carried as a tagged union of a match result and an EMPTY STRUCT, and
|
|
1647
|
+
// an `Array.prototype` method on that has no static receiver at all --
|
|
1648
|
+
// the read fell back to boxing the arm and asking a dynamic
|
|
1649
|
+
// `getProperty("map")` that nothing answers.
|
|
1650
|
+
//
|
|
1651
|
+
// Dropped only when the union keeps an arm that is itself indexable by
|
|
1652
|
+
// number, so a `never[]` standing alone (or beside non-array arms) is
|
|
1653
|
+
// untouched: this removes a REDUNDANT arm, it does not decide that an
|
|
1654
|
+
// empty array is some other type.
|
|
1655
|
+
const numericElementOf = (arm) => checker.getIndexTypeOfType(arm, ts.IndexKind.Number);
|
|
1656
|
+
// Contentless means EMPTY, not merely tuple-shaped: a tuple's numeric
|
|
1657
|
+
// index type is the union of its own elements, so a `[T, Params]` arm
|
|
1658
|
+
// answers a real element type and is a distinct shape this must not
|
|
1659
|
+
// touch (`Result<T>`'s two arms in hono's own router are a 1-tuple and a
|
|
1660
|
+
// 2-tuple). The two contentless spellings are `never[]` and the
|
|
1661
|
+
// zero-length tuple `[]`, which is what `x.match(re) || []` derives:
|
|
1662
|
+
// 13.2.4.2 gives an ArrayLiteral with no elements an Array of length 0,
|
|
1663
|
+
// and a value with no element cannot disagree with any element type, so
|
|
1664
|
+
// it is already a value of the arm beside it.
|
|
1665
|
+
const isEmptyArrayArm = (arm) => {
|
|
1666
|
+
// `isArrayType` answers only for `Array<T>` -- a tuple is an array-LIKE
|
|
1667
|
+
// whose target is its own synthetic type -- so the tuple is asked first.
|
|
1668
|
+
if (checker.isTupleType(arm)) {
|
|
1669
|
+
const shape = arm.target;
|
|
1670
|
+
return shape.fixedLength === 0 && shape.elementFlags.length === 0;
|
|
1671
|
+
}
|
|
1672
|
+
if (!checker.isArrayType(arm))
|
|
1673
|
+
return false;
|
|
1674
|
+
const element = checker.getTypeArguments(arm)[0];
|
|
1675
|
+
return element !== undefined && (element.flags & ts.TypeFlags.Never) !== 0;
|
|
1676
|
+
};
|
|
1677
|
+
const withoutEmptyArrays = type.types.filter((arm) => !isEmptyArrayArm(arm));
|
|
1678
|
+
const arms = withoutEmptyArrays.length === type.types.length ||
|
|
1679
|
+
withoutEmptyArrays.length === 0 ||
|
|
1680
|
+
!withoutEmptyArrays.some((arm) => numericElementOf(arm) !== undefined)
|
|
1681
|
+
? type.types
|
|
1682
|
+
: withoutEmptyArrays;
|
|
1683
|
+
const sole = arms.length === 1 ? arms[0] : undefined;
|
|
1684
|
+
if (sole)
|
|
1685
|
+
return remember(type, typeOf(absent.substituteAbsentType(sole)));
|
|
1686
|
+
const present = arms.map((member) => absent.substituteAbsentType(member));
|
|
1687
|
+
// A union of pure INDEX-SIGNATURE objects is one table whose values are
|
|
1688
|
+
// the union. `Record<string, string> | Record<string, string[]>` (hono's
|
|
1689
|
+
// `_getQueryParam`, `utils/url.ts:255`) describes one object either way:
|
|
1690
|
+
// the arms differ in what an entry HOLDS, never in how entries are
|
|
1691
|
+
// stored, so the physical answer is a single `gea::Dictionary` over the
|
|
1692
|
+
// union of the value types. A tagged union of two dictionaries is the
|
|
1693
|
+
// wrong shape for it, and provably so: `results[name] = []` writes an
|
|
1694
|
+
// array through a carrier whose tag says the entries are strings, which
|
|
1695
|
+
// no per-arm dispatch can make correct -- there is one object and its
|
|
1696
|
+
// tag was fixed when `{}` was allocated.
|
|
1697
|
+
const table_ = joinedIndexUnionOf(checker, table, typeOf, present);
|
|
1698
|
+
return remember(type, table_ ?? table.intern({ kind: 'union', members: present.map(typeOf) }));
|
|
1699
|
+
}
|
|
1700
|
+
if (type.isIntersection()) {
|
|
1701
|
+
// The alias's own anchor, recorded beside the members rather than instead
|
|
1702
|
+
// of them: a branded alias (`type Rgb565 = number & { readonly
|
|
1703
|
+
// __geaRgb565: unique symbol }`) erases to its substantive member, and
|
|
1704
|
+
// the name is the only thing left that says which host type it is. This
|
|
1705
|
+
// still interns and derives as an intersection -- `derive.ts` reads the
|
|
1706
|
+
// anchor only where an installed host states a carrier for it.
|
|
1707
|
+
const anchor = declaredAnchorOf(type);
|
|
1708
|
+
const declaration = anchor?.kind === 'declared' ? anchor.declaration : null;
|
|
1709
|
+
// A type guard's `Member & { field: Narrower }` is the family object
|
|
1710
|
+
// itself -- see `familyMemberNarrowedBy`. Asked before the members are
|
|
1711
|
+
// interned: the narrowing's own object literal would otherwise be laid
|
|
1712
|
+
// out as a record nothing converts the family reference into. Asked
|
|
1713
|
+
// for a NAMED intersection too (`type LiteralImportTypeNode =
|
|
1714
|
+
// ImportTypeNode & { readonly argument: LiteralTypeNode & { ... } }`):
|
|
1715
|
+
// the alias names a view, and the anchor a branded alias keeps below
|
|
1716
|
+
// never applies -- a family member is never a brand's substantive half.
|
|
1717
|
+
const narrowedMember = familyMemberNarrowedBy(type);
|
|
1718
|
+
if (narrowedMember !== null)
|
|
1719
|
+
return remember(type, narrowedMember);
|
|
1720
|
+
const members = type.types.map(typeOf);
|
|
1721
|
+
const joined = declaration === null ? joinedCallableOf(table, type, members) : null;
|
|
1722
|
+
if (joined)
|
|
1723
|
+
return remember(type, joined);
|
|
1724
|
+
const distributed = declaration === null ? distributedIntersectionOf(members) : null;
|
|
1725
|
+
if (distributed !== null)
|
|
1726
|
+
return remember(type, distributed);
|
|
1727
|
+
// The checker's own reconciliation of the members, interned beside them.
|
|
1728
|
+
// See the `resolved` field's doc comment (`model/structural-types.ts`):
|
|
1729
|
+
// reading `A & B`'s members off the intersection TYPE is asking the one
|
|
1730
|
+
// authority that owns the reduction, instead of merging carriers pairwise
|
|
1731
|
+
// a layer later.
|
|
1732
|
+
// A deferred member means the checker has not reconciled this
|
|
1733
|
+
// intersection. Asking for its synthesized properties forces the
|
|
1734
|
+
// checker to instantiate the deferred conditional recursively and also
|
|
1735
|
+
// gives each equivalent unfolding a fresh resolved shape. Keep the
|
|
1736
|
+
// explicit members as the fail-closed answer until monomorphization has
|
|
1737
|
+
// supplied an instantiated image. This lets recursive generic APIs fold
|
|
1738
|
+
// on their physical member layout instead of expanding type-only fluent
|
|
1739
|
+
// history indefinitely.
|
|
1740
|
+
const resolved = carriesDeferredForm(type) ? null : table.intern(objectShapeOf(type, null, 'interface'));
|
|
1741
|
+
return remember(type, table.intern({ kind: 'intersection', members, declaration, resolved }));
|
|
1742
|
+
}
|
|
1743
|
+
const indexed = indexedShapeOf(type);
|
|
1744
|
+
if (indexed)
|
|
1745
|
+
return remember(type, table.intern(indexed));
|
|
1746
|
+
const declared = declaredAnchorOf(type);
|
|
1747
|
+
if (declared) {
|
|
1748
|
+
// Anchor before walking members. Every cycle in the type graph passes
|
|
1749
|
+
// through a declared name, so this is the one place that makes recursion
|
|
1750
|
+
// terminate: a member that refers back resolves to an id that already
|
|
1751
|
+
// exists instead of re-entering translation.
|
|
1752
|
+
// The key uses the arguments' canonical structural ids, not the checker's
|
|
1753
|
+
// type objects: the checker hands back a fresh object for each mention of
|
|
1754
|
+
// one instantiation, so object identity would mint a new anchor per member
|
|
1755
|
+
// and the member walk below would never converge.
|
|
1756
|
+
//
|
|
1757
|
+
// A class or interface's own type parameter that never reaches a stored
|
|
1758
|
+
// field -- `layoutRelevantParameterIndices`'s own question -- is folded
|
|
1759
|
+
// to one canonical placeholder instead of its real argument. Two
|
|
1760
|
+
// instantiations that disagree ONLY on such a parameter (hono's
|
|
1761
|
+
// `Hono<E,S,BasePath,CurrentPath>` across every distinct route
|
|
1762
|
+
// registration, `S` never stored) are the SAME physical layout, and
|
|
1763
|
+
// keying them apart mints one specialization per call site -- the
|
|
1764
|
+
// shape of the `#addRoute` producer stack overflow this exists to cut
|
|
1765
|
+
// off. `Context<E,...>`'s `env: E['Bindings']` keeps `E` unerased: an
|
|
1766
|
+
// unproven position is never folded, only one the field walk actually
|
|
1767
|
+
// proved irrelevant.
|
|
1768
|
+
const genericOwner = ts.isClassLike(declared.declarationNode) || ts.isInterfaceDeclaration(declared.declarationNode) ? declared.declarationNode : null;
|
|
1769
|
+
const layoutRelevant = genericOwner ? layoutRelevantParameterIndices(checker, genericOwner) : null;
|
|
1770
|
+
//
|
|
1771
|
+
// A class's CONSTRUCTOR type (`typeof Box`) carries no type arguments,
|
|
1772
|
+
// so the constructor side of a generic class was one anchor for every
|
|
1773
|
+
// instantiation -- one construct signature, one instance carrier and
|
|
1774
|
+
// one thunk, whichever copy completed it first, and `new Box<string>`
|
|
1775
|
+
// beside `new Box<number>` converted its argument to the other copy's
|
|
1776
|
+
// parameter. Inside a copy of the class, when the class's copies can
|
|
1777
|
+
// differ in layout at all (`copiesMayDifferInLayout`), the copy's own
|
|
1778
|
+
// fillings are the arguments the constructor object is being read AT
|
|
1779
|
+
// (`this.constructor`, `new Box(...)` in a method, and every
|
|
1780
|
+
// `new Box<string>(...)` site, which the census types in the copy it
|
|
1781
|
+
// reaches), folded exactly as the instance side folds its written
|
|
1782
|
+
// arguments; the deriver's `physicalClassDeclarationOf` then keys the
|
|
1783
|
+
// two sides of one instantiation to one physical class. Outside any
|
|
1784
|
+
// copy the arguments stay empty, which is the root's own constructor
|
|
1785
|
+
// object.
|
|
1786
|
+
const copy = declared.kind === 'class-constructor' &&
|
|
1787
|
+
ts.isClassLike(declared.declarationNode) &&
|
|
1788
|
+
specializations.copiesMayDifferInLayout(declared.declarationNode)
|
|
1789
|
+
? foldedCopyOf(declared.declarationNode, layoutRelevant)
|
|
1790
|
+
: null;
|
|
1791
|
+
// A class whose copies must not split has ONE struct. Keying each
|
|
1792
|
+
// instantiation's anchor on its own written fillings gives that one
|
|
1793
|
+
// struct several shapes, and its field carriers then come from
|
|
1794
|
+
// whichever shape completed the anchor first -- for
|
|
1795
|
+
// `ReadableStream<any>` beside `ReadableStream<Uint8Array>` that was
|
|
1796
|
+
// the `any` one, so the struct stored `dynamic` and every read in the
|
|
1797
|
+
// concrete copy refused a narrowing no target installs. The census
|
|
1798
|
+
// names the most specific copy instead; keying every instantiation
|
|
1799
|
+
// there gives the collapse a single honest shape, and the wider
|
|
1800
|
+
// copies' reads widen out of it.
|
|
1801
|
+
const canonical = declared.kind === 'class-instance' && genericOwner && ts.isClassLike(genericOwner)
|
|
1802
|
+
? specializations.canonicalLayoutFillings(genericOwner)
|
|
1803
|
+
: null;
|
|
1804
|
+
const typeArguments = declared.kind === 'class-constructor'
|
|
1805
|
+
? (copy?.typeArguments ?? [])
|
|
1806
|
+
: typeArgumentsOf(type).map((argument, index) => {
|
|
1807
|
+
if (layoutRelevant && !layoutRelevant.has(index))
|
|
1808
|
+
return erasedTypeArgument();
|
|
1809
|
+
return typeOf(canonical?.[index] ?? argument);
|
|
1810
|
+
});
|
|
1811
|
+
// Reserved before the body is built, because building it walks members and
|
|
1812
|
+
// a member can reach this same anchor through a second checker type
|
|
1813
|
+
// object. `fresh` says which of the two this call is: the reserver
|
|
1814
|
+
// completes, everyone else just reads the id back.
|
|
1815
|
+
const { id: anchor, fresh } = table.anchor(`${declared.kind}:${declared.declaration}:${typeArguments.join(',')}`);
|
|
1816
|
+
if (copy)
|
|
1817
|
+
recordClassCopy(declared.declaration, copy.ordinal, copy.typeArguments, anchor);
|
|
1818
|
+
inProgress.set(type, anchor);
|
|
1819
|
+
remember(type, anchor);
|
|
1820
|
+
let settled = false;
|
|
1821
|
+
try {
|
|
1822
|
+
if (fresh)
|
|
1823
|
+
table.complete(anchor, buildDeclaredShape(type, declared, typeArguments));
|
|
1824
|
+
settled = true;
|
|
1825
|
+
}
|
|
1826
|
+
finally {
|
|
1827
|
+
inProgress.delete(type);
|
|
1828
|
+
// An unwound walk leaves nothing standing: not the memo, and -- when
|
|
1829
|
+
// this walk is the one that reserved it -- not the reservation either.
|
|
1830
|
+
if (!settled) {
|
|
1831
|
+
completed.delete(type);
|
|
1832
|
+
if (fresh)
|
|
1833
|
+
table.abandon(anchor);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
return anchor;
|
|
1837
|
+
}
|
|
1838
|
+
const callSignatures = type.getCallSignatures();
|
|
1839
|
+
const constructSignatures = type.getConstructSignatures();
|
|
1840
|
+
if (callSignatures.length > 0 || constructSignatures.length > 0) {
|
|
1841
|
+
// The type of an overloaded SOURCE function is every declared overload,
|
|
1842
|
+
// which is the checker's right answer for resolving a call and the
|
|
1843
|
+
// wrong one for the VALUE: the one function object that exists is the
|
|
1844
|
+
// implementation, and it declares exactly one signature.
|
|
1845
|
+
// `sharedAbiOf` (derive.ts) saw N conventions here and boxed every read
|
|
1846
|
+
// of `pad` -- and every unannotated `const padder = pad`, field and
|
|
1847
|
+
// parameter that shares the type object -- as
|
|
1848
|
+
// `dynamic(unjoinable-declared-overload-set)`, a typed function value
|
|
1849
|
+
// boxed. Inside a copy of a GENERIC implementation it was worse: the
|
|
1850
|
+
// overloads' own type parameters, which no copy ever binds, reached
|
|
1851
|
+
// representation as naked holes (TypeScript's `core.ts` `some`, `find`,
|
|
1852
|
+
// `every`, `filter`, `map`...). One answer at the one place the type
|
|
1853
|
+
// is interned, through this copy's own `signatureOf`, so the
|
|
1854
|
+
// implementation's `T` is substituted exactly as its body's would be.
|
|
1855
|
+
// `valueTypeAt` gives the DECLARATION the same answer.
|
|
1856
|
+
const implementation = sourceOverloadImplementationOf(callSignatures, constructSignatures);
|
|
1857
|
+
const generic = genericSourceFunctionOf(type, callSignatures, constructSignatures, implementation);
|
|
1858
|
+
return remember(type, table.intern({
|
|
1859
|
+
kind: 'signature',
|
|
1860
|
+
call: implementation ? [signatureOf(implementation)] : callSignatures.map((one) => signatureOf(one)),
|
|
1861
|
+
construct: constructSignatures.map((one) => signatureOf(one)),
|
|
1862
|
+
...(generic ? { generic } : {})
|
|
1863
|
+
}));
|
|
1864
|
+
}
|
|
1865
|
+
if (type.flags & ts.TypeFlags.Object) {
|
|
1866
|
+
const symbol = type.getSymbol();
|
|
1867
|
+
const location = symbol ? identities.declarationOfSymbol(symbol) : null;
|
|
1868
|
+
if (location) {
|
|
1869
|
+
// An object literal with at least one method whose OWN body reads
|
|
1870
|
+
// `this` can have that method's member signature read `this` back to
|
|
1871
|
+
// the literal itself (`{ imageId: 1, describe() { return
|
|
1872
|
+
// this.imageId } }`) -- `implicitReceiverOf` above now answers such a
|
|
1873
|
+
// method's receiver with `layoutTypeAt(parent)`, which is THIS type
|
|
1874
|
+
// (or the type it shares identity with via the contextual-type
|
|
1875
|
+
// preference). Interning the body plainly, as the pure-data branch
|
|
1876
|
+
// below does, would walk `describe`'s own signature *while this exact
|
|
1877
|
+
// walk is still running* and recurse forever -- there is no anchor
|
|
1878
|
+
// yet for the receiver to resolve to. So a self-referencing object
|
|
1879
|
+
// literal is anchored EAGERLY, before its members are walked, exactly
|
|
1880
|
+
// as `declaredAnchorOf`'s interface/class/type-alias branch above
|
|
1881
|
+
// already anchors before descending -- the one difference being the
|
|
1882
|
+
// anchor here is keyed by the literal's own declaration
|
|
1883
|
+
// (`ObjectLiteralExpression`) rather than by a named
|
|
1884
|
+
// interface/class/alias, since a bare literal has no such name.
|
|
1885
|
+
//
|
|
1886
|
+
// Scoped to a method whose body ACTUALLY reads `this` (not merely
|
|
1887
|
+
// "has a method", and not an accessor -- an accessor's member type in
|
|
1888
|
+
// the shape is the property type, not its own signature, so it never
|
|
1889
|
+
// re-enters through `objectShapeOf`'s member walk the way a method
|
|
1890
|
+
// does, exactly as `implicitReceiverOf` above reasons). Anchoring
|
|
1891
|
+
// every callable-bearing literal regardless of `this` usage was tried
|
|
1892
|
+
// first and cost 25/116 corpus programs their certification --
|
|
1893
|
+
// ordinary event-handler-shaped literals (`{ onClick() { ... } }`,
|
|
1894
|
+
// never reading `this`) do not need this identity change and paid for
|
|
1895
|
+
// it anyway, by widening which literals reach `implicitReceiverOf`'s
|
|
1896
|
+
// interface-signature branch downstream (removed in edit 4 -- see
|
|
1897
|
+
// that edit's discussion, "Cause 3" in `risks.md`). A pure-data
|
|
1898
|
+
// object literal, and a callable-bearing one whose methods never read
|
|
1899
|
+
// `this`, both keep interning straight into `objectShapeOf`,
|
|
1900
|
+
// completely unchanged, below.
|
|
1901
|
+
//
|
|
1902
|
+
// A `function` expression held by a PROPERTY (`{ m: function () {
|
|
1903
|
+
// return this } }`) is the same method spelled the ES5 way, and
|
|
1904
|
+
// `structural-receiver.ts`'s `jsConstructorReceiverOf` grants it the
|
|
1905
|
+
// same receiver behind the same body gate -- so it needs the same
|
|
1906
|
+
// anchor, or the receiver's self-reference has no nominal carrier.
|
|
1907
|
+
const hasSelfReferencingMethod = type.getProperties().some((property) => {
|
|
1908
|
+
const declaration = identities.declarationOfSymbol(property);
|
|
1909
|
+
if (declaration === null)
|
|
1910
|
+
return false;
|
|
1911
|
+
if ((property.flags & ts.SymbolFlags.Method) !== 0) {
|
|
1912
|
+
return ts.isMethodDeclaration(declaration) && declaration.body !== undefined && bodyReadsThis(declaration.body);
|
|
1913
|
+
}
|
|
1914
|
+
return (ts.isPropertyAssignment(declaration) &&
|
|
1915
|
+
ts.isFunctionExpression(declaration.initializer) &&
|
|
1916
|
+
declaration.initializer.body !== undefined &&
|
|
1917
|
+
bodyReadsThis(declaration.initializer.body));
|
|
1918
|
+
});
|
|
1919
|
+
if (!hasSelfReferencingMethod) {
|
|
1920
|
+
return remember(type, table.intern(objectShapeOf(type, location)));
|
|
1921
|
+
}
|
|
1922
|
+
const declarationKey = `object-literal:${identities.declarationIdOf(location)}`;
|
|
1923
|
+
const { id: anchor, fresh } = table.anchor(declarationKey);
|
|
1924
|
+
inProgress.set(type, anchor);
|
|
1925
|
+
remember(type, anchor);
|
|
1926
|
+
let settled = false;
|
|
1927
|
+
try {
|
|
1928
|
+
if (fresh) {
|
|
1929
|
+
const body = table.intern(objectShapeOf(type, location));
|
|
1930
|
+
table.complete(anchor, { kind: 'object-anchor', declaration: identities.declarationIdOf(location), body });
|
|
1931
|
+
}
|
|
1932
|
+
settled = true;
|
|
1933
|
+
}
|
|
1934
|
+
finally {
|
|
1935
|
+
inProgress.delete(type);
|
|
1936
|
+
if (!settled) {
|
|
1937
|
+
completed.delete(type);
|
|
1938
|
+
if (fresh)
|
|
1939
|
+
table.abandon(anchor);
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
return anchor;
|
|
1943
|
+
}
|
|
1944
|
+
// The object itself has no declaring symbol to anchor a `location` on --
|
|
1945
|
+
// `typeof globalThis` is the standing example, a synthetic checker type
|
|
1946
|
+
// whose OWN symbol has zero declarations (verified directly against the
|
|
1947
|
+
// checker: `type.getSymbol()` answers a real symbol named `globalThis`,
|
|
1948
|
+
// but `getDeclarations()` on it is empty). Its members are not
|
|
1949
|
+
// similarly synthetic: each is an ordinary ambient binding with a real
|
|
1950
|
+
// declaration of its own, and `memberOf` already prefers a member's own
|
|
1951
|
+
// declaration over the `location` it is passed (`declaration ?? location`
|
|
1952
|
+
// above), so any member here resolves correctly without ever consulting
|
|
1953
|
+
// `location`. Borrowing one member's declaration as the fallback only
|
|
1954
|
+
// matters for a member that itself has none, which is exactly the case
|
|
1955
|
+
// this branch could not previously tell apart from "every member is
|
|
1956
|
+
// fine, only the container lacks a name" -- and that harder case still
|
|
1957
|
+
// refuses below, unchanged.
|
|
1958
|
+
//
|
|
1959
|
+
// `data-only` mode is not just `declaredBodyOf`'s existing "we do not
|
|
1960
|
+
// implement ambient methods" reason (structural.ts's `declaredBodyOf`,
|
|
1961
|
+
// a few lines below): for a declarationless object it is also what
|
|
1962
|
+
// keeps this walk finite. `typeof globalThis`'s own `globalThis`
|
|
1963
|
+
// property mentions the type again (`declare var globalThis: typeof
|
|
1964
|
+
// globalThis`) and there is no anchor reserved here to break that
|
|
1965
|
+
// cycle on, unlike the `declared`/`class-instance` branch above. But
|
|
1966
|
+
// `globalThis` is checker-flagged `Module`, not `Property` -- like
|
|
1967
|
+
// every other ambient `var`/`function` binding at global scope
|
|
1968
|
+
// (`Array`, `console`, `eval`, ...), which are *not*
|
|
1969
|
+
// `SymbolFlags.Property` even though they read as ordinary data from
|
|
1970
|
+
// JS. `data-only` mode (`isDataMember`, below) filters exactly these
|
|
1971
|
+
// out, so the self-reference is never visited and never has a chance
|
|
1972
|
+
// to recurse.
|
|
1973
|
+
// A checker type flagged `Object`, with no declaring symbol AND no
|
|
1974
|
+
// structural facet at all -- no property, no index signature (call and
|
|
1975
|
+
// construct signatures were already excluded by the check above) -- is
|
|
1976
|
+
// not a shape this program wrote and this walk failed to normalize. It
|
|
1977
|
+
// is TypeScript's own internal answer to "some value, narrowed only to
|
|
1978
|
+
// exclude `null`/`undefined`": what `unknown` (or an unconstrained
|
|
1979
|
+
// generic, or the `{}` top type) becomes after a truthy check with no
|
|
1980
|
+
// `typeof`/`instanceof` narrowing to say anything more. `typeToString`
|
|
1981
|
+
// prints it `{}`, which reads exactly like an empty object literal, but
|
|
1982
|
+
// it is not one: a real `{}` literal anchors on its own
|
|
1983
|
+
// `ObjectLiteralExpression` and is caught by the `location` branch
|
|
1984
|
+
// above, as a genuinely, physically empty record. This one has no
|
|
1985
|
+
// declaration anywhere to anchor on because nothing in the program
|
|
1986
|
+
// wrote it -- the checker synthesized it purely to narrow the runtime
|
|
1987
|
+
// set of possible values without exposing a name for it. Laying it out
|
|
1988
|
+
// as an empty C++ record would claim a shape the runtime value might
|
|
1989
|
+
// not physically have at all (only `null`/`undefined` are excluded; it
|
|
1990
|
+
// could still be a `number`, a `string`, a function, anything), so the
|
|
1991
|
+
// honest carrier is the one plain `unknown` already gets: `dynamic`,
|
|
1992
|
+
// not a refusal.
|
|
1993
|
+
if (type.getProperties().length === 0 && checker.getIndexInfosOfType(type).length === 0) {
|
|
1994
|
+
return remember(type, table.intern({ kind: 'primitive', primitive: 'unknown' }));
|
|
1995
|
+
}
|
|
1996
|
+
// A member's own declaration is what `memberOf` asks at; the borrowed
|
|
1997
|
+
// sibling declaration below only ever answered for a member that has
|
|
1998
|
+
// NONE, and it is `null` when no member has one. That used to be a
|
|
1999
|
+
// refusal, on the reasoning that a location had to come from somewhere --
|
|
2000
|
+
// but the location was never the question. `getTypeOfSymbol` asks a
|
|
2001
|
+
// declarationless symbol for its type directly (`structural-parts.ts`'s
|
|
2002
|
+
// `typeOfSymbolAt`), which is available here and strictly more truthful
|
|
2003
|
+
// than borrowing an unrelated member's node. Every member with a
|
|
2004
|
+
// declaration still resolves at its own, so nothing that already worked
|
|
2005
|
+
// moves; what this unblocks is three.js, whose JSDoc-typed objects reach
|
|
2006
|
+
// here with no member declaration anywhere (three.js app violations 157 -> 21).
|
|
2007
|
+
const anchorLocation = type
|
|
2008
|
+
.getProperties()
|
|
2009
|
+
.map((property) => identities.declarationOfSymbol(property))
|
|
2010
|
+
.find((declaration) => declaration !== null) ?? null;
|
|
2011
|
+
return remember(type, table.intern(objectShapeOf(type, anchorLocation, 'data-only')));
|
|
2012
|
+
}
|
|
2013
|
+
// The `object` keyword type -- "any value that is not a primitive" -- is
|
|
2014
|
+
// its own flag (`NonPrimitive`), not `TypeFlags.Object`: it is a pure
|
|
2015
|
+
// keyword with no declaring symbol, so `type.getSymbol()` above is always
|
|
2016
|
+
// `undefined` for it and the branch that needs one never applies. It also
|
|
2017
|
+
// has no properties, no call/construct signature, and no index signature
|
|
2018
|
+
// of its own to enumerate (verified against the checker directly), so an
|
|
2019
|
+
// object shape with an empty member list and no index is not a guess --
|
|
2020
|
+
// it is exactly what `getProperties()`/`getIndexInfosOfType()` already
|
|
2021
|
+
// report for it. That is the same physical SHAPE `{}` gets -- no members,
|
|
2022
|
+
// no index -- but NOT the same physical CARRIER, and the difference
|
|
2023
|
+
// matters. `representation/derive.ts` turns an empty object shape into a
|
|
2024
|
+
// `record` with zero fields, and `record`'s conversion-from-dynamic has no
|
|
2025
|
+
// installed materializer anywhere in this codebase
|
|
2026
|
+
// (`conversion/build.ts`'s `emptyConversionRegistry.recordMaterializer: ()
|
|
2027
|
+
// => null`, never overridden by the C++ backend). That gap is universal
|
|
2028
|
+
// across every record shape today, so this choice costs nothing YET -- but
|
|
2029
|
+
// it is a latent trap, not a safe default. Record structs are nominal and
|
|
2030
|
+
// per-shape (`targets/cpp/records.ts`'s `cppRecordStructName(shapeId)`, one
|
|
2031
|
+
// distinct C++ struct per shape, no shared base), so the day anyone
|
|
2032
|
+
// installs a record materializer, a dynamic value narrowing to `record` of
|
|
2033
|
+
// this empty shape will either fabricate a fresh, identity-unrelated empty
|
|
2034
|
+
// struct -- breaking anything that depended on WHICH object it was, a
|
|
2035
|
+
// WeakMap key or an `===` -- or be reinterpreted as a struct type it never
|
|
2036
|
+
// was. Measured on the three.js app: 56 obligations of exactly this form, every one
|
|
2037
|
+
// a key argument to a bare `new WeakMap()` in three's renderer, where TS's
|
|
2038
|
+
// own `K extends object = object` default filled in for inference it had
|
|
2039
|
+
// nothing to work from. The cure is upstream -- infer the collection's type
|
|
2040
|
+
// arguments from its uses -- NOT a carrier general enough to swallow the
|
|
2041
|
+
// question, which would box the renderer's hot path and hide the gap.
|
|
2042
|
+
if (type.flags & ts.TypeFlags.NonPrimitive)
|
|
2043
|
+
return remember(type, table.intern({ kind: 'object', members: [], index: [], membersDropped: false }));
|
|
2044
|
+
// A SUBSTITUTION type is its base type, with a narrower constraint the
|
|
2045
|
+
// checker remembers for inference -- nothing more.
|
|
2046
|
+
//
|
|
2047
|
+
// TypeScript mints one inside the TRUE branch of a conditional, where it
|
|
2048
|
+
// knows `T extends X` held: the type of a value there is still `T`, but
|
|
2049
|
+
// every inference made from it may assume `X`. So the two are mutually
|
|
2050
|
+
// assignable and `getReducedType` erases the wrapper; the base is the
|
|
2051
|
+
// answer, and taking the CONSTRAINT instead would name an upper bound the
|
|
2052
|
+
// value need not have.
|
|
2053
|
+
//
|
|
2054
|
+
// Not any of the flags the tests above match, so without this a
|
|
2055
|
+
// substitution falls through to the bare-flags refusal below. Measured
|
|
2056
|
+
// ZERO on the mongodb probe and kept for the reason the reduction itself
|
|
2057
|
+
// states: a form the language erases must not be a refusal, and the one
|
|
2058
|
+
// line costs nothing.
|
|
2059
|
+
if (type.flags & ts.TypeFlags.Substitution)
|
|
2060
|
+
return remember(type, typeOf(type.baseType));
|
|
2061
|
+
// An ANONYMOUS deferred conditional -- `X extends Y ? A : B` written
|
|
2062
|
+
// inline, with no alias to name it.
|
|
2063
|
+
//
|
|
2064
|
+
// Named separately from the bare-flags refusal below because that refusal
|
|
2065
|
+
// reads as a gap in this switch and this is not one: it is the same wall
|
|
2066
|
+
// `structural-declared-body.ts` states for an ALIASED conditional, reached
|
|
2067
|
+
// by a type that has no alias symbol and so never becomes a `declared`
|
|
2068
|
+
// shape at all. There is nothing to reduce it with -- `resolvedTrueType`/
|
|
2069
|
+
// `resolvedFalseType` on a deferred conditional read `undefined` from
|
|
2070
|
+
// outside the checker, and `reducedOperator` above can only answer for the
|
|
2071
|
+
// two operators the checker exposes -- so the only routes out are the
|
|
2072
|
+
// instantiated image `translate` already consults first, or closing the
|
|
2073
|
+
// check type upstream. "checker type with flags 16777216" sent a reader
|
|
2074
|
+
// looking for a missing type FORM; the form is modelled, the reduction is
|
|
2075
|
+
// not.
|
|
2076
|
+
return remember(type, unresolved(`checker type with flags ${type.flags} is not modelled`));
|
|
2077
|
+
}
|
|
2078
|
+
const remember = (type, id) => {
|
|
2079
|
+
completed.set(type, id);
|
|
2080
|
+
journal?.push(type); // so an unwind can take it back -- see `typeOf`'s retry
|
|
2081
|
+
return id;
|
|
2082
|
+
};
|
|
2083
|
+
const layoutTypeAt = createLayoutTypeResolver(checker, parameters, absent);
|
|
2084
|
+
/**
|
|
2085
|
+
* The type at a node, with an absent host type collapsed -- and with that
|
|
2086
|
+
* collapse followed through a member read.
|
|
2087
|
+
*
|
|
2088
|
+
* `substituteAbsentType` answers about the type a node was declared with, so
|
|
2089
|
+
* it collapses the RECEIVER on its own: `canvas`, declared
|
|
2090
|
+
* `HTMLCanvasElement` by three.js's JSDoc, is `never` on a host with no DOM.
|
|
2091
|
+
* The member read is a different node, and the checker still answers it with
|
|
2092
|
+
* `HTMLCanvasElement.addEventListener`'s whole overload set -- so one
|
|
2093
|
+
* expression ends up carrying two incompatible facts: a receiver no value can
|
|
2094
|
+
* inhabit, and a member typed by the class that receiver cannot be. The
|
|
2095
|
+
* member is the half that has to give. Reading a property of a value that
|
|
2096
|
+
* cannot exist produces a value that cannot exist.
|
|
2097
|
+
*
|
|
2098
|
+
* This is not an optimization. `three-angle-metal`'s seven violations and
|
|
2099
|
+
* seven unresolved carriers were all this one shape -- `canvas.getContext`
|
|
2100
|
+
* (five overloads) and `canvas.addEventListener`/`removeEventListener` (two
|
|
2101
|
+
* each) -- refused as "no primitive joining N overload signatures into one
|
|
2102
|
+
* calling convention". That refusal was correct about the overloads and
|
|
2103
|
+
* wrong about the question: the overload set is a phantom. On this target
|
|
2104
|
+
* `canvas` is a native handle, and joining arms of a class that cannot exist
|
|
2105
|
+
* was never something the program asked for.
|
|
2106
|
+
*
|
|
2107
|
+
* It recurses through the receiver rather than reading `layoutTypeAt` there
|
|
2108
|
+
* directly, so a chain collapses from wherever the absent type actually is:
|
|
2109
|
+
* in `a.b.c` it is `a` that cannot exist, and `a.b` has to be `never` before
|
|
2110
|
+
* `a.b.c` can be.
|
|
2111
|
+
*/
|
|
2112
|
+
const absentSubstitutedTypeAt = (node) => {
|
|
2113
|
+
const own = absent.substituteAbsentType(layoutTypeAt(node));
|
|
2114
|
+
if ((own.flags & ts.TypeFlags.Never) !== 0)
|
|
2115
|
+
return own;
|
|
2116
|
+
if (!ts.isPropertyAccessExpression(node) && !ts.isElementAccessExpression(node))
|
|
2117
|
+
return own;
|
|
2118
|
+
const receiver = absentSubstitutedTypeAt(node.expression);
|
|
2119
|
+
return (receiver.flags & ts.TypeFlags.Never) !== 0 ? receiver : own;
|
|
2120
|
+
};
|
|
2121
|
+
/**
|
|
2122
|
+
* A value declared `any`/`unknown` and narrowed only to the bare `object`
|
|
2123
|
+
* type is still a dynamic boundary. `typeof value === 'object'` proves that
|
|
2124
|
+
* property operations are permitted; it does not discover a field layout
|
|
2125
|
+
* or turn the value into a closed empty record. Keeping the declaration's
|
|
2126
|
+
* carrier here lets `key in value` and later dynamic reads consult the real
|
|
2127
|
+
* runtime object instead of asking a zero-field C++ struct to answer them.
|
|
2128
|
+
* A stronger narrowing (an interface, class, array, or other named shape)
|
|
2129
|
+
* has ordinary Object flags rather than NonPrimitive and remains untouched.
|
|
2130
|
+
*/
|
|
2131
|
+
const dynamicObjectBoundaryAt = (node) => {
|
|
2132
|
+
if (!ts.isIdentifier(node))
|
|
2133
|
+
return null;
|
|
2134
|
+
if ((absentSubstitutedTypeAt(node).flags & ts.TypeFlags.NonPrimitive) === 0)
|
|
2135
|
+
return null;
|
|
2136
|
+
const symbol = checker.getSymbolAtLocation(node);
|
|
2137
|
+
const declaration = symbol?.valueDeclaration ?? symbol?.declarations?.[0];
|
|
2138
|
+
if (!symbol || !declaration)
|
|
2139
|
+
return null;
|
|
2140
|
+
const declared = checker.getTypeOfSymbolAtLocation(symbol, declaration);
|
|
2141
|
+
return (declared.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0 ? declared : null;
|
|
2142
|
+
};
|
|
2143
|
+
/**
|
|
2144
|
+
* A read the checker's control-flow analysis cannot place. An unannotated,
|
|
2145
|
+
* uninitialized `var t;` is auto-typed: the checker evolves the cell through
|
|
2146
|
+
* the assignments it can SEE, and a read that follows only the declaration
|
|
2147
|
+
* answers `undefined` -- the initial state -- even when a nested function
|
|
2148
|
+
* (`{ m: function () { t = this } }`, called before the read) has written the
|
|
2149
|
+
* cell in between, because the analysis never follows a call. The census read
|
|
2150
|
+
* every write through the flow index and bound the cell to what they store;
|
|
2151
|
+
* a bare-`undefined` read of such a cell tested nothing, so it is not a
|
|
2152
|
+
* narrowing the cell has to be converted for. The cell's own type is the
|
|
2153
|
+
* answer. A read the checker places from a write in the reader's OWN scope,
|
|
2154
|
+
* and a cell every write of which sits beside its reads, keep the checker's
|
|
2155
|
+
* view: there the `undefined` is the program's, not the analysis's.
|
|
2156
|
+
*/
|
|
2157
|
+
const unplacedHoistedReadAt = (node) => {
|
|
2158
|
+
if (!flow || !ts.isIdentifier(node))
|
|
2159
|
+
return null;
|
|
2160
|
+
const own = absentSubstitutedTypeAt(node);
|
|
2161
|
+
if ((own.flags & ts.TypeFlags.Undefined) === 0 || own.isUnion())
|
|
2162
|
+
return null;
|
|
2163
|
+
const declaration = checker.getSymbolAtLocation(node)?.valueDeclaration;
|
|
2164
|
+
if (!declaration || !ts.isVariableDeclaration(declaration) || declaration.type || declaration.initializer)
|
|
2165
|
+
return null;
|
|
2166
|
+
if (node === declaration.name || !ts.isIdentifier(declaration.name))
|
|
2167
|
+
return null;
|
|
2168
|
+
const reader = ts.findAncestor(node, ts.isFunctionLike) ?? null;
|
|
2169
|
+
const writes = flow.writesToDeclaration(declaration).filter((write) => write.slot === 'whole');
|
|
2170
|
+
if (!writes.length || !writes.some((write) => (ts.findAncestor(write.site, ts.isFunctionLike) ?? null) !== reader))
|
|
2171
|
+
return null;
|
|
2172
|
+
const cell = parameters.typeAt(declaration);
|
|
2173
|
+
return cell && (cell.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Undefined)) === 0 ? cell : null;
|
|
2174
|
+
};
|
|
2175
|
+
/**
|
|
2176
|
+
* Whether this node is the one its parent site NAMES, rather than merely a
|
|
2177
|
+
* child of it.
|
|
2178
|
+
*
|
|
2179
|
+
* A call is recorded as one instantiation site, and everything under it --
|
|
2180
|
+
* the callee, but also every ARGUMENT -- has that call as its parent. Only
|
|
2181
|
+
* the callee is typed by the copy the call reaches; an argument is typed by
|
|
2182
|
+
* the scope it is written in, which is the ENCLOSING copy, and reading it
|
|
2183
|
+
* through the callee's copy loses whatever that enclosing copy binds. In
|
|
2184
|
+
* `outer<T>(op: T) { inner(op) }` compiled as `outer<Heavy>`, `op` read
|
|
2185
|
+
* through `inner`'s copy is a naked `T` again -- the exact hole
|
|
2186
|
+
* monomorphization removes, put back one node to the right of where it was
|
|
2187
|
+
* removed.
|
|
2188
|
+
*
|
|
2189
|
+
* A type reference (`Foo<Bar>`) is recorded on the reference node itself and
|
|
2190
|
+
* names no separate callee, so it answers `true` and behaves as before.
|
|
2191
|
+
*/
|
|
2192
|
+
const namesItsSite = (node) => {
|
|
2193
|
+
const site = node.parent;
|
|
2194
|
+
if (ts.isCallOrNewExpression(site))
|
|
2195
|
+
return site.expression === node;
|
|
2196
|
+
if (ts.isTaggedTemplateExpression(site))
|
|
2197
|
+
return site.tag === node;
|
|
2198
|
+
if (ts.isJsxOpeningLikeElement(site))
|
|
2199
|
+
return site.tagName === node;
|
|
2200
|
+
return true;
|
|
2201
|
+
};
|
|
2202
|
+
/**
|
|
2203
|
+
* The type of the *value* a declaration introduces.
|
|
2204
|
+
*
|
|
2205
|
+
* `getTypeAtLocation` on a class declaration answers with the instance type,
|
|
2206
|
+
* because that is what the name means in a type position. The value the
|
|
2207
|
+
* declaration binds is the constructor object, which is the symbol's type --
|
|
2208
|
+
* a different type with different members, and asking the wrong one is how a
|
|
2209
|
+
* constructor ends up carried as one of its own instances.
|
|
2210
|
+
*/
|
|
2211
|
+
const localUnionAt = createLocalUnionResolver(checker, table, parameters, flow, (node) => mapper.typeAt(node), (node) => (ts.isExpression(node) ? objectDescriptorReturnTypeAt(unwrapErasedExpression(node)) : null));
|
|
2212
|
+
const callResultAt = createStructuralCallResultResolver(checker, table, (node) => mapper.typeAt(node));
|
|
2213
|
+
const constructResultAt = createStructuralConstructResultResolver(table, (node) => mapper.typeAt(node));
|
|
2214
|
+
const impliedPatternArrayLiteralType = (node) => {
|
|
2215
|
+
// A tuple, or the empty literal the checker types `never[]` against a
|
|
2216
|
+
// rest pattern's `any[]` silhouette (`f([])` for `function f([...r])`).
|
|
2217
|
+
const own = checker.getNonNullableType(absentSubstitutedTypeAt(node));
|
|
2218
|
+
if (!checker.isTupleType(own) && !(node.elements.length === 0 && checker.isArrayType(own)))
|
|
2219
|
+
return null;
|
|
2220
|
+
const target = impliedPatternTargetOf(checker, node);
|
|
2221
|
+
if (!target)
|
|
2222
|
+
return null;
|
|
2223
|
+
if (node.elements.some((element) => ts.isSpreadElement(element)))
|
|
2224
|
+
return null;
|
|
2225
|
+
// A nested element's default (`[[x, y, z] = [4, 5, 6]]`) is stored in
|
|
2226
|
+
// THAT element's slot -- the census's own binding for it, which is the
|
|
2227
|
+
// outer array's element (a tuple record here) -- not in the root
|
|
2228
|
+
// parameter's: reading the root's slot typed this literal as an array OF
|
|
2229
|
+
// its own tuple and passed `4` into a three-field record.
|
|
2230
|
+
if (target.element) {
|
|
2231
|
+
const slot = parameters.typeAt(target.element);
|
|
2232
|
+
return slot && !isUnusableEvidence(slot) ? typeOf(slot) : null;
|
|
2233
|
+
}
|
|
2234
|
+
// The parameter's census slot (every tuple arm's positions, joined) is
|
|
2235
|
+
// the element this literal is stored as; the literal's own tuple shape
|
|
2236
|
+
// is not, or `f([1, 2]); f([])` would pass a `never[]` into a `number[]`.
|
|
2237
|
+
const bound = target.parameter ? parameters.typeAt(target.parameter) : null;
|
|
2238
|
+
const boundElement = target.parameter
|
|
2239
|
+
? (impliedPatternArrayElementAt(checker, parameters, target.parameter) ??
|
|
2240
|
+
(bound ? checker.getIndexTypeOfType(checker.getNonNullableType(bound), ts.IndexKind.Number) : undefined))
|
|
2241
|
+
: undefined;
|
|
2242
|
+
// A hole (`[,]`) is a position holding nothing -- the array's element
|
|
2243
|
+
// read there is `undefined`, which the pattern's own absence already
|
|
2244
|
+
// covers -- so it states no element type of its own.
|
|
2245
|
+
const written = node.elements
|
|
2246
|
+
.filter((element) => !ts.isOmittedExpression(element))
|
|
2247
|
+
.map((element) => checker.getBaseTypeOfLiteralType(absentSubstitutedTypeAt(element)));
|
|
2248
|
+
const element = boundElement && !isUnusableEvidence(boundElement)
|
|
2249
|
+
? boundElement
|
|
2250
|
+
: written.length === 0
|
|
2251
|
+
? checker.getNeverType()
|
|
2252
|
+
: widestOf(checker, written);
|
|
2253
|
+
if (!element)
|
|
2254
|
+
return null;
|
|
2255
|
+
return table.intern({ kind: 'array', element: typeOf(element), readonly: false, extension: [] });
|
|
2256
|
+
};
|
|
2257
|
+
/**
|
|
2258
|
+
* A rest element of an array pattern over a plain array IS that array's
|
|
2259
|
+
* type -- the remaining elements, in an Array -- and the checker's own
|
|
2260
|
+
* answer is not: `var [x, ...rest] = [1, 2, 3]` types `rest` as the tuple
|
|
2261
|
+
* `[number, number]` because it typed the literal as a tuple, while the
|
|
2262
|
+
* value the pattern reads out of (`impliedPatternArrayLiteralType`) is an
|
|
2263
|
+
* ordinary array of unknown length. Answered for the element and for every
|
|
2264
|
+
* reference to it, since both are laid out from the same cell. A pattern
|
|
2265
|
+
* over a source that stays a tuple keeps the checker's tuple.
|
|
2266
|
+
*
|
|
2267
|
+
* Answers only for `rest` itself, never for a cell some OTHER assignment
|
|
2268
|
+
* also reaches. `rest = JSON.parse(...)` after `var [x, ...rest] = [1, 2,
|
|
2269
|
+
* 3]` is the identical defect `restAssignmentArrayShapeAt` (below) was
|
|
2270
|
+
* fixed for, one syntax over: this function is keyed by the symbol's
|
|
2271
|
+
* DECLARATION alone and, before this guard, never asked whether anything
|
|
2272
|
+
* else writes it, so a genuinely dynamic later value stored into `rest`
|
|
2273
|
+
* still read back as `array-object(scalar(number))` from the pattern
|
|
2274
|
+
* alone -- a fail-open `unboxDynamicArray<double>` that aborted the moment
|
|
2275
|
+
* the dynamic value held something else. See that function's own header
|
|
2276
|
+
* for the full trace; this is its DECLARATION-pattern twin.
|
|
2277
|
+
*/
|
|
2278
|
+
const arrayPatternRestTypeAt = (node) => {
|
|
2279
|
+
const element = ts.isBindingElement(node)
|
|
2280
|
+
? node
|
|
2281
|
+
: ts.isIdentifier(node)
|
|
2282
|
+
? checker.getSymbolAtLocation(node)?.valueDeclaration
|
|
2283
|
+
: undefined;
|
|
2284
|
+
if (!element || !ts.isBindingElement(element) || !element.dotDotDotToken || !ts.isArrayBindingPattern(element.parent))
|
|
2285
|
+
return null;
|
|
2286
|
+
if (flow) {
|
|
2287
|
+
const symbol = ts.isIdentifier(element.name) ? checker.getSymbolAtLocation(element.name) : undefined;
|
|
2288
|
+
if (!symbol)
|
|
2289
|
+
return null;
|
|
2290
|
+
// The element's OWN binding is itself recorded as a write (`destructuring`,
|
|
2291
|
+
// `value: null` -- `recordBindingPattern`), so a real value here is always
|
|
2292
|
+
// a SEPARATE, later assignment this function has no way to fold in.
|
|
2293
|
+
const reassigned = flow.writesToSymbol(symbol).some((write) => write.slot === 'whole' && write.value !== null);
|
|
2294
|
+
if (reassigned)
|
|
2295
|
+
return null;
|
|
2296
|
+
}
|
|
2297
|
+
const source = mapper.typeAt(element.parent);
|
|
2298
|
+
return table.get(source).shape.kind === 'array' ? source : null;
|
|
2299
|
+
};
|
|
2300
|
+
/**
|
|
2301
|
+
* A REST target of an array-destructuring ASSIGNMENT (`var a, r; [a, ...r]
|
|
2302
|
+
* = [1, 2, 3]`), for a bare `r` with no annotation and no initializer.
|
|
2303
|
+
*
|
|
2304
|
+
* `arrayPatternRestTypeAt` above answers the DECLARATION-pattern twin of
|
|
2305
|
+
* this (`var [x, ...rest] = ...`), where the rest names a `ts.BindingElement`
|
|
2306
|
+
* this layer can walk straight to the pattern from. An assignment target
|
|
2307
|
+
* names no such element -- `r` is an ordinary bare `VariableDeclaration`,
|
|
2308
|
+
* written later through `[a, ...r] = arr`, and `local-bindings.ts`'s
|
|
2309
|
+
* `identifierWritesOf` (which types every OTHER bare-declaration write
|
|
2310
|
+
* through a recovered `ts.Expression`) explicitly refuses a rest target:
|
|
2311
|
+
* there is no single sub-expression that states "the remaining elements,"
|
|
2312
|
+
* and there is no public checker API to synthesize one --
|
|
2313
|
+
* `structural-array-element.ts`'s header documents the identical wall for
|
|
2314
|
+
* `never[]`.
|
|
2315
|
+
*
|
|
2316
|
+
* The source array's OWN resolved carrier already answers the question
|
|
2317
|
+
* this layer needs, without synthesizing anything: a rest capture over an
|
|
2318
|
+
* `array`-shaped source holds exactly that source's element, whatever the
|
|
2319
|
+
* capture's start position -- the identical fact `arrayPatternRestTypeAt`
|
|
2320
|
+
* trades on. So this asks every REST write of the symbol for its pattern's
|
|
2321
|
+
* source, resolves that source through this same mapper, and adopts its
|
|
2322
|
+
* shape outright when it is an `array` -- never a `tuple`, which states a
|
|
2323
|
+
* fixed arity the rest slice does not share, and never anything else,
|
|
2324
|
+
* which states a value no array carrier could hold.
|
|
2325
|
+
*
|
|
2326
|
+
* Several rest writes to the same cell must AGREE (the identical shape) or
|
|
2327
|
+
* this refuses outright -- a real disagreement is not this layer's to
|
|
2328
|
+
* resolve, and a wrong pick would be worse than the box the cell keeps
|
|
2329
|
+
* today. A write whose source cannot be resolved to an array shape states
|
|
2330
|
+
* nothing either way and is skipped rather than treated as a conflict.
|
|
2331
|
+
*
|
|
2332
|
+
* The premise this whole function trades on is "`r` is written ONLY
|
|
2333
|
+
* through rest capture" (the header's own words: "written LATER through
|
|
2334
|
+
* `[a, ...r] = arr]`"). It used to take that on faith -- the write loop
|
|
2335
|
+
* below `continue`d past any write that was not itself a recognised rest
|
|
2336
|
+
* capture, silently discarding it rather than checking whether the
|
|
2337
|
+
* premise actually held. A plain `r = JSON.parse(...)` reassignment after
|
|
2338
|
+
* `[a, ...r] = [1, 2, 3]` reached exactly that `continue`, so this
|
|
2339
|
+
* function answered "array of number" from the ONE write it understood
|
|
2340
|
+
* while a genuinely dynamic value flowed into the SAME cell from the one
|
|
2341
|
+
* it ignored -- the store then read that dynamic value back through
|
|
2342
|
+
* `unboxDynamicArray<double>`, which aborted at runtime the moment the
|
|
2343
|
+
* parsed JSON held strings. Certified clean, compiled clean, `gea:
|
|
2344
|
+
* SIGABRT`. Fixed by refusing outright the moment ANY write this
|
|
2345
|
+
* authority cannot itself vouch for as a rest capture exists, rather than
|
|
2346
|
+
* silently answering from the subset it does understand -- the same
|
|
2347
|
+
* "a write that states nothing is not a write that disagrees, but a write
|
|
2348
|
+
* this authority never SAW is not evidence of agreement either" correction
|
|
2349
|
+
* `local-bindings.ts`'s `branchArmsOf` made for `||`/`??`/`?:` writes.
|
|
2350
|
+
*/
|
|
2351
|
+
const restAssignmentArrayShapeAt = (node) => {
|
|
2352
|
+
if (!flow)
|
|
2353
|
+
return null;
|
|
2354
|
+
const declaration = ts.isVariableDeclaration(node)
|
|
2355
|
+
? node
|
|
2356
|
+
: ts.isIdentifier(node)
|
|
2357
|
+
? checker.getSymbolAtLocation(node)?.valueDeclaration
|
|
2358
|
+
: undefined;
|
|
2359
|
+
if (!declaration ||
|
|
2360
|
+
!ts.isVariableDeclaration(declaration) ||
|
|
2361
|
+
declaration.type ||
|
|
2362
|
+
declaration.initializer ||
|
|
2363
|
+
!ts.isIdentifier(declaration.name))
|
|
2364
|
+
return null;
|
|
2365
|
+
const symbol = checker.getSymbolAtLocation(declaration.name);
|
|
2366
|
+
if (!symbol)
|
|
2367
|
+
return null;
|
|
2368
|
+
let agreed = null;
|
|
2369
|
+
let sawRestWrite = false;
|
|
2370
|
+
for (const write of flow.writesToSymbol(symbol)) {
|
|
2371
|
+
if (write.slot !== 'whole')
|
|
2372
|
+
continue;
|
|
2373
|
+
const target = write.edge === 'destructuring' && write.value === null && write.naming ? arrayAssignmentTargetOf(write.naming) : null;
|
|
2374
|
+
if (!target || !ts.isSpreadElement(target.keyNode)) {
|
|
2375
|
+
// Not a rest capture this authority recognises -- a bare/defaulted
|
|
2376
|
+
// destructuring element, a plain reassignment, a reused for-of head,
|
|
2377
|
+
// whatever it is, it is a write this loop cannot fold into `agreed`,
|
|
2378
|
+
// so the "written ONLY through rest capture" premise is false and
|
|
2379
|
+
// the honest answer is refusal, not an answer from a subset.
|
|
2380
|
+
return null;
|
|
2381
|
+
}
|
|
2382
|
+
sawRestWrite = true;
|
|
2383
|
+
const source = arrayAssignmentPatternSourceExpression(target.pattern);
|
|
2384
|
+
if (!source)
|
|
2385
|
+
continue;
|
|
2386
|
+
const sourceShape = mapper.typeAt(source);
|
|
2387
|
+
if (table.get(sourceShape).shape.kind !== 'array')
|
|
2388
|
+
continue;
|
|
2389
|
+
if (agreed !== null && agreed !== sourceShape)
|
|
2390
|
+
return null;
|
|
2391
|
+
agreed = sourceShape;
|
|
2392
|
+
}
|
|
2393
|
+
return sawRestWrite ? agreed : null;
|
|
2394
|
+
};
|
|
2395
|
+
/**
|
|
2396
|
+
* The copy a site's instantiation names, as a path this mapper can be asked
|
|
2397
|
+
* for: the copies enclosing the *site's* declaration, not this walk's whole
|
|
2398
|
+
* path. A generic named from inside an unrelated generic's body is not
|
|
2399
|
+
* nested in it, and carrying that outer step would compose `decl|X@0.0` --
|
|
2400
|
+
* an id the census, which walks that generic from its own scope, never
|
|
2401
|
+
* publishes.
|
|
2402
|
+
*
|
|
2403
|
+
* A SELF-instantiation (`Hono#clone()` naming `new Hono<...>` with its own
|
|
2404
|
+
* type parameters) resolves to the identical (declaration, ordinal) pair as
|
|
2405
|
+
* the enclosing path's own last step, since `prefixFor` is inclusive of
|
|
2406
|
+
* self-containment. Appending a second frame there composes `decl|Hono@0.0`
|
|
2407
|
+
* for a copy already named `decl|Hono@0` -- the spurious-nesting shape, one
|
|
2408
|
+
* step short -- so the enclosing path is reused unchanged when its last
|
|
2409
|
+
* step already IS this copy.
|
|
2410
|
+
*/
|
|
2411
|
+
/**
|
|
2412
|
+
* The generic source function `type` is the OPEN type of, from this view.
|
|
2413
|
+
*
|
|
2414
|
+
* `typeof identity` where `function identity<T>(x: T): T` is a module-level
|
|
2415
|
+
* function with a body, read from a view that binds none of its type
|
|
2416
|
+
* parameters (the root, or a copy of something else). Inside `identity`'s
|
|
2417
|
+
* own copy the same `ts.Type` reads with `T` bound, and is the copy's own
|
|
2418
|
+
* closed callable, not a choice. Only a module- or namespace-level
|
|
2419
|
+
* declaration qualifies: a nested generic closes over its frame, and a
|
|
2420
|
+
* choice among closures would need the captured environment beside the
|
|
2421
|
+
* tag. See `StructuralShape`'s `generic` and `representation/model.ts`'s
|
|
2422
|
+
* `generic-function-set`.
|
|
2423
|
+
*/
|
|
2424
|
+
const genericSourceFunctionOf = (type, callSignatures, constructSignatures, implementation) => {
|
|
2425
|
+
if (constructSignatures.length > 0 || callSignatures.length === 0)
|
|
2426
|
+
return null;
|
|
2427
|
+
const signatures = implementation ? [implementation] : callSignatures;
|
|
2428
|
+
// Open = this PATH binds none of it. Not `substituteTypeParameter`: that
|
|
2429
|
+
// also answers from the instantiation census's one-instantiation fallback,
|
|
2430
|
+
// which closes a root-view `T` whose only copy is the one a set call
|
|
2431
|
+
// minted -- reading the choice's own member as that copy's closed callable.
|
|
2432
|
+
const open = signatures.every((signature) => {
|
|
2433
|
+
const parameters = signature.getTypeParameters() ?? [];
|
|
2434
|
+
return (parameters.length > 0 &&
|
|
2435
|
+
parameters.some((parameter) => {
|
|
2436
|
+
const declared = parameter.getSymbol()?.declarations?.[0];
|
|
2437
|
+
return declared === undefined || boundByPath(declared) === null;
|
|
2438
|
+
}));
|
|
2439
|
+
});
|
|
2440
|
+
if (!open)
|
|
2441
|
+
return null;
|
|
2442
|
+
const declaration = implementation?.declaration ?? type.getSymbol()?.valueDeclaration;
|
|
2443
|
+
if (!declaration || !ts.isFunctionDeclaration(declaration) || declaration.body === undefined)
|
|
2444
|
+
return null;
|
|
2445
|
+
if (declaration.getSourceFile().isDeclarationFile)
|
|
2446
|
+
return null;
|
|
2447
|
+
if (!(ts.isSourceFile(declaration.parent) || ts.isModuleBlock(declaration.parent)))
|
|
2448
|
+
return null;
|
|
2449
|
+
if (declaration.asteriskToken !== undefined || (ts.getCombinedModifierFlags(declaration) & ts.ModifierFlags.Async) !== 0)
|
|
2450
|
+
return null;
|
|
2451
|
+
return identities.declarationIdOf(declaration, rootSpecialization);
|
|
2452
|
+
};
|
|
2453
|
+
const copyPathOf = (site) => {
|
|
2454
|
+
const enclosing = identities.prefixFor(site.declaration, path);
|
|
2455
|
+
const last = enclosing[enclosing.length - 1];
|
|
2456
|
+
const isSelfReference = last !== undefined && last.owner === site.declaration && last.ordinal === site.ordinal;
|
|
2457
|
+
return isSelfReference ? enclosing : [...enclosing, { owner: site.declaration, ordinal: site.ordinal }];
|
|
2458
|
+
};
|
|
2459
|
+
/**
|
|
2460
|
+
* The implementation signature behind a call-signature set that is one
|
|
2461
|
+
* overloaded SOURCE function or method -- two or more signatures, every one
|
|
2462
|
+
* declared by a body-less overload or the body of the same symbol, in a
|
|
2463
|
+
* source file -- or `null` for any other callable type. An ambient overload
|
|
2464
|
+
* set (`document.createElement`) has no body to be the value and keeps the
|
|
2465
|
+
* checker's answer.
|
|
2466
|
+
*/
|
|
2467
|
+
const sourceOverloadImplementationOf = (callSignatures, constructSignatures) => {
|
|
2468
|
+
if (callSignatures.length < 2 || constructSignatures.length > 0)
|
|
2469
|
+
return null;
|
|
2470
|
+
let symbol;
|
|
2471
|
+
for (const signature of callSignatures) {
|
|
2472
|
+
const declaration = signature.getDeclaration();
|
|
2473
|
+
if (!declaration || !(ts.isFunctionDeclaration(declaration) || ts.isMethodDeclaration(declaration)))
|
|
2474
|
+
return null;
|
|
2475
|
+
if (declaration.getSourceFile().isDeclarationFile)
|
|
2476
|
+
return null;
|
|
2477
|
+
const name = ts.getNameOfDeclaration(declaration);
|
|
2478
|
+
const owner = name ? checker.getSymbolAtLocation(name) : undefined;
|
|
2479
|
+
if (!owner || (symbol !== undefined && owner !== symbol))
|
|
2480
|
+
return null;
|
|
2481
|
+
symbol = owner;
|
|
2482
|
+
}
|
|
2483
|
+
const first = callSignatures[0]?.getDeclaration();
|
|
2484
|
+
return first ? implementationSignatureOf(checker, first) : null;
|
|
2485
|
+
};
|
|
2486
|
+
/**
|
|
2487
|
+
* A member read off an EVOLVING array -- `var xs = []; xs.push('a')` -- whose
|
|
2488
|
+
* element the census proved (`inferredArrayElementAt`) but the checker still
|
|
2489
|
+
* carries as `any`/`never` at the read. The checker instantiates
|
|
2490
|
+
* `Array<T>.push` from the receiver EXPRESSION's type, so its signature says
|
|
2491
|
+
* `(...items: any[]) => number`, and every argument the call packs into that
|
|
2492
|
+
* rest slot is boxed on the way in and unboxed again by the native `push`
|
|
2493
|
+
* -- a `gea::Value` per pushed element for an array whose storage is
|
|
2494
|
+
* already `ArrayObject<std::string>`. Two authorities over one slot; the
|
|
2495
|
+
* census's element is the one the storage was chosen by, so it is the one
|
|
2496
|
+
* the member's own parameters carry too. Only the argument positions that
|
|
2497
|
+
* are the ELEMENT (`any`) or a rest of it (`any[]`) are rewritten -- the
|
|
2498
|
+
* shapes of `push`/`unshift`/`splice`/`indexOf`/`includes`/`fill` -- a
|
|
2499
|
+
* result or a nested callback stays the checker's, since nothing here is
|
|
2500
|
+
* asked about it and a wrong guess there is a silent miscompile.
|
|
2501
|
+
*/
|
|
2502
|
+
const evolvingArrayMemberTypeAt = (node) => {
|
|
2503
|
+
if (!ts.isPropertyAccessExpression(node))
|
|
2504
|
+
return null;
|
|
2505
|
+
const element = inferredArrayElementAt(checker, collections, layoutTypeAt, node.expression);
|
|
2506
|
+
if (!element || (element.flags & (ts.TypeFlags.Any | ts.TypeFlags.Never)) !== 0)
|
|
2507
|
+
return null;
|
|
2508
|
+
// The checker's own member type, interned directly: asking `typeAt` of
|
|
2509
|
+
// this same node would re-enter here.
|
|
2510
|
+
const declared = typeOf(checker.getTypeAtLocation(node));
|
|
2511
|
+
const shape = table.get(declared).shape;
|
|
2512
|
+
if (shape.kind !== 'signature' || shape.call.length !== 1 || shape.construct.length !== 0)
|
|
2513
|
+
return null;
|
|
2514
|
+
// `any` for the evolving array the checker gave up on, `never` for the one
|
|
2515
|
+
// it is still tracking (`push` off a fresh `[]` is `(...items: never[])`).
|
|
2516
|
+
const unstated = new Set();
|
|
2517
|
+
for (const primitive of ['any', 'never']) {
|
|
2518
|
+
const id = table.intern({ kind: 'primitive', primitive });
|
|
2519
|
+
unstated.add(id);
|
|
2520
|
+
unstated.add(table.intern({ kind: 'array', element: id, readonly: false, extension: [] }));
|
|
2521
|
+
}
|
|
2522
|
+
const elementId = typeOf(element);
|
|
2523
|
+
const elementArray = table.intern({ kind: 'array', element: elementId, readonly: false, extension: [] });
|
|
2524
|
+
const substitute = (id) => {
|
|
2525
|
+
if (!unstated.has(id))
|
|
2526
|
+
return id;
|
|
2527
|
+
return table.get(id).shape.kind === 'array' ? elementArray : elementId;
|
|
2528
|
+
};
|
|
2529
|
+
const call = shape.call[0];
|
|
2530
|
+
if (!call || !call.parameters.some((parameter) => unstated.has(parameter.type)))
|
|
2531
|
+
return null;
|
|
2532
|
+
const parameters = call.parameters.map((parameter) => ({
|
|
2533
|
+
...parameter,
|
|
2534
|
+
type: substitute(parameter.type),
|
|
2535
|
+
slot: substitute(parameter.slot)
|
|
2536
|
+
}));
|
|
2537
|
+
return table.intern({ kind: 'signature', call: [{ ...call, parameters }], construct: [] });
|
|
2538
|
+
};
|
|
2539
|
+
/**
|
|
2540
|
+
* The signature of a member read off a receiver the CENSUS typed and the
|
|
2541
|
+
* checker carries as `any` -- three's `LOD.addLevel` reading `levels`
|
|
2542
|
+
* through a descriptor-defined field -- when the member is an overload set
|
|
2543
|
+
* the census could not narrow to one convention: `memberTypeOf`'s
|
|
2544
|
+
* `singleConventionAt` needs the checker's resolved signature to pick, and a
|
|
2545
|
+
* call through an `any` receiver resolves to the fabricated no-parameter
|
|
2546
|
+
* signature instead. Picked here by the argument count, the checker's own
|
|
2547
|
+
* first overload-resolution step (`arityAdmittedSignature`), and interned as
|
|
2548
|
+
* the ONE selected signature over the census receiver's instantiation -- so
|
|
2549
|
+
* `levels.splice( l, 0, level )` names the rest-taking overload and the
|
|
2550
|
+
* lowering packs the item, where the joined overload set declared no rest
|
|
2551
|
+
* slot and the item reached `Array.prototype.splice`'s renderer bare.
|
|
2552
|
+
*/
|
|
2553
|
+
const censusMemberSignatureAt = (node) => {
|
|
2554
|
+
if (!ts.isPropertyAccessExpression(node))
|
|
2555
|
+
return null;
|
|
2556
|
+
if ((absentSubstitutedTypeAt(node).flags & ts.TypeFlags.Any) === 0)
|
|
2557
|
+
return null;
|
|
2558
|
+
const call = node.parent;
|
|
2559
|
+
if (!call || !ts.isCallExpression(call) || call.expression !== node)
|
|
2560
|
+
return null;
|
|
2561
|
+
const receiver = parameters.typeAt(node.expression);
|
|
2562
|
+
if (!receiver || (receiver.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Never)) !== 0)
|
|
2563
|
+
return null;
|
|
2564
|
+
const property = checker.getPropertyOfType(checker.getNonNullableType(receiver), node.name.text);
|
|
2565
|
+
if (!property)
|
|
2566
|
+
return null;
|
|
2567
|
+
const member = checker.getTypeOfSymbolAtLocation(property, node);
|
|
2568
|
+
if (member.getCallSignatures().length < 2 || member.getConstructSignatures().length > 0)
|
|
2569
|
+
return null;
|
|
2570
|
+
const selected = arityAdmittedSignature(member, call);
|
|
2571
|
+
if (!selected || (selected.getTypeParameters()?.length ?? 0) > 0)
|
|
2572
|
+
return null;
|
|
2573
|
+
return table.intern({ kind: 'signature', call: [signatureOf(selected)], construct: [] });
|
|
2574
|
+
};
|
|
2575
|
+
/**
|
|
2576
|
+
* `Object.getOwnPropertyDescriptor(receiver, key)`'s result, minted from the
|
|
2577
|
+
* RECEIVER's own structural shape rather than the ambient `PropertyDescriptor`
|
|
2578
|
+
* interface's own declared `value?: any`.
|
|
2579
|
+
*
|
|
2580
|
+
* The library's own signature is `getOwnPropertyDescriptor(o: any, p:
|
|
2581
|
+
* PropertyKey): PropertyDescriptor | undefined` -- fixed and non-generic, so
|
|
2582
|
+
* every call resolves to the identical ambient shape no matter what `o` is.
|
|
2583
|
+
* That is the right answer for a receiver this compiler never gave a shape of
|
|
2584
|
+
* its own (`Math`, `Array.prototype`, a value the program declared `any`):
|
|
2585
|
+
* there is no narrower fact to publish, and `value: any` is honest. It is the
|
|
2586
|
+
* wrong answer for a record literal, an array, or an in-program function,
|
|
2587
|
+
* whose OWN declared members already answer "what is `receiver[key]`" -- and
|
|
2588
|
+
* publishing the ambient `any` there is exactly the "typed value lowered into
|
|
2589
|
+
* `gea_cpp_value`" defect this compiler exists to refuse:
|
|
2590
|
+
* `Object.getOwnPropertyDescriptor({ a: 1 }, "a").value` would box a `number`
|
|
2591
|
+
* the record's own layout already states, for no reason but the library
|
|
2592
|
+
* text's own `any`.
|
|
2593
|
+
*
|
|
2594
|
+
* Lives here, in `typeAt`'s own module, rather than beside
|
|
2595
|
+
* `producers/invocations.ts`'s other result overrides: this is asked of the
|
|
2596
|
+
* bare CallExpression node ITSELF (not just consulted from inside the
|
|
2597
|
+
* invocation producer's own result computation), because `context.types.typeAt`
|
|
2598
|
+
* is the ONE authority every OTHER consumer of this same node's type reads
|
|
2599
|
+
* from -- a property access's own receiver type
|
|
2600
|
+
* (`producers/properties.ts`), a local binding's declared type
|
|
2601
|
+
* (`local-bindings.ts`) -- and an override that only changed what the
|
|
2602
|
+
* invocation producer PUBLISHES for its own operation result left every one
|
|
2603
|
+
* of those asking `context.types.typeAt` on the very same node with the
|
|
2604
|
+
* old, ambient, boxed answer: the call's own SSA value came out fully
|
|
2605
|
+
* native while the record it got stored into, and the receiver of a plain
|
|
2606
|
+
* `d.value` off it, still boxed. `evolvingArrayMemberTypeAt` above is
|
|
2607
|
+
* exposed the same way for the identical reason.
|
|
2608
|
+
*
|
|
2609
|
+
* Gated to receivers this compiler already treats as having a REAL,
|
|
2610
|
+
* in-program shape: `membersDropped === false` for an object literal
|
|
2611
|
+
* (`membersDropped` is `true` for an ambient interface enumerated
|
|
2612
|
+
* `data-only`, `host/object-protocol.ts`'s own distinction between the two),
|
|
2613
|
+
* and a physical, non-ambient value declaration for a function. A host
|
|
2614
|
+
* intrinsic still falls through to the ambient signature below untouched --
|
|
2615
|
+
* its own static reflection, if any, is a separate, host-table-driven
|
|
2616
|
+
* mechanism this function has no business pre-empting.
|
|
2617
|
+
*
|
|
2618
|
+
* A literal key that names a member answers with that member's own type. A
|
|
2619
|
+
* runtime key, or a literal that names no member, answers with the union of
|
|
2620
|
+
* every member this receiver states (an array: its element and `length`; a
|
|
2621
|
+
* function: `name` and `length`), plus the record's dynamic-property
|
|
2622
|
+
* SIDECAR's own boxed arm for a key `Object.defineProperty` could have
|
|
2623
|
+
* added after the fact -- the one accepted, bounded exception this feature
|
|
2624
|
+
* carries, matching the sidecar's own storage
|
|
2625
|
+
* (`emit-dynamic-properties.ts`).
|
|
2626
|
+
*/
|
|
2627
|
+
const objectDescriptorReturnTypeAt = (call) => {
|
|
2628
|
+
if (!ts.isCallExpression(call))
|
|
2629
|
+
return null;
|
|
2630
|
+
const node = call.expression;
|
|
2631
|
+
if (!ts.isPropertyAccessExpression(node) || node.name.text !== 'getOwnPropertyDescriptor')
|
|
2632
|
+
return null;
|
|
2633
|
+
if (!isIntrinsicDescriptorCall(call))
|
|
2634
|
+
return null;
|
|
2635
|
+
const target = call.arguments[0];
|
|
2636
|
+
const keyArgument = call.arguments[1];
|
|
2637
|
+
if (!target)
|
|
2638
|
+
return null;
|
|
2639
|
+
const literalKey = keyArgument
|
|
2640
|
+
? ts.isStringLiteralLike(keyArgument)
|
|
2641
|
+
? keyArgument.text
|
|
2642
|
+
: ts.isNumericLiteral(keyArgument)
|
|
2643
|
+
? keyArgument.text
|
|
2644
|
+
: null
|
|
2645
|
+
: null;
|
|
2646
|
+
const intern = (built) => table.intern(built);
|
|
2647
|
+
const boolId = intern({ kind: 'primitive', primitive: 'boolean' });
|
|
2648
|
+
// The `value` this descriptor carries for one candidate receiver shape, or
|
|
2649
|
+
// `null` when this shape names no rendering this feature supports (a plain
|
|
2650
|
+
// `dynamic`/`unknown` receiver, an interface flattened to `membersDropped`).
|
|
2651
|
+
// Split out of the top level so a receiver typed as a UNION of shapes --
|
|
2652
|
+
// `describe(obj, key)` called once with a record and once with an array,
|
|
2653
|
+
// neither call site specializing the shared body -- can ask this same
|
|
2654
|
+
// question of each arm and union the answers, rather than refusing the
|
|
2655
|
+
// whole call the way an unhandled `shape.kind` correctly does.
|
|
2656
|
+
// `any | T` is `any`: an arm that already admits every value absorbs the
|
|
2657
|
+
// others, exactly as the checker reduces the same union. Interning the
|
|
2658
|
+
// unreduced pair instead published `tagged-union(dynamic | number)` for
|
|
2659
|
+
// `Array.prototype`'s `any` element, a carrier no installed conversion
|
|
2660
|
+
// reaches from the boxed read the array arm performs, and the whole call
|
|
2661
|
+
// was refused for a receiver whose honest answer was simply `any`.
|
|
2662
|
+
const anyId = intern({ kind: 'primitive', primitive: 'any' });
|
|
2663
|
+
const unionOf = (arms) => {
|
|
2664
|
+
const distinct = [...new Set(arms)];
|
|
2665
|
+
if (distinct.includes(anyId))
|
|
2666
|
+
return anyId;
|
|
2667
|
+
const first = distinct[0];
|
|
2668
|
+
return distinct.length === 1 && first !== undefined ? first : intern({ kind: 'union', members: distinct });
|
|
2669
|
+
};
|
|
2670
|
+
const valueIdOfShape = (shape) => {
|
|
2671
|
+
// A native class anchor carries its own member layout in the same body
|
|
2672
|
+
// as an ordinary declared record. Discarding that body here widens a
|
|
2673
|
+
// known field into ambient PropertyDescriptor.value:any before the
|
|
2674
|
+
// result is even lowered, forcing a needless box/unbox round trip.
|
|
2675
|
+
if ((shape.kind === 'declared' || shape.kind === 'class-instance') && shape.body !== null)
|
|
2676
|
+
return valueIdOfShape(table.get(shape.body).shape);
|
|
2677
|
+
if (shape.kind === 'object' && !shape.membersDropped) {
|
|
2678
|
+
if (literalKey !== null) {
|
|
2679
|
+
// A literal key that names no member this record's own structural
|
|
2680
|
+
// type declares is not proof the key is absent: `Object.defineProperty(o,
|
|
2681
|
+
// "b", ...)` adds "b" to the object's dynamic-property SIDECAR (see
|
|
2682
|
+
// `emit-dynamic-properties.ts`), which this type never sees, because
|
|
2683
|
+
// a record's structural shape only ever tracks its declared literal
|
|
2684
|
+
// fields. The sidecar stores its values boxed (`gea::Value` -- the
|
|
2685
|
+
// one accepted, bounded exception this feature carries, matching a
|
|
2686
|
+
// genuinely dynamic key with no static type to give it), so the
|
|
2687
|
+
// descriptor's `value` for a key the shape doesn't declare must stay
|
|
2688
|
+
// `dynamic` rather than borrowing an unrelated declared field's type.
|
|
2689
|
+
const match = shape.members.find((member) => member.key.kind === 'string' && member.key.value === literalKey);
|
|
2690
|
+
if (match)
|
|
2691
|
+
return match.type;
|
|
2692
|
+
const index = shape.index.find((candidate) => candidate.key === 'string' || (candidate.key === 'number' && literalKey !== '' && Number.isFinite(Number(literalKey))));
|
|
2693
|
+
return index?.value ?? intern({ kind: 'primitive', primitive: 'any' });
|
|
2694
|
+
}
|
|
2695
|
+
else if (shape.members.length > 0) {
|
|
2696
|
+
// A runtime (non-literal) key: `describe(obj, key)`'s `value` must
|
|
2697
|
+
// be able to hold whichever declared field `key` names at runtime,
|
|
2698
|
+
// so it is the union of the record's own field types -- the
|
|
2699
|
+
// emitter renders this as a switch over the record's known keys
|
|
2700
|
+
// (`finiteRecordUnionGetText`'s pattern), never a boxed carrier. A
|
|
2701
|
+
// runtime key can ALSO name a key the type declares nothing about,
|
|
2702
|
+
// so the value must also admit the sidecar's own boxed arm, exactly
|
|
2703
|
+
// as the literal-miss case above does, or a key the switch does not
|
|
2704
|
+
// recognize has nowhere sound to fall through to.
|
|
2705
|
+
const arms = [...new Set(shape.members.map((member) => member.type))];
|
|
2706
|
+
const keyType = keyArgument ? checker.getTypeAtLocation(keyArgument) : null;
|
|
2707
|
+
const index = shape.index.find((candidate) => keyType !== null &&
|
|
2708
|
+
((candidate.key === 'string' && (keyType.flags & ts.TypeFlags.StringLike) !== 0) ||
|
|
2709
|
+
(candidate.key === 'number' && (keyType.flags & ts.TypeFlags.NumberLike) !== 0) ||
|
|
2710
|
+
(candidate.key === 'symbol' && (keyType.flags & ts.TypeFlags.ESSymbolLike) !== 0)));
|
|
2711
|
+
arms.push(index?.value ?? intern({ kind: 'primitive', primitive: 'any' }));
|
|
2712
|
+
// Through `unionOf`, like every sibling branch: an unreduced
|
|
2713
|
+
// `any | number` pair published `tagged-union(dynamic | number)`
|
|
2714
|
+
// for the `?.value` read, and the optional chain's `undefined`
|
|
2715
|
+
// arm has no conversion into that carrier, so a
|
|
2716
|
+
// `getOwnPropertyDescriptor(item, String(key))?.value` was refused
|
|
2717
|
+
// where its honest answer, as for `Array.prototype`'s element
|
|
2718
|
+
// above, is simply `any`.
|
|
2719
|
+
return unionOf(arms);
|
|
2720
|
+
}
|
|
2721
|
+
return null;
|
|
2722
|
+
}
|
|
2723
|
+
if (shape.kind === 'array') {
|
|
2724
|
+
const numberId = intern({ kind: 'primitive', primitive: 'number' });
|
|
2725
|
+
if (literalKey === 'length')
|
|
2726
|
+
return numberId;
|
|
2727
|
+
// An index's descriptor `value` is the STORED element, and an Array's
|
|
2728
|
+
// storage admits the language's `undefined` at a present index
|
|
2729
|
+
// independently of what its element type says: 12.9.6 gives a tagged
|
|
2730
|
+
// template's invalid escape an `undefined` cooked element inside an
|
|
2731
|
+
// array the checker still types `string`, and the runtime carries
|
|
2732
|
+
// exactly that as `ArrayObject`'s `undefineds` bit beside its element.
|
|
2733
|
+
// Answering with a bare `shape.element` gave the descriptor record no
|
|
2734
|
+
// carrier for that case, so the emitter proved the read unreachable
|
|
2735
|
+
// and `test/runtime/template-strings-array-identity.ts` aborted on
|
|
2736
|
+
// `gea::host::unreachableValue<std::string>()` -- with the emitter
|
|
2737
|
+
// side already correct (`indexDescriptor` in
|
|
2738
|
+
// `targets/cpp/host/emit-host-object.ts` handles the absent value) and
|
|
2739
|
+
// simply fed a false premise. Only the reflective read widens: a
|
|
2740
|
+
// TYPED read of the same index still publishes the element, because
|
|
2741
|
+
// the element type is what a typed read is entitled to.
|
|
2742
|
+
if (literalKey !== null && /^(0|[1-9]\d*)$/.test(literalKey))
|
|
2743
|
+
return unionOf([shape.element, intern({ kind: 'primitive', primitive: 'undefined' })]);
|
|
2744
|
+
// `extension` is the data an interface ADDS to the Array it extends --
|
|
2745
|
+
// `TemplateStringsArray`'s own `raw`, or `NodeArray<T>`'s `pos`/`end`.
|
|
2746
|
+
// A literal key naming one of those fields answers with that field's
|
|
2747
|
+
// OWN type: it is not an element (the element type is a red herring
|
|
2748
|
+
// for it) and not the generic "any other key" case either. Missing
|
|
2749
|
+
// this let `Object.getOwnPropertyDescriptor(templateStrings,
|
|
2750
|
+
// "raw").value` -- an array-object -- fall into the element/number
|
|
2751
|
+
// union below and mint `TaggedUnion<std::string, double>`, which then
|
|
2752
|
+
// refused every real read of `raw`'s array value at runtime.
|
|
2753
|
+
if (literalKey !== null) {
|
|
2754
|
+
const extensionMatch = shape.extension.find((member) => member.key.kind === 'string' && member.key.value === literalKey);
|
|
2755
|
+
if (extensionMatch)
|
|
2756
|
+
return extensionMatch.type;
|
|
2757
|
+
}
|
|
2758
|
+
else if (shape.extension.length > 0) {
|
|
2759
|
+
// A runtime key can equally name an extension field, so it must be
|
|
2760
|
+
// in the union the same way a record's runtime-key case unions its
|
|
2761
|
+
// declared members above.
|
|
2762
|
+
return unionOf([shape.element, numberId, ...shape.extension.map((member) => member.type)]);
|
|
2763
|
+
}
|
|
2764
|
+
return unionOf([shape.element, numberId]);
|
|
2765
|
+
}
|
|
2766
|
+
if (shape.kind === 'signature') {
|
|
2767
|
+
const name = ts.isPropertyAccessExpression(target) ? target.name : ts.isIdentifier(target) ? target : null;
|
|
2768
|
+
const symbol = name ? checker.getSymbolAtLocation(name) : undefined;
|
|
2769
|
+
const declaration = symbol ? identities.valueDeclarationOfSymbol(symbol) : null;
|
|
2770
|
+
// A host's own method (`Date.prototype.getTime`, `Array.from`) answers
|
|
2771
|
+
// the same two questions with the same two types: 10.2.10's `name`
|
|
2772
|
+
// and `length` are what a builtin function owns, and the emitter reads
|
|
2773
|
+
// both off the callable's facts. What stays refused is a callable
|
|
2774
|
+
// interface with declared members of its own, whose `name` could be
|
|
2775
|
+
// a data member the declaration states.
|
|
2776
|
+
// An OVERLOADED host method (`Array.from`, 4 signatures) stays on the
|
|
2777
|
+
// boxed path: its value has no single calling convention to carry,
|
|
2778
|
+
// so the typed descriptor arm could not receive it.
|
|
2779
|
+
const isRealFunction = declaration &&
|
|
2780
|
+
(ts.isFunctionDeclaration(declaration) ||
|
|
2781
|
+
ts.isFunctionExpression(declaration) ||
|
|
2782
|
+
ts.isArrowFunction(declaration) ||
|
|
2783
|
+
((ts.isMethodSignature(declaration) || ts.isMethodDeclaration(declaration)) && shape.call.length === 1));
|
|
2784
|
+
if (!isRealFunction)
|
|
2785
|
+
return null;
|
|
2786
|
+
const stringId = intern({ kind: 'primitive', primitive: 'string' });
|
|
2787
|
+
const numberId = intern({ kind: 'primitive', primitive: 'number' });
|
|
2788
|
+
if (literalKey === 'name')
|
|
2789
|
+
return stringId;
|
|
2790
|
+
if (literalKey === 'length')
|
|
2791
|
+
return numberId;
|
|
2792
|
+
return intern({ kind: 'union', members: [stringId, numberId] });
|
|
2793
|
+
}
|
|
2794
|
+
if (shape.kind === 'union') {
|
|
2795
|
+
const arms = [];
|
|
2796
|
+
for (const member of shape.members) {
|
|
2797
|
+
const memberValueId = valueIdOfShape(table.get(member).shape);
|
|
2798
|
+
if (memberValueId === null)
|
|
2799
|
+
return null;
|
|
2800
|
+
if (!arms.includes(memberValueId))
|
|
2801
|
+
arms.push(memberValueId);
|
|
2802
|
+
}
|
|
2803
|
+
if (arms.length === 0)
|
|
2804
|
+
return null;
|
|
2805
|
+
return unionOf(arms);
|
|
2806
|
+
}
|
|
2807
|
+
return null;
|
|
2808
|
+
};
|
|
2809
|
+
const valueId = valueIdOfShape(table.get(mapper.typeAt(target)).shape);
|
|
2810
|
+
if (valueId === null)
|
|
2811
|
+
return null;
|
|
2812
|
+
const descriptor = intern({
|
|
2813
|
+
kind: 'object',
|
|
2814
|
+
members: [
|
|
2815
|
+
{ key: { kind: 'string', value: 'value' }, type: valueId, optional: false, readonly: false, accessor: null },
|
|
2816
|
+
{ key: { kind: 'string', value: 'writable' }, type: boolId, optional: false, readonly: false, accessor: null },
|
|
2817
|
+
{ key: { kind: 'string', value: 'enumerable' }, type: boolId, optional: false, readonly: false, accessor: null },
|
|
2818
|
+
{ key: { kind: 'string', value: 'configurable' }, type: boolId, optional: false, readonly: false, accessor: null }
|
|
2819
|
+
],
|
|
2820
|
+
index: [],
|
|
2821
|
+
membersDropped: false
|
|
2822
|
+
});
|
|
2823
|
+
return intern({ kind: 'union', members: [descriptor, intern({ kind: 'primitive', primitive: 'undefined' })] });
|
|
2824
|
+
};
|
|
2825
|
+
// `X.prototype` on an ambient constructor. The checker types the slot as the
|
|
2826
|
+
// INSTANCE type, and following that answer makes `Date.prototype` a Date --
|
|
2827
|
+
// the same carrier as `new Date()`, which is exactly the object it is not:
|
|
2828
|
+
// reflection over it (`hasOwnProperty`, `getOwnPropertyDescriptor`, the
|
|
2829
|
+
// property helper's delete/restore) asks about the prototype's OWN
|
|
2830
|
+
// members. `bindHostObjectClosure` registers the slot's declaration as a
|
|
2831
|
+
// protocol of its own; this anchors a declared shape on that declaration,
|
|
2832
|
+
// carrying the instance's body so the member reads keep their signatures.
|
|
2833
|
+
const borrowedPrototypeMethodNames = new Set(['call', 'apply', 'bind']);
|
|
2834
|
+
// The ambient constructors whose `.prototype` methods, read as values, carry
|
|
2835
|
+
// an invoke that brand-checks a boxed receiver and dispatches to the
|
|
2836
|
+
// instance's own member (`hostPrototypeMethodValueText`, targets/cpp). A
|
|
2837
|
+
// constructor is added here only together with that dispatch: without it a
|
|
2838
|
+
// borrow through the prototype's method would compile to a callable that
|
|
2839
|
+
// throws for every receiver, which is a wrong answer where the instance
|
|
2840
|
+
// path at least refuses.
|
|
2841
|
+
const receiverDispatchingPrototypes = new Set(['Date']);
|
|
2842
|
+
/**
|
|
2843
|
+
* Prototype members whose `[[Call]]` is GENERIC over the receiver -- ECMA-262
|
|
2844
|
+
* 21.4.4.37 `Date.prototype.toJSON` runs ToPrimitive(this, number) and then
|
|
2845
|
+
* invokes `toISOString` on whatever it was given, never a brand check -- so
|
|
2846
|
+
* the boxed-receiver stub (`hostPrototypeMethodValueText`), whose invoke IS
|
|
2847
|
+
* a brand check, would render a borrow of it as a TypeError the language does
|
|
2848
|
+
* not throw. Such a borrow keeps the instance path's compile-time refusal
|
|
2849
|
+
* until the target states the generic form (ToPrimitive over a boxed value is
|
|
2850
|
+
* a runtime capability it does not carry yet); the VALUE read still renders,
|
|
2851
|
+
* so `name`/`length`/descriptor reflection over the member is untouched.
|
|
2852
|
+
*/
|
|
2853
|
+
const receiverGenericPrototypeMembers = new Set(['toJSON']);
|
|
2854
|
+
const prototypeObjectTypeAt = (node) => {
|
|
2855
|
+
if (!ts.isPropertyAccessExpression(node) || node.name.text !== 'prototype')
|
|
2856
|
+
return null;
|
|
2857
|
+
const receiverType = checker.getTypeAtLocation(node.expression);
|
|
2858
|
+
if (receiverType.getConstructSignatures().length === 0)
|
|
2859
|
+
return null;
|
|
2860
|
+
const slot = checker.getPropertyOfType(receiverType, 'prototype');
|
|
2861
|
+
const declaration = slot?.valueDeclaration ?? slot?.declarations?.[0];
|
|
2862
|
+
if (!slot || !declaration || !declaration.getSourceFile().isDeclarationFile)
|
|
2863
|
+
return null;
|
|
2864
|
+
const instanceType = checker.getTypeOfSymbolAtLocation(slot, declaration);
|
|
2865
|
+
// `String.prototype.trim.call(s)` borrows the INSTANCE method: the read
|
|
2866
|
+
// off the prototype is the method the instance carrier already renders,
|
|
2867
|
+
// and the borrow lowers through it (`deferredFunctionCallCalleeOf`). A
|
|
2868
|
+
// prototype whose methods dispatch on a boxed receiver in the target
|
|
2869
|
+
// (`receiverDispatchingPrototypes`) has no use for that path: its own
|
|
2870
|
+
// method IS the borrow, brand check included, for a Date receiver and for
|
|
2871
|
+
// the this-value cases alike -- and the instance path never rendered the
|
|
2872
|
+
// `X.prototype` operand it needs (a handle into an instance cell).
|
|
2873
|
+
const member = node.parent;
|
|
2874
|
+
if (ts.isPropertyAccessExpression(member) && member.expression === node) {
|
|
2875
|
+
const borrow = member.parent;
|
|
2876
|
+
if (ts.isPropertyAccessExpression(borrow) && borrow.expression === member && borrowedPrototypeMethodNames.has(borrow.name.text)) {
|
|
2877
|
+
if (!receiverDispatchingPrototypes.has(instanceType.getSymbol()?.name ?? '') ||
|
|
2878
|
+
receiverGenericPrototypeMembers.has(member.name.text)) {
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
const instance = table.get(typeOf(instanceType)).shape;
|
|
2884
|
+
// `Object.prototype`: the ONE ambient instance interface `typeOf`
|
|
2885
|
+
// deliberately collapses to `any` everywhere else
|
|
2886
|
+
// (`derived-expression-type.ts`'s `isGlobalObjectInterface` -- a
|
|
2887
|
+
// `: Object`-typed value states nothing, and that collapse is measured
|
|
2888
|
+
// and load-bearing, so it must keep firing for every OTHER read of this
|
|
2889
|
+
// exact `ts.Type`). This one occurrence names the SLOT itself, not an
|
|
2890
|
+
// ordinary Object-typed value: the declared shape it anchors is keyed by
|
|
2891
|
+
// the `prototype` slot's own declaration id, never by `instanceType`'s
|
|
2892
|
+
// shared identity, so it can safely carry a body the collapsed cache does
|
|
2893
|
+
// not. `Object`'s instance interface declares no DATA members at all --
|
|
2894
|
+
// `toString`/`valueOf`/`hasOwnProperty`/`isPrototypeOf`/
|
|
2895
|
+
// `propertyIsEnumerable`/`toLocaleString` are all methods -- so an empty
|
|
2896
|
+
// ambient body is the exact starting point `prototypeMethodBodyOf` needs
|
|
2897
|
+
// to inject them, the same way an ordinary ambient interned body is for
|
|
2898
|
+
// Date/RegExp/Boolean/String/Number.
|
|
2899
|
+
const dataBody = instance.kind === 'declared'
|
|
2900
|
+
? instance.body
|
|
2901
|
+
: isGlobalObjectInterface(checker, declaration, instanceType)
|
|
2902
|
+
? table.intern({ kind: 'object', members: [], index: [], membersDropped: true })
|
|
2903
|
+
: null;
|
|
2904
|
+
if (instance.kind !== 'declared' && dataBody === null)
|
|
2905
|
+
return null;
|
|
2906
|
+
const id = identities.declarationIdOf(declaration);
|
|
2907
|
+
const { id: anchor, fresh } = table.anchor(`declared:${id}:`);
|
|
2908
|
+
if (fresh)
|
|
2909
|
+
table.complete(anchor, {
|
|
2910
|
+
kind: 'declared',
|
|
2911
|
+
declaration: id,
|
|
2912
|
+
typeArguments: [],
|
|
2913
|
+
body: prototypeMethodBodyOf(dataBody, instanceType)
|
|
2914
|
+
});
|
|
2915
|
+
return anchor;
|
|
2916
|
+
};
|
|
2917
|
+
// The prototype object's body: the instance's data members, plus every
|
|
2918
|
+
// method the instance interface declares -- an ambient body is interned
|
|
2919
|
+
// DATA-ONLY (`membersDropped`), and the prototype is exactly the object
|
|
2920
|
+
// whose own members those methods are. A prototype method read as a VALUE
|
|
2921
|
+
// takes its receiver from whoever calls it -- `getTime.call(0)`,
|
|
2922
|
+
// `getTime.call(new Date())` -- and 21.4.4's `thisTimeValue(this value)`
|
|
2923
|
+
// decides at that moment whether it is a Date. An interface method's
|
|
2924
|
+
// signature carries no receiver (its `this` is the instance, implicitly,
|
|
2925
|
+
// never a physical slot), so the prototype's copy of each method states
|
|
2926
|
+
// one: `any`, the carrier that holds every value a caller may pass. The
|
|
2927
|
+
// emitted callable (`hostPrototypeMethodValueText`) performs the brand
|
|
2928
|
+
// check on it.
|
|
2929
|
+
const prototypeMethodBodyOf = (body, instanceType) => {
|
|
2930
|
+
if (body === null)
|
|
2931
|
+
return null;
|
|
2932
|
+
const shape = table.get(body).shape;
|
|
2933
|
+
if (shape.kind !== 'object')
|
|
2934
|
+
return body;
|
|
2935
|
+
const receiver = table.intern({ kind: 'primitive', primitive: 'any' });
|
|
2936
|
+
const methods = [];
|
|
2937
|
+
for (const symbol of checker.getPropertiesOfType(instanceType)) {
|
|
2938
|
+
const method = symbol.declarations?.find(ts.isMethodSignature);
|
|
2939
|
+
if (!method || shape.members.some((member) => member.key.kind === 'string' && member.key.value === symbol.getName()))
|
|
2940
|
+
continue;
|
|
2941
|
+
const type = table.get(typeOf(checker.getTypeOfSymbolAtLocation(symbol, method))).shape;
|
|
2942
|
+
if (type.kind !== 'signature' || type.call.length === 0)
|
|
2943
|
+
continue;
|
|
2944
|
+
// An overloaded method (`toLocaleDateString(): string` beside
|
|
2945
|
+
// `(locales?, options?): string`) is one function object with one
|
|
2946
|
+
// frame; the copy states its widest overload, which every narrower
|
|
2947
|
+
// call fits through its optionals.
|
|
2948
|
+
const widest = type.call.reduce((best, signature) => (signature.parameters.length > best.parameters.length ? signature : best));
|
|
2949
|
+
methods.push({
|
|
2950
|
+
key: { kind: 'string', value: symbol.getName() },
|
|
2951
|
+
type: table.intern({ ...type, call: [{ ...widest, thisParameter: receiver }] }),
|
|
2952
|
+
optional: false,
|
|
2953
|
+
readonly: false,
|
|
2954
|
+
accessor: null
|
|
2955
|
+
});
|
|
2956
|
+
}
|
|
2957
|
+
return table.intern({ ...shape, members: [...shape.members, ...methods], membersDropped: false });
|
|
2958
|
+
};
|
|
2959
|
+
// A method read off the prototype object (`Date.prototype.getTime`, or
|
|
2960
|
+
// `obj.getTime` where `obj` is the prototype through a parameter) is the
|
|
2961
|
+
// prototype's own copy of it -- the receiver-taking signature above -- not
|
|
2962
|
+
// the instance's, which is what the checker answers for the access.
|
|
2963
|
+
const prototypeObjectMemberTypeAt = (node) => {
|
|
2964
|
+
if (!ts.isPropertyAccessExpression(node))
|
|
2965
|
+
return null;
|
|
2966
|
+
const receiver = prototypeObjectTypeAt(node.expression) ?? prototypeObjectParameterTypeAt(node.expression);
|
|
2967
|
+
if (receiver === null)
|
|
2968
|
+
return null;
|
|
2969
|
+
const shape = table.get(receiver).shape;
|
|
2970
|
+
if (shape.kind !== 'declared' || shape.body === null)
|
|
2971
|
+
return null;
|
|
2972
|
+
const body = table.get(shape.body).shape;
|
|
2973
|
+
if (body.kind !== 'object')
|
|
2974
|
+
return null;
|
|
2975
|
+
const member = body.members.find((candidate) => candidate.key.kind === 'string' && candidate.key.value === node.name.text);
|
|
2976
|
+
return member?.type ?? null;
|
|
2977
|
+
};
|
|
2978
|
+
// A local initialized to the prototype object or one of its methods
|
|
2979
|
+
// (`var getTime = Date.prototype.getTime`) and never written again holds
|
|
2980
|
+
// exactly that value: the declaration and every read of it answer the
|
|
2981
|
+
// prototype's own type, ahead of the local census, whose ts.Type-space
|
|
2982
|
+
// answer is the instance's. Asked at the declaration AND at each reference
|
|
2983
|
+
// so the cell and its reads cannot disagree (the trap the note at the top
|
|
2984
|
+
// of `typeAt` describes).
|
|
2985
|
+
const prototypeObjectLocalTypeAt = (node) => {
|
|
2986
|
+
const declaration = ts.isVariableDeclaration(node)
|
|
2987
|
+
? node
|
|
2988
|
+
: ts.isIdentifier(node) && !ts.isVariableDeclaration(node.parent)
|
|
2989
|
+
? (checker.getSymbolAtLocation(node)?.valueDeclaration ?? null)
|
|
2990
|
+
: null;
|
|
2991
|
+
if (declaration === null || !ts.isVariableDeclaration(declaration) || !declaration.initializer || !ts.isIdentifier(declaration.name))
|
|
2992
|
+
return null;
|
|
2993
|
+
const initializer = declaration.initializer;
|
|
2994
|
+
if (!ts.isPropertyAccessExpression(initializer))
|
|
2995
|
+
return null;
|
|
2996
|
+
const writes = flow?.writesToDeclaration(declaration) ?? null;
|
|
2997
|
+
// Only a WHOLE-slot write re-binds the cell; `f[k] = v` on the held method
|
|
2998
|
+
// (propertyHelper's `isWritable` writing `length`) is a member write on
|
|
2999
|
+
// the function object the cell keeps holding.
|
|
3000
|
+
if (writes === null || writes.some((write) => write.slot === 'whole' && write.value !== initializer))
|
|
3001
|
+
return null;
|
|
3002
|
+
return prototypeObjectMemberTypeAt(initializer) ?? prototypeObjectTypeAt(initializer);
|
|
3003
|
+
};
|
|
3004
|
+
// A parameter every call site hands `X.prototype` to, and every read of it:
|
|
3005
|
+
// the census bound it to the checker's image of the argument (the instance
|
|
3006
|
+
// type), so it is re-asked here from the argument expressions themselves.
|
|
3007
|
+
// One disagreeing site returns the question to the census's answer.
|
|
3008
|
+
const prototypeObjectParameterTypeAt = (node, visiting = new Set()) => {
|
|
3009
|
+
const parameter = ts.isParameter(node)
|
|
3010
|
+
? node
|
|
3011
|
+
: ts.isIdentifier(node) && !ts.isParameter(node.parent)
|
|
3012
|
+
? (checker.getSymbolAtLocation(node)?.valueDeclaration ?? null)
|
|
3013
|
+
: null;
|
|
3014
|
+
if (parameter === null || !ts.isParameter(parameter) || visiting.has(parameter))
|
|
3015
|
+
return null;
|
|
3016
|
+
const passed = parameters.argumentsAt?.(parameter) ?? null;
|
|
3017
|
+
if (passed === null || passed.length === 0)
|
|
3018
|
+
return null;
|
|
3019
|
+
visiting.add(parameter);
|
|
3020
|
+
let agreed = null;
|
|
3021
|
+
for (const argument of passed) {
|
|
3022
|
+
// The handle travels through helper calls (`verifyProperty(obj, ...)`
|
|
3023
|
+
// forwards `obj` to `isWritable(obj, ...)`), so an argument that is
|
|
3024
|
+
// itself such a parameter is asked the same question.
|
|
3025
|
+
const own = prototypeObjectTypeAt(argument) ??
|
|
3026
|
+
prototypeObjectMemberTypeAt(argument) ??
|
|
3027
|
+
prototypeObjectLocalTypeAt(argument) ??
|
|
3028
|
+
prototypeObjectParameterTypeAt(argument, visiting);
|
|
3029
|
+
if (own === null || (agreed !== null && agreed !== own))
|
|
3030
|
+
return null;
|
|
3031
|
+
agreed = own;
|
|
3032
|
+
}
|
|
3033
|
+
return agreed;
|
|
3034
|
+
};
|
|
3035
|
+
// The SIGNATURE side of the `unstated-never-array` rule's parameter form.
|
|
3036
|
+
// A parameter the collection census refused as part of an array's alias
|
|
3037
|
+
// component carries the box the caller's own cell carries; without this the
|
|
3038
|
+
// body's binding reads that box while the ABI still declares the checker's
|
|
3039
|
+
// image of the parameter, and `projection/abi.ts` refuses the convention
|
|
3040
|
+
// with "parameter N is bound as X but the ABI declares Y".
|
|
3041
|
+
const refusedArrayParameterTypeAt = (parameter) => {
|
|
3042
|
+
if (!unstatedNeverArray(checker, collections, layoutTypeAt, parameter))
|
|
3043
|
+
return null;
|
|
3044
|
+
return table.intern({
|
|
3045
|
+
kind: 'array',
|
|
3046
|
+
element: table.intern({ kind: 'primitive', primitive: 'any' }),
|
|
3047
|
+
readonly: false,
|
|
3048
|
+
extension: []
|
|
3049
|
+
});
|
|
3050
|
+
};
|
|
3051
|
+
/** A callable type with the receiver its signatures state removed: what `Function.prototype.bind` produces. */
|
|
3052
|
+
const withoutReceiver = (id) => {
|
|
3053
|
+
const shape = table.get(id).shape;
|
|
3054
|
+
if (shape.kind === 'union')
|
|
3055
|
+
return table.intern({ ...shape, members: shape.members.map(withoutReceiver) });
|
|
3056
|
+
if (shape.kind !== 'signature' || shape.call.every((call) => call.thisParameter === null))
|
|
3057
|
+
return id;
|
|
3058
|
+
return table.intern({ ...shape, call: shape.call.map((call) => ({ ...call, thisParameter: null })) });
|
|
3059
|
+
};
|
|
3060
|
+
const boundCallResultAt = (node) => ts.isCallExpression(node) && builtinBindSignatureAt(node.expression) ? withoutReceiver(typeOf(checker.getTypeAtLocation(node))) : null;
|
|
3061
|
+
/**
|
|
3062
|
+
* `const readFile = host.readFile.bind(host)`: the cell, and every read of
|
|
3063
|
+
* it, holds what the bind produced. The checker types both with the
|
|
3064
|
+
* METHOD's own type (the same object `OmitThisParameter` hands back), so
|
|
3065
|
+
* the answer has to come from the initializer. A `let` keeps the checker's
|
|
3066
|
+
* type: a later write may store a method value the cell then has to bind.
|
|
3067
|
+
*/
|
|
3068
|
+
const boundCellResultAt = (node) => {
|
|
3069
|
+
const declaration = ts.isVariableDeclaration(node)
|
|
3070
|
+
? node
|
|
3071
|
+
: ts.isIdentifier(node)
|
|
3072
|
+
? checker.getSymbolAtLocation(node)?.valueDeclaration
|
|
3073
|
+
: undefined;
|
|
3074
|
+
if (!declaration || !ts.isVariableDeclaration(declaration) || declaration.type !== undefined || !declaration.initializer)
|
|
3075
|
+
return null;
|
|
3076
|
+
if ((ts.getCombinedNodeFlags(declaration) & ts.NodeFlags.Const) === 0)
|
|
3077
|
+
return null;
|
|
3078
|
+
return boundCallResultAt(declaration.initializer);
|
|
3079
|
+
};
|
|
3080
|
+
/** The one `Function.prototype.bind` overload this call site resolved to, or `null` where the read is not that. */
|
|
3081
|
+
const builtinBindSignatureAt = (node) => {
|
|
3082
|
+
if (!ts.isPropertyAccessExpression(node) || node.name.text !== 'bind')
|
|
3083
|
+
return null;
|
|
3084
|
+
const call = node.parent;
|
|
3085
|
+
if (!ts.isCallExpression(call) || call.expression !== node)
|
|
3086
|
+
return null;
|
|
3087
|
+
// `host.realpath?.bind(host)`: an optional link's own type is the union
|
|
3088
|
+
// with the absence, which declares no call signature at all -- the
|
|
3089
|
+
// callable this binds is the payload.
|
|
3090
|
+
const receiver = checker.getNonNullableType(checker.getTypeAtLocation(node.expression));
|
|
3091
|
+
if (checker.getSignaturesOfType(receiver, ts.SignatureKind.Call).length === 0)
|
|
3092
|
+
return null;
|
|
3093
|
+
if (checker.getNonNullableType(checker.getTypeAtLocation(node)).getCallSignatures().length < 2)
|
|
3094
|
+
return null;
|
|
3095
|
+
const resolved = checker.getResolvedSignature(call);
|
|
3096
|
+
// Only the ambient declaration's own overloads: a program declaring its
|
|
3097
|
+
// own `bind` member keeps whatever its declaration states.
|
|
3098
|
+
return resolved?.declaration?.getSourceFile().isDeclarationFile ? resolved : null;
|
|
3099
|
+
};
|
|
3100
|
+
/** Whether `node` is a `for (const key in object)` head the loop declares, or a read of one. */
|
|
3101
|
+
const forInKeyAt = (node) => {
|
|
3102
|
+
// The declaration node itself is what `producers/bindings.ts` asks for the
|
|
3103
|
+
// cell's carrier; an identifier is every read of it.
|
|
3104
|
+
const declarations = ts.isVariableDeclaration(node)
|
|
3105
|
+
? [node]
|
|
3106
|
+
: ts.isIdentifier(node)
|
|
3107
|
+
? (checker.getSymbolAtLocation(node)?.declarations ?? [])
|
|
3108
|
+
: [];
|
|
3109
|
+
const declaration = declarations.length === 1 ? declarations[0] : undefined;
|
|
3110
|
+
if (!declaration || !ts.isVariableDeclaration(declaration) || !ts.isIdentifier(declaration.name))
|
|
3111
|
+
return false;
|
|
3112
|
+
const list = declaration.parent;
|
|
3113
|
+
if (!ts.isVariableDeclarationList(list))
|
|
3114
|
+
return false;
|
|
3115
|
+
const statement = list.parent;
|
|
3116
|
+
return ts.isForInStatement(statement) && statement.initializer === list;
|
|
3117
|
+
};
|
|
3118
|
+
/**
|
|
3119
|
+
* What a binding pattern's own INITIALIZER is worth to the pattern.
|
|
3120
|
+
*
|
|
3121
|
+
* Normally the initializer expression itself, which is what the pattern
|
|
3122
|
+
* destructures. An `as`/`satisfies`/`!`/`<T>x` wrapper is the exception, and
|
|
3123
|
+
* only when what it wraps is an ARRAY: those wrappers evaluate to nothing of
|
|
3124
|
+
* their own (`producers/erasure.ts`), so `citeExpressionResult` cites the
|
|
3125
|
+
* WRAPPED expression's result -- and the pattern that then reads that result
|
|
3126
|
+
* by index was being typed off the assertion instead. hono's
|
|
3127
|
+
* `defineWebSocketHelper` writes the shape exactly: `const [createEvents,
|
|
3128
|
+
* options] = args as [(c: Ctx) => Events, number?]` over a rest parameter,
|
|
3129
|
+
* whose value is one Array. `lower-destructuring.ts` refused the pair --
|
|
3130
|
+
* 'an array binding pattern's source resolved to "array-object(...)", but its
|
|
3131
|
+
* own iterator-record result selected "record(...)"' -- and it was right to:
|
|
3132
|
+
* the two really did describe different values.
|
|
3133
|
+
*
|
|
3134
|
+
* The assertion is not discarded, it is put where it belongs. A tuple
|
|
3135
|
+
* assertion over an array states the ARITY and the per-position types the
|
|
3136
|
+
* program is claiming, which the element reads still take from the pattern's
|
|
3137
|
+
* raw checker type (`producers/destructuring.ts`'s `elementTypeOf` asks
|
|
3138
|
+
* `isTupleType` of it); what it cannot state is a different CARRIER, because
|
|
3139
|
+
* `as` performs no conversion. Gated on the wrapped value actually being an
|
|
3140
|
+
* array so nothing else moves: an assertion over a `foo()` whose own type is
|
|
3141
|
+
* `unknown` keeps answering from the assertion, where it is the only thing
|
|
3142
|
+
* that states anything at all.
|
|
3143
|
+
*/
|
|
3144
|
+
const patternSourceTypeAt = (initializer) => {
|
|
3145
|
+
const erased = unwrapErasedExpression(initializer);
|
|
3146
|
+
if (erased === initializer)
|
|
3147
|
+
return mapper.typeAt(initializer);
|
|
3148
|
+
const source = mapper.typeAt(erased);
|
|
3149
|
+
return table.get(source).shape.kind === 'array' ? source : mapper.typeAt(initializer);
|
|
3150
|
+
};
|
|
3151
|
+
/**
|
|
3152
|
+
* Every step of `typeAt`, in the order the chain asked them.
|
|
3153
|
+
*
|
|
3154
|
+
* the frontend's evidence-policy tables. This was thirty-nine `if (answer)
|
|
3155
|
+
* return answer` statements whose ORDER was the answer wherever two of them
|
|
3156
|
+
* could speak for one node -- and which of them could was not written down
|
|
3157
|
+
* anywhere, because an `if` states no domain. Stating each step as a rule
|
|
3158
|
+
* that names the FORMS it serves makes the domain a declaration: a rule that
|
|
3159
|
+
* cannot answer for a node is never asked, and two rules claiming one form
|
|
3160
|
+
* are a disagreement `GEA_STRUCTURAL_DISAGREEMENT` can name, rather than a
|
|
3161
|
+
* precedence nobody chose.
|
|
3162
|
+
*
|
|
3163
|
+
* Order is preserved exactly as the chain had it, so this port changes no
|
|
3164
|
+
* answer. `forms: null` means the step's own first test is not a node-kind
|
|
3165
|
+
* test, so its domain is still unknown and order still decides for it; each
|
|
3166
|
+
* one is a row this phase owes a form, and the count of them is the honest
|
|
3167
|
+
* measure of how far the port has got.
|
|
3168
|
+
*/
|
|
3169
|
+
const mutableMethods = createMutableMethodResolver(checker, table, flow, signatureOf, (node) => mapper.typeAt(node), (node) => mapper.rawTypeAt(node));
|
|
3170
|
+
const structuralRules = [
|
|
3171
|
+
{
|
|
3172
|
+
name: 'mutable-method-storage',
|
|
3173
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression, ts.SyntaxKind.ElementAccessExpression],
|
|
3174
|
+
resolve: mutableMethods.readTypeAt
|
|
3175
|
+
},
|
|
3176
|
+
{
|
|
3177
|
+
// A CommonJS wrapper's `module` is not the ambient `{ exports: any }`
|
|
3178
|
+
// silhouette when the source itself proves one exact top-level callable
|
|
3179
|
+
// export. Keep the record local to that source module and map the same
|
|
3180
|
+
// expression at `module.exports` and a resolved `require` so a binding
|
|
3181
|
+
// cannot store a function while its read asks for a dynamic record.
|
|
3182
|
+
name: 'module-exports-record',
|
|
3183
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
3184
|
+
resolve: (node) => {
|
|
3185
|
+
const moduleExport = moduleRecords.moduleExportExpressionAt(node);
|
|
3186
|
+
if (moduleExport) {
|
|
3187
|
+
return table.intern({
|
|
3188
|
+
kind: 'object',
|
|
3189
|
+
members: [
|
|
3190
|
+
{
|
|
3191
|
+
key: { kind: 'string', value: 'exports' },
|
|
3192
|
+
type: mapper.typeAt(moduleExport),
|
|
3193
|
+
optional: false,
|
|
3194
|
+
readonly: false,
|
|
3195
|
+
accessor: null
|
|
3196
|
+
}
|
|
3197
|
+
],
|
|
3198
|
+
index: [],
|
|
3199
|
+
membersDropped: false
|
|
3200
|
+
});
|
|
3201
|
+
}
|
|
3202
|
+
return null;
|
|
3203
|
+
}
|
|
3204
|
+
},
|
|
3205
|
+
{
|
|
3206
|
+
name: 'exported-expression',
|
|
3207
|
+
// The erasure wrappers are in the domain because `unwrapExpression` peels
|
|
3208
|
+
// them before testing for an `exports` access, so the node ASKED about can
|
|
3209
|
+
// be the wrapper rather than the access underneath it.
|
|
3210
|
+
forms: [
|
|
3211
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
3212
|
+
ts.SyntaxKind.ElementAccessExpression,
|
|
3213
|
+
ts.SyntaxKind.ParenthesizedExpression,
|
|
3214
|
+
ts.SyntaxKind.AsExpression,
|
|
3215
|
+
ts.SyntaxKind.TypeAssertionExpression,
|
|
3216
|
+
ts.SyntaxKind.NonNullExpression,
|
|
3217
|
+
ts.SyntaxKind.SatisfiesExpression,
|
|
3218
|
+
ts.SyntaxKind.PartiallyEmittedExpression,
|
|
3219
|
+
ts.SyntaxKind.CallExpression
|
|
3220
|
+
],
|
|
3221
|
+
resolve: (node) => {
|
|
3222
|
+
const exported = moduleRecords.exportExpressionAt(node) ?? moduleRecords.requiredExportExpressionAt(node);
|
|
3223
|
+
if (exported)
|
|
3224
|
+
return mapper.typeAt(exported);
|
|
3225
|
+
return null;
|
|
3226
|
+
}
|
|
3227
|
+
},
|
|
3228
|
+
{
|
|
3229
|
+
// `undefined as unknown as number` -- the shape every hand-written
|
|
3230
|
+
// iterator's `done: true` result has. An assertion is not a conversion:
|
|
3231
|
+
// the value that actually arrives is still the literal, and the asserted
|
|
3232
|
+
// type is only what consumers must accept. Publishing the asserted type
|
|
3233
|
+
// alone gave `{ value: undefined as unknown as number }` a `double` field,
|
|
3234
|
+
// and the emitter then had nowhere to put an `undefined` that faults --
|
|
3235
|
+
// `cppConstantLiteral` refuses a `double` for exactly that reason, so the
|
|
3236
|
+
// absence has to be in the carrier or the program has no honest emission.
|
|
3237
|
+
name: 'absence-assertion',
|
|
3238
|
+
forms: [ts.SyntaxKind.AsExpression, ts.SyntaxKind.TypeAssertionExpression],
|
|
3239
|
+
resolve: (node) => {
|
|
3240
|
+
if (ts.isAsExpression(node) || ts.isTypeAssertionExpression(node)) {
|
|
3241
|
+
const inner = unwrapErasedExpression(node.expression);
|
|
3242
|
+
const absent = inner.kind === ts.SyntaxKind.NullKeyword ? 'null' : ts.isIdentifier(inner) && inner.text === 'undefined' ? 'undefined' : null;
|
|
3243
|
+
if (absent !== null) {
|
|
3244
|
+
const asserted = typeOf(checker.getTypeAtLocation(node));
|
|
3245
|
+
return table.intern({ kind: 'union', members: [asserted, table.intern({ kind: 'primitive', primitive: absent })] });
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
return null;
|
|
3249
|
+
}
|
|
3250
|
+
},
|
|
3251
|
+
{
|
|
3252
|
+
// A `for (const key in object)` head, and every read of it. The language
|
|
3253
|
+
// answers outright and without reference to the object: for-in enumerates
|
|
3254
|
+
// own enumerable STRING keys. TypeScript spells the binding
|
|
3255
|
+
// `Extract<keyof T, string>` so an index back into the same object narrows,
|
|
3256
|
+
// and inside a generic that spelling stays a conditional the checker
|
|
3257
|
+
// defers -- so the binding and every read in the loop body published an
|
|
3258
|
+
// unresolved carrier. tsc's `assign` and `copyProperties` are the measured
|
|
3259
|
+
// case; the census answers `string` for the bare-identifier and
|
|
3260
|
+
// destructured heads already, and a head the loop DECLARES had no rule.
|
|
3261
|
+
name: 'for-in-key-is-a-string',
|
|
3262
|
+
forms: [ts.SyntaxKind.VariableDeclaration, ts.SyntaxKind.Identifier],
|
|
3263
|
+
resolve: (node) => {
|
|
3264
|
+
if (forInKeyAt(node))
|
|
3265
|
+
return typeOf(checker.getStringType());
|
|
3266
|
+
return null;
|
|
3267
|
+
}
|
|
3268
|
+
},
|
|
3269
|
+
{
|
|
3270
|
+
// A binding, a read of it, or the choice expression itself, holding one of
|
|
3271
|
+
// several generic source functions: the union of the members' OPEN types,
|
|
3272
|
+
// never the checker's subtype-reduced declared type -- see
|
|
3273
|
+
// `generic-function-choice.ts`. Interned through this view's `typeOf`, so
|
|
3274
|
+
// a member whose type parameters THIS path binds (its own copy) reads as
|
|
3275
|
+
// that copy's closed callable, exactly as its bare name would.
|
|
3276
|
+
name: 'generic-function-choice',
|
|
3277
|
+
forms: [
|
|
3278
|
+
ts.SyntaxKind.ConditionalExpression,
|
|
3279
|
+
ts.SyntaxKind.BinaryExpression,
|
|
3280
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3281
|
+
ts.SyntaxKind.Identifier,
|
|
3282
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
3283
|
+
ts.SyntaxKind.ParenthesizedExpression,
|
|
3284
|
+
ts.SyntaxKind.AsExpression,
|
|
3285
|
+
ts.SyntaxKind.NonNullExpression,
|
|
3286
|
+
ts.SyntaxKind.SatisfiesExpression,
|
|
3287
|
+
ts.SyntaxKind.TypeAssertionExpression
|
|
3288
|
+
],
|
|
3289
|
+
resolve: (node) => {
|
|
3290
|
+
const choice = genericFunctionChoiceMembersOf(checker, node);
|
|
3291
|
+
if (choice) {
|
|
3292
|
+
return table.intern({
|
|
3293
|
+
kind: 'union',
|
|
3294
|
+
members: choice.map((member) => typeOf(checker.getTypeAtLocation(member.name ?? member)))
|
|
3295
|
+
});
|
|
3296
|
+
}
|
|
3297
|
+
return null;
|
|
3298
|
+
}
|
|
3299
|
+
},
|
|
3300
|
+
{
|
|
3301
|
+
// A generic source function handed to a slot that states ONE closed
|
|
3302
|
+
// signature: `match: typeof match<Router<T>, T> = match` (hono's
|
|
3303
|
+
// `RegExpRouter`), `const f: (x: number) => number = identity`.
|
|
3304
|
+
//
|
|
3305
|
+
// The checker's type for the name is the OPEN generic, which derives to
|
|
3306
|
+
// `generic-function-set` -- a choice tag, not a callable -- while the
|
|
3307
|
+
// slot derives to `function-value-dispatch`. No conversion exists
|
|
3308
|
+
// between the two and none can: a set index is not a frame. The two
|
|
3309
|
+
// authorities disagree and the slot is the one that is right, because it
|
|
3310
|
+
// states the instantiation and the name states none.
|
|
3311
|
+
//
|
|
3312
|
+
// Reading the contextual signature here is the SAME question
|
|
3313
|
+
// `specialization.ts`'s `fromValueUse` already asks at this same node to
|
|
3314
|
+
// mint the copy (its "contextual type is a closed signature" branch), so
|
|
3315
|
+
// the copy this type names exists by construction rather than by
|
|
3316
|
+
// coincidence. Only a contextual type with exactly one call signature
|
|
3317
|
+
// and no type parameters of its own qualifies: a generic contextual type
|
|
3318
|
+
// (`const nodeVisitor: NodeVisitor = visitNode`) is a set the value stays
|
|
3319
|
+
// open in, and an overload set states no single frame.
|
|
3320
|
+
name: 'generic-function-value-at-stated-instantiation',
|
|
3321
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
3322
|
+
resolve: (node) => {
|
|
3323
|
+
if (!ts.isIdentifier(node) || !ts.isExpression(node))
|
|
3324
|
+
return null;
|
|
3325
|
+
const declaration = checker.getSymbolAtLocation(node)?.declarations?.[0];
|
|
3326
|
+
if (!declaration || !genericSourceFunctionDeclarationOf(declaration))
|
|
3327
|
+
return null;
|
|
3328
|
+
const contextual = checker.getContextualType(node);
|
|
3329
|
+
const signatures = contextual?.getCallSignatures() ?? [];
|
|
3330
|
+
const only = signatures.length === 1 ? signatures[0] : undefined;
|
|
3331
|
+
if (!contextual || !only || (only.getTypeParameters()?.length ?? 0) > 0)
|
|
3332
|
+
return null;
|
|
3333
|
+
if (contextual.getConstructSignatures().length > 0)
|
|
3334
|
+
return null;
|
|
3335
|
+
return typeOf(contextual);
|
|
3336
|
+
}
|
|
3337
|
+
},
|
|
3338
|
+
{
|
|
3339
|
+
// A binding pattern's type IS its source's: the pattern is the reference
|
|
3340
|
+
// half of `bind(reference, value)` and holds nothing of its own. The
|
|
3341
|
+
// checker types the pattern node from its own shape instead (a `[]`
|
|
3342
|
+
// initializer contextually typed by the pattern becomes the empty TUPLE
|
|
3343
|
+
// at the pattern while the literal itself is an array).
|
|
3344
|
+
name: 'binding-pattern-is-its-source',
|
|
3345
|
+
forms: [ts.SyntaxKind.ArrayBindingPattern, ts.SyntaxKind.ObjectBindingPattern],
|
|
3346
|
+
resolve: (node) => {
|
|
3347
|
+
// Re-tested rather than left to `forms`: a rule must answer correctly
|
|
3348
|
+
// for ANY node it is handed. `forms` is a claim the dispatcher can act
|
|
3349
|
+
// on and the audit can check, never the thing that makes a rule right
|
|
3350
|
+
// -- and this rule proved why. It was the first one ported, its kind
|
|
3351
|
+
// test was lifted into `forms` instead of kept, and it then answered
|
|
3352
|
+
// for call expressions, identifiers and string literals the moment
|
|
3353
|
+
// `GEA_STRUCTURAL_FORM_AUDIT` asked it outside its declared forms.
|
|
3354
|
+
if (!ts.isArrayBindingPattern(node) && !ts.isObjectBindingPattern(node))
|
|
3355
|
+
return null;
|
|
3356
|
+
const parent = node.parent;
|
|
3357
|
+
if (ts.isVariableDeclaration(parent) && parent.initializer)
|
|
3358
|
+
return patternSourceTypeAt(parent.initializer);
|
|
3359
|
+
if (ts.isParameter(parent) || ts.isBindingElement(parent))
|
|
3360
|
+
return mapper.typeAt(parent);
|
|
3361
|
+
return null;
|
|
3362
|
+
}
|
|
3363
|
+
},
|
|
3364
|
+
{
|
|
3365
|
+
// `Function.prototype.bind`, read as the callee of its own call. The
|
|
3366
|
+
// ambient declaration is FIVE overloads -- one per bound-argument arity --
|
|
3367
|
+
// and a value cannot be five conventions, so interning the read's own type
|
|
3368
|
+
// published `unresolved(no primitive joining 2 overload signatures into
|
|
3369
|
+
// one calling convention)` and killed every `host.readFile.bind(host)` in
|
|
3370
|
+
// the program (tsc's `program.ts`, `maybeBind`). TypeScript has already
|
|
3371
|
+
// chosen one overload at this site -- the argument count and the source's
|
|
3372
|
+
// own `this` type decide it -- so the read is that one signature, asked
|
|
3373
|
+
// for at the call the read is the callee of and nowhere else.
|
|
3374
|
+
//
|
|
3375
|
+
// `.call`/`.apply` need no such rule: each is declared once, and a borrow
|
|
3376
|
+
// through them is rewritten at the call anyway
|
|
3377
|
+
// (`ir/lower-invocation.ts`'s `deferredExplicitThisCalleeOf`).
|
|
3378
|
+
//
|
|
3379
|
+
// Asked EARLY: an optional link (`host.realpath?.bind`) is a union of the
|
|
3380
|
+
// overload set with the absence, and the local-union resolver above would
|
|
3381
|
+
// otherwise publish that union -- overload set included -- before this
|
|
3382
|
+
// rule was ever reached. The absence itself is kept, since the read really
|
|
3383
|
+
// can produce none.
|
|
3384
|
+
name: 'builtin-bind-signature',
|
|
3385
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3386
|
+
resolve: (node) => {
|
|
3387
|
+
const boundBuiltin = builtinBindSignatureAt(node);
|
|
3388
|
+
if (boundBuiltin) {
|
|
3389
|
+
// The overload's result is the bound callable, receiver-less -- the
|
|
3390
|
+
// same answer the call node gives below, so the invocation producer
|
|
3391
|
+
// sees one return type from both.
|
|
3392
|
+
const signature = signatureOf(boundBuiltin);
|
|
3393
|
+
const bound = table.intern({
|
|
3394
|
+
kind: 'signature',
|
|
3395
|
+
call: [{ ...signature, result: withoutReceiver(signature.result) }],
|
|
3396
|
+
construct: []
|
|
3397
|
+
});
|
|
3398
|
+
const own = checker.getTypeAtLocation(node);
|
|
3399
|
+
const absences = (own.isUnion() ? own.types : []).filter((member) => (member.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) !== 0);
|
|
3400
|
+
return absences.length === 0 ? bound : table.intern({ kind: 'union', members: [bound, ...absences.map(typeOf)] });
|
|
3401
|
+
}
|
|
3402
|
+
return null;
|
|
3403
|
+
}
|
|
3404
|
+
},
|
|
3405
|
+
{
|
|
3406
|
+
// The bound function `host.readFile.bind(host)` PRODUCES: the checker
|
|
3407
|
+
// types it `OmitThisParameter<T>`, which for a method is `T` itself, and
|
|
3408
|
+
// `T`'s signature still names the method's implicit receiver
|
|
3409
|
+
// (`structural-receiver.ts`). The bound callable has none -- `bind` fixed
|
|
3410
|
+
// it -- so a value read out of this call must state a receiver-less
|
|
3411
|
+
// convention, or every slot it enters would be asked to bind the receiver
|
|
3412
|
+
// a second time. The absence of an optional link is kept as above.
|
|
3413
|
+
name: 'bound-call-result',
|
|
3414
|
+
forms: [ts.SyntaxKind.CallExpression, ts.SyntaxKind.VariableDeclaration, ts.SyntaxKind.Identifier],
|
|
3415
|
+
resolve: (node) => {
|
|
3416
|
+
const bound = boundCallResultAt(node) ?? boundCellResultAt(node);
|
|
3417
|
+
if (bound !== null)
|
|
3418
|
+
return bound;
|
|
3419
|
+
return null;
|
|
3420
|
+
}
|
|
3421
|
+
},
|
|
3422
|
+
{
|
|
3423
|
+
name: 'prototype-object-local',
|
|
3424
|
+
forms: [ts.SyntaxKind.VariableDeclaration, ts.SyntaxKind.Identifier],
|
|
3425
|
+
resolve: (node) => {
|
|
3426
|
+
const prototypeLocal = prototypeObjectLocalTypeAt(node);
|
|
3427
|
+
if (prototypeLocal)
|
|
3428
|
+
return prototypeLocal;
|
|
3429
|
+
return null;
|
|
3430
|
+
}
|
|
3431
|
+
},
|
|
3432
|
+
{
|
|
3433
|
+
name: 'array-pattern-rest',
|
|
3434
|
+
// The identifier arm resolves a SYMBOL to its declaration, so what that
|
|
3435
|
+
// declaration turns out to be does not widen the domain: the node asked
|
|
3436
|
+
// about is still only ever the element or a name for it.
|
|
3437
|
+
forms: [ts.SyntaxKind.BindingElement, ts.SyntaxKind.Identifier],
|
|
3438
|
+
resolve: (node) => {
|
|
3439
|
+
const restArray = arrayPatternRestTypeAt(node);
|
|
3440
|
+
if (restArray)
|
|
3441
|
+
return restArray;
|
|
3442
|
+
return null;
|
|
3443
|
+
}
|
|
3444
|
+
},
|
|
3445
|
+
{
|
|
3446
|
+
name: 'rest-assignment-array-shape',
|
|
3447
|
+
forms: [ts.SyntaxKind.VariableDeclaration, ts.SyntaxKind.Identifier],
|
|
3448
|
+
resolve: (node) => {
|
|
3449
|
+
const restAssignmentArray = restAssignmentArrayShapeAt(node);
|
|
3450
|
+
if (restAssignmentArray)
|
|
3451
|
+
return restAssignmentArray;
|
|
3452
|
+
return null;
|
|
3453
|
+
}
|
|
3454
|
+
},
|
|
3455
|
+
{
|
|
3456
|
+
name: 'local-union',
|
|
3457
|
+
forms: [ts.SyntaxKind.VariableDeclaration, ts.SyntaxKind.Identifier],
|
|
3458
|
+
resolve: (node) => {
|
|
3459
|
+
const localUnion = localUnionAt(node);
|
|
3460
|
+
if (localUnion)
|
|
3461
|
+
return localUnion;
|
|
3462
|
+
return null;
|
|
3463
|
+
}
|
|
3464
|
+
},
|
|
3465
|
+
{
|
|
3466
|
+
name: 'implicit-arguments-object',
|
|
3467
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
3468
|
+
resolve: (node) => {
|
|
3469
|
+
if (!isArgumentsObjectIdentifier(node, checker))
|
|
3470
|
+
return null;
|
|
3471
|
+
const owner = enclosingArgumentsFunction(node);
|
|
3472
|
+
const signature = owner ? checker.getSignatureFromDeclaration(owner) : undefined;
|
|
3473
|
+
const slot = signature ? implicitArgumentsSlotOf(signature) : null;
|
|
3474
|
+
if (!signature || !slot)
|
|
3475
|
+
return null;
|
|
3476
|
+
// The ABI and arguments allocation already use this signature's sealed
|
|
3477
|
+
// phantom slot. Publish that same carrier at the expression, so indexed
|
|
3478
|
+
// reads do not recover their element from lib.d.ts's erased IArguments.
|
|
3479
|
+
const frame = table.get(mapper.resolvedSignatureTypeOf(signature, 'call')).shape;
|
|
3480
|
+
return frame.kind === 'signature' ? (frame.call[0]?.parameters[slot.ordinal]?.type ?? null) : null;
|
|
3481
|
+
}
|
|
3482
|
+
},
|
|
3483
|
+
{
|
|
3484
|
+
// `Array.isArray(x) ? x[0] : x` where nothing in `x` is assignable to
|
|
3485
|
+
// the predicate's `any[]`: TypeScript narrows `x` to `T & any[]` rather
|
|
3486
|
+
// than to `never`, and types the read `any`. That `any` is the failed
|
|
3487
|
+
// narrowing's artifact, not a boundary the program declared -- see
|
|
3488
|
+
// `arrayPredicateNarrowedTypeOf`. Asked BEFORE the array read below,
|
|
3489
|
+
// because the receiver is still that intersection and the carrier it
|
|
3490
|
+
// interns is not the one the read should be resolved through.
|
|
3491
|
+
name: 'array-predicate-narrowed-element',
|
|
3492
|
+
forms: [ts.SyntaxKind.ElementAccessExpression],
|
|
3493
|
+
resolve: (node) => {
|
|
3494
|
+
if (!ts.isElementAccessExpression(node))
|
|
3495
|
+
return null;
|
|
3496
|
+
const element = arrayPredicateNarrowedElementTypeOf(checker, node);
|
|
3497
|
+
return element === null ? null : typeOf(element);
|
|
3498
|
+
}
|
|
3499
|
+
},
|
|
3500
|
+
{
|
|
3501
|
+
name: 'structural-array-read',
|
|
3502
|
+
forms: [ts.SyntaxKind.ElementAccessExpression],
|
|
3503
|
+
resolve: (node) => {
|
|
3504
|
+
const censusedArrayElement = ts.isElementAccessExpression(node)
|
|
3505
|
+
? inferredArrayElementAt(checker, collections, layoutTypeAt, node.expression)
|
|
3506
|
+
: null;
|
|
3507
|
+
// Read through the receiver's actual structural carrier whenever the
|
|
3508
|
+
// checker left the indexed result unstated. A parameter census was the
|
|
3509
|
+
// first place this mattered, but it is not the only place: an evolving
|
|
3510
|
+
// local `const values = []` is deliberately corrected below to
|
|
3511
|
+
// `array<any>` when no write census can prove a narrower element, while
|
|
3512
|
+
// `values[i]` can still be reported as `never` at an earlier flow point.
|
|
3513
|
+
// Taking the result from that stale checker view gives one cell two
|
|
3514
|
+
// answers -- an array that physically stores values and an indexed read
|
|
3515
|
+
// with no carrier. The receiver is a child of the access, so resolving it
|
|
3516
|
+
// here strictly descends the AST and cannot recurse back to this node.
|
|
3517
|
+
const arrayReadSource = ts.isElementAccessExpression(node)
|
|
3518
|
+
? censusedArrayElement
|
|
3519
|
+
? table.intern({ kind: 'array', element: typeOf(censusedArrayElement), readonly: false, extension: [] })
|
|
3520
|
+
: (localUnionAt(node.expression) ?? mapper.typeAt(node.expression))
|
|
3521
|
+
: null;
|
|
3522
|
+
const arrayRead = structuralArrayReadAt(checker, table, arrayReadSource, node);
|
|
3523
|
+
if (arrayRead)
|
|
3524
|
+
return arrayRead;
|
|
3525
|
+
return null;
|
|
3526
|
+
}
|
|
3527
|
+
},
|
|
3528
|
+
{
|
|
3529
|
+
// A recovered dynamic receiver makes the checker's downstream `never`
|
|
3530
|
+
// stale as well. This occurs one link after an evolving-array repair:
|
|
3531
|
+
// the checker typed `values[i]` as `never`, so it also typed
|
|
3532
|
+
// `values[i].field` as `never`; the mapper has since established that
|
|
3533
|
+
// the indexed value is `any`, whose property result is necessarily the
|
|
3534
|
+
// same dynamic boundary. Follow only that exact bottom-vs-any mismatch.
|
|
3535
|
+
// A genuinely `never` receiver and every statically shaped receiver keep
|
|
3536
|
+
// their own property type.
|
|
3537
|
+
name: 'never-property-of-any-receiver',
|
|
3538
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3539
|
+
resolve: (node) => {
|
|
3540
|
+
if (ts.isPropertyAccessExpression(node) && (absentSubstitutedTypeAt(node).flags & ts.TypeFlags.Never) !== 0) {
|
|
3541
|
+
const receiver = mapper.typeAt(node.expression);
|
|
3542
|
+
const receiverShape = table.get(receiver).shape;
|
|
3543
|
+
if (receiverShape.kind === 'primitive' && receiverShape.primitive === 'any')
|
|
3544
|
+
return receiver;
|
|
3545
|
+
}
|
|
3546
|
+
return null;
|
|
3547
|
+
}
|
|
3548
|
+
},
|
|
3549
|
+
{
|
|
3550
|
+
name: 'prototype-object',
|
|
3551
|
+
// The union of the three resolvers this rule ORs: two answer for a
|
|
3552
|
+
// property access, the third for a parameter or a name of one.
|
|
3553
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression, ts.SyntaxKind.Parameter, ts.SyntaxKind.Identifier],
|
|
3554
|
+
resolve: (node) => {
|
|
3555
|
+
const prototypeObject = prototypeObjectTypeAt(node) ?? prototypeObjectParameterTypeAt(node) ?? prototypeObjectMemberTypeAt(node);
|
|
3556
|
+
if (prototypeObject)
|
|
3557
|
+
return prototypeObject;
|
|
3558
|
+
return null;
|
|
3559
|
+
}
|
|
3560
|
+
},
|
|
3561
|
+
{
|
|
3562
|
+
name: 'evolving-array-member',
|
|
3563
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3564
|
+
resolve: (node) => {
|
|
3565
|
+
const evolvingArrayMember = evolvingArrayMemberTypeAt(node);
|
|
3566
|
+
if (evolvingArrayMember)
|
|
3567
|
+
return evolvingArrayMember;
|
|
3568
|
+
return null;
|
|
3569
|
+
}
|
|
3570
|
+
},
|
|
3571
|
+
{
|
|
3572
|
+
name: 'census-member-signature',
|
|
3573
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3574
|
+
resolve: (node) => {
|
|
3575
|
+
const censusMemberSignature = censusMemberSignatureAt(node);
|
|
3576
|
+
if (censusMemberSignature)
|
|
3577
|
+
return censusMemberSignature;
|
|
3578
|
+
return null;
|
|
3579
|
+
}
|
|
3580
|
+
},
|
|
3581
|
+
{
|
|
3582
|
+
name: 'call-result',
|
|
3583
|
+
forms: [ts.SyntaxKind.CallExpression],
|
|
3584
|
+
resolve: (node) => {
|
|
3585
|
+
const callResult = callResultAt(node);
|
|
3586
|
+
if (callResult)
|
|
3587
|
+
return callResult;
|
|
3588
|
+
return null;
|
|
3589
|
+
}
|
|
3590
|
+
},
|
|
3591
|
+
{
|
|
3592
|
+
// The generator half of `physical-overload` below, asked at the CALL
|
|
3593
|
+
// rather than at a binding: the callee already publishes the one
|
|
3594
|
+
// convention its implementation has, and this is the same fact on the
|
|
3595
|
+
// result side. See `physicalGeneratorOverloadResultAt`.
|
|
3596
|
+
name: 'physical-generator-overload-result',
|
|
3597
|
+
forms: [ts.SyntaxKind.CallExpression],
|
|
3598
|
+
resolve: (node) => {
|
|
3599
|
+
const physicalResult = physicalGeneratorOverloadResultAt(checker, node);
|
|
3600
|
+
if (physicalResult)
|
|
3601
|
+
return typeOf(physicalResult);
|
|
3602
|
+
return null;
|
|
3603
|
+
}
|
|
3604
|
+
},
|
|
3605
|
+
{
|
|
3606
|
+
name: 'constructor-choice-result',
|
|
3607
|
+
forms: [ts.SyntaxKind.NewExpression],
|
|
3608
|
+
resolve: constructResultAt
|
|
3609
|
+
},
|
|
3610
|
+
{
|
|
3611
|
+
name: 'object-descriptor-return',
|
|
3612
|
+
forms: [ts.SyntaxKind.CallExpression],
|
|
3613
|
+
resolve: (node) => {
|
|
3614
|
+
const descriptorReturn = objectDescriptorReturnTypeAt(node);
|
|
3615
|
+
if (descriptorReturn)
|
|
3616
|
+
return descriptorReturn;
|
|
3617
|
+
return null;
|
|
3618
|
+
}
|
|
3619
|
+
},
|
|
3620
|
+
{
|
|
3621
|
+
// A parenthesized expression is its operand: the language attaches no
|
|
3622
|
+
// type of its own to the parentheses (`(cache = new Map())` inside a `||`
|
|
3623
|
+
// is the assignment, and the assignment's value is the allocation this
|
|
3624
|
+
// mapper laid out from its context). Asking the checker at the
|
|
3625
|
+
// parentheses instead hands back its own, pre-contextual reading of the
|
|
3626
|
+
// inside -- `Map<any, any>` -- and the merge that cites this node then
|
|
3627
|
+
// publishes a value nobody allocates.
|
|
3628
|
+
name: 'parenthesized-is-its-operand',
|
|
3629
|
+
forms: [ts.SyntaxKind.ParenthesizedExpression],
|
|
3630
|
+
resolve: (node) => (ts.isParenthesizedExpression(node) ? mapper.typeAt(node.expression) : null)
|
|
3631
|
+
},
|
|
3632
|
+
{
|
|
3633
|
+
// Likewise a plain assignment is the value it assigns (`AssignmentExpression
|
|
3634
|
+
// : LeftHandSideExpression = AssignmentExpression` completes with the RHS
|
|
3635
|
+
// value after PutValue) -- the rule `producers/computations.ts`'s
|
|
3636
|
+
// `finishComputation` already applies to the assignment OPERATION's own
|
|
3637
|
+
// result, asked here for the node so a merge citing `(cache = new Map())`
|
|
3638
|
+
// sees the same value the operation publishes.
|
|
3639
|
+
name: 'assignment-is-its-right-hand-side',
|
|
3640
|
+
forms: [ts.SyntaxKind.BinaryExpression],
|
|
3641
|
+
resolve: (node) => ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.EqualsToken ? mapper.typeAt(node.right) : null
|
|
3642
|
+
},
|
|
3643
|
+
{
|
|
3644
|
+
// A read off a type guard's narrowed family view publishes the FAMILY's
|
|
3645
|
+
// field, not the guard's restatement of it. `node.arguments` after
|
|
3646
|
+
// `isRequireCall(node)` is `NodeArray<Expression> & [StringLiteralLike]`
|
|
3647
|
+
// to the checker -- an intersection member's property is the
|
|
3648
|
+
// intersection of the members' properties -- and `NodeArray<Expression>`
|
|
3649
|
+
// in the one object the family lays out (`familyMemberNarrowedBy`). The
|
|
3650
|
+
// guard restated what the field holds; the storage the read loads from
|
|
3651
|
+
// is the family's, and the array-and-tuple intersection is a shape no
|
|
3652
|
+
// carrier spells (its overload sets never join).
|
|
3653
|
+
name: 'narrowed-family-property',
|
|
3654
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3655
|
+
resolve: (node) => {
|
|
3656
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
3657
|
+
const receiver = checker.getTypeAtLocation(node.expression);
|
|
3658
|
+
const narrowedMember = receiver.isIntersection() ? narrowedFamilyMemberOf(receiver) : null;
|
|
3659
|
+
const property = narrowedMember ? checker.getPropertyOfType(narrowedMember, node.name.text) : undefined;
|
|
3660
|
+
if (property)
|
|
3661
|
+
return typeOf(checker.getTypeOfSymbolAtLocation(property, node));
|
|
3662
|
+
}
|
|
3663
|
+
return null;
|
|
3664
|
+
}
|
|
3665
|
+
},
|
|
3666
|
+
{
|
|
3667
|
+
// Compiler-minted records can refine an ambient any/unknown member (for
|
|
3668
|
+
// example PropertyDescriptor.value). A concrete checker read is already
|
|
3669
|
+
// flow-sensitive: replacing it with the field's storage type would widen
|
|
3670
|
+
// `number | Wrapped` back after a typeof guard. Storage and a narrowed
|
|
3671
|
+
// read are different questions; preserve the checker's concrete answer.
|
|
3672
|
+
name: 'dynamic-property-of-shaped-receiver',
|
|
3673
|
+
forms: [ts.SyntaxKind.PropertyAccessExpression],
|
|
3674
|
+
resolve: (node) => {
|
|
3675
|
+
if (ts.isPropertyAccessExpression(node) &&
|
|
3676
|
+
(checker.getTypeAtLocation(node).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0) {
|
|
3677
|
+
const receiverType = mapper.typeAt(node.expression);
|
|
3678
|
+
const receiverShape = table.get(receiverType).shape;
|
|
3679
|
+
const presentShapes = receiverShape.kind === 'union'
|
|
3680
|
+
? receiverShape.members
|
|
3681
|
+
.map((member) => table.get(member).shape)
|
|
3682
|
+
.filter((shape) => !(shape.kind === 'primitive' && (shape.primitive === 'undefined' || shape.primitive === 'null')))
|
|
3683
|
+
: [receiverShape];
|
|
3684
|
+
// A nullable record has one present shape. A choice of records does
|
|
3685
|
+
// not: choosing its first object would discard the other arms' fields.
|
|
3686
|
+
const objectShape = presentShapes.length === 1 ? presentShapes[0] : null;
|
|
3687
|
+
if (objectShape?.kind === 'object' && !objectShape.membersDropped) {
|
|
3688
|
+
const field = objectShape.members.find((member) => member.key.kind === 'string' && member.key.value === node.name.text);
|
|
3689
|
+
if (field)
|
|
3690
|
+
return field.type;
|
|
3691
|
+
}
|
|
3692
|
+
}
|
|
3693
|
+
return null;
|
|
3694
|
+
}
|
|
3695
|
+
},
|
|
3696
|
+
{
|
|
3697
|
+
// A name in callee position whose call instantiates a generic is typed by
|
|
3698
|
+
// the copy that call reaches, not by the generic it was written against:
|
|
3699
|
+
// the identifier `identity` in `identity(1)` holds `(value: number) =>
|
|
3700
|
+
// number`, and holding the unbound `<T>(value: T) => T` there is the hole
|
|
3701
|
+
// monomorphization removes. The checker performed exactly this
|
|
3702
|
+
// substitution to type-check the call; this reads its answer back through
|
|
3703
|
+
// the copy's own view rather than redoing the inference.
|
|
3704
|
+
// A callee names its call's site; a generic function named as a VALUE
|
|
3705
|
+
// (`binarySearch(array, insert, identity, compare)`, `emitNodeList(emit,
|
|
3706
|
+
// ...)`) names its own -- `specialization.ts`'s `fromValueUse` keys the
|
|
3707
|
+
// copy that value is on the reference itself, and reading the name
|
|
3708
|
+
// through that copy's view is what closes its parameters: the checker's
|
|
3709
|
+
// instantiation where it made one, the constraints where it did not.
|
|
3710
|
+
// The value-use site is keyed on the REFERENCE, whatever its parent is:
|
|
3711
|
+
// an argument's parent is the call it is passed to, but a parameter
|
|
3712
|
+
// default's is the parameter (`nodeVisitor: NodeVisitor = visitNode`,
|
|
3713
|
+
// TypeScript's `visitEachChild`) and a property's is the assignment, and
|
|
3714
|
+
// none of those parents is a site of its own. So the parent is asked
|
|
3715
|
+
// only where it names the reference as its callee, and the reference
|
|
3716
|
+
// itself is asked whenever the parent answered nothing.
|
|
3717
|
+
name: 'specialization-copy',
|
|
3718
|
+
// The one rule 4.3 could not key, and the reason is a finding rather than
|
|
3719
|
+
// an omission: `namesItsSite` returns true by DEFAULT -- for every node
|
|
3720
|
+
// whose parent is not a call, new, tagged template or JSX opening element
|
|
3721
|
+
// -- so this rule asks about `node.parent` for arbitrary children of an
|
|
3722
|
+
// arrow function, a function expression, a type reference or an
|
|
3723
|
+
// `extends` clause. An arrow's concise body is any expression at all, so
|
|
3724
|
+
// the domain is not a closed set of forms; it is "almost everything",
|
|
3725
|
+
// which `forms: null` states honestly. Keying it means narrowing
|
|
3726
|
+
// `namesItsSite` to the positions that really name a site, which is a
|
|
3727
|
+
// change to what the rule ANSWERS and so not part of this port.
|
|
3728
|
+
forms: null,
|
|
3729
|
+
resolve: (node) => {
|
|
3730
|
+
const site = (namesItsSite(node) ? specializations.specializationAt(node.parent, substituteTypeParameter) : null) ??
|
|
3731
|
+
// A namespace-qualified name is the reference itself, exactly as an
|
|
3732
|
+
// identifier is -- `specialization.ts`'s `valueUseSubjectOf` keys the
|
|
3733
|
+
// value-use site on the whole `State.enter` access, because that is
|
|
3734
|
+
// what denotes the declaration (`namespace-paths.ts`). Asking for any
|
|
3735
|
+
// other property access costs nothing: only a node the census
|
|
3736
|
+
// recorded a site on answers, and a plain property read never is one.
|
|
3737
|
+
(ts.isIdentifier(node) || ts.isPropertyAccessExpression(node)
|
|
3738
|
+
? specializations.specializationAt(node, substituteTypeParameter)
|
|
3739
|
+
: null);
|
|
3740
|
+
if (site) {
|
|
3741
|
+
const copy = mapperFor(copyPathOf(site));
|
|
3742
|
+
// The synthesized-union check of the non-specialized path below.
|
|
3743
|
+
const specializedUnionArms = parameters.unionArmsAt(node);
|
|
3744
|
+
if (specializedUnionArms)
|
|
3745
|
+
return table.intern({ kind: 'union', members: specializedUnionArms.map((arm) => copy.typeOf(arm)) });
|
|
3746
|
+
return copy.typeOf(absentSubstitutedTypeAt(node));
|
|
3747
|
+
}
|
|
3748
|
+
return null;
|
|
3749
|
+
}
|
|
3750
|
+
},
|
|
3751
|
+
{
|
|
3752
|
+
// The same absent-TYPE substitution the union arm above performs, at the
|
|
3753
|
+
// one other place a type enters from a source position: a binding whose
|
|
3754
|
+
// whole declared type is an absent host class, rather than one arm of a
|
|
3755
|
+
// union of them.
|
|
3756
|
+
name: 'array-literal-implied-pattern',
|
|
3757
|
+
forms: [ts.SyntaxKind.ArrayLiteralExpression],
|
|
3758
|
+
resolve: (node) => (ts.isArrayLiteralExpression(node) ? impliedPatternArrayLiteralType(node) : null)
|
|
3759
|
+
},
|
|
3760
|
+
{
|
|
3761
|
+
name: 'inferred-array-element',
|
|
3762
|
+
forms: [
|
|
3763
|
+
ts.SyntaxKind.ArrayLiteralExpression,
|
|
3764
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3765
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3766
|
+
ts.SyntaxKind.Identifier,
|
|
3767
|
+
ts.SyntaxKind.PropertyAccessExpression
|
|
3768
|
+
],
|
|
3769
|
+
resolve: (node) => {
|
|
3770
|
+
const inferredElement = inferredArrayElementAt(checker, collections, layoutTypeAt, node);
|
|
3771
|
+
if (inferredElement)
|
|
3772
|
+
return table.intern({ kind: 'array', element: typeOf(inferredElement), readonly: false, extension: [] });
|
|
3773
|
+
return null;
|
|
3774
|
+
}
|
|
3775
|
+
},
|
|
3776
|
+
{
|
|
3777
|
+
// See `unstatedNeverArray` for why `never` is the wrong answer for an
|
|
3778
|
+
// array whose element nothing states, and the box the right one.
|
|
3779
|
+
name: 'unstated-never-array',
|
|
3780
|
+
forms: [
|
|
3781
|
+
ts.SyntaxKind.ArrayLiteralExpression,
|
|
3782
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3783
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3784
|
+
ts.SyntaxKind.Identifier,
|
|
3785
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
3786
|
+
// A parameter is here for ONE case: it is an alias of an array whose
|
|
3787
|
+
// component the collection census refused, so it must carry the same
|
|
3788
|
+
// boxed element the caller's cell does. See `unstatedNeverArray`.
|
|
3789
|
+
ts.SyntaxKind.Parameter
|
|
3790
|
+
],
|
|
3791
|
+
resolve: (node) => {
|
|
3792
|
+
if (unstatedNeverArray(checker, collections, layoutTypeAt, node)) {
|
|
3793
|
+
return table.intern({
|
|
3794
|
+
kind: 'array',
|
|
3795
|
+
element: table.intern({ kind: 'primitive', primitive: 'any' }),
|
|
3796
|
+
readonly: false,
|
|
3797
|
+
extension: []
|
|
3798
|
+
});
|
|
3799
|
+
}
|
|
3800
|
+
return null;
|
|
3801
|
+
}
|
|
3802
|
+
},
|
|
3803
|
+
{
|
|
3804
|
+
// The K/(V) a bare `new Map()`/`new Set()`/`new WeakMap()`/`new
|
|
3805
|
+
// WeakSet()` never states -- `collection-bindings.ts` has bound it since
|
|
3806
|
+
// its creation, and nothing downstream ever asked until now. See
|
|
3807
|
+
// `inferredCollectionTypeArgumentsAt`'s own header, in this file's
|
|
3808
|
+
// `structural-array-element.ts` sibling.
|
|
3809
|
+
//
|
|
3810
|
+
// Asked BEFORE the bag census, not after, because the two answer the
|
|
3811
|
+
// same node about the same storage and the collection census is the one
|
|
3812
|
+
// that looked at this cell's own uses. `WebGLRenderer.js`'s `let
|
|
3813
|
+
// programs = materialProperties.programs` is the shape: `programs` is a
|
|
3814
|
+
// slot of the `WebGLProperties` bag, so `bagShapeTypeAt` answers first
|
|
3815
|
+
// with the slot's own type -- `Map<any, any> | undefined`, the checker's
|
|
3816
|
+
// reading of the `new Map()` stored into it -- and the declaration kept
|
|
3817
|
+
// `optional(keyed-collection(map, dynamic, dynamic))` while every read
|
|
3818
|
+
// past the `if ( programs === undefined )` guard carried the census's
|
|
3819
|
+
// `keyed-collection(map, string, dynamic)`. Two authorities over one
|
|
3820
|
+
// cell, surfacing as an unsatisfiable `binding-read-conversion` per
|
|
3821
|
+
// read. Neither census is wrong about what it looked at; the collection
|
|
3822
|
+
// census simply looked at more (`programs.set( programCacheKey, ... )`
|
|
3823
|
+
// says what K is, the stored value's type does not), so it goes first.
|
|
3824
|
+
// It answers for a far narrower set of nodes than the bag census does --
|
|
3825
|
+
// only where a collection was actually bound for this exact owner,
|
|
3826
|
+
// allocation or read -- so this does not take work away from bags
|
|
3827
|
+
// generally, only where both describe one storage.
|
|
3828
|
+
name: 'inferred-collection-type-arguments',
|
|
3829
|
+
// Every one of these five is also a form `bag-shape` serves, which is what
|
|
3830
|
+
// makes the collection-before-bag order above load-bearing rather than
|
|
3831
|
+
// incidental: on exactly these kinds both rules can answer for one node.
|
|
3832
|
+
// The prose said so; the two form lists now make it checkable.
|
|
3833
|
+
forms: [
|
|
3834
|
+
ts.SyntaxKind.NewExpression,
|
|
3835
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3836
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3837
|
+
ts.SyntaxKind.Identifier,
|
|
3838
|
+
ts.SyntaxKind.PropertyAccessExpression
|
|
3839
|
+
],
|
|
3840
|
+
resolve: (node) => {
|
|
3841
|
+
const inferredCollection = inferredCollectionTypeArgumentsAt(collections, table, typeOf, bags, layoutTypeAt(node), node);
|
|
3842
|
+
if (inferredCollection)
|
|
3843
|
+
return inferredCollection;
|
|
3844
|
+
return null;
|
|
3845
|
+
}
|
|
3846
|
+
},
|
|
3847
|
+
{
|
|
3848
|
+
// The position's own statement, where the census had no writes to read
|
|
3849
|
+
// and the allocation itself states nothing -- and the syntax that carries
|
|
3850
|
+
// that allocation, unchanged, to the call the checker resolved off its
|
|
3851
|
+
// own dynamic reading. See `statedCollectionTypeAt`.
|
|
3852
|
+
name: 'stated-collection',
|
|
3853
|
+
forms: [
|
|
3854
|
+
ts.SyntaxKind.NewExpression,
|
|
3855
|
+
ts.SyntaxKind.ParenthesizedExpression,
|
|
3856
|
+
ts.SyntaxKind.BinaryExpression,
|
|
3857
|
+
ts.SyntaxKind.CallExpression
|
|
3858
|
+
],
|
|
3859
|
+
resolve: (node) => {
|
|
3860
|
+
const statedCollection = statedCollectionTypeAt(checker, node);
|
|
3861
|
+
if (statedCollection)
|
|
3862
|
+
return typeOf(statedCollection);
|
|
3863
|
+
return null;
|
|
3864
|
+
}
|
|
3865
|
+
},
|
|
3866
|
+
{
|
|
3867
|
+
// The same statement for `new Array(n)`, whose ambient overload is
|
|
3868
|
+
// `any[]` for the identical reason a bare `new Map()` is `Map<any,
|
|
3869
|
+
// any>`. See `contextualArrayConstructTypeAt`. An assignment carries it
|
|
3870
|
+
// to the cell's merge through `assignment-is-its-right-hand-side`, so
|
|
3871
|
+
// only the allocation itself needs a form here.
|
|
3872
|
+
name: 'contextual-array-construct',
|
|
3873
|
+
forms: [ts.SyntaxKind.NewExpression],
|
|
3874
|
+
resolve: (node) => {
|
|
3875
|
+
const contextualArray = contextualArrayConstructTypeAt(checker, node);
|
|
3876
|
+
if (contextualArray)
|
|
3877
|
+
return typeOf(contextualArray);
|
|
3878
|
+
return null;
|
|
3879
|
+
}
|
|
3880
|
+
},
|
|
3881
|
+
{
|
|
3882
|
+
// The receiver's own type is not enough: `Map`/`WeakMap`'s `get` is a
|
|
3883
|
+
// prototype call, and a prototype call's result comes from the callee's
|
|
3884
|
+
// SIGNATURE -- which the checker instantiates from the receiver
|
|
3885
|
+
// EXPRESSION's type, not from what this compiler selected for it. See
|
|
3886
|
+
// `collectionMemberResultTypeAt` (`structural-array-element.ts`).
|
|
3887
|
+
name: 'collection-member-result',
|
|
3888
|
+
forms: [ts.SyntaxKind.CallExpression],
|
|
3889
|
+
resolve: (node) => {
|
|
3890
|
+
const collectionMember = collectionMemberResultTypeAt(collections, table, typeOf, bags, layoutTypeAt, node);
|
|
3891
|
+
if (collectionMember)
|
|
3892
|
+
return collectionMember;
|
|
3893
|
+
return null;
|
|
3894
|
+
}
|
|
3895
|
+
},
|
|
3896
|
+
{
|
|
3897
|
+
name: 'bag-shape',
|
|
3898
|
+
// A JS field written `this.field = {}` in a constructor makes the ASSIGNMENT
|
|
3899
|
+
// the field symbol's declaration as far as the checker is concerned, which
|
|
3900
|
+
// is why an `=` BinaryExpression is an owner form here and not only a
|
|
3901
|
+
// VariableDeclaration.
|
|
3902
|
+
forms: [
|
|
3903
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3904
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3905
|
+
ts.SyntaxKind.Parameter,
|
|
3906
|
+
ts.SyntaxKind.BinaryExpression,
|
|
3907
|
+
ts.SyntaxKind.CallExpression,
|
|
3908
|
+
ts.SyntaxKind.NewExpression,
|
|
3909
|
+
ts.SyntaxKind.Identifier,
|
|
3910
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
3911
|
+
ts.SyntaxKind.ElementAccessExpression,
|
|
3912
|
+
ts.SyntaxKind.ObjectLiteralExpression
|
|
3913
|
+
],
|
|
3914
|
+
resolve: (node) => {
|
|
3915
|
+
const inferredBag = bagShapeTypeAt(table, typeOf, bags, node);
|
|
3916
|
+
if (inferredBag)
|
|
3917
|
+
return inferredBag;
|
|
3918
|
+
return null;
|
|
3919
|
+
}
|
|
3920
|
+
},
|
|
3921
|
+
{
|
|
3922
|
+
name: 'rest-parameter-array-element',
|
|
3923
|
+
forms: [ts.SyntaxKind.Parameter, ts.SyntaxKind.Identifier],
|
|
3924
|
+
resolve: (node) => {
|
|
3925
|
+
// Real call-site evidence (`parameter-bindings.ts`'s `restElementTypeAt`,
|
|
3926
|
+
// joined over every reachable caller's actual arguments) outranks the
|
|
3927
|
+
// checker's own contextual-tuple widening -- the same priority an
|
|
3928
|
+
// ordinary parameter's census answer already has over a bare checker
|
|
3929
|
+
// guess. `structural-parts.ts`'s `parameterOf` asks the identical
|
|
3930
|
+
// question the identical way, so the ABI and this body-side reference
|
|
3931
|
+
// to the same parameter cannot disagree about which one answered.
|
|
3932
|
+
// In `parameterOf`'s own order: census evidence, then a union of
|
|
3933
|
+
// tuples collapsed to one element, then the unannotated-tuple widening.
|
|
3934
|
+
const restElement = censusRestElementAt(checker, identities, parameters, node) ??
|
|
3935
|
+
restParameterUnionOfTuplesElementAt(checker, identities, node) ??
|
|
3936
|
+
restParameterArrayElementAt(checker, identities, node);
|
|
3937
|
+
if (restElement)
|
|
3938
|
+
return table.intern({ kind: 'array', element: typeOf(restElement), readonly: false, extension: [] });
|
|
3939
|
+
return null;
|
|
3940
|
+
}
|
|
3941
|
+
},
|
|
3942
|
+
{
|
|
3943
|
+
name: 'implied-pattern-array-element',
|
|
3944
|
+
// NOT ObjectBindingPattern, though `impliedPatternParameterOf` admits one:
|
|
3945
|
+
// the pattern it finds IS this node, and the caller then requires the
|
|
3946
|
+
// parameter's name to be an ARRAY pattern, so an object pattern can never
|
|
3947
|
+
// reach a non-null answer here.
|
|
3948
|
+
forms: [ts.SyntaxKind.Parameter, ts.SyntaxKind.ArrayBindingPattern],
|
|
3949
|
+
resolve: (node) => {
|
|
3950
|
+
const impliedElement = impliedPatternArrayElementAt(checker, parameters, node);
|
|
3951
|
+
if (impliedElement)
|
|
3952
|
+
return table.intern({ kind: 'array', element: typeOf(impliedElement), readonly: false, extension: [] });
|
|
3953
|
+
return null;
|
|
3954
|
+
}
|
|
3955
|
+
},
|
|
3956
|
+
{
|
|
3957
|
+
// A name bound to ONE function but annotated with an overloaded type.
|
|
3958
|
+
// `physicalOverloadTypeAt` states the rule; asked here, at the binding,
|
|
3959
|
+
// because the allocation already answers it from the initializer and the
|
|
3960
|
+
// two must not disagree about how many conventions one value has.
|
|
3961
|
+
name: 'physical-overload',
|
|
3962
|
+
forms: [
|
|
3963
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3964
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3965
|
+
ts.SyntaxKind.PropertyAssignment,
|
|
3966
|
+
ts.SyntaxKind.ImportSpecifier,
|
|
3967
|
+
ts.SyntaxKind.ExportSpecifier,
|
|
3968
|
+
ts.SyntaxKind.ImportClause,
|
|
3969
|
+
ts.SyntaxKind.Identifier
|
|
3970
|
+
],
|
|
3971
|
+
resolve: (node) => {
|
|
3972
|
+
const physical = physicalOverloadTypeAt(checker, node, parameters);
|
|
3973
|
+
if (physical)
|
|
3974
|
+
return typeOf(physical);
|
|
3975
|
+
return null;
|
|
3976
|
+
}
|
|
3977
|
+
},
|
|
3978
|
+
{
|
|
3979
|
+
// `new String(x) as T` -- the same shape one type-object over. See `physicalStringObjectTypeAt`.
|
|
3980
|
+
name: 'physical-string-object',
|
|
3981
|
+
forms: [
|
|
3982
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
3983
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
3984
|
+
ts.SyntaxKind.PropertyAssignment,
|
|
3985
|
+
ts.SyntaxKind.Identifier
|
|
3986
|
+
],
|
|
3987
|
+
resolve: (node) => {
|
|
3988
|
+
const stringObjectPhysical = physicalStringObjectTypeAt(checker, node, parameters);
|
|
3989
|
+
if (stringObjectPhysical)
|
|
3990
|
+
return typeOf(stringObjectPhysical);
|
|
3991
|
+
return null;
|
|
3992
|
+
}
|
|
3993
|
+
},
|
|
3994
|
+
{
|
|
3995
|
+
// The checker's constraint erasure over this copy's own binding. Guarded
|
|
3996
|
+
// on the substitution actually resolving: a generic whose copy binds
|
|
3997
|
+
// nothing has no better answer than the constraint, and answering with a
|
|
3998
|
+
// naked parameter there would trade a wide carrier for no carrier.
|
|
3999
|
+
name: 'constraint-erased-parameter',
|
|
4000
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
4001
|
+
resolve: (node) => {
|
|
4002
|
+
const erased = constraintErasedParameterAt(checker, node);
|
|
4003
|
+
if (erased !== null && substituteTypeParameter(erased) !== erased)
|
|
4004
|
+
return typeOf(erased);
|
|
4005
|
+
return null;
|
|
4006
|
+
}
|
|
4007
|
+
},
|
|
4008
|
+
{
|
|
4009
|
+
// A disagreement the census resolved to a SYNTHESIZED union.
|
|
4010
|
+
// `unionArmsAt`'s own comment says why this is not a `ts.Type`
|
|
4011
|
+
// (`getUnionType` is not public); the structural union is built at
|
|
4012
|
+
// the one place `table.intern` and this copy's `typeOf` are both in
|
|
4013
|
+
// scope, where the plain `bound` fallback would have found nothing
|
|
4014
|
+
// and fallen through to `any`.
|
|
4015
|
+
name: 'parameter-union-arms',
|
|
4016
|
+
// The union of four composed censuses -- parameter, return, local, field --
|
|
4017
|
+
// each of which owns a different slice of this list.
|
|
4018
|
+
forms: [
|
|
4019
|
+
ts.SyntaxKind.Parameter,
|
|
4020
|
+
ts.SyntaxKind.Identifier,
|
|
4021
|
+
ts.SyntaxKind.VariableDeclaration,
|
|
4022
|
+
ts.SyntaxKind.PropertyDeclaration,
|
|
4023
|
+
ts.SyntaxKind.PropertyAccessExpression,
|
|
4024
|
+
ts.SyntaxKind.FunctionDeclaration,
|
|
4025
|
+
ts.SyntaxKind.FunctionExpression,
|
|
4026
|
+
ts.SyntaxKind.ArrowFunction,
|
|
4027
|
+
ts.SyntaxKind.MethodDeclaration,
|
|
4028
|
+
ts.SyntaxKind.GetAccessor,
|
|
4029
|
+
ts.SyntaxKind.CallExpression,
|
|
4030
|
+
ts.SyntaxKind.NewExpression
|
|
4031
|
+
],
|
|
4032
|
+
resolve: (node) => {
|
|
4033
|
+
const unionArms = parameters.unionArmsAt(node);
|
|
4034
|
+
if (unionArms)
|
|
4035
|
+
return table.intern({ kind: 'union', members: unionArms.map((arm) => typeOf(arm)) });
|
|
4036
|
+
return null;
|
|
4037
|
+
}
|
|
4038
|
+
},
|
|
4039
|
+
{
|
|
4040
|
+
name: 'dynamic-object-boundary',
|
|
4041
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
4042
|
+
resolve: (node) => {
|
|
4043
|
+
const dynamicObjectBoundary = dynamicObjectBoundaryAt(node);
|
|
4044
|
+
if (dynamicObjectBoundary)
|
|
4045
|
+
return typeOf(dynamicObjectBoundary);
|
|
4046
|
+
return null;
|
|
4047
|
+
}
|
|
4048
|
+
},
|
|
4049
|
+
{
|
|
4050
|
+
name: 'unplaced-hoisted-read',
|
|
4051
|
+
forms: [ts.SyntaxKind.Identifier],
|
|
4052
|
+
resolve: (node) => {
|
|
4053
|
+
const unplacedHoistedRead = unplacedHoistedReadAt(node);
|
|
4054
|
+
if (unplacedHoistedRead)
|
|
4055
|
+
return typeOf(unplacedHoistedRead);
|
|
4056
|
+
return null;
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
];
|
|
4060
|
+
const preparedRules = prepareStructuralRules(structuralRules);
|
|
4061
|
+
// Decided once per mapper, never per node: `typeAt` is asked for essentially
|
|
4062
|
+
// every node in the program, and reading an environment variable there would
|
|
4063
|
+
// make the instrument's own cost the thing it measures.
|
|
4064
|
+
const recordDisagreement = structuralDisagreementsEnabled()
|
|
4065
|
+
? (disagreement) => {
|
|
4066
|
+
disagreements.push(disagreement);
|
|
4067
|
+
}
|
|
4068
|
+
: undefined;
|
|
4069
|
+
const typeAt = (node) => preparedRules.resolve(node, recordDisagreement) ?? typeOf(absentSubstitutedTypeAt(node));
|
|
4070
|
+
const rawTypeAt = (node) => {
|
|
4071
|
+
// A binding pattern is the reference half of binding its source and has no
|
|
4072
|
+
// independent value type. TypeScript does not support every direct
|
|
4073
|
+
// `getTypeAtLocation` query on these pattern nodes, so expose the same raw
|
|
4074
|
+
// source type that `typeAt` above interns.
|
|
4075
|
+
if (ts.isArrayBindingPattern(node) || ts.isObjectBindingPattern(node)) {
|
|
4076
|
+
const parent = node.parent;
|
|
4077
|
+
if (ts.isVariableDeclaration(parent) && parent.initializer)
|
|
4078
|
+
return rawTypeAt(parent.initializer);
|
|
4079
|
+
if (ts.isParameter(parent) || ts.isBindingElement(parent))
|
|
4080
|
+
return rawTypeAt(parent);
|
|
4081
|
+
}
|
|
4082
|
+
return absentSubstitutedTypeAt(node);
|
|
4083
|
+
};
|
|
4084
|
+
const mapper = {
|
|
4085
|
+
forSpecialization: mapperFor,
|
|
4086
|
+
substituteTypeParameter,
|
|
4087
|
+
typeOf,
|
|
4088
|
+
typeAt,
|
|
4089
|
+
mutableMethodStorageTypeAt: mutableMethods.storageTypeAt,
|
|
4090
|
+
mutableMethodReadTypeAt: mutableMethods.readTypeAt,
|
|
4091
|
+
boundCallResultAt,
|
|
4092
|
+
constructResultAt,
|
|
4093
|
+
evolvingArrayMemberTypeAt,
|
|
4094
|
+
objectDescriptorReturnTypeAt,
|
|
4095
|
+
instanceTypeAt: (node) => {
|
|
4096
|
+
if (!ts.isClassExpression(node))
|
|
4097
|
+
return typeAt(node);
|
|
4098
|
+
const construct = checker.getTypeAtLocation(node).getConstructSignatures()[0];
|
|
4099
|
+
return construct ? typeOf(construct.getReturnType()) : typeAt(node);
|
|
4100
|
+
},
|
|
4101
|
+
valueTypeAt: (node) => {
|
|
4102
|
+
const localUnion = localUnionAt(node);
|
|
4103
|
+
if (localUnion)
|
|
4104
|
+
return localUnion;
|
|
4105
|
+
const accessor = accessorSignatureOf(checker, node);
|
|
4106
|
+
if (accessor)
|
|
4107
|
+
return table.intern({ kind: 'signature', call: [signatureOf(accessor)], construct: [] });
|
|
4108
|
+
// An overload set's implementation declares the one signature that
|
|
4109
|
+
// physically exists -- see `implementationSignatureOf`. Asked before the
|
|
4110
|
+
// symbol-level answer below, which is every overload and no single
|
|
4111
|
+
// convention.
|
|
4112
|
+
const implementation = implementationSignatureOf(checker, node);
|
|
4113
|
+
if (implementation)
|
|
4114
|
+
return table.intern({ kind: 'signature', call: [signatureOf(implementation)], construct: [] });
|
|
4115
|
+
// A `?`-marked method WITH A BODY allocates its function object
|
|
4116
|
+
// unconditionally -- see `optionalMethodSignatureOf`. Asked before the
|
|
4117
|
+
// symbol-level answer below, which is `T | undefined` for an optional
|
|
4118
|
+
// member whether read through the symbol or the node, and states a
|
|
4119
|
+
// fact about READING the member, never about whether this declaration's
|
|
4120
|
+
// own allocation runs.
|
|
4121
|
+
const optionalMethod = optionalMethodSignatureOf(checker, node);
|
|
4122
|
+
if (optionalMethod)
|
|
4123
|
+
return table.intern({ kind: 'signature', call: [signatureOf(optionalMethod)], construct: [] });
|
|
4124
|
+
// A return census answers the RESULT of a callable declaration, never
|
|
4125
|
+
// the value allocated for the declaration itself. `layoutTypeAt` reads
|
|
4126
|
+
// that census for ordinary nodes, so asking it directly of an arrow or
|
|
4127
|
+
// function expression whose stated upper bound was refined returns the
|
|
4128
|
+
// concrete result type (an Array for `(): Iterable<T> => [...]`) and
|
|
4129
|
+
// would publish an Array allocation where the source allocates a
|
|
4130
|
+
// function. Rebuild the callable shape from its own signature here;
|
|
4131
|
+
// `signatureOf` consults the same composed census for the result slot,
|
|
4132
|
+
// preserving both facts without letting one replace the other.
|
|
4133
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
4134
|
+
(parameters.typeAt(node) !== null || parameters.unionArmsAt(node) !== null)) {
|
|
4135
|
+
const signature = checker.getSignatureFromDeclaration(node);
|
|
4136
|
+
if (signature)
|
|
4137
|
+
return table.intern({ kind: 'signature', call: [signatureOf(signature)], construct: [] });
|
|
4138
|
+
}
|
|
4139
|
+
const declared = declaredValueTypeOf(checker, node);
|
|
4140
|
+
if (declared) {
|
|
4141
|
+
// A binding ANNOTATED with an overloaded type but INITIALIZED with one
|
|
4142
|
+
// function has exactly one physical convention -- the initializer's.
|
|
4143
|
+
// `structural-parts.ts`'s `memberOf` already asks this for a member;
|
|
4144
|
+
// a module-level `const` is the same fact spelled at file scope, and
|
|
4145
|
+
// hono's `export const parseBody: ParseBody = async (...)` is the
|
|
4146
|
+
// case that showed the two answers apart.
|
|
4147
|
+
return typeOf(physicalInitializerTypeOf(checker, node, declared, parameters) ?? declared);
|
|
4148
|
+
}
|
|
4149
|
+
const layout = layoutTypeAt(node);
|
|
4150
|
+
// A function LITERAL contextually typed by an overload set. Only a
|
|
4151
|
+
// `function` declaration merges into several conventions; an arrow or a
|
|
4152
|
+
// function expression is one function with one signature, whatever the
|
|
4153
|
+
// position expecting it declares -- so the literal's own signature is
|
|
4154
|
+
// the answer, exactly as `implementationSignatureOf` above answers the
|
|
4155
|
+
// merged-declaration spelling of the same fact.
|
|
4156
|
+
//
|
|
4157
|
+
// The overload set is not always written as one. `[].map` over a UNION
|
|
4158
|
+
// of two array types resolves to a callback parameter that is the
|
|
4159
|
+
// INTERSECTION of the two arms' callbacks -- contravariance -- and an
|
|
4160
|
+
// intersection of callables is exactly an overload set. hono's
|
|
4161
|
+
// `this.#matchResult[0].map(([[, route]]) => route)` (`request.ts:421`)
|
|
4162
|
+
// is that, and the arrow written there has one parameter list.
|
|
4163
|
+
//
|
|
4164
|
+
// Gated on the layout actually carrying more than one signature, so an
|
|
4165
|
+
// ordinary arrow keeps resolving through `layoutTypeAt` untouched.
|
|
4166
|
+
if (process.env.GEA_DEBUG_VALUETYPE &&
|
|
4167
|
+
(ts.isArrowFunction(node) || ts.isFunctionExpression(node)) &&
|
|
4168
|
+
node.getText().includes(process.env.GEA_DEBUG_VALUETYPE)) {
|
|
4169
|
+
console.error('[DEBUG valueTypeAt]', node.getText().slice(0, 80));
|
|
4170
|
+
console.error(' declared(before):', declared);
|
|
4171
|
+
console.error(' layout sig count:', layout.getCallSignatures().length);
|
|
4172
|
+
console.error(' layout typeToString:', checker.typeToString(layout));
|
|
4173
|
+
const own = checker.getSignatureFromDeclaration(node);
|
|
4174
|
+
console.error(' own signature exists:', !!own);
|
|
4175
|
+
if (own) {
|
|
4176
|
+
for (const p of own.getParameters()) {
|
|
4177
|
+
const t = checker.getTypeOfSymbolAtLocation(p, node);
|
|
4178
|
+
console.error(' param', p.getName(), checker.typeToString(t, undefined, ts.TypeFormatFlags.NoTruncation), 'isTuple:', checker.isTupleType(t));
|
|
4179
|
+
}
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
// TRIED AND MEASURED DEAD (2026-09-03): widening this `> 1` gate to
|
|
4183
|
+
// also fire on an unannotated trailing rest -- hono's `newResponse:
|
|
4184
|
+
// NewResponse = (...args) => ...`, whose `layout` here is ONE
|
|
4185
|
+
// TypeScript-joined signature (`args_0: any, args_1?: any, args_2?:
|
|
4186
|
+
// unknown`), the checker's own collapse of a bare-rest literal against
|
|
4187
|
+
// several overloads, done before this function runs. Preferring `own`
|
|
4188
|
+
// there is a no-op: isolated A/B (snapshot, hono-hello + the three.js app)
|
|
4189
|
+
// byte-identical -- `own`'s contextual type for the rest
|
|
4190
|
+
// parameter is EQUALLY `any`/`unknown`-degraded by that same join, so
|
|
4191
|
+
// `own`/`layout` are two views of one already-lossy checker answer,
|
|
4192
|
+
// not two to disagree between. Also checked: the call-site census
|
|
4193
|
+
// (`StructuralPartsInput.parameters`) never binds a rest parameter's
|
|
4194
|
+
// declaration either (`bound` null for every `...args` in hono,
|
|
4195
|
+
// confirmed directly). The richer per-position record `abiBlockers`
|
|
4196
|
+
// reports seeing comes from neither path -- likely the `args as
|
|
4197
|
+
// Parameters<NewResponse>` cast at its one use site, narrowing a
|
|
4198
|
+
// DIFFERENT operand. Separate work; do not retry this selection point.
|
|
4199
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && layout.getCallSignatures().length > 1) {
|
|
4200
|
+
const own = checker.getSignatureFromDeclaration(node);
|
|
4201
|
+
if (own)
|
|
4202
|
+
return table.intern({ kind: 'signature', call: [signatureOf(own)], construct: [] });
|
|
4203
|
+
}
|
|
4204
|
+
return typeOf(layout);
|
|
4205
|
+
},
|
|
4206
|
+
resolvedSignatureTypeOf: (signature, kind, resultOverride) => table.intern({
|
|
4207
|
+
kind: 'signature',
|
|
4208
|
+
call: kind === 'call' ? [signatureOf(signature, resultOverride)] : [],
|
|
4209
|
+
construct: kind === 'construct' ? [signatureOf(signature, resultOverride)] : []
|
|
4210
|
+
}),
|
|
4211
|
+
rawTypeAt,
|
|
4212
|
+
patternReadTypeAt: (element) => parameters.patternReadTypeAt?.(element) ?? null,
|
|
4213
|
+
structuralDisagreements: disagreements,
|
|
4214
|
+
structuralFormViolations: preparedRules.formViolations,
|
|
4215
|
+
classCopies: () => new Map([...classCopyKeys].map(([root, copies]) => [root, [...copies.values()].sort((a, b) => a.ordinal - b.ordinal)]))
|
|
4216
|
+
};
|
|
4217
|
+
return mapper;
|
|
4218
|
+
};
|