@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,2546 @@
|
|
|
1
|
+
import { instantiatedParameterTypes } from '../semantics/model/selected-signature.js';
|
|
2
|
+
import { genericFunctionSetMembersOf, runtimeSymbolMemberIndexOf } from '../semantics/model/structural-types.js';
|
|
3
|
+
import { carriableIndexesOf, dictionaryIndexOf, isDataOnlyObjectShape, recordAccessorsOf, recordFieldKeyOf } from './object-shape.js';
|
|
4
|
+
import { abiKey, passingOf, representationKey } from './model.js';
|
|
5
|
+
import { createIntersectionFlattener, intersectPropertyRepresentations, intersectionMemberKindOf, isPrimitiveValueShape } from './intersection.js';
|
|
6
|
+
import { widestSubsumingAbi } from './host-abi.js';
|
|
7
|
+
import { primitiveCarrier, storedCarrier, unresolved } from './primitives.js';
|
|
8
|
+
import { createUnionDeriver } from './union.js';
|
|
9
|
+
import { deriveKeyedCollection } from './collections.js';
|
|
10
|
+
import { defaultClassCopyPolicy, defaultDateDeclarationPolicy, defaultHostBindingPolicy, defaultHostNamespaceRootPolicy, defaultKeyedCollectionPolicy, defaultOwnershipPolicy, defaultPromiseDeclarationPolicy, defaultGeneratorDeclarationPolicy, defaultRegExpDeclarationPolicy, defaultStandardBufferPolicy, defaultStringObjectDeclarationPolicy, defaultErrorDeclarationPolicy, defaultFunctionDeclarationPolicy, defaultClassHeritagePolicy, defaultInterfaceImplementorPolicy, defaultTypedArrayElementPolicy, defaultValueRecordPolicy } from './policies.js';
|
|
11
|
+
export { defaultClassCopyPolicy, defaultDateDeclarationPolicy, defaultHostBindingPolicy, defaultHostNamespaceRootPolicy, defaultKeyedCollectionPolicy, defaultOwnershipPolicy, defaultPromiseDeclarationPolicy, defaultGeneratorDeclarationPolicy, defaultRegExpDeclarationPolicy, defaultStandardBufferPolicy, defaultStringObjectDeclarationPolicy, defaultErrorDeclarationPolicy, defaultFunctionDeclarationPolicy, defaultClassHeritagePolicy, defaultInterfaceImplementorPolicy, defaultTypedArrayElementPolicy, defaultValueRecordPolicy };
|
|
12
|
+
/**
|
|
13
|
+
* The `SignatureShape` a checker-resolved invocation actually calls.
|
|
14
|
+
*
|
|
15
|
+
* A callee's own declared type is an overload *set*, and `sharedAbiOf` below
|
|
16
|
+
* correctly refuses to join it into one convention when the overloads are not
|
|
17
|
+
* physically identical -- that is not a gap, it is the honest fact that one
|
|
18
|
+
* value's general-purpose carrier has no single calling convention to state.
|
|
19
|
+
* A call site is a different question: the checker already resolved it to
|
|
20
|
+
* exactly one signature (`InvocationOperation.selectedSignature`,
|
|
21
|
+
* `semantics/model/selected-signature.ts`), with no sibling overload left to
|
|
22
|
+
* disagree with it, and `SelectedSignature` already carries every field
|
|
23
|
+
* `abiOf` needs to answer that question -- it is a `SignatureShape` under
|
|
24
|
+
* `returnType` instead of `result`. Naming that correspondence here, instead
|
|
25
|
+
* of leaving it as an unstated coincidence two field lists happen to share, is
|
|
26
|
+
* what makes it the one thing an invocation lowering has to reach for instead
|
|
27
|
+
* of a joined lowest-common-denominator carrier it was never going to get.
|
|
28
|
+
*/
|
|
29
|
+
export const signatureShapeOfSelectedSignature = (signature) => ({
|
|
30
|
+
parameters: signature.parameters,
|
|
31
|
+
minimumArity: signature.minimumArity,
|
|
32
|
+
thisParameter: signature.thisParameter,
|
|
33
|
+
result: signature.returnType
|
|
34
|
+
});
|
|
35
|
+
/**
|
|
36
|
+
* The frame one `new` of a host constructor fills, read off the overload the
|
|
37
|
+
* checker selected at that site -- the construct-side use of
|
|
38
|
+
* `signatureShapeOfSelectedSignature` above.
|
|
39
|
+
*
|
|
40
|
+
* `hostInvocationAbiOf` answers for the constructor VALUE, and for
|
|
41
|
+
* `MapConstructor` (`new ()` beside `new <K, V>(entries?)`),
|
|
42
|
+
* `WeakMapConstructor` (generic, plus an `Iterable` overload) and every
|
|
43
|
+
* typed-array constructor (`length` / `ArrayLike<number>` / `buffer,
|
|
44
|
+
* byteOffset?, length?`) it correctly answers "no single convention". Yet
|
|
45
|
+
* every three.js renderer module builds its cache as `new WeakMap()` or
|
|
46
|
+
* `new Map()` (`WebGLProperties`, `WebGLRenderStates`, `WebGLShaderCache`,
|
|
47
|
+
* `WebGLGeometries`, ...), and each of those SITES resolved to exactly one
|
|
48
|
+
* overload. Without a frame to test, the reflection census read each of them
|
|
49
|
+
* as an unknown construction and published the new collection's key and
|
|
50
|
+
* value carriers -- every field of every render-state record they hold.
|
|
51
|
+
*
|
|
52
|
+
* Only the formals the site FILLS are laid out. A formal the site omits is
|
|
53
|
+
* optional by the checker's own resolution (`minimumArity`), the host
|
|
54
|
+
* construction reads its absence itself (`emitKeyedCollectionConstruct`'s
|
|
55
|
+
* zero-argument `gea::makeRef<T>()`), and no value is transported into it --
|
|
56
|
+
* so it states nothing about the frame and, for a generic overload, never has
|
|
57
|
+
* to be instantiated. A FILLED formal of a generic overload whose type
|
|
58
|
+
* arguments the checker inferred is refused: `instantiatedParameterTypes`
|
|
59
|
+
* withholds those on purpose, and reconstructing them here would be the
|
|
60
|
+
* rediscovery that authority exists to prevent. A rest formal has no fixed
|
|
61
|
+
* position to lay out and is refused with it.
|
|
62
|
+
*
|
|
63
|
+
* The result is the carrier the construction itself holds, not the
|
|
64
|
+
* signature's return type: the checker defaults `new WeakMap()` to
|
|
65
|
+
* `WeakMap<WeakKey, any>` while the collection census bound the key and value
|
|
66
|
+
* the program actually stores (`collection-construct-type-inference`), and the
|
|
67
|
+
* host renderer mints the held carrier directly. That is how a generic
|
|
68
|
+
* overload's K/V are instantiated here -- from the construction's own result,
|
|
69
|
+
* never from argument syntax.
|
|
70
|
+
*/
|
|
71
|
+
export const selectedHostConstructFrameOf = (deriver, signature, received, result) => {
|
|
72
|
+
if (signature.provenance !== 'ambient' || signature.thisParameter !== null)
|
|
73
|
+
return null;
|
|
74
|
+
if (received < signature.minimumArity || received > signature.parameters.length)
|
|
75
|
+
return null;
|
|
76
|
+
const filled = signature.parameters.slice(0, received);
|
|
77
|
+
if (filled.some((parameter) => parameter.rest))
|
|
78
|
+
return null;
|
|
79
|
+
if (filled.length > 0 && instantiatedParameterTypes(signature) === null)
|
|
80
|
+
return null;
|
|
81
|
+
const abi = deriver.abiOf({ parameters: filled, minimumArity: received, thisParameter: null, result: signature.returnType });
|
|
82
|
+
if (abi === null || abi.receiver !== null || abi.restFrom !== null)
|
|
83
|
+
return null;
|
|
84
|
+
if (abi.parameters.some((parameter) => parameter.value.kind === 'unresolved'))
|
|
85
|
+
return null;
|
|
86
|
+
return { ...abi, result };
|
|
87
|
+
};
|
|
88
|
+
export const createRepresentationDeriver = (types, ownership = defaultOwnershipPolicy, binding = defaultHostBindingPolicy, elements = defaultTypedArrayElementPolicy, promise = defaultPromiseDeclarationPolicy, collections = defaultKeyedCollectionPolicy, buffers = defaultStandardBufferPolicy, namespaceRoots = defaultHostNamespaceRootPolicy, date = defaultDateDeclarationPolicy, generator = defaultGeneratorDeclarationPolicy, regexp = defaultRegExpDeclarationPolicy, stringObject = defaultStringObjectDeclarationPolicy, functionType = defaultFunctionDeclarationPolicy, heritage = defaultClassHeritagePolicy, valueRecords = defaultValueRecordPolicy, implementors = defaultInterfaceImplementorPolicy, errors = defaultErrorDeclarationPolicy, dynamicFallback = false, dynamicFallbackTypes = new Set(), dynamicCallableShapes = new Map(), dynamicWrittenTypes = new Set(), classCopies = defaultClassCopyPolicy) => {
|
|
89
|
+
const memo = new Map();
|
|
90
|
+
// Every C++ spelling this deriver stamped on a Date's carrier, so `isDateCarrier` can read the fact back off a carrier.
|
|
91
|
+
const dateNatives = new Set();
|
|
92
|
+
const active = new Set();
|
|
93
|
+
// `active` answers membership; the ordered path says which native container
|
|
94
|
+
// owns a back edge that returns through a callable or an optional rather than
|
|
95
|
+
// through the container's own structural id.
|
|
96
|
+
const activePath = [];
|
|
97
|
+
// A back-edge through a native container is not a record reference: Map and
|
|
98
|
+
// Array have no struct name of their own that C++ can forward-declare. Keep
|
|
99
|
+
// one explicit indirection per structural identity while its equation is
|
|
100
|
+
// built, then close it as the outer native wrapper. The reference is a
|
|
101
|
+
// native-record-ref carrying a recursive marker: it is intentionally a leaf
|
|
102
|
+
// to every existing record walker, so no visitor has to infer a JS object
|
|
103
|
+
// cycle or impose its own depth limit.
|
|
104
|
+
const recursiveReferences = new Map();
|
|
105
|
+
// A named alias commonly has a distinct structural id for its `Map`/Array
|
|
106
|
+
// body. Once the alias closes the equation, that body must read back as the
|
|
107
|
+
// same wrapper too; otherwise a later body lookup could publish
|
|
108
|
+
// `Map<K, Ref<wrapper>>` beside `Ref<wrapper>` for one physical object.
|
|
109
|
+
const recursiveBodyIds = new Map();
|
|
110
|
+
// A replay of an active non-container root replaces exactly the container
|
|
111
|
+
// edge that closes the equation. It is deliberately scoped to that replay:
|
|
112
|
+
// publishing this reference as the container's ordinary answer would lose
|
|
113
|
+
// its definition and leave the wrapper undeclared.
|
|
114
|
+
const recursiveReplayReferences = new Map();
|
|
115
|
+
const replaying = new Set();
|
|
116
|
+
// Frames below a container back edge have been derived against its temporary
|
|
117
|
+
// reference, not its closed definition. They may be returned to the active
|
|
118
|
+
// container, but they cannot become canonical memo answers: map-first
|
|
119
|
+
// derivation would otherwise leave a callable ABI permanently pointing only
|
|
120
|
+
// at the reference, so a later root-only plan could not discover the wrapper
|
|
121
|
+
// definition.
|
|
122
|
+
const provisionalDependents = new Set();
|
|
123
|
+
// Records whose own derivation re-entered their id through a field -- see
|
|
124
|
+
// `nameSelfReferencedRecord` -- and the layouts `layoutOf` serves for them
|
|
125
|
+
// once `derive` has started answering the name instead.
|
|
126
|
+
const selfReferencedRecords = new Set();
|
|
127
|
+
const definitions = new Map();
|
|
128
|
+
// Record and native-container cycles have finite indirection. Any remaining
|
|
129
|
+
// cycle reached this far has no carrier-specific way to close and must not
|
|
130
|
+
// be memoized as though its individual structural id were sound.
|
|
131
|
+
let guardFired = 0;
|
|
132
|
+
const shapeOf = (id) => types.get(id)?.shape ?? null;
|
|
133
|
+
const typedArrayBufferKindOf = (shape) => {
|
|
134
|
+
for (const argument of shape.typeArguments) {
|
|
135
|
+
const candidate = shapeOf(argument);
|
|
136
|
+
if (candidate?.kind === 'declared' && buffers.forDeclaration(candidate.declaration) === 'shared-array-buffer')
|
|
137
|
+
return 'shared-array-buffer';
|
|
138
|
+
}
|
|
139
|
+
return 'array-buffer';
|
|
140
|
+
};
|
|
141
|
+
/**
|
|
142
|
+
* The class-instance shape an interface's sole implementor was interned
|
|
143
|
+
* under, for the type arguments this reference carries.
|
|
144
|
+
*
|
|
145
|
+
* Built lazily and once: an index over the sealed structural table, which is
|
|
146
|
+
* the only place an INSTANTIATED class shape exists. There is no public
|
|
147
|
+
* checker API to instantiate `PatternRouter<T>` at `Router<[H,
|
|
148
|
+
* RouterRoute]>`'s own arguments, and there is no need for one -- the
|
|
149
|
+
* program constructed the class somewhere, so the checker already interned
|
|
150
|
+
* that instantiation and this finds it rather than rebuilding it.
|
|
151
|
+
*
|
|
152
|
+
* Exact type arguments first. Falling back to a lone instantiation is not a
|
|
153
|
+
* guess: one class-instance shape for the class means the program has
|
|
154
|
+
* exactly one, so it is the shape any slot of that class holds. Two or more
|
|
155
|
+
* with no exact match refuses, because picking between them would be one.
|
|
156
|
+
*/
|
|
157
|
+
let implementorShapes = null;
|
|
158
|
+
/** Every class-instance shape the sealed table holds for this class declaration; empty for a class the program never instantiates or names. */
|
|
159
|
+
const instanceShapesOf = (declaration) => {
|
|
160
|
+
if (implementorShapes === null) {
|
|
161
|
+
implementorShapes = new Map();
|
|
162
|
+
for (const [candidate, entry] of types) {
|
|
163
|
+
if (entry.shape.kind !== 'class-instance')
|
|
164
|
+
continue;
|
|
165
|
+
const known = implementorShapes.get(entry.shape.declaration);
|
|
166
|
+
if (known)
|
|
167
|
+
known.push(candidate);
|
|
168
|
+
else
|
|
169
|
+
implementorShapes.set(entry.shape.declaration, [candidate]);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return implementorShapes.get(declaration) ?? [];
|
|
173
|
+
};
|
|
174
|
+
const implementorShapeFor = (declaration, typeArguments) => {
|
|
175
|
+
const candidates = instanceShapesOf(declaration);
|
|
176
|
+
if (candidates.length === 0)
|
|
177
|
+
return null;
|
|
178
|
+
const exact = candidates.filter((candidate) => {
|
|
179
|
+
const shape = shapeOf(candidate);
|
|
180
|
+
if (shape?.kind !== 'class-instance' || shape.typeArguments.length !== typeArguments.length)
|
|
181
|
+
return false;
|
|
182
|
+
return shape.typeArguments.every((argument, index) => argument === typeArguments[index]);
|
|
183
|
+
});
|
|
184
|
+
if (exact.length === 1)
|
|
185
|
+
return exact[0] ?? null;
|
|
186
|
+
return candidates.length === 1 ? (candidates[0] ?? null) : null;
|
|
187
|
+
};
|
|
188
|
+
/** The carrier a *stored* position holds -- see `storedCarrier`. */
|
|
189
|
+
const deriveStored = (id) => storedCarrier(derive(id));
|
|
190
|
+
const isDataOnlyBody = (id) => isDataOnlyObjectShape(shapeOf(id), shapeOf);
|
|
191
|
+
/**
|
|
192
|
+
* The container which a recursive type identity denotes, without expanding
|
|
193
|
+
* its recursive argument. Named records intentionally do not pass here:
|
|
194
|
+
* their existing `native-record-ref` is the native indirection. This answers
|
|
195
|
+
* the three containers, and the plain callable, which otherwise have no
|
|
196
|
+
* finite C++ spelling.
|
|
197
|
+
*/
|
|
198
|
+
const recursiveContainerSourceOf = (id) => {
|
|
199
|
+
const outer = shapeOf(id);
|
|
200
|
+
if (!outer)
|
|
201
|
+
return null;
|
|
202
|
+
const body = outer.kind === 'declared' && outer.body !== null ? shapeOf(outer.body) : null;
|
|
203
|
+
const source = body ?? outer;
|
|
204
|
+
const sourceId = body === null ? id : outer.body;
|
|
205
|
+
if (source.kind === 'array') {
|
|
206
|
+
return { kind: 'array', shape: source, bodyId: sourceId, ownershipShape: source, ownershipId: sourceId };
|
|
207
|
+
}
|
|
208
|
+
if (source.kind === 'object' && dictionaryIndexOf(source)) {
|
|
209
|
+
// A declared dictionary is selected in the declared branch itself, so
|
|
210
|
+
// its ownership comes from that declaration rather than its body. The
|
|
211
|
+
// identity memoized after the equation closes is still the actual body:
|
|
212
|
+
// ownership identity and structural body identity answer different
|
|
213
|
+
// questions and aliasing one to the other publishes two carriers.
|
|
214
|
+
return { kind: 'dictionary', shape: source, bodyId: sourceId, ownershipShape: outer, ownershipId: id };
|
|
215
|
+
}
|
|
216
|
+
if (source.kind === 'declared' && collections.forDeclaration(source.declaration)) {
|
|
217
|
+
return { kind: 'keyed-collection', shape: source, bodyId: sourceId, ownershipShape: source, ownershipId: sourceId };
|
|
218
|
+
}
|
|
219
|
+
// Exactly the shapes `deriveSignature` turns into `function-value-dispatch`.
|
|
220
|
+
// A construct signature, a call/construct pair, and the open type of a
|
|
221
|
+
// generic source function all select a different carrier, and naming a
|
|
222
|
+
// wrapper for one of those here would claim a fixpoint whose base type
|
|
223
|
+
// this file cannot spell.
|
|
224
|
+
if (source.kind === 'signature' && source.call.length > 0 && source.construct.length === 0 && !source.generic) {
|
|
225
|
+
return { kind: 'callable', shape: source, bodyId: sourceId };
|
|
226
|
+
}
|
|
227
|
+
return null;
|
|
228
|
+
};
|
|
229
|
+
/** Builds the explicit reference half of one recursive container equation. */
|
|
230
|
+
const recursiveReferenceOf = (id) => {
|
|
231
|
+
const markProvisionalDependents = () => {
|
|
232
|
+
const activeContainer = activePath.lastIndexOf(id);
|
|
233
|
+
if (activeContainer >= 0) {
|
|
234
|
+
for (let position = activeContainer + 1; position < activePath.length; position += 1) {
|
|
235
|
+
const dependent = activePath[position];
|
|
236
|
+
if (dependent !== undefined)
|
|
237
|
+
provisionalDependents.add(dependent);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const cached = recursiveReferences.get(id);
|
|
242
|
+
if (cached) {
|
|
243
|
+
markProvisionalDependents();
|
|
244
|
+
return cached;
|
|
245
|
+
}
|
|
246
|
+
const source = recursiveContainerSourceOf(id);
|
|
247
|
+
if (!source)
|
|
248
|
+
return null;
|
|
249
|
+
markProvisionalDependents();
|
|
250
|
+
const reference = {
|
|
251
|
+
kind: 'native-record-ref',
|
|
252
|
+
shapeId: id,
|
|
253
|
+
ownership: source.kind === 'callable' ? 'owned' : ownership.forShape(source.ownershipShape, source.ownershipId),
|
|
254
|
+
// A non-null marker makes `records.ts` correctly treat this as a name
|
|
255
|
+
// whose body belongs elsewhere. `cppTypeOf` ignores the marker text and
|
|
256
|
+
// spells the wrapper from `recursive`; it is never a host-native name.
|
|
257
|
+
native: `recursive-container:${id}`,
|
|
258
|
+
recursive: { type: id, container: source.kind === 'array' ? 'array-object' : source.kind, role: 'reference' }
|
|
259
|
+
};
|
|
260
|
+
recursiveReferences.set(id, reference);
|
|
261
|
+
recursiveBodyIds.set(id, source.bodyId);
|
|
262
|
+
return reference;
|
|
263
|
+
};
|
|
264
|
+
/** Marks the outer native container as the definition for a back-edge. */
|
|
265
|
+
const closeRecursiveContainer = (id, representation) => {
|
|
266
|
+
const reference = recursiveReferences.get(id);
|
|
267
|
+
if (!reference)
|
|
268
|
+
return representation;
|
|
269
|
+
if (reference.kind !== 'native-record-ref' || reference.recursive?.role !== 'reference' || representation.kind === 'unresolved') {
|
|
270
|
+
guardFired += 1;
|
|
271
|
+
return unresolved(`recursive type ${id} does not close over one native container carrier`);
|
|
272
|
+
}
|
|
273
|
+
switch (representation.kind) {
|
|
274
|
+
// A callable wrapper is one by-value struct with no pointer to own, so
|
|
275
|
+
// the shared-refcount indirection the containers need does not apply --
|
|
276
|
+
// `gea::CallableObject` stores a function pointer and a capture, never
|
|
277
|
+
// the parameter types, so its own incomplete self is a legal base.
|
|
278
|
+
case 'function-value-dispatch': {
|
|
279
|
+
if (reference.ownership !== 'owned') {
|
|
280
|
+
guardFired += 1;
|
|
281
|
+
return unresolved(`recursive type ${id} carries a callable back edge that is not held by value`);
|
|
282
|
+
}
|
|
283
|
+
const callable = { ...representation, recursive: { type: id, container: 'callable', role: 'definition' } };
|
|
284
|
+
const callableBody = recursiveBodyIds.get(id);
|
|
285
|
+
if (callableBody !== undefined && callableBody !== id)
|
|
286
|
+
memo.set(callableBody, callable);
|
|
287
|
+
return callable;
|
|
288
|
+
}
|
|
289
|
+
case 'array-object':
|
|
290
|
+
case 'dictionary':
|
|
291
|
+
case 'keyed-collection':
|
|
292
|
+
if (representation.ownership !== reference.ownership) {
|
|
293
|
+
guardFired += 1;
|
|
294
|
+
return unresolved(`recursive type ${id} changes ownership between its definition and back edge`);
|
|
295
|
+
}
|
|
296
|
+
if (representation.ownership !== 'shared-refcount') {
|
|
297
|
+
guardFired += 1;
|
|
298
|
+
return unresolved(`recursive type ${id} needs shared-refcount ownership for its native reference indirection`);
|
|
299
|
+
}
|
|
300
|
+
const definition = { ...representation, recursive: { type: id, container: representation.kind, role: 'definition' } };
|
|
301
|
+
const body = recursiveBodyIds.get(id);
|
|
302
|
+
if (body !== undefined && body !== id)
|
|
303
|
+
memo.set(body, definition);
|
|
304
|
+
return definition;
|
|
305
|
+
default:
|
|
306
|
+
guardFired += 1;
|
|
307
|
+
return unresolved(`recursive type ${id} closed through non-container carrier ${representation.kind}`);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
/** The innermost native container between an active root and its back edge. */
|
|
311
|
+
const recursiveContainerOnActivePath = (from) => {
|
|
312
|
+
for (let position = activePath.length - 1; position >= from; position -= 1) {
|
|
313
|
+
const candidate = activePath[position];
|
|
314
|
+
if (candidate !== undefined && recursiveContainerSourceOf(candidate))
|
|
315
|
+
return candidate;
|
|
316
|
+
}
|
|
317
|
+
return null;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Re-derive an active function, constructor, optional, or alias with the
|
|
321
|
+
* enclosing container already named. The replay gives the function's ABI its
|
|
322
|
+
* real finite result type (`Ref<Wrapper>`); returning that ABI at the back
|
|
323
|
+
* edge is essential, because a container reference cannot stand in for a
|
|
324
|
+
* function value stored by that container.
|
|
325
|
+
*/
|
|
326
|
+
const replayThroughRecursiveContainer = (id, container) => {
|
|
327
|
+
if (replaying.has(id)) {
|
|
328
|
+
guardFired += 1;
|
|
329
|
+
return unresolved(`structural type ${id} recurs again before native container ${container} can close its carrier`);
|
|
330
|
+
}
|
|
331
|
+
const reference = recursiveReferenceOf(container);
|
|
332
|
+
if (!reference) {
|
|
333
|
+
guardFired += 1;
|
|
334
|
+
return unresolved(`structural type ${id} recurs through ${container}, which has no native container carrier`);
|
|
335
|
+
}
|
|
336
|
+
replaying.add(id);
|
|
337
|
+
recursiveReplayReferences.set(container, reference);
|
|
338
|
+
try {
|
|
339
|
+
const shape = shapeOf(id);
|
|
340
|
+
return shape ? deriveShape(id, shape) : unresolved(`structural type ${id} is not present in the sealed table`);
|
|
341
|
+
}
|
|
342
|
+
finally {
|
|
343
|
+
recursiveReplayReferences.delete(container);
|
|
344
|
+
replaying.delete(id);
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
const derive = (id) => {
|
|
348
|
+
const replayReference = recursiveReplayReferences.get(id);
|
|
349
|
+
if (replayReference)
|
|
350
|
+
return replayReference;
|
|
351
|
+
const cached = memo.get(id);
|
|
352
|
+
if (cached)
|
|
353
|
+
return cached;
|
|
354
|
+
if (active.has(id)) {
|
|
355
|
+
const recursive = recursiveReferenceOf(id);
|
|
356
|
+
if (recursive)
|
|
357
|
+
return recursive;
|
|
358
|
+
const recurrenceStart = activePath.lastIndexOf(id);
|
|
359
|
+
const container = recurrenceStart < 0 ? null : recursiveContainerOnActivePath(recurrenceStart);
|
|
360
|
+
if (container)
|
|
361
|
+
return replayThroughRecursiveContainer(id, container);
|
|
362
|
+
// A record shape that recurs back to itself -- `self: Window & typeof
|
|
363
|
+
// globalThis` interns to the identical `intersection` shape id as the
|
|
364
|
+
// very type `Window`'s own "self" member declares, so flattening that
|
|
365
|
+
// intersection (`deriveIntersection`) re-enters the id already
|
|
366
|
+
// `active` -- has no finite BY-VALUE layout (a C++ aggregate cannot
|
|
367
|
+
// embed itself), but it has an entirely finite BY-REFERENCE one: the
|
|
368
|
+
// same `native-record-ref` a `'declared'`/`'class-instance'` wrapper
|
|
369
|
+
// already hands every OTHER reference to a named record, naming the
|
|
370
|
+
// shape rather than expanding it (see those cases above, and
|
|
371
|
+
// `native-record-ref`'s own doc comment: "expanding a name whose body
|
|
372
|
+
// refers back to itself has no finite carrier, so the name stays the
|
|
373
|
+
// carrier"). Reusing it here -- for a record shape that cycles
|
|
374
|
+
// directly, not only through a nominal wrapper -- is the
|
|
375
|
+
// "shared-refcount handle with a forward declaration" this cycle
|
|
376
|
+
// needs: `targets/cpp/records.ts` already forward-declares every
|
|
377
|
+
// struct before defining it, so a field naming the struct's own shape
|
|
378
|
+
// id compiles as a pointer to an as-yet-incomplete type, same as any
|
|
379
|
+
// other native-record-ref field does.
|
|
380
|
+
//
|
|
381
|
+
// `'object'` and `'intersection'` are the only two structural shape
|
|
382
|
+
// kinds `deriveShape` (below) ever turns into a `record`/
|
|
383
|
+
// `record-with-index` carrier keyed by `shapeId: id` -- `deriveObject`
|
|
384
|
+
// and `deriveIntersection` respectively -- so those are the only two
|
|
385
|
+
// kinds a cycle back to `id` can mean "this record contains itself."
|
|
386
|
+
// Every OTHER structural shape kind keeps the previous fail-closed
|
|
387
|
+
// answer unchanged: a function, union, or tuple that cycles has no
|
|
388
|
+
// such by-reference primitive, and inventing one for a shape this
|
|
389
|
+
// deriver does not know how to indirect would be exactly the guess
|
|
390
|
+
// this guard exists to refuse.
|
|
391
|
+
const cyclic = shapeOf(id);
|
|
392
|
+
if (cyclic?.kind === 'object' || cyclic?.kind === 'intersection') {
|
|
393
|
+
selfReferencedRecords.add(id);
|
|
394
|
+
return { kind: 'native-record-ref', shapeId: id, ownership: ownership.forShape(cyclic, id), native: null };
|
|
395
|
+
}
|
|
396
|
+
// A DECLARED name that cycles is the easiest case of all, and it only
|
|
397
|
+
// became reachable once `structural-self-reference.ts` started closing a
|
|
398
|
+
// re-instantiated alias into a real cycle instead of unrolling it into a
|
|
399
|
+
// tower of distinct ids: mongodb reaches here 2,195 times. The answer is
|
|
400
|
+
// the one the ordinary declared path already gives every OTHER reference
|
|
401
|
+
// to a named record -- the name, not the expansion -- so the cycle takes
|
|
402
|
+
// the same nominal carrier rather than a refusal. Only when the body is
|
|
403
|
+
// a record layout: naming a union or a signature body here would hand
|
|
404
|
+
// `records.ts` a struct id whose fields it cannot find, which is a
|
|
405
|
+
// different failure wearing this one's clothes.
|
|
406
|
+
if (cyclic?.kind === 'declared' && cyclic.body !== null) {
|
|
407
|
+
const body = shapeOf(cyclic.body);
|
|
408
|
+
if (body?.kind === 'object' || body?.kind === 'intersection')
|
|
409
|
+
return { kind: 'native-record-ref', shapeId: cyclic.body, ownership: ownership.forShape(cyclic, id), native: null };
|
|
410
|
+
// A named union is its body: the ordinary declared path derives a
|
|
411
|
+
// union-bodied alias as `derive(shape.body)`, and the body id is
|
|
412
|
+
// active alongside its name, so the union rule below answers.
|
|
413
|
+
if (body?.kind === 'union')
|
|
414
|
+
return derive(cyclic.body);
|
|
415
|
+
}
|
|
416
|
+
// A UNION that recurs has the by-reference layout its ARMS have. tsc's
|
|
417
|
+
// `type TypeMapper = { kind: Simple; ... } | { kind: Composite; mapper1:
|
|
418
|
+
// TypeMapper; mapper2: TypeMapper }` re-enters the union from inside an
|
|
419
|
+
// arm's own field, and the checker's narrowed `(A & Node & { name?:
|
|
420
|
+
// undefined }) | (B & Node & ...)` unions re-enter through the `Node`
|
|
421
|
+
// family's parent field: 800 refusals on the tsc self-compile. Nothing
|
|
422
|
+
// about the union needs a new indirection -- every record arm stores as
|
|
423
|
+
// a `native-record-ref` already, and an arm that is itself active on the
|
|
424
|
+
// cycle takes the record rule above -- so the union is derived here
|
|
425
|
+
// exactly as its non-recursive form is, through the one union deriver,
|
|
426
|
+
// and reaches the identical tagged-union the top-level derivation
|
|
427
|
+
// memoizes: same shape, same canonical arm order, same discriminant. An
|
|
428
|
+
// arm with no by-reference form (an array or signature that cycles) is
|
|
429
|
+
// still refused by its own kind's guard on the way, so this loosens
|
|
430
|
+
// nothing for the shapes the comment above rules out.
|
|
431
|
+
if (cyclic?.kind === 'union') {
|
|
432
|
+
// Memoized under the top-level rule (no guard fired while deriving),
|
|
433
|
+
// because every later re-entry through any of the union's arms would
|
|
434
|
+
// otherwise derive the same union again -- and tsc's Node-family
|
|
435
|
+
// unions re-enter from hundreds of fields.
|
|
436
|
+
const before = guardFired;
|
|
437
|
+
const derived = deriveUnionShape(cyclic);
|
|
438
|
+
if (guardFired === before)
|
|
439
|
+
memo.set(id, derived);
|
|
440
|
+
return derived;
|
|
441
|
+
}
|
|
442
|
+
guardFired += 1;
|
|
443
|
+
return unresolved(`structural type ${id} recurs without a nominal carrier on the cycle`);
|
|
444
|
+
}
|
|
445
|
+
const before = guardFired;
|
|
446
|
+
active.add(id);
|
|
447
|
+
activePath.push(id);
|
|
448
|
+
const shape = shapeOf(id);
|
|
449
|
+
const derived = dynamicFallback && dynamicFallbackTypes.has(id)
|
|
450
|
+
? { kind: 'dynamic', reason: 'opt-in-fallback' }
|
|
451
|
+
: dynamicWrittenTypes.has(id)
|
|
452
|
+
? { kind: 'dynamic', reason: 'declared-any-never-narrowed' }
|
|
453
|
+
: shape
|
|
454
|
+
? deriveShape(id, shape)
|
|
455
|
+
: unresolved(`structural type ${id} is not present in the sealed table`);
|
|
456
|
+
active.delete(id);
|
|
457
|
+
const popped = activePath.pop();
|
|
458
|
+
if (popped !== id)
|
|
459
|
+
throw new Error(`representation derivation path lost structural type ${id}`);
|
|
460
|
+
const provisional = provisionalDependents.delete(id);
|
|
461
|
+
// Deriving a body first can enter its declared alias, close the recursive
|
|
462
|
+
// equation there, and install this body's canonical definition while the
|
|
463
|
+
// outer body derivation is still unwinding. Keep that exact object instead
|
|
464
|
+
// of overwriting it with the non-recursive expansion computed before the
|
|
465
|
+
// alias closed.
|
|
466
|
+
const canonical = memo.get(id);
|
|
467
|
+
if (canonical) {
|
|
468
|
+
if (guardFired === before && !provisional)
|
|
469
|
+
return canonical;
|
|
470
|
+
// The outer derivation found a defect after the nested alias installed
|
|
471
|
+
// the provisional body answer. Do not let that partial answer survive a
|
|
472
|
+
// fail-closed guard.
|
|
473
|
+
memo.delete(id);
|
|
474
|
+
}
|
|
475
|
+
const closed = guardFired === before ? nameSelfReferencedRecord(id, closeRecursiveContainer(id, derived)) : derived;
|
|
476
|
+
if (guardFired === before && !provisional)
|
|
477
|
+
memo.set(id, closed);
|
|
478
|
+
return closed;
|
|
479
|
+
};
|
|
480
|
+
/**
|
|
481
|
+
* A record that contains itself is spelled BY NAME at every value position,
|
|
482
|
+
* and its layout is kept aside for `layoutOf`.
|
|
483
|
+
*
|
|
484
|
+
* A declared interface has two structural ids -- the name, which derives to
|
|
485
|
+
* a `native-record-ref` without ever expanding, and the body, which is the
|
|
486
|
+
* record -- so every reference to `interface Node { next: Node }` spells
|
|
487
|
+
* one way no matter which walk reaches it first. An anonymous object type
|
|
488
|
+
* that recurs (tsc's `type TypeMapper = {...} | { kind: Composite; mapper1:
|
|
489
|
+
* TypeMapper; mapper2: TypeMapper }`, whose fifth arm is a type literal) has
|
|
490
|
+
* ONE id for both roles, and until this rule it was spelled by whichever
|
|
491
|
+
* role the walk happened to be in: the cycle rule above closes a back edge
|
|
492
|
+
* as `native-record-ref(id)`, while a walk that entered the union from
|
|
493
|
+
* outside the record expanded the same arm inline as `record(id, ...)`. Two
|
|
494
|
+
* keys for one `gea::Ref<Struct>`, decided by memo order -- `let mapper:
|
|
495
|
+
* TypeMapper | undefined` held the inline spelling and the narrowed read
|
|
496
|
+
* after `mapper === undefined` wanted the by-name one, and no conversion
|
|
497
|
+
* exists between them because none should: 19 binding-read rows on the tsc
|
|
498
|
+
* self-compile, plus every merge and narrowed-arm read beside them.
|
|
499
|
+
*
|
|
500
|
+
* Only a shared-refcount record can take the rule: the name is a pointer to
|
|
501
|
+
* an as-yet-incomplete struct, which is exactly what `records.ts`'s forward
|
|
502
|
+
* declarations exist for, whereas a by-value record naming itself would be
|
|
503
|
+
* the "by-value incomplete type" `compiler.ts`'s ownership policy refuses.
|
|
504
|
+
* The by-name answer is memoized as the carrier; the record itself is the
|
|
505
|
+
* definition `layoutOf` serves to every layout lookup, so a field read
|
|
506
|
+
* through the name still finds its fields.
|
|
507
|
+
*/
|
|
508
|
+
const nameSelfReferencedRecord = (id, closed) => {
|
|
509
|
+
if (!selfReferencedRecords.has(id))
|
|
510
|
+
return closed;
|
|
511
|
+
if ((closed.kind !== 'record' && closed.kind !== 'record-with-index') || closed.ownership !== 'shared-refcount')
|
|
512
|
+
return closed;
|
|
513
|
+
definitions.set(id, closed);
|
|
514
|
+
return { kind: 'native-record-ref', shapeId: id, ownership: closed.ownership, native: null };
|
|
515
|
+
};
|
|
516
|
+
const layoutOf = (id) => {
|
|
517
|
+
const carrier = derive(id);
|
|
518
|
+
return definitions.get(id) ?? carrier;
|
|
519
|
+
};
|
|
520
|
+
/**
|
|
521
|
+
* The physical calling convention of one signature.
|
|
522
|
+
*
|
|
523
|
+
* A rest parameter has no fixed physical arity, and this layer has no
|
|
524
|
+
* primitive that turns one into a call frame. Returning `null` states that
|
|
525
|
+
* rather than silently lowering the rest parameter to its array type, which
|
|
526
|
+
* would compile and then pass the wrong number of arguments.
|
|
527
|
+
*/
|
|
528
|
+
const abiOf = (signature) => {
|
|
529
|
+
const parameters = [];
|
|
530
|
+
let restFrom = null;
|
|
531
|
+
for (const [position, parameter] of signature.parameters.entries()) {
|
|
532
|
+
// A rest parameter's declared type is already the Array the language
|
|
533
|
+
// binds it to, so the slot derives like any other. Only a rest parameter
|
|
534
|
+
// that is not the last one would be a frame this layer cannot lay out,
|
|
535
|
+
// and TypeScript does not admit one.
|
|
536
|
+
if (parameter.rest) {
|
|
537
|
+
if (position !== signature.parameters.length - 1)
|
|
538
|
+
return null;
|
|
539
|
+
restFrom = position;
|
|
540
|
+
}
|
|
541
|
+
// An omitted argument is `undefined`, never `null`, and a defaulted
|
|
542
|
+
// parameter widens the same way an optional one does: the physical slot
|
|
543
|
+
// has to hold "the caller didn't supply a value" as well as the payload,
|
|
544
|
+
// because the initializer runs at call time inside the callee, over
|
|
545
|
+
// exactly this carrier (`semantics/normalize/producers/bindings.ts`'s
|
|
546
|
+
// `contributeParameter`).
|
|
547
|
+
//
|
|
548
|
+
// The widening itself is not done here. It is a question about a TYPE --
|
|
549
|
+
// `T` or `T | null` unioned with `undefined` -- and this layer cannot
|
|
550
|
+
// ask it: the structural table is sealed by the time a carrier is
|
|
551
|
+
// chosen, so there is no way to name a union that was not already
|
|
552
|
+
// interned. Layering an absence FLAG over the derived carrier instead is
|
|
553
|
+
// what this used to do, and it could not express the case where the
|
|
554
|
+
// declared type already spends absence on `null`: one flag cannot say
|
|
555
|
+
// which of the two absent values it holds, so `f(x: T | null = null)`
|
|
556
|
+
// was refused outright. `SignatureParameter.slot` is that union, interned
|
|
557
|
+
// by the normalizer where types are still being made, and it derives to
|
|
558
|
+
// the three-armed tagged union the union deriver has always built.
|
|
559
|
+
let value = deriveStored(parameter.slot);
|
|
560
|
+
const slot = shapeOf(parameter.slot);
|
|
561
|
+
// Rest packing creates a fresh ordinary Array; it cannot produce a proxy.
|
|
562
|
+
// Keep the call frame concrete even when observable arrays of this type use fallback dispatch.
|
|
563
|
+
if (parameter.rest && value.kind === 'dynamic' && value.reason === 'opt-in-fallback' && slot?.kind === 'array') {
|
|
564
|
+
value = { kind: 'array-object', element: deriveStored(slot.element), ownership: 'shared-refcount', extension: null };
|
|
565
|
+
}
|
|
566
|
+
const parameterOwnership = ownership.forParameter(value);
|
|
567
|
+
parameters.push({ value, ownership: parameterOwnership, passing: passingOf(value, parameterOwnership) });
|
|
568
|
+
}
|
|
569
|
+
const declaredReceiver = signature.thisParameter ? derive(signature.thisParameter) : null;
|
|
570
|
+
return {
|
|
571
|
+
parameters,
|
|
572
|
+
restFrom,
|
|
573
|
+
result: derive(signature.result),
|
|
574
|
+
// `this: void` is TypeScript's declaration that a function does not use
|
|
575
|
+
// or require a receiver. It is not an `undefined` value passed in a
|
|
576
|
+
// hidden receiver slot. BSON's optional WASM helpers deliberately use
|
|
577
|
+
// this form so `(condition ? helpers.a : helpers.b)(...)` is an ordinary
|
|
578
|
+
// unbound call. Preserve every other explicit this type as stored data.
|
|
579
|
+
receiver: declaredReceiver?.kind === 'void' ? null : declaredReceiver === null ? null : storedCarrier(declaredReceiver)
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
/**
|
|
583
|
+
* The one physical convention a set of signatures shares, or `null`.
|
|
584
|
+
*
|
|
585
|
+
* An overload set is a checker-level fact about which signature a *call site*
|
|
586
|
+
* resolved; it is not automatically a physical fact about the value. Where the
|
|
587
|
+
* overloads project to the same frame -- which is what declaration merging
|
|
588
|
+
* produces, and what an overload differing only in an erased type argument
|
|
589
|
+
* produces -- there is exactly one convention, and refusing it would refuse a
|
|
590
|
+
* value that has a single unambiguous layout.
|
|
591
|
+
*
|
|
592
|
+
* An exact match is tried first; failing that, `widestSubsumingAbi`
|
|
593
|
+
* (host-abi.ts) tries the same widening test a host handle's own overload
|
|
594
|
+
* set already gets -- one frame with a trailing optional parameter, spelled
|
|
595
|
+
* as several overloads instead of one signature, which is what declaration
|
|
596
|
+
* merging produces regardless of whether the merged declarations happen to
|
|
597
|
+
* live in an ambient host library or in the program's own source. There is
|
|
598
|
+
* nothing host-specific about the fact two overloads share a frame up to a
|
|
599
|
+
* trailing optional; restricting the widening test to host bindings only
|
|
600
|
+
* refused ordinary program-defined overloaded values -- `function f(x:
|
|
601
|
+
* number): void; function f(x: number, y = 0): void {}` used as a
|
|
602
|
+
* first-class value, never called through this exact reference -- for a
|
|
603
|
+
* reason that has nothing to do with what makes the widening sound. Where
|
|
604
|
+
* the overloads genuinely project to different frames, neither test passes
|
|
605
|
+
* and this stays refused: a caller reaching one of them through the
|
|
606
|
+
* other's frame would still pass the wrong arguments.
|
|
607
|
+
*/
|
|
608
|
+
/**
|
|
609
|
+
* The convention a set of overloads share once each parameter position is
|
|
610
|
+
* allowed to become the UNION of what the overloads declare there.
|
|
611
|
+
*
|
|
612
|
+
* `widestSubsumingAbi` joins only by subsumption, so
|
|
613
|
+
* `interface Operation { (v: number): number; (v: string): number }` -- used
|
|
614
|
+
* as a stored FIELD, which is the shape `overloaded-callable-fields.ts`,
|
|
615
|
+
* `generic-field-initializer.ts` and `builtin-function-name-length.runtime.js`
|
|
616
|
+
* all refuse on -- has no join: `double` and `std::string` subsume neither
|
|
617
|
+
* way. A field holds ONE frame for both calls, so per-call overload
|
|
618
|
+
* selection (`singleConventionAt`) cannot answer it either.
|
|
619
|
+
*
|
|
620
|
+
* The frame that does hold both is the one the implementation already has:
|
|
621
|
+
* TypeScript requires the value to satisfy every signature, so
|
|
622
|
+
* `(value: string | number) => number` is what is actually assigned, and
|
|
623
|
+
* `(TaggedUnion<double, std::string>) -> double` is its convention.
|
|
624
|
+
*
|
|
625
|
+
* Built from the SIGNATURES rather than from their ABIs, which is the whole
|
|
626
|
+
* reason this lives here and not in `widestSubsumingAbi`: a `TaggedUnionArm`
|
|
627
|
+
* needs a `semanticType` and an `AbiParameter` carries only a
|
|
628
|
+
* `Representation`, so a join working on ABIs alone has nothing to build
|
|
629
|
+
* arms from. Each `SignatureParameter.slot` is already an interned id, so
|
|
630
|
+
* the ordinary union deriver produces the arms -- no hand-built union, and
|
|
631
|
+
* nothing new interned into the sealed table.
|
|
632
|
+
*
|
|
633
|
+
* Refused, deliberately, where the join would be a guess rather than a
|
|
634
|
+
* widening: a declared receiver or a rest parameter (either makes the frames
|
|
635
|
+
* genuinely different rather than merely differently-typed), results that
|
|
636
|
+
* disagree, and any position some overload does not declare -- differing
|
|
637
|
+
* ARITY is an optionality question `widestSubsumingAbi` already answers, and
|
|
638
|
+
* two answers to it here is the duplication this refactor exists to remove.
|
|
639
|
+
*/
|
|
640
|
+
const unionJoinedAbi = (signatures) => {
|
|
641
|
+
if (signatures.length < 2)
|
|
642
|
+
return null;
|
|
643
|
+
if (signatures.some((signature) => signature.thisParameter !== null))
|
|
644
|
+
return null;
|
|
645
|
+
if (signatures.some((signature) => signature.parameters.some((parameter) => parameter.rest)))
|
|
646
|
+
return null;
|
|
647
|
+
const results = signatures.map((signature) => derive(signature.result));
|
|
648
|
+
const firstResult = results[0];
|
|
649
|
+
if (!firstResult)
|
|
650
|
+
return null;
|
|
651
|
+
const resultKey = representationKey(firstResult);
|
|
652
|
+
if (results.some((result) => representationKey(result) !== resultKey))
|
|
653
|
+
return null;
|
|
654
|
+
const arity = signatures[0]?.parameters.length ?? 0;
|
|
655
|
+
if (signatures.some((signature) => signature.parameters.length !== arity))
|
|
656
|
+
return null;
|
|
657
|
+
const parameters = [];
|
|
658
|
+
for (let position = 0; position < arity; position += 1) {
|
|
659
|
+
const slots = [];
|
|
660
|
+
for (const signature of signatures) {
|
|
661
|
+
const own = signature.parameters[position];
|
|
662
|
+
if (own === undefined)
|
|
663
|
+
return null;
|
|
664
|
+
if (!slots.includes(own.slot))
|
|
665
|
+
slots.push(own.slot);
|
|
666
|
+
}
|
|
667
|
+
const sole = slots[0];
|
|
668
|
+
if (sole === undefined)
|
|
669
|
+
return null;
|
|
670
|
+
const value = slots.length === 1 ? deriveStored(sole) : storedCarrier(deriveUnionShape({ kind: 'union', members: slots }));
|
|
671
|
+
// A union the deriver could not carry is not a frame; refusing keeps the
|
|
672
|
+
// caller's existing message rather than publishing an unresolved slot.
|
|
673
|
+
if (value.kind === 'unresolved')
|
|
674
|
+
return null;
|
|
675
|
+
const parameterOwnership = ownership.forParameter(value);
|
|
676
|
+
parameters.push({ value, ownership: parameterOwnership, passing: passingOf(value, parameterOwnership) });
|
|
677
|
+
}
|
|
678
|
+
return { parameters, restFrom: null, result: firstResult, receiver: null };
|
|
679
|
+
};
|
|
680
|
+
const sharedAbiOf = (signatures, role, joinsByUnion = false) => {
|
|
681
|
+
const abis = [];
|
|
682
|
+
for (const signature of signatures) {
|
|
683
|
+
const abi = abiOf(signature);
|
|
684
|
+
// `abiOf` refuses exactly one thing, and naming it here keeps a variadic
|
|
685
|
+
// signature from being reported as an overload disagreement.
|
|
686
|
+
if (!abi)
|
|
687
|
+
return 'no primitive for a variadic calling convention';
|
|
688
|
+
abis.push(abi);
|
|
689
|
+
}
|
|
690
|
+
const first = abis[0];
|
|
691
|
+
if (!first)
|
|
692
|
+
return role === 'construct' ? 'shape with no construct signature' : 'callable shape with no call signature';
|
|
693
|
+
const firstKey = abiKey(first);
|
|
694
|
+
if (abis.every((abi) => abiKey(abi) === firstKey))
|
|
695
|
+
return first;
|
|
696
|
+
const widened = widestSubsumingAbi(abis);
|
|
697
|
+
if (typeof widened !== 'string')
|
|
698
|
+
return widened;
|
|
699
|
+
// Only where the caller says a union frame is admissible. A HOST overload
|
|
700
|
+
// set is bound to a native implementation whose calling convention the
|
|
701
|
+
// host layer states, so widening its parameters would rewrite the very ABI
|
|
702
|
+
// that binding matches against -- the same reason the interface-receiver
|
|
703
|
+
// work had to exclude ambient declarations.
|
|
704
|
+
const unionJoined = joinsByUnion ? unionJoinedAbi(signatures) : null;
|
|
705
|
+
if (unionJoined)
|
|
706
|
+
return unionJoined;
|
|
707
|
+
return role === 'construct'
|
|
708
|
+
? `no primitive joining ${signatures.length} construct signatures into one calling convention: ${widened}`
|
|
709
|
+
: `no primitive joining ${signatures.length} overload signatures into one calling convention: ${widened}`;
|
|
710
|
+
};
|
|
711
|
+
/**
|
|
712
|
+
* A handle's own `[[Call]]`/`[[Construct]]` convention, or `null` (not
|
|
713
|
+
* `unresolved`: unjoinable still leaves the handle usable for property
|
|
714
|
+
* access). `sharedAbiOf` already tries the exact join and the widening
|
|
715
|
+
* test; only the failure carrier differs here, because a handle stays
|
|
716
|
+
* usable for property access with no callable convention at all.
|
|
717
|
+
*/
|
|
718
|
+
const hostInvocationAbiOf = (signatures, role) => {
|
|
719
|
+
if (signatures.length === 0)
|
|
720
|
+
return null;
|
|
721
|
+
const joined = sharedAbiOf(signatures, role);
|
|
722
|
+
return typeof joined === 'string' ? null : joined;
|
|
723
|
+
};
|
|
724
|
+
// An accessor-backed member has no storage, so it contributes no field. Both
|
|
725
|
+
// halves read the same member list so the two can never disagree about which
|
|
726
|
+
// members are laid out and which are called.
|
|
727
|
+
const recordFieldsOf = (shape) => shape.members
|
|
728
|
+
.filter((member) => member.accessor === null && runtimeSymbolMemberIndexOf(shape, member.key) === null)
|
|
729
|
+
.map((member) => ({ key: recordFieldKeyOf(member.key), value: deriveStored(member.type), required: !member.optional }));
|
|
730
|
+
/**
|
|
731
|
+
* Derive and canonicalize the disjoint physical key domains of a record.
|
|
732
|
+
* Number property keys alias their canonical string form in JavaScript, so a
|
|
733
|
+
* string+number pair can share one string table only when its native value
|
|
734
|
+
* carrier is exactly the same. Symbols never alias text and keep a separate
|
|
735
|
+
* identity-keyed table.
|
|
736
|
+
*/
|
|
737
|
+
const canonicalRecordIndexes = (indexes) => {
|
|
738
|
+
const byKey = new Map();
|
|
739
|
+
for (const index of indexes) {
|
|
740
|
+
const existing = byKey.get(index.key);
|
|
741
|
+
if (existing && representationKey(existing) !== representationKey(index.value))
|
|
742
|
+
return `no primitive for a record whose ${index.key} index signatures have incompatible native value carriers`;
|
|
743
|
+
byKey.set(index.key, existing ?? index.value);
|
|
744
|
+
}
|
|
745
|
+
const stringValue = byKey.get('string');
|
|
746
|
+
const numberValue = byKey.get('number');
|
|
747
|
+
if (stringValue && numberValue && representationKey(stringValue) !== representationKey(numberValue))
|
|
748
|
+
return 'no primitive for a record whose string and number index signatures have incompatible native value carriers';
|
|
749
|
+
const result = [];
|
|
750
|
+
if (stringValue)
|
|
751
|
+
result.push({ key: 'string', value: stringValue });
|
|
752
|
+
else if (numberValue)
|
|
753
|
+
result.push({ key: 'number', value: numberValue });
|
|
754
|
+
const symbolValue = byKey.get('symbol');
|
|
755
|
+
if (symbolValue)
|
|
756
|
+
result.push({ key: 'symbol', value: symbolValue });
|
|
757
|
+
return result;
|
|
758
|
+
};
|
|
759
|
+
const recordIndexesOf = (shape) => {
|
|
760
|
+
const structural = carriableIndexesOf(shape);
|
|
761
|
+
if (typeof structural === 'string')
|
|
762
|
+
return structural;
|
|
763
|
+
if (structural.length > 0 && shape.members.some((member) => member.accessor !== null))
|
|
764
|
+
return 'no native record carrier preserves both index storage and accessor descriptors';
|
|
765
|
+
return canonicalRecordIndexes(structural.map((index) => ({ key: index.key, value: deriveStored(index.value) })));
|
|
766
|
+
};
|
|
767
|
+
/**
|
|
768
|
+
* The fields an array-extending interface adds (`structural-types.ts`'s
|
|
769
|
+
* `extension`), as the record fields the generated sidecar struct will
|
|
770
|
+
* declare. Every field is a plain data member; an optional one carries the
|
|
771
|
+
* same presence bit `records.ts` gives a record's optional field (tsc's
|
|
772
|
+
* `JSDocArray extends Array<JSDoc>` declares `jsDocCache?`, and a read of
|
|
773
|
+
* it before any write must be `undefined`, not a default-constructed
|
|
774
|
+
* array). An accessor has a body and no storage, so it refuses by name
|
|
775
|
+
* rather than laying out a member that lies.
|
|
776
|
+
*/
|
|
777
|
+
const arrayExtensionFieldsOf = (extension) => {
|
|
778
|
+
if (extension.length === 0)
|
|
779
|
+
return null;
|
|
780
|
+
const fields = [];
|
|
781
|
+
for (const member of extension) {
|
|
782
|
+
const key = recordFieldKeyOf(member.key);
|
|
783
|
+
if (member.accessor !== null)
|
|
784
|
+
return `an interface extending Array declares accessor "${key}"; only data fields are carried on an array's extension`;
|
|
785
|
+
fields.push({ key, value: deriveStored(member.type), required: !member.optional });
|
|
786
|
+
}
|
|
787
|
+
return fields;
|
|
788
|
+
};
|
|
789
|
+
const deriveObject = (id, shape) => {
|
|
790
|
+
const dictionaryIndex = dictionaryIndexOf(shape);
|
|
791
|
+
if (dictionaryIndex) {
|
|
792
|
+
return {
|
|
793
|
+
kind: 'dictionary',
|
|
794
|
+
key: dictionaryIndex.key,
|
|
795
|
+
value: deriveStored(dictionaryIndex.value),
|
|
796
|
+
ownership: ownership.forShape(shape, id)
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
const fields = recordFieldsOf(shape);
|
|
800
|
+
const indexes = recordIndexesOf(shape);
|
|
801
|
+
if (typeof indexes === 'string')
|
|
802
|
+
return unresolved(indexes);
|
|
803
|
+
if (shape.members.length === 0 && indexes.length === 1) {
|
|
804
|
+
const [index] = indexes;
|
|
805
|
+
if (index)
|
|
806
|
+
return { kind: 'dictionary', key: index.key, value: index.value, ownership: ownership.forShape(shape, id) };
|
|
807
|
+
}
|
|
808
|
+
// `Record<string | symbol, any>` states no layout at all: every key of
|
|
809
|
+
// every kind holds anything. Programs pass class instances and prototype
|
|
810
|
+
// objects through it and store onto them by symbol, which only the object
|
|
811
|
+
// itself can hold, so it is the dynamic object it declares rather than a
|
|
812
|
+
// fresh sidecar record a conversion would copy into.
|
|
813
|
+
const openDynamic = (value) => value.kind === 'dynamic' && value.reason === 'declared-any-never-narrowed';
|
|
814
|
+
if (shape.members.length === 0 && indexes.length > 1 && indexes.every((index) => openDynamic(index.value)))
|
|
815
|
+
return indexes[0].value;
|
|
816
|
+
if (indexes.length > 0) {
|
|
817
|
+
return {
|
|
818
|
+
kind: 'record-with-index',
|
|
819
|
+
shapeId: id,
|
|
820
|
+
fields,
|
|
821
|
+
indexes,
|
|
822
|
+
ownership: ownership.forShape(shape, id)
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
return {
|
|
826
|
+
kind: 'record',
|
|
827
|
+
shapeId: id,
|
|
828
|
+
fields,
|
|
829
|
+
accessors: recordAccessorsOf(shape, deriveStored),
|
|
830
|
+
ownership: ownership.forShape(shape, id)
|
|
831
|
+
};
|
|
832
|
+
};
|
|
833
|
+
/**
|
|
834
|
+
* The object shape a member of an intersection contributes.
|
|
835
|
+
*
|
|
836
|
+
* A declared name contributes its body, because an intersection of two named
|
|
837
|
+
* record types is one record with both member sets -- the names do not survive
|
|
838
|
+
* the merge. A class instance contributes nothing: it is nominal, and merging
|
|
839
|
+
* a class into a structural record would silently drop its identity.
|
|
840
|
+
*/
|
|
841
|
+
const intersectionMemberShape = (member) => {
|
|
842
|
+
const shape = shapeOf(member);
|
|
843
|
+
if (!shape)
|
|
844
|
+
return null;
|
|
845
|
+
if (shape.kind === 'object')
|
|
846
|
+
return shape;
|
|
847
|
+
if (shape.kind !== 'declared' || !shape.body)
|
|
848
|
+
return null;
|
|
849
|
+
const body = shapeOf(shape.body);
|
|
850
|
+
return body?.kind === 'object' ? body : null;
|
|
851
|
+
};
|
|
852
|
+
/**
|
|
853
|
+
* A brand marker contributes no runtime structure to an intersection.
|
|
854
|
+
*
|
|
855
|
+
* `{ readonly [brand]?: never }` is the standard nominal-typing trick: every
|
|
856
|
+
* member is optional and typed `never`, so no value can ever actually carry
|
|
857
|
+
* one, and the checker's structural comparison only cares about what *can* be
|
|
858
|
+
* assigned. A member shaped like this is a type-system-only fence around its
|
|
859
|
+
* sibling and has no runtime footprint of its own -- `type f32 = number &
|
|
860
|
+
* {...}` in the framework's own `.d.ts` is exactly this pattern, applied to a
|
|
861
|
+
* primitive, which is why it never had a record shape to contribute.
|
|
862
|
+
*
|
|
863
|
+
* The declared `never` never actually reaches here as `never`, though:
|
|
864
|
+
* `structural.ts` reads an optional member's type through
|
|
865
|
+
* `checker.getTypeOfSymbolAtLocation`, which reports the type a *read* of the
|
|
866
|
+
* property produces -- absent counts, so it is `never | undefined`, and the
|
|
867
|
+
* checker eliminates the uninhabited arm before this sees it, leaving plain
|
|
868
|
+
* `undefined`. Checking for `never` here would therefore never match the one
|
|
869
|
+
* shape this exists to recognize; `undefined` is the observable fact.
|
|
870
|
+
*/
|
|
871
|
+
const isAbsentMember = (member) => {
|
|
872
|
+
const memberShape = shapeOf(member);
|
|
873
|
+
return memberShape?.kind === 'primitive' && (memberShape.primitive === 'never' || memberShape.primitive === 'undefined');
|
|
874
|
+
};
|
|
875
|
+
/**
|
|
876
|
+
* `unique symbol` is TypeScript's other brand idiom, alongside the
|
|
877
|
+
* optional-`never` one this sits beside -- `type Rgb565 = number & {
|
|
878
|
+
* readonly __geaRgb565: unique symbol }` in the framework's own `.d.ts`
|
|
879
|
+
* (`rgb565()`'s return type). Where the never-brand fences a member no
|
|
880
|
+
* value can ever populate, this one fences a *type* no ordinary expression
|
|
881
|
+
* can ever produce: a `unique symbol` names exactly one symbol tied to its
|
|
882
|
+
* own declaration, so the only way a value ever reaches that member's type
|
|
883
|
+
* is a cast (`as Rgb565`), never a literal object expression. That makes
|
|
884
|
+
* `required` a non-issue here, unlike the never-brand below: a required
|
|
885
|
+
* `unique symbol` member is not a real, inhabited constraint the way a
|
|
886
|
+
* required `never` member is -- it is exactly as vacuous as the optional
|
|
887
|
+
* form, always, so this check does not consult `optional` at all.
|
|
888
|
+
*/
|
|
889
|
+
const isUniqueSymbolMember = (member) => shapeOf(member)?.kind === 'unique-symbol';
|
|
890
|
+
const isVacuousBrand = (member) => {
|
|
891
|
+
const object = intersectionMemberShape(member);
|
|
892
|
+
if (!object || object.index.length > 0 || object.members.length === 0)
|
|
893
|
+
return false;
|
|
894
|
+
// `optional` is load-bearing for the never-brand test specifically: a
|
|
895
|
+
// *required* member typed `never` means the object itself is
|
|
896
|
+
// uninhabited, a real (if bizarre) constraint this must not silently
|
|
897
|
+
// discard by treating it as a no-op brand. The unique-symbol test above
|
|
898
|
+
// has no such exception, so it is checked unconditionally.
|
|
899
|
+
return object.members.every((property) => isUniqueSymbolMember(property.type) || (property.optional && isAbsentMember(property.type)));
|
|
900
|
+
};
|
|
901
|
+
/**
|
|
902
|
+
* Whether a member is a CLASS INSTANCE -- a type whose identity is its
|
|
903
|
+
* declaration rather than its members.
|
|
904
|
+
*
|
|
905
|
+
* Asked through the declared wrapper as well as directly, because a class
|
|
906
|
+
* reaches the deriver both ways: named in its own right, and as the body of
|
|
907
|
+
* a `declared` shape.
|
|
908
|
+
*/
|
|
909
|
+
const isNominalClassMember = (member) => {
|
|
910
|
+
const shape = shapeOf(member);
|
|
911
|
+
if (!shape)
|
|
912
|
+
return false;
|
|
913
|
+
if (shape.kind === 'class-instance')
|
|
914
|
+
return true;
|
|
915
|
+
return shape.kind === 'declared' && shape.body !== null && shapeOf(shape.body)?.kind === 'class-instance';
|
|
916
|
+
};
|
|
917
|
+
/**
|
|
918
|
+
* One of the three standard regular-expression declarations
|
|
919
|
+
* (`RegExpDeclarationPolicy`): a member whose only layout is the compiler's
|
|
920
|
+
* own native one, so an intersection holding it is that native value.
|
|
921
|
+
*/
|
|
922
|
+
const isNativeRegExpMember = (member) => {
|
|
923
|
+
const shape = shapeOf(member);
|
|
924
|
+
return shape?.kind === 'declared' && regexp.forDeclaration(shape.declaration) !== null;
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* One of the standard `Error` family declarations
|
|
928
|
+
* (`ErrorDeclarationPolicy`): a member whose only layout is the compiler's
|
|
929
|
+
* own `gea::runtime::Error`, so an intersection holding it is that native
|
|
930
|
+
* value -- the same statement `isNativeRegExpMember` makes about a pattern.
|
|
931
|
+
*/
|
|
932
|
+
const isNativeErrorMember = (member) => {
|
|
933
|
+
const shape = shapeOf(member);
|
|
934
|
+
return shape?.kind === 'declared' && errors.forDeclaration(shape.declaration) !== null;
|
|
935
|
+
};
|
|
936
|
+
/** The class a nominal member names, or `null` when the member is not one. */
|
|
937
|
+
const nominalClassDeclarationOf = (member) => {
|
|
938
|
+
const shape = shapeOf(member);
|
|
939
|
+
if (!shape)
|
|
940
|
+
return null;
|
|
941
|
+
if (shape.kind === 'class-instance')
|
|
942
|
+
return shape.declaration;
|
|
943
|
+
if (shape.kind !== 'declared' || shape.body === null)
|
|
944
|
+
return null;
|
|
945
|
+
const body = shapeOf(shape.body);
|
|
946
|
+
return body?.kind === 'class-instance' ? body.declaration : null;
|
|
947
|
+
};
|
|
948
|
+
/**
|
|
949
|
+
* The one member of `nominal` that every other one is an ancestor of, or
|
|
950
|
+
* `null` when no such member exists.
|
|
951
|
+
*
|
|
952
|
+
* `T & AggregateOperation` -- what `operation instanceof AggregateOperation`
|
|
953
|
+
* narrows a `T extends AbstractOperation` parameter to, once
|
|
954
|
+
* monomorphization has bound `T` to a concrete class -- has two nominal
|
|
955
|
+
* members and exactly one inhabitant: an object can only pass the
|
|
956
|
+
* `instanceof` if it IS an AggregateOperation, and it can only have reached
|
|
957
|
+
* the parameter if it is a `T`, so the intersection is whichever of the two
|
|
958
|
+
* descends from the other. That is the same argument the single-nominal
|
|
959
|
+
* branch below already makes ("the class carrier is the only inhabited
|
|
960
|
+
* one"), extended to the case the narrowing actually produces.
|
|
961
|
+
*
|
|
962
|
+
* When NEITHER descends from the other the pair stays refused, and that is
|
|
963
|
+
* correct rather than conservative: two unrelated classes intersected is a
|
|
964
|
+
* value with two identities, no C++ object is both, and the branch is dead
|
|
965
|
+
* code this compiler has no way to prove dead.
|
|
966
|
+
*/
|
|
967
|
+
const mostDerivedNominal = (nominal) => {
|
|
968
|
+
const declarations = nominal.map((member) => nominalClassDeclarationOf(member));
|
|
969
|
+
if (declarations.some((declaration) => declaration === null))
|
|
970
|
+
return null;
|
|
971
|
+
for (const [index, member] of nominal.entries()) {
|
|
972
|
+
const own = declarations[index];
|
|
973
|
+
if (own === undefined || own === null)
|
|
974
|
+
continue;
|
|
975
|
+
const ancestors = heritage.forDeclaration(own);
|
|
976
|
+
// Compared by MEMBER, not by declaration: two members of one generic
|
|
977
|
+
// class at different type arguments (`Box<string> & Box<number>`) share
|
|
978
|
+
// a declaration and are not one carrier, and a class is not its own
|
|
979
|
+
// ancestor -- so that pair reduces to nothing and stays refused, which
|
|
980
|
+
// is the correct answer for an intersection with no inhabitant this
|
|
981
|
+
// compiler can name.
|
|
982
|
+
const descendsFromEveryOther = nominal.every((other, position) => {
|
|
983
|
+
if (position === index)
|
|
984
|
+
return true;
|
|
985
|
+
const otherDeclaration = declarations[position];
|
|
986
|
+
return other === member || (otherDeclaration !== null && otherDeclaration !== undefined && ancestors.includes(otherDeclaration));
|
|
987
|
+
});
|
|
988
|
+
if (descendsFromEveryOther)
|
|
989
|
+
return member;
|
|
990
|
+
}
|
|
991
|
+
return null;
|
|
992
|
+
};
|
|
993
|
+
/**
|
|
994
|
+
* Whether an intersection's nominal members prove it has NO INHABITANT.
|
|
995
|
+
*
|
|
996
|
+
* Two class members whose declarations are different and where neither
|
|
997
|
+
* descends from the other describe a value with two identities. No object in
|
|
998
|
+
* this backend is both -- `records.ts` emits one struct per class and a
|
|
999
|
+
* struct has one base chain -- and no object in JavaScript is either, since
|
|
1000
|
+
* a prototype chain is linear. TypeScript does not reduce the pair to
|
|
1001
|
+
* `never` itself (it only does that for disjoint primitives and unit types),
|
|
1002
|
+
* so the fact has to be stated here.
|
|
1003
|
+
*
|
|
1004
|
+
* `mostDerivedNominal` returning `null` is NOT the same question and cannot
|
|
1005
|
+
* stand in for this one: it also answers `null` for `Box<string> &
|
|
1006
|
+
* Box<number>`, two instantiations of ONE declaration, where the erased
|
|
1007
|
+
* runtime class really is shared. Distinct declarations is what makes the
|
|
1008
|
+
* pair impossible, so that is what is tested.
|
|
1009
|
+
*
|
|
1010
|
+
* This is what `execute_operation.ts:198` compiles to, 28 monomorphized
|
|
1011
|
+
* copies over: `tryOperation<T extends AbstractOperation>` tests `operation
|
|
1012
|
+
* instanceof AggregateOperation`, and in every copy whose `T` is some other
|
|
1013
|
+
* operation class the narrowed type is two unrelated classes intersected.
|
|
1014
|
+
*/
|
|
1015
|
+
const isUninhabitedNominalIntersection = (substantive) => {
|
|
1016
|
+
const declarations = substantive.flatMap((member) => {
|
|
1017
|
+
const declaration = nominalClassDeclarationOf(member);
|
|
1018
|
+
return declaration === null ? [] : [declaration];
|
|
1019
|
+
});
|
|
1020
|
+
return declarations.some((one, index) => declarations.some((other, position) => position !== index &&
|
|
1021
|
+
one !== other &&
|
|
1022
|
+
!heritage.forDeclaration(one).includes(other) &&
|
|
1023
|
+
!heritage.forDeclaration(other).includes(one)));
|
|
1024
|
+
};
|
|
1025
|
+
/**
|
|
1026
|
+
* The primitive DOMAIN a member pins a value to, when it pins one: the name
|
|
1027
|
+
* of a primitive shape, or of the primitive a literal belongs to, read
|
|
1028
|
+
* through the declared wrapper the way `isPrimitiveValueShape` reads it.
|
|
1029
|
+
* The top types pin nothing and answer `null`.
|
|
1030
|
+
*/
|
|
1031
|
+
const primitiveDomainOf = (member) => {
|
|
1032
|
+
const memberShape = shapeOf(member);
|
|
1033
|
+
const body = memberShape?.kind === 'declared' && memberShape.body !== null ? shapeOf(memberShape.body) : memberShape;
|
|
1034
|
+
if (!body)
|
|
1035
|
+
return null;
|
|
1036
|
+
if (body.kind === 'primitive') {
|
|
1037
|
+
return body.primitive === 'any' || body.primitive === 'unknown' || body.primitive === 'never'
|
|
1038
|
+
? null
|
|
1039
|
+
: { domain: body.primitive, text: null };
|
|
1040
|
+
}
|
|
1041
|
+
if (body.kind === 'literal')
|
|
1042
|
+
return { domain: body.primitive, text: body.text };
|
|
1043
|
+
return null;
|
|
1044
|
+
};
|
|
1045
|
+
/**
|
|
1046
|
+
* Two PRIMITIVE members of different domains -- `number & null`, `string &
|
|
1047
|
+
* number` -- or two literals of one domain with different texts (`'a' &
|
|
1048
|
+
* 'b'`) leave the intersection uninhabited: a value has one primitive
|
|
1049
|
+
* domain, and this is exactly `isUninhabitedNominalIntersection`'s fact at
|
|
1050
|
+
* the other kind of member that cannot be merged.
|
|
1051
|
+
*
|
|
1052
|
+
* Where it comes from, every time: a monomorphized copy. The checker
|
|
1053
|
+
* narrows `value: T | undefined` under `value !== undefined` to `T & ({} |
|
|
1054
|
+
* null)` and distributes it to `(T & {}) | (T & null)`; against the generic
|
|
1055
|
+
* it leaves `T & null` unreduced, and the copy then substitutes the
|
|
1056
|
+
* argument for `T` structurally, so `number & null` reaches this deriver
|
|
1057
|
+
* with no checker ever having seen it. Refused as a merge ("`number` is not
|
|
1058
|
+
* a record shape"), that arm took the whole union down -- every
|
|
1059
|
+
* `Debug.checkDefined(x)` in TypeScript's own compiler, in every copy.
|
|
1060
|
+
*/
|
|
1061
|
+
const isUninhabitedPrimitiveIntersection = (substantive) => {
|
|
1062
|
+
const domains = substantive.flatMap((member) => {
|
|
1063
|
+
const domain = primitiveDomainOf(member);
|
|
1064
|
+
return domain === null ? [] : [domain];
|
|
1065
|
+
});
|
|
1066
|
+
if (domains.some((one, index) => domains.some((other, position) => position !== index && (one.domain !== other.domain || (one.text !== null && other.text !== null && one.text !== other.text)))))
|
|
1067
|
+
return true;
|
|
1068
|
+
// A primitive beside a member only an OBJECT can satisfy -- an array, a
|
|
1069
|
+
// tuple, a callable, a class instance -- is the same fact one kind over:
|
|
1070
|
+
// `number & readonly any[]` has no value either. The checker's
|
|
1071
|
+
// `isArray(v)` guard narrows a `U` to `U & readonly any[]` in the taken
|
|
1072
|
+
// branch, and a copy with `U := number` substitutes it structurally, so
|
|
1073
|
+
// the arm reaches here unreduced exactly as `number & null` does. A
|
|
1074
|
+
// record member stays out of this rule on purpose: `string & { __brand:
|
|
1075
|
+
// 'id' }` is the ordinary branded primitive, and which of those are
|
|
1076
|
+
// fences is `isVacuousBrand`'s question, not this one's.
|
|
1077
|
+
return domains.length > 0 && substantive.some(isObjectOnlyMember);
|
|
1078
|
+
};
|
|
1079
|
+
/** A member no primitive value can satisfy: an array, a tuple, a callable or a class instance, read through the declared wrapper. */
|
|
1080
|
+
const isObjectOnlyMember = (member) => {
|
|
1081
|
+
if (isNominalClassMember(member))
|
|
1082
|
+
return true;
|
|
1083
|
+
const memberShape = shapeOf(member);
|
|
1084
|
+
const body = memberShape?.kind === 'declared' && memberShape.body !== null ? shapeOf(memberShape.body) : memberShape;
|
|
1085
|
+
return body?.kind === 'array' || body?.kind === 'tuple' || body?.kind === 'signature';
|
|
1086
|
+
};
|
|
1087
|
+
/**
|
|
1088
|
+
* `(A | B | ...) & p & q` for primitive-domain `p`, `q`: the union of the
|
|
1089
|
+
* arms whose domain agrees with every primitive member, each carried as
|
|
1090
|
+
* itself. `null` unless exactly one member is a union, the others are all
|
|
1091
|
+
* primitive-domain members, and every surviving arm is itself a
|
|
1092
|
+
* primitive-domain member -- an arm that is structure beside a primitive is
|
|
1093
|
+
* the branded-primitive shape the branch below this one already answers.
|
|
1094
|
+
*/
|
|
1095
|
+
const distributeUnionOverPrimitives = (substantive) => {
|
|
1096
|
+
const unions = substantive.filter((member) => shapeOf(member)?.kind === 'union');
|
|
1097
|
+
if (unions.length !== 1)
|
|
1098
|
+
return null;
|
|
1099
|
+
const others = substantive.filter((member) => shapeOf(member)?.kind !== 'union');
|
|
1100
|
+
if (others.length === 0 || !others.every((member) => primitiveDomainOf(member) !== null))
|
|
1101
|
+
return null;
|
|
1102
|
+
const union = shapeOf(unions[0]);
|
|
1103
|
+
if (!union || union.kind !== 'union')
|
|
1104
|
+
return null;
|
|
1105
|
+
const kept = union.members.filter((arm) => !isUninhabitedIntersection([arm, ...others]));
|
|
1106
|
+
if (kept.length === 0)
|
|
1107
|
+
return { kind: 'void' };
|
|
1108
|
+
if (!kept.every((arm) => primitiveDomainOf(arm) !== null))
|
|
1109
|
+
return null;
|
|
1110
|
+
return kept.length === 1 ? derive(kept[0]) : deriveUnion({ kind: 'union', members: kept });
|
|
1111
|
+
};
|
|
1112
|
+
/** ONE answer to "can no value have this intersection's type", for the carrier and the reachability question alike. */
|
|
1113
|
+
const isUninhabitedIntersection = (substantive) => isUninhabitedNominalIntersection(substantive) || isUninhabitedPrimitiveIntersection(substantive);
|
|
1114
|
+
const intersectionMemberKind = (member) => intersectionMemberKindOf(shapeOf, member);
|
|
1115
|
+
const isPrimitiveValueMember = (member) => isPrimitiveValueShape(shapeOf, member);
|
|
1116
|
+
const flattenedIntersectionMembers = createIntersectionFlattener(shapeOf, (declaration) => Boolean(binding.forDeclaration(declaration)?.native));
|
|
1117
|
+
/**
|
|
1118
|
+
* `unknown` is the identity of `&`: `X & unknown` is `X`, for every X. It
|
|
1119
|
+
* reaches an intersection as a member because the empty object type `{}`
|
|
1120
|
+
* interns as the top type, and `T & {}` -- what the checker narrows `T |
|
|
1121
|
+
* undefined` to under a nullish test, and the whole of `NonNullable<T>` --
|
|
1122
|
+
* is the most common intersection a monomorphized copy ever meets. Against
|
|
1123
|
+
* the generic the checker reduces nothing; the copy substitutes `number`
|
|
1124
|
+
* for `T` and hands this deriver `number & unknown`, which as a merge
|
|
1125
|
+
* refused (`number` "is not a record shape").
|
|
1126
|
+
*/
|
|
1127
|
+
const isIdentityMember = (member) => {
|
|
1128
|
+
const memberShape = shapeOf(member);
|
|
1129
|
+
const body = memberShape?.kind === 'declared' && memberShape.body !== null ? shapeOf(memberShape.body) : memberShape;
|
|
1130
|
+
return body?.kind === 'primitive' && body.primitive === 'unknown';
|
|
1131
|
+
};
|
|
1132
|
+
/**
|
|
1133
|
+
* The members of an intersection that contribute a constraint: flattened,
|
|
1134
|
+
* with the brand fences and the identity members dropped. ONE list, read by
|
|
1135
|
+
* the carrier derivation and by `isNeverType`, so the two cannot disagree
|
|
1136
|
+
* about which members an intersection is made of.
|
|
1137
|
+
*/
|
|
1138
|
+
const substantiveMembersOf = (members) => {
|
|
1139
|
+
const substantive = flattenedIntersectionMembers(members).filter((member) => !isVacuousBrand(member) && !isIdentityMember(member));
|
|
1140
|
+
// `any[]` is the identity of `&` over ARRAY-shaped members, the way
|
|
1141
|
+
// `unknown` is over every member: `string[] & readonly any[]` is
|
|
1142
|
+
// `string[]`. The checker's `isArray(v)` guard narrows a generic `U` to
|
|
1143
|
+
// `U & readonly any[]`, and a copy with `U := string[]` substitutes it
|
|
1144
|
+
// structurally, so the intersection reaches here unreduced; merged as two
|
|
1145
|
+
// records it became a record-with-index no array converts to.
|
|
1146
|
+
return substantive.some(isArrayShapedMember) && substantive.some(isAnyArrayMember)
|
|
1147
|
+
? substantive.filter((member) => !isAnyArrayMember(member))
|
|
1148
|
+
: substantive;
|
|
1149
|
+
};
|
|
1150
|
+
const bodyShapeOf = (member) => {
|
|
1151
|
+
const memberShape = shapeOf(member);
|
|
1152
|
+
return (memberShape?.kind === 'declared' && memberShape.body !== null ? shapeOf(memberShape.body) : memberShape) ?? null;
|
|
1153
|
+
};
|
|
1154
|
+
/**
|
|
1155
|
+
* A callable member of an intersection contributes its invocation
|
|
1156
|
+
* conventions, while a structural object member contributes only expando
|
|
1157
|
+
* claims on that same native callable object. Unwrap a declared alias here
|
|
1158
|
+
* for the same reason `intersectionMemberShape` unwraps an object alias:
|
|
1159
|
+
* aliases do not erase the physical callable carrier.
|
|
1160
|
+
*/
|
|
1161
|
+
const intersectionCallableMemberShape = (member) => {
|
|
1162
|
+
const body = bodyShapeOf(member);
|
|
1163
|
+
return body?.kind === 'signature' ? body : null;
|
|
1164
|
+
};
|
|
1165
|
+
const isArrayShapedMember = (member) => {
|
|
1166
|
+
const body = bodyShapeOf(member);
|
|
1167
|
+
return body?.kind === 'array' || body?.kind === 'tuple';
|
|
1168
|
+
};
|
|
1169
|
+
const isAnyArrayMember = (member) => {
|
|
1170
|
+
const body = bodyShapeOf(member);
|
|
1171
|
+
if (body?.kind !== 'array')
|
|
1172
|
+
return false;
|
|
1173
|
+
const element = shapeOf(body.element);
|
|
1174
|
+
return element?.kind === 'primitive' && element.primitive === 'any';
|
|
1175
|
+
};
|
|
1176
|
+
/**
|
|
1177
|
+
* The carrier of an intersection whose every member is a declared name for
|
|
1178
|
+
* the SAME interned object body, or `null` when the members name more than
|
|
1179
|
+
* one layout. Same body id means same struct: the deriver's declared path
|
|
1180
|
+
* carries a name as `native-record-ref` of its body, so every member here
|
|
1181
|
+
* derives to the identical reference and the first one answers for all.
|
|
1182
|
+
*/
|
|
1183
|
+
const sharedBodyRefOf = (members) => {
|
|
1184
|
+
const first = members[0];
|
|
1185
|
+
if (first === undefined || members.length < 2)
|
|
1186
|
+
return null;
|
|
1187
|
+
let body = null;
|
|
1188
|
+
for (const member of members) {
|
|
1189
|
+
const memberShape = shapeOf(member);
|
|
1190
|
+
if (memberShape?.kind !== 'declared' || memberShape.body === null)
|
|
1191
|
+
return null;
|
|
1192
|
+
if (shapeOf(memberShape.body)?.kind !== 'object')
|
|
1193
|
+
return null;
|
|
1194
|
+
if (body === null)
|
|
1195
|
+
body = memberShape.body;
|
|
1196
|
+
else if (body !== memberShape.body)
|
|
1197
|
+
return null;
|
|
1198
|
+
}
|
|
1199
|
+
const derived = derive(first);
|
|
1200
|
+
return derived.kind === 'native-record-ref' ? derived : null;
|
|
1201
|
+
};
|
|
1202
|
+
const deriveIntersection = (id, shape) => {
|
|
1203
|
+
// A HOST'S OWN NAME outranks the structure it erases to.
|
|
1204
|
+
//
|
|
1205
|
+
// The brand collapse below is right about the language -- `type Rgb565 =
|
|
1206
|
+
// number & { readonly __geaRgb565: unique symbol }` IS a number, and every
|
|
1207
|
+
// arithmetic use of one type-checks as one. It is wrong about the physical
|
|
1208
|
+
// carrier the moment a host states one: the framework's plugin maps
|
|
1209
|
+
// `Rgb565` to `gea::framework::graphics::pixel::NativeColor`, a value
|
|
1210
|
+
// already in the panel's native pixel format, and collapsing it to `double`
|
|
1211
|
+
// hands that native pixel to `canvasRgb565`'s ARITHMETIC overload, which
|
|
1212
|
+
// reads it as an `0xRRGGBBAA` app colour and repacks it. `rgb565(r, g, b)`
|
|
1213
|
+
// survived as a colour with r and g gone -- 64 randomly-coloured balls all
|
|
1214
|
+
// rendered blue, with nothing anywhere to report, because a number is a
|
|
1215
|
+
// number and every step compiled.
|
|
1216
|
+
//
|
|
1217
|
+
// Read before the collapse, never instead of it: a branded alias no host
|
|
1218
|
+
// states a carrier for still erases to its substantive member exactly as
|
|
1219
|
+
// before, which is what keeps every ordinary `A & B` unchanged.
|
|
1220
|
+
const stated = shape.declaration ? binding.forDeclaration(shape.declaration) : null;
|
|
1221
|
+
if (stated?.native) {
|
|
1222
|
+
return {
|
|
1223
|
+
kind: 'native-handle',
|
|
1224
|
+
protocol: stated.protocol,
|
|
1225
|
+
version: stated.version,
|
|
1226
|
+
native: stated.native,
|
|
1227
|
+
bases: binding.basesOf(stated.native),
|
|
1228
|
+
call: null,
|
|
1229
|
+
construct: null
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
// Brand members drop out before anything else asks whether a member "is a
|
|
1233
|
+
// record shape": they never were one, and answering that question about
|
|
1234
|
+
// them is what produced a refusal for a primitive that has its own
|
|
1235
|
+
// perfectly good carrier.
|
|
1236
|
+
const substantive = substantiveMembersOf(shape.members);
|
|
1237
|
+
if (substantive.length === 0) {
|
|
1238
|
+
// Nothing but identity members (`unknown & unknown`): the intersection
|
|
1239
|
+
// IS the top type, and carries what the top type carries.
|
|
1240
|
+
const identity = flattenedIntersectionMembers(shape.members).find(isIdentityMember);
|
|
1241
|
+
if (identity !== undefined)
|
|
1242
|
+
return derive(identity);
|
|
1243
|
+
return unresolved('no primitive for an intersection with no substantive member');
|
|
1244
|
+
}
|
|
1245
|
+
const only = substantive.length === 1 ? substantive[0] : undefined;
|
|
1246
|
+
if (only !== undefined) {
|
|
1247
|
+
// With every other member vacuous, the intersection *is* this member --
|
|
1248
|
+
// not a record built to resemble it. A class instance keeps its own
|
|
1249
|
+
// nominal carrier instead of being flattened into a structural record and
|
|
1250
|
+
// losing its identity, and a primitive keeps its own scalar carrier
|
|
1251
|
+
// instead of being refused for not being a record at all.
|
|
1252
|
+
return derive(only);
|
|
1253
|
+
}
|
|
1254
|
+
// ONE LAYOUT, several names. Interface families (`interface-families.ts`)
|
|
1255
|
+
// give every `extends`-connected source interface the same interned body,
|
|
1256
|
+
// so `Identifier & Statement` -- what the checker produces when a type
|
|
1257
|
+
// predicate narrows a family-typed value, `hasJSDocNodes(updated)` on a
|
|
1258
|
+
// `T extends Node` -- is a value of that ONE layout seen through two of
|
|
1259
|
+
// its names. The checker's own reconciliation of the pair is a fresh
|
|
1260
|
+
// object shape, and deriving THAT below mints a by-value record no family
|
|
1261
|
+
// ref converts to: 117 rows on tsc, every one a narrowed read of a Node.
|
|
1262
|
+
// The intersection of names for one layout is that layout's own carrier.
|
|
1263
|
+
const familyRef = sharedBodyRefOf(substantive);
|
|
1264
|
+
if (familyRef !== null)
|
|
1265
|
+
return familyRef;
|
|
1266
|
+
// A callable intersection has one native CallableObject carrier: callable
|
|
1267
|
+
// members contribute call/construct conventions and plain object members
|
|
1268
|
+
// contribute fields/expandos to its existing dynamic-property sidecar.
|
|
1269
|
+
// Treating the latter as a record would drop [[Call]]/[[Construct]];
|
|
1270
|
+
// treating the former as a record is the named AJV/Fastify census root.
|
|
1271
|
+
//
|
|
1272
|
+
// The signatures pool through `deriveSignature`, the one ABI authority
|
|
1273
|
+
// that already joins compatible overloads and refuses conflicting frames.
|
|
1274
|
+
// No FunctionId is invented here: structural signatures have no exact
|
|
1275
|
+
// source-function membership, and callable origins/mutation facts keep
|
|
1276
|
+
// that proof separately by FunctionId.
|
|
1277
|
+
const signatureShapes = substantive.map(intersectionCallableMemberShape);
|
|
1278
|
+
const callableSignatures = signatureShapes.filter((candidate) => candidate !== null);
|
|
1279
|
+
if (callableSignatures.length > 0 &&
|
|
1280
|
+
substantive.every((member, index) => {
|
|
1281
|
+
const signature = signatureShapes[index];
|
|
1282
|
+
return signature !== undefined && signature !== null ? true : intersectionMemberShape(member) !== null;
|
|
1283
|
+
})) {
|
|
1284
|
+
return deriveSignature({
|
|
1285
|
+
kind: 'signature',
|
|
1286
|
+
call: callableSignatures.flatMap((candidate) => candidate.call),
|
|
1287
|
+
construct: callableSignatures.flatMap((candidate) => candidate.construct)
|
|
1288
|
+
});
|
|
1289
|
+
}
|
|
1290
|
+
// `any & T` IS `any` -- that is the language's own reduction, not a policy
|
|
1291
|
+
// choice here, and TypeScript applies it before anything else an
|
|
1292
|
+
// intersection means. A member declared `any` is a deliberate dynamic
|
|
1293
|
+
// boundary: the program said it has no static type, so the intersection
|
|
1294
|
+
// has none either, and the honest carrier is the dynamic one. Writing a
|
|
1295
|
+
// record carrier for `{ [k: string]: number } & { [k: string]: any }`
|
|
1296
|
+
// instead would silently narrow what the program declared it could hold.
|
|
1297
|
+
//
|
|
1298
|
+
// Checked before every carrier branch below because it OUTRANKS them: a
|
|
1299
|
+
// class or a primitive intersected with `any` is still `any`, and picking
|
|
1300
|
+
// the class's layout would be a claim the type does not make. Only the
|
|
1301
|
+
// host-stated name above outranks it, because a host naming a carrier is
|
|
1302
|
+
// stating a physical fact about a value the program never sees loosely.
|
|
1303
|
+
const dynamicMember = substantive.find((member) => {
|
|
1304
|
+
const candidate = shapeOf(member);
|
|
1305
|
+
return candidate?.kind === 'primitive' && candidate.primitive === 'any';
|
|
1306
|
+
});
|
|
1307
|
+
if (dynamicMember !== undefined)
|
|
1308
|
+
return derive(dynamicMember);
|
|
1309
|
+
// A TYPED ARRAY intersected with structural additions keeps its typed-array
|
|
1310
|
+
// carrier.
|
|
1311
|
+
//
|
|
1312
|
+
// BSON spells its local Node buffer view as
|
|
1313
|
+
// `ArrayBufferView & Uint8Array & { write(...); copy(...); ... }`. The
|
|
1314
|
+
// intersection still denotes the same byte view: every value has the
|
|
1315
|
+
// Uint8Array storage, indexing and aliasing semantics, while the final
|
|
1316
|
+
// member only describes additional operations on that view. Flattening the
|
|
1317
|
+
// checker-resolved body into `record-with-index` loses that physical fact
|
|
1318
|
+
// and makes Buffer-returning functions incompatible with Uint8Array-
|
|
1319
|
+
// returning slots even though TypeScript proves the subtype relationship.
|
|
1320
|
+
//
|
|
1321
|
+
// This is the buffer-shaped counterpart of the nominal-class rule below.
|
|
1322
|
+
// Exactly one physical typed-array carrier may survive (several members are
|
|
1323
|
+
// allowed only when they derive to the identical carrier), and every other
|
|
1324
|
+
// member must be plain structural shape. `Uint8Array & Int8Array` therefore
|
|
1325
|
+
// still refuses instead of choosing one element interpretation, while
|
|
1326
|
+
// `Uint8Array & { extra: ... }` preserves the one identity the value can
|
|
1327
|
+
// have. Added methods remain host-member questions at their own call sites;
|
|
1328
|
+
// this branch does not claim implementations for them.
|
|
1329
|
+
// Recognize the physical typed-array member before deriving structural
|
|
1330
|
+
// additions. A method on that structural half may return `this`, which is
|
|
1331
|
+
// the intersection currently being derived. Descending into it first
|
|
1332
|
+
// trips the general recursive-record guard and mints a nominal record
|
|
1333
|
+
// reference for a value whose typed-array carrier is already stated by
|
|
1334
|
+
// another member (`BufferFacade.swap32(): this` is the concrete case).
|
|
1335
|
+
//
|
|
1336
|
+
// Standard typed-array declarations are identified from the same
|
|
1337
|
+
// declaration policy used by the ordinary `declared` branch below. Plain
|
|
1338
|
+
// object members need no carrier of their own for this decision, so leave
|
|
1339
|
+
// them unexpanded. Other members still derive normally, preserving the
|
|
1340
|
+
// refusal for incompatible physical carriers.
|
|
1341
|
+
const intersectionCarriers = substantive.map((member) => {
|
|
1342
|
+
const memberShape = shapeOf(member);
|
|
1343
|
+
if (memberShape?.kind === 'declared') {
|
|
1344
|
+
const element = elements.forDeclaration(memberShape.declaration);
|
|
1345
|
+
if (element) {
|
|
1346
|
+
return {
|
|
1347
|
+
member,
|
|
1348
|
+
carrier: {
|
|
1349
|
+
kind: 'typed-array',
|
|
1350
|
+
element,
|
|
1351
|
+
buffer: typedArrayBufferKindOf(memberShape),
|
|
1352
|
+
ownership: ownership.forShape(memberShape, member)
|
|
1353
|
+
}
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return { member, carrier: intersectionMemberShape(member) === null ? derive(member) : null };
|
|
1358
|
+
});
|
|
1359
|
+
const typedArrayCarriers = intersectionCarriers.filter((candidate) => candidate.carrier?.kind === 'typed-array');
|
|
1360
|
+
const typedArray = typedArrayCarriers[0]?.carrier;
|
|
1361
|
+
if (typedArray !== undefined &&
|
|
1362
|
+
intersectionCarriers.every(({ member, carrier }) => carrier === null
|
|
1363
|
+
? intersectionMemberShape(member) !== null
|
|
1364
|
+
: carrier.kind === 'typed-array'
|
|
1365
|
+
? representationKey(carrier) === representationKey(typedArray)
|
|
1366
|
+
: intersectionMemberShape(member) !== null)) {
|
|
1367
|
+
return typedArray;
|
|
1368
|
+
}
|
|
1369
|
+
// A NOMINAL class intersected with structure carries the class.
|
|
1370
|
+
//
|
|
1371
|
+
// `x in obj` is where this shows up and it is ordinary TypeScript: narrowing
|
|
1372
|
+
// by a key the receiver's type does not declare produces `Vector3 &
|
|
1373
|
+
// Record<"w", unknown>`, and three.js writes the idiom directly --
|
|
1374
|
+
// `if ( 'w' in target ) target.w = 0;` in `Triangle.getInterpolation`, so
|
|
1375
|
+
// that one line refused a carrier for `target` throughout the file.
|
|
1376
|
+
//
|
|
1377
|
+
// The merge below cannot answer it, and correctly says so: a class is
|
|
1378
|
+
// nominal, and flattening one into a structural record drops the identity
|
|
1379
|
+
// that IS its carrier. But the intersection does not ask for a merge. A
|
|
1380
|
+
// value of `Vector3 & Record<"w", unknown>` is a `Vector3` -- the language
|
|
1381
|
+
// has no way to make it anything else -- and the structural half is a claim
|
|
1382
|
+
// about properties ON that instance. So the class's own carrier is the
|
|
1383
|
+
// answer, and reading `w` off it becomes the class's own question, which
|
|
1384
|
+
// its member rules answer or refuse BY NAME. That is strictly more precise
|
|
1385
|
+
// than refusing the carrier of every value that flows through the narrowing.
|
|
1386
|
+
//
|
|
1387
|
+
// Exactly one nominal member, and every other member a record shape: two
|
|
1388
|
+
// classes intersected is a value with two identities and no carrier, which
|
|
1389
|
+
// stays refused, and a member that is neither is the case the merge's own
|
|
1390
|
+
// refusal below still names.
|
|
1391
|
+
//
|
|
1392
|
+
// A PRIMITIVE member counts as structure here, and the class still wins.
|
|
1393
|
+
// `instanceof` narrowing is where that pair comes from: mongodb's
|
|
1394
|
+
// `ReadConcern.fromOptions` tests `readConcern instanceof ReadConcern`
|
|
1395
|
+
// where `readConcern: ReadConcern | { level: ReadConcernLevel } |
|
|
1396
|
+
// ReadConcernLevel`, and TypeScript narrows the string-literal arms by
|
|
1397
|
+
// intersecting rather than discarding them, so the true branch's type has
|
|
1398
|
+
// `'local' & ReadConcern` in it. Only an instance can pass `instanceof`;
|
|
1399
|
+
// a string never can, so the class carrier is the only inhabited one, and
|
|
1400
|
+
// the branch's `return readConcern` really does return a `ReadConcern`.
|
|
1401
|
+
// The checker agrees the other way and is no help: it reduces that pair to
|
|
1402
|
+
// `{ length, level }`, the String apparent members merged with the class's,
|
|
1403
|
+
// which is a carrier for neither. Note the ORDER -- the primitive branch
|
|
1404
|
+
// below answers `string & HtmlEscaped`, where the structural half is an
|
|
1405
|
+
// interface and no class is involved; when both a class and a primitive
|
|
1406
|
+
// are present the class is the one that can exist at runtime.
|
|
1407
|
+
const nominal = substantive.filter((member) => isNominalClassMember(member));
|
|
1408
|
+
const onlyNominal = nominal.length === 1 ? nominal[0] : (mostDerivedNominal(nominal) ?? undefined);
|
|
1409
|
+
if (onlyNominal !== undefined &&
|
|
1410
|
+
substantive.every(
|
|
1411
|
+
// Another NOMINAL member passes only because `mostDerivedNominal`
|
|
1412
|
+
// already proved `onlyNominal` descends from every one of them, which
|
|
1413
|
+
// is the whole warrant for reducing to it -- so it is admitted here by
|
|
1414
|
+
// membership in that proven set, never by being a class.
|
|
1415
|
+
(member) => member === onlyNominal || nominal.includes(member) || isPrimitiveValueMember(member) || intersectionMemberShape(member) !== null)) {
|
|
1416
|
+
return derive(onlyNominal);
|
|
1417
|
+
}
|
|
1418
|
+
// A NATIVE REGULAR-EXPRESSION member carries the intersection for the
|
|
1419
|
+
// reason a nominal class does: `gea::runtime::regex::Pattern` is the one
|
|
1420
|
+
// layout a pattern has (`RegExpDeclarationPolicy`), and the structural
|
|
1421
|
+
// half of `RegExp & { route?: string }` (`test/runtime/dynamic-regexp.ts`)
|
|
1422
|
+
// is an expando the pattern's own dynamic-property sidecar already holds,
|
|
1423
|
+
// resolved at its access site. `RegExp` is an INTERFACE in `lib.es5.d.ts`,
|
|
1424
|
+
// so the nominal branch never sees it, and the checker's `resolved` bag
|
|
1425
|
+
// won in the merge below: the cell became a by-value struct of the ten
|
|
1426
|
+
// `Pattern` fields plus `route`, a copy that shares no identity with the
|
|
1427
|
+
// pattern written into it and drifts against the initializer's
|
|
1428
|
+
// `native-record-ref`.
|
|
1429
|
+
const nativeRegExp = substantive.filter((member) => isNativeRegExpMember(member));
|
|
1430
|
+
if (nativeRegExp.length === 1 &&
|
|
1431
|
+
substantive.every((member) => member === nativeRegExp[0] || isPrimitiveValueMember(member) || intersectionMemberShape(member) !== null)) {
|
|
1432
|
+
return derive(nativeRegExp[0]);
|
|
1433
|
+
}
|
|
1434
|
+
// A NATIVE ERROR member carries the intersection, for the reason the
|
|
1435
|
+
// pattern immediately above does. `Error` is an INTERFACE in
|
|
1436
|
+
// `lib.es5.d.ts`, so the nominal branch never sees it, and the checker's
|
|
1437
|
+
// `resolved` bag won in the merge below: `Error & { code: string }` --
|
|
1438
|
+
// `@hono/node-server`'s `handleResponseError`, and Node's own
|
|
1439
|
+
// `NodeJS.ErrnoException` shape -- became a by-value struct of Error's four
|
|
1440
|
+
// members plus `code`, a copy that shares no identity with the
|
|
1441
|
+
// `gea::runtime::Error` written into it. Nothing could produce one either:
|
|
1442
|
+
// both arms of `e instanceof Error ? e : new Error(...)` are the native
|
|
1443
|
+
// handle, so the declaration refused for want of a conversion that cannot
|
|
1444
|
+
// exist. The extra members are a claim about properties ON that error, and
|
|
1445
|
+
// reading one becomes the error carrier's own question, answered or refused
|
|
1446
|
+
// BY NAME at the access -- strictly more precise than refusing the carrier
|
|
1447
|
+
// of every value that flows through the alias.
|
|
1448
|
+
const nativeError = substantive.filter((member) => isNativeErrorMember(member));
|
|
1449
|
+
if (nativeError.length === 1 &&
|
|
1450
|
+
substantive.every((member) => member === nativeError[0] || isPrimitiveValueMember(member) || intersectionMemberShape(member) !== null)) {
|
|
1451
|
+
return derive(nativeError[0]);
|
|
1452
|
+
}
|
|
1453
|
+
// No most-derived nominal member, and two of them cannot coexist: the
|
|
1454
|
+
// intersection is UNINHABITED, so this position is `never`. The carrier
|
|
1455
|
+
// that answers is the one `never` already has (`primitives.ts`: "a value
|
|
1456
|
+
// that is never produced carries nothing"), not a refusal -- refusing
|
|
1457
|
+
// demands a carrier for a value that cannot exist, and every consumer that
|
|
1458
|
+
// asked for one got `unresolved` and turned a provably dead branch into a
|
|
1459
|
+
// reported gap. `isNeverType` below answers the same fact for the
|
|
1460
|
+
// reachability question, which is the one the obligation builders ask.
|
|
1461
|
+
if (isUninhabitedIntersection(substantive))
|
|
1462
|
+
return { kind: 'void' };
|
|
1463
|
+
// A UNION member beside primitive members distributes, as TypeScript's
|
|
1464
|
+
// own reduction does: `(A | B) & undefined` is `(A & undefined) | (B &
|
|
1465
|
+
// undefined)`, each arm uninhabited where the domains disagree and the
|
|
1466
|
+
// arm itself where they agree. `value` narrowed by `=== undefined` inside
|
|
1467
|
+
// a copy of `assertIsDefined<T>` whose `T` is a union is the shape
|
|
1468
|
+
// (TypeScript's `debug.ts`, 410 rows once composite fillings closed those
|
|
1469
|
+
// copies): the checker's `resolved` keeps the intersection unreduced, and
|
|
1470
|
+
// the record merge below refuses a union member outright.
|
|
1471
|
+
const distributed = distributeUnionOverPrimitives(substantive);
|
|
1472
|
+
if (distributed !== null)
|
|
1473
|
+
return distributed;
|
|
1474
|
+
// A PRIMITIVE intersected with structure carries the primitive -- the same
|
|
1475
|
+
// argument the nominal-class branch above makes, at the other kind of
|
|
1476
|
+
// member the record merge cannot absorb.
|
|
1477
|
+
//
|
|
1478
|
+
// `type HtmlEscapedString = string & HtmlEscaped` (hono's `utils/html.ts`,
|
|
1479
|
+
// where `HtmlEscaped` is `{ isEscaped: true; callbacks?: ... }`) is the
|
|
1480
|
+
// case, and it is not the brand shape `isVacuousBrand` already collapses:
|
|
1481
|
+
// these members are real, required, and written to. But a value of
|
|
1482
|
+
// `string & HtmlEscaped` IS a string -- the language has no way to make it
|
|
1483
|
+
// anything else, and every string use of one type-checks as one -- while
|
|
1484
|
+
// the structural half is a claim about properties ON that value. So the
|
|
1485
|
+
// primitive's own carrier is the answer, and reading `isEscaped` off it
|
|
1486
|
+
// becomes the string carrier's own question, which its member rules answer
|
|
1487
|
+
// or refuse BY NAME at the access. That is strictly more precise than
|
|
1488
|
+
// refusing a carrier for every value that flows through the alias, which
|
|
1489
|
+
// is what the merge below did: 96 obligations on one type alias.
|
|
1490
|
+
//
|
|
1491
|
+
// Exactly one primitive member, and every other member a record shape --
|
|
1492
|
+
// two primitives intersected is a value with two incompatible carriers and
|
|
1493
|
+
// stays refused, and a member that is neither is still the case the
|
|
1494
|
+
// merge's own refusal names.
|
|
1495
|
+
const primitives = substantive.filter((member) => {
|
|
1496
|
+
const candidate = shapeOf(member);
|
|
1497
|
+
return (candidate?.kind === 'primitive' ||
|
|
1498
|
+
(candidate?.kind === 'declared' && candidate.body !== null && shapeOf(candidate.body)?.kind === 'primitive'));
|
|
1499
|
+
});
|
|
1500
|
+
const onlyPrimitive = primitives.length === 1 ? primitives[0] : undefined;
|
|
1501
|
+
if (onlyPrimitive !== undefined &&
|
|
1502
|
+
substantive.every((member) => member === onlyPrimitive || intersectionMemberShape(member) !== null)) {
|
|
1503
|
+
return derive(onlyPrimitive);
|
|
1504
|
+
}
|
|
1505
|
+
// THE CHECKER ALREADY RECONCILED THIS INTERSECTION.
|
|
1506
|
+
//
|
|
1507
|
+
// Every branch above answers a question about CARRIERS -- which member is
|
|
1508
|
+
// nominal, which alias a host binds, whether the members are all callable,
|
|
1509
|
+
// whether a primitive survives the brand. None of those are type
|
|
1510
|
+
// arithmetic, and the checker does not answer them. What is left IS type
|
|
1511
|
+
// arithmetic: "what does key `k` of `A & B` hold", and TypeScript computes
|
|
1512
|
+
// it -- `getPropertiesOfType` synthesizes each property with the
|
|
1513
|
+
// constituents' types already intersected, `getIndexInfosOfType` the same
|
|
1514
|
+
// for the index. `structural.ts` interns that answer as `resolved`.
|
|
1515
|
+
//
|
|
1516
|
+
// The pairwise merge below was a SECOND authority over that one question,
|
|
1517
|
+
// and it disagreed with the first wherever TypeScript's reduction is not
|
|
1518
|
+
// carrier equality: `{ [k: string]: number } & { [k: string]: any }` is
|
|
1519
|
+
// `[k: string]: any` to the checker and two irreconcilable carriers to the
|
|
1520
|
+
// merge, which is why every mongodb update operator refused. Enumerating
|
|
1521
|
+
// reductions here can never finish -- there is no end to the pairs a
|
|
1522
|
+
// program can write -- so the fix is to stop having a second answer, not to
|
|
1523
|
+
// write more cases.
|
|
1524
|
+
//
|
|
1525
|
+
// Gated on no member having a carrier of its OWN that OUTRANKS the
|
|
1526
|
+
// reduction, which is a different question from every member being a
|
|
1527
|
+
// record shape -- and the reason the first spelling refused 53 carriers in
|
|
1528
|
+
// the mongodb driver over five intersections whose reconciliation the
|
|
1529
|
+
// checker had already computed. `WithId<T> = EnhancedOmit<T,'_id'> & {_id:
|
|
1530
|
+
// ...}` is the case, and `EnhancedOmit` is a CONDITIONAL type alias, so
|
|
1531
|
+
// `structural-declared-body.ts` interns it with no body at all: not a
|
|
1532
|
+
// record shape, not any other shape either, and nothing the merge below
|
|
1533
|
+
// could have walked. Demanding a record of it asked the wrong member the
|
|
1534
|
+
// wrong question -- the resolved branch reads NO member, only
|
|
1535
|
+
// `shape.resolved`.
|
|
1536
|
+
//
|
|
1537
|
+
// What genuinely outranks the checker's answer is a member whose own
|
|
1538
|
+
// carrier the branches ABOVE exist to keep: a nominal class or a primitive
|
|
1539
|
+
// value (each states in its own comment why the reduction is "a carrier for
|
|
1540
|
+
// neither"), a signature (a callable is not a record and the reduction
|
|
1541
|
+
// drops the call signature), and a type parameter (whose carrier is
|
|
1542
|
+
// monomorphization's to decide, not a structural reduction of its
|
|
1543
|
+
// constraint). Every one of those already has its own branch with its own
|
|
1544
|
+
// gate; this condition is what keeps this branch from swallowing a case one
|
|
1545
|
+
// of them is meant to answer. Everything else -- a conditional alias, a
|
|
1546
|
+
// mapped type, an interned shape the table could not build -- has no
|
|
1547
|
+
// competing carrier to lose, so the checker's reconciliation is the only
|
|
1548
|
+
// answer there is and also the right one.
|
|
1549
|
+
//
|
|
1550
|
+
// A shape interned with no reconciliation (the self-referential retry,
|
|
1551
|
+
// which has no table to intern one into) still falls through to the merge.
|
|
1552
|
+
const outranksCheckerReduction = (member) => {
|
|
1553
|
+
if (isNominalClassMember(member) || isPrimitiveValueMember(member))
|
|
1554
|
+
return true;
|
|
1555
|
+
const candidate = bodyShapeOf(member)?.kind;
|
|
1556
|
+
return candidate === 'signature' || candidate === 'type-parameter';
|
|
1557
|
+
};
|
|
1558
|
+
if (shape.resolved !== null && !substantive.some(outranksCheckerReduction)) {
|
|
1559
|
+
return derive(shape.resolved);
|
|
1560
|
+
}
|
|
1561
|
+
const merged = new Map();
|
|
1562
|
+
// Every substantive member's own index signature applies at once, exactly
|
|
1563
|
+
// like a named field does below: a value satisfying the intersection has
|
|
1564
|
+
// one dynamic-property sidecar, not one per member, so two members with
|
|
1565
|
+
// an index must agree on its value carrier the same way two members with
|
|
1566
|
+
// the same named key must agree on theirs.
|
|
1567
|
+
const sidecars = new Map();
|
|
1568
|
+
for (const member of substantive) {
|
|
1569
|
+
const object = intersectionMemberShape(member);
|
|
1570
|
+
if (!object)
|
|
1571
|
+
return unresolved(`no primitive for an intersection whose member ${member} (${intersectionMemberKind(member)}) is not a record shape`);
|
|
1572
|
+
const structuralIndexes = carriableIndexesOf(object);
|
|
1573
|
+
if (typeof structuralIndexes === 'string')
|
|
1574
|
+
return unresolved(structuralIndexes);
|
|
1575
|
+
// An index signature that can hold nothing is a type-system fence, not
|
|
1576
|
+
// storage -- `isVacuousBrand` above says the same about a member, and
|
|
1577
|
+
// this is that fact one spelling over. `type NotAcceptedFields<TSchema,
|
|
1578
|
+
// FieldType> = { readonly [key in KeysOfOtherType<TSchema, FieldType>]?:
|
|
1579
|
+
// never }` (mongodb's `mongo_types.ts`) is the shape: a mapped type whose
|
|
1580
|
+
// whole purpose is to FORBID the keys it names, intersected alongside the
|
|
1581
|
+
// member that really does carry them. Reading its `undefined` as a
|
|
1582
|
+
// competing sidecar makes every `PushOperator`/`PullOperator`/
|
|
1583
|
+
// `PullAllOperator` disagree with itself.
|
|
1584
|
+
//
|
|
1585
|
+
// `isAbsentMember` is the same test the named-member fence uses, asked of
|
|
1586
|
+
// the index's value, so the two can never disagree about what "holds
|
|
1587
|
+
// nothing" means. It reads `undefined` rather than `never` for the reason
|
|
1588
|
+
// stated there: the checker has already eliminated the uninhabited arm by
|
|
1589
|
+
// the time an optional member's type arrives.
|
|
1590
|
+
for (const sidecar of structuralIndexes) {
|
|
1591
|
+
if (isAbsentMember(sidecar.value))
|
|
1592
|
+
continue;
|
|
1593
|
+
const value = deriveStored(sidecar.value);
|
|
1594
|
+
// The key domain is as much a part of "the index signature carrier" as
|
|
1595
|
+
// the value type is: a member contributing `[k: string]: T` and one
|
|
1596
|
+
// contributing `[k: number]: T` do not describe one sidecar, even when
|
|
1597
|
+
// `T` happens to match, and merging them would silently pick whichever
|
|
1598
|
+
// arm's key domain the loop saw first.
|
|
1599
|
+
//
|
|
1600
|
+
// The VALUES reconcile through `intersectPropertyRepresentations`, the
|
|
1601
|
+
// same authority a named key present in two members goes through below
|
|
1602
|
+
// -- the comment above this loop already says an index must agree "the
|
|
1603
|
+
// same way two members with the same named key must agree", and raw key
|
|
1604
|
+
// equality was not that way. A reduction that fails still refuses by
|
|
1605
|
+
// name, exactly as it did.
|
|
1606
|
+
const existingSidecar = sidecars.get(sidecar.key);
|
|
1607
|
+
const reconciled = existingSidecar ? intersectPropertyRepresentations(existingSidecar, value) : value;
|
|
1608
|
+
if (existingSidecar && !reconciled) {
|
|
1609
|
+
return unresolved('no primitive for an intersection whose members disagree on the index signature carrier');
|
|
1610
|
+
}
|
|
1611
|
+
sidecars.set(sidecar.key, reconciled ?? value);
|
|
1612
|
+
}
|
|
1613
|
+
for (const property of object.members) {
|
|
1614
|
+
const key = recordFieldKeyOf(property.key);
|
|
1615
|
+
const value = deriveStored(property.type);
|
|
1616
|
+
const existing = merged.get(key);
|
|
1617
|
+
// Every arm's constraint applies at once, so a key present twice must
|
|
1618
|
+
// agree -- reduced through `intersectPropertyRepresentations`, not
|
|
1619
|
+
// raw equality, so an absence arm one member disproves does not read
|
|
1620
|
+
// as a disagreement. Picking either side blind would make lookup
|
|
1621
|
+
// order decide the layout; a failed reduction still refuses by name.
|
|
1622
|
+
const reconciled = existing ? intersectPropertyRepresentations(existing.value, value) : value;
|
|
1623
|
+
if (existing && !reconciled) {
|
|
1624
|
+
return unresolved(`no primitive for an intersection whose members disagree on the carrier of "${key}"`);
|
|
1625
|
+
}
|
|
1626
|
+
// Required in any arm is required overall: an intersection satisfies
|
|
1627
|
+
// every arm, so an optional field paired with a required one is present.
|
|
1628
|
+
merged.set(key, { key, value: reconciled, required: (existing?.required ?? false) || !property.optional });
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
if (merged.size === 0 && sidecars.size === 0)
|
|
1632
|
+
return unresolved('no primitive for an empty intersection carrier');
|
|
1633
|
+
const fields = [...merged.values()];
|
|
1634
|
+
const indexes = canonicalRecordIndexes([...sidecars].map(([key, value]) => ({ key, value })));
|
|
1635
|
+
if (typeof indexes === 'string')
|
|
1636
|
+
return unresolved(indexes);
|
|
1637
|
+
if (indexes.length > 0) {
|
|
1638
|
+
return {
|
|
1639
|
+
kind: 'record-with-index',
|
|
1640
|
+
shapeId: id,
|
|
1641
|
+
fields,
|
|
1642
|
+
indexes,
|
|
1643
|
+
ownership: ownership.forShape(shape, id)
|
|
1644
|
+
};
|
|
1645
|
+
}
|
|
1646
|
+
// An intersection merges member *types*; neither side's accessors survive
|
|
1647
|
+
// as one member set this deriver could name, and TypeScript cannot produce
|
|
1648
|
+
// an intersection of two accessor-backed literals in the first place.
|
|
1649
|
+
return { kind: 'record', shapeId: id, fields, accessors: [], ownership: ownership.forShape(shape, id) };
|
|
1650
|
+
};
|
|
1651
|
+
/** A member list with every member that is itself a union -- directly or through a declared alias -- spliced in: the flat list `union.ts` expects, which the checker's own unions always are. */
|
|
1652
|
+
const flattenedUnionMembersOf = (members) => {
|
|
1653
|
+
const flat = [];
|
|
1654
|
+
const visit = (member) => {
|
|
1655
|
+
const body = bodyShapeOf(member);
|
|
1656
|
+
if (body?.kind === 'union') {
|
|
1657
|
+
for (const inner of body.members)
|
|
1658
|
+
visit(inner);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
if (!flat.includes(member))
|
|
1662
|
+
flat.push(member);
|
|
1663
|
+
};
|
|
1664
|
+
for (const member of members)
|
|
1665
|
+
visit(member);
|
|
1666
|
+
return flat;
|
|
1667
|
+
};
|
|
1668
|
+
const deriveTuple = (id, shape) => {
|
|
1669
|
+
// [] is still an observable Array: even an empty rest binding has length
|
|
1670
|
+
// and identity. An empty record lost that protocol and routed `.length`
|
|
1671
|
+
// through a boxed property read. Use the same uninhabited element storage
|
|
1672
|
+
// as never[] (storedCarrier maps never's void carrier to undefined).
|
|
1673
|
+
if (shape.elements.length === 0) {
|
|
1674
|
+
return { kind: 'array-object', element: { kind: 'undefined' }, ownership: ownership.forShape(shape, id), extension: null };
|
|
1675
|
+
}
|
|
1676
|
+
// A homogeneous closed tuple and T[] are views of the same JS array.
|
|
1677
|
+
// Positional record storage would require a copying conversion at that
|
|
1678
|
+
// boundary and break aliasing. Arity remains in the semantic tuple shape;
|
|
1679
|
+
// it does not require a different physical carrier.
|
|
1680
|
+
const first = shape.elements[0];
|
|
1681
|
+
const fixedArity = first !== undefined && shape.elements.every((element) => !element.optional && !element.rest && !element.variadic);
|
|
1682
|
+
// Homogeneous by CARRIER, not by structural type id. `['a', 'b'] as const`
|
|
1683
|
+
// is `readonly ["a", "b"]`: two distinct literal types, one physical
|
|
1684
|
+
// element -- `std::string` both times -- so it is a JS array in exactly
|
|
1685
|
+
// the sense this branch's own comment means, and laying it out as a
|
|
1686
|
+
// positional record is what left `names.forEach(...)` refusing with
|
|
1687
|
+
// `"Array.prototype.forEach" has no rendering off a record receiver`
|
|
1688
|
+
// (`overloaded-callable-fields.ts`). Comparing ids answered that question
|
|
1689
|
+
// with the SEMANTIC type, which is not the one aliasing and
|
|
1690
|
+
// `Array.prototype` dispatch depend on; the arity a read narrows with
|
|
1691
|
+
// still lives in the semantic tuple shape either way.
|
|
1692
|
+
const uniformElement = (() => {
|
|
1693
|
+
if (!fixedArity || first === undefined)
|
|
1694
|
+
return null;
|
|
1695
|
+
const carrier = deriveStored(first.type);
|
|
1696
|
+
if (carrier.kind === 'unresolved')
|
|
1697
|
+
return null;
|
|
1698
|
+
const key = representationKey(carrier);
|
|
1699
|
+
return shape.elements.every((element) => representationKey(deriveStored(element.type)) === key) ? carrier : null;
|
|
1700
|
+
})();
|
|
1701
|
+
if (uniformElement) {
|
|
1702
|
+
return { kind: 'array-object', element: uniformElement, ownership: ownership.forShape(shape, id), extension: null };
|
|
1703
|
+
}
|
|
1704
|
+
// A rest or variadic position has no fixed arity, so the tuple is not a
|
|
1705
|
+
// record with a known field set -- it is an ARRAY, and its carrier is the
|
|
1706
|
+
// array carrier over the union of every position's type. tsc's
|
|
1707
|
+
// `[DiagnosticMessage, ...DiagnosticArguments]` (what `extraValidation`
|
|
1708
|
+
// returns, spread straight into `createDiagnostic`) is a runtime Array
|
|
1709
|
+
// whose length is a runtime fact; only its per-position TYPES are static,
|
|
1710
|
+
// and those are what the reads that know their position narrow to
|
|
1711
|
+
// (`spread-arguments.ts`'s open-tuple expansion, `structural-array-read.ts`).
|
|
1712
|
+
// Refusing the carrier outright cost 163 rows on the self-compile.
|
|
1713
|
+
if (shape.elements.some((element) => element.rest || element.variadic)) {
|
|
1714
|
+
const members = [];
|
|
1715
|
+
for (const element of shape.elements) {
|
|
1716
|
+
if (!element.variadic) {
|
|
1717
|
+
members.push(element.type);
|
|
1718
|
+
continue;
|
|
1719
|
+
}
|
|
1720
|
+
// `...T` where `T extends any[]`: the position spreads T's own
|
|
1721
|
+
// elements. A checker-instantiated tuple type already has that
|
|
1722
|
+
// spread normalized away; this is the generic declaration's own shape.
|
|
1723
|
+
const spread = bodyShapeOf(element.type);
|
|
1724
|
+
if (spread?.kind === 'array')
|
|
1725
|
+
members.push(spread.element);
|
|
1726
|
+
else if (spread?.kind === 'tuple') {
|
|
1727
|
+
for (const inner of spread.elements) {
|
|
1728
|
+
if (inner.rest || inner.variadic)
|
|
1729
|
+
return unresolved('a variadic tuple position spreads a tuple that is itself open-ended');
|
|
1730
|
+
members.push(inner.type);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
else
|
|
1734
|
+
return unresolved('a variadic tuple position spreads a type that is neither an array nor a tuple');
|
|
1735
|
+
}
|
|
1736
|
+
const distinct = flattenedUnionMembersOf(members);
|
|
1737
|
+
const sole = distinct.length === 1 ? distinct[0] : undefined;
|
|
1738
|
+
const element = sole !== undefined ? deriveStored(sole) : storedCarrier(deriveUnionShape({ kind: 'union', members: distinct }));
|
|
1739
|
+
if (element.kind === 'unresolved')
|
|
1740
|
+
return unresolved(`no primitive for an open-ended tuple's element: ${element.reason}`);
|
|
1741
|
+
return { kind: 'array-object', element, ownership: ownership.forShape(shape, id), extension: null };
|
|
1742
|
+
}
|
|
1743
|
+
const fields = [];
|
|
1744
|
+
for (const [position, element] of shape.elements.entries()) {
|
|
1745
|
+
// There is deliberately no tuple carrier: a closed tuple is a record
|
|
1746
|
+
// whose keys are its indices.
|
|
1747
|
+
fields.push({ key: String(position), value: deriveStored(element.type), required: !element.optional });
|
|
1748
|
+
}
|
|
1749
|
+
return { kind: 'record', shapeId: id, fields, accessors: [], ownership: ownership.forShape(shape, id) };
|
|
1750
|
+
};
|
|
1751
|
+
/**
|
|
1752
|
+
* The carrier of a class's constructor object.
|
|
1753
|
+
*
|
|
1754
|
+
* The family is closed: this class, plus every derived class the program
|
|
1755
|
+
* stores where this constructor is declared. That is a stronger fact than a
|
|
1756
|
+
* dispatching callable, and stating it is what lets construction resolve to
|
|
1757
|
+
* a known class rather than a runtime lookup when the family has one member.
|
|
1758
|
+
*/
|
|
1759
|
+
/**
|
|
1760
|
+
* The physical class a class shape denotes.
|
|
1761
|
+
*
|
|
1762
|
+
* A generic class is one struct per LAYOUT, not per copy and not per
|
|
1763
|
+
* class: `Box<number>` and `Box<string>` store different things and are
|
|
1764
|
+
* two structs, while hono's `Hono<E,S,BasePath>` across every route
|
|
1765
|
+
* registration is one, and so are `Carrier<'a' | 'b'>` and
|
|
1766
|
+
* `Carrier<string>`, whose `data` fields are the same carrier. The
|
|
1767
|
+
* layouts are the groups of the class's copies by the REPRESENTATION of
|
|
1768
|
+
* their layout-relevant fillings (`ClassCopyPolicy`), and a group is
|
|
1769
|
+
* named by its lowest copy ordinal -- `decl|f0|36@1`, a spelling
|
|
1770
|
+
* `identity/ids.ts` reserves for a copy, so the class-lifecycle events
|
|
1771
|
+
* that copy minted, its constructor body and its struct name meet under
|
|
1772
|
+
* one id (`projection/classes.ts`'s `physicalOf`). With one group the
|
|
1773
|
+
* root names it, exactly as before there were groups.
|
|
1774
|
+
*
|
|
1775
|
+
* Asked with the shape's own folded arguments: the instance side's written
|
|
1776
|
+
* ones, the constructor side's copy fillings. A shape whose arguments
|
|
1777
|
+
* match no copy (a constructor object read outside every copy, an
|
|
1778
|
+
* instantiation the census never minted) is the root's, which owns no
|
|
1779
|
+
* layout once there are two -- and fails closed downstream rather than
|
|
1780
|
+
* being handed one of them.
|
|
1781
|
+
*
|
|
1782
|
+
* A filling that is itself an instance of the class being grouped
|
|
1783
|
+
* (`Box<Box<number>>`) is keyed by its structural id rather than
|
|
1784
|
+
* derived: deriving it would ask for the groups this walk is computing.
|
|
1785
|
+
*/
|
|
1786
|
+
const classGroups = new Map();
|
|
1787
|
+
const classArgumentKeyOf = (root, id) => {
|
|
1788
|
+
const argument = shapeOf(id);
|
|
1789
|
+
// A filling that is itself this class (`Box<Box<number>>`) is keyed by
|
|
1790
|
+
// its structural id rather than derived: deriving it would ask for the
|
|
1791
|
+
// groups this walk is computing.
|
|
1792
|
+
if (argument && (argument.kind === 'class-instance' || argument.kind === 'class-constructor') && argument.declaration === root)
|
|
1793
|
+
return `self:${id}`;
|
|
1794
|
+
return representationKey(deriveStored(id));
|
|
1795
|
+
};
|
|
1796
|
+
const classGroupsOf = (root) => {
|
|
1797
|
+
const known = classGroups.get(root);
|
|
1798
|
+
if (known !== undefined)
|
|
1799
|
+
return known;
|
|
1800
|
+
const copies = classCopies.copiesOf(root);
|
|
1801
|
+
if (copies.length < 2) {
|
|
1802
|
+
classGroups.set(root, null);
|
|
1803
|
+
return null;
|
|
1804
|
+
}
|
|
1805
|
+
// Reserved as "one group" while the copies' fillings derive, for a filling
|
|
1806
|
+
// that reaches this class through another (`Box<Pair<Box<T>>>`).
|
|
1807
|
+
classGroups.set(root, null);
|
|
1808
|
+
const seen = new Map();
|
|
1809
|
+
for (const copy of copies) {
|
|
1810
|
+
const key = copy.typeArguments.map((id) => classArgumentKeyOf(root, id)).join(',');
|
|
1811
|
+
if (!seen.has(key))
|
|
1812
|
+
seen.set(key, copy.ordinal);
|
|
1813
|
+
}
|
|
1814
|
+
classGroups.set(root, seen);
|
|
1815
|
+
return seen;
|
|
1816
|
+
};
|
|
1817
|
+
/**
|
|
1818
|
+
* The physical class a class shape denotes, its group's REPRESENTATIVE copy
|
|
1819
|
+
* (the lowest ordinal, whose constructor convention the whole group shares),
|
|
1820
|
+
* and the family the shape's VALUE names.
|
|
1821
|
+
*
|
|
1822
|
+
* A shape with no type arguments is the class value read outside every copy
|
|
1823
|
+
* -- `Box.count`, `x instanceof Box`, `Box.create(...)`. There is one
|
|
1824
|
+
* such object however many structs the class has, so it names the whole
|
|
1825
|
+
* family: its static members resolve through the shared static owner, and
|
|
1826
|
+
* an `instanceof` against it admits an instance of any layout.
|
|
1827
|
+
*/
|
|
1828
|
+
const physicalClassGroupOf = (shape) => {
|
|
1829
|
+
const root = shape.declaration;
|
|
1830
|
+
const groups = classGroupsOf(root);
|
|
1831
|
+
if (groups === null)
|
|
1832
|
+
return { declaration: root, representative: null, family: [root] };
|
|
1833
|
+
const ordinals = [...new Set(groups.values())].sort((left, right) => left - right);
|
|
1834
|
+
if (shape.typeArguments.length === 0) {
|
|
1835
|
+
const representative = ordinals[0] ?? null;
|
|
1836
|
+
return {
|
|
1837
|
+
declaration: root,
|
|
1838
|
+
representative,
|
|
1839
|
+
family: groups.size > 1 ? ordinals.map((ordinal) => `${root}@${ordinal}`) : [root]
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
const ordinal = groups.get(shape.typeArguments.map((id) => classArgumentKeyOf(root, id)).join(',')) ?? null;
|
|
1843
|
+
// One group is one physical class, named by the root exactly as before
|
|
1844
|
+
// there were groups; its representative is still the lowest copy, whose
|
|
1845
|
+
// constructor convention every copy of the class shares.
|
|
1846
|
+
if (groups.size < 2)
|
|
1847
|
+
return { declaration: root, representative: ordinal, family: [root] };
|
|
1848
|
+
const declaration = ordinal === null ? root : `${root}@${ordinal}`;
|
|
1849
|
+
return { declaration, representative: ordinal, family: [declaration] };
|
|
1850
|
+
};
|
|
1851
|
+
const physicalClassDeclarationOf = (shape) => physicalClassGroupOf(shape).declaration;
|
|
1852
|
+
const deriveClassConstructor = (shape) => {
|
|
1853
|
+
// An ambient `declare class`'s value IS a host handle, on the same
|
|
1854
|
+
// ground the `declared` case a few hundred lines below already stands on
|
|
1855
|
+
// for `declare var Map: MapConstructor` -- reaching the identical fact
|
|
1856
|
+
// through class syntax instead of interface-plus-var syntax is not a
|
|
1857
|
+
// different fact. Checked before `shape.construct`: a bound ambient class
|
|
1858
|
+
// with no declared constructor (`static`-only, e.g. `ObjCTarget`) is
|
|
1859
|
+
// still a real host handle, just one nothing may `new`.
|
|
1860
|
+
const bound = binding.forDeclaration(shape.declaration);
|
|
1861
|
+
if (bound) {
|
|
1862
|
+
const signature = shape.construct ? shapeOf(shape.construct) : null;
|
|
1863
|
+
const construct = signature?.kind === 'signature' ? hostInvocationAbiOf(signature.construct, 'construct') : null;
|
|
1864
|
+
return {
|
|
1865
|
+
kind: 'native-handle',
|
|
1866
|
+
protocol: bound.protocol,
|
|
1867
|
+
version: bound.version,
|
|
1868
|
+
native: bound.native,
|
|
1869
|
+
bases: binding.basesOf(bound.native),
|
|
1870
|
+
call: null,
|
|
1871
|
+
construct
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
// The convention is the physical class's, which is its group's
|
|
1875
|
+
// REPRESENTATIVE copy's -- the lowest ordinal, the copy that completed
|
|
1876
|
+
// the one shared anchor before there were copies. Two copies of one
|
|
1877
|
+
// layout can still spell two construct signatures (`Carrier<'a' | 'b'>`
|
|
1878
|
+
// and `Carrier<string>` take a `Payload<'a' | 'b'>` and a
|
|
1879
|
+
// `Payload<string>`, two records), and one struct has one thunk:
|
|
1880
|
+
// publishing each copy's own would give the class two conventions and
|
|
1881
|
+
// the thunk whichever the projection kept last.
|
|
1882
|
+
const group = physicalClassGroupOf(shape);
|
|
1883
|
+
const representative = group.representative === null
|
|
1884
|
+
? null
|
|
1885
|
+
: classCopies.copiesOf(shape.declaration).find((copy) => copy.ordinal === group.representative)?.constructor;
|
|
1886
|
+
const representativeShape = representative === undefined || representative === null ? null : shapeOf(representative);
|
|
1887
|
+
const construct = representativeShape?.kind === 'class-constructor' ? representativeShape.construct : shape.construct;
|
|
1888
|
+
if (!construct)
|
|
1889
|
+
return unresolved(`class ${shape.declaration} declares no construct signature to invoke`);
|
|
1890
|
+
const signature = shapeOf(construct);
|
|
1891
|
+
if (!signature || signature.kind !== 'signature')
|
|
1892
|
+
return unresolved(`class ${shape.declaration} has no interned construct signature`);
|
|
1893
|
+
if (signature.construct.length === 0)
|
|
1894
|
+
return unresolved(`class ${shape.declaration} has no interned construct signature`);
|
|
1895
|
+
const abi = sharedAbiOf(signature.construct, 'construct');
|
|
1896
|
+
if (typeof abi === 'string')
|
|
1897
|
+
return unresolved(abi);
|
|
1898
|
+
// A derived class the program stores into this constructor's slot is a
|
|
1899
|
+
// member too: naming only the base would let construction and static
|
|
1900
|
+
// reads resolve to the base while the cell holds the derived class.
|
|
1901
|
+
const members = [...group.family, ...heritage.constructorSlotSubclassesOf(shape.declaration)];
|
|
1902
|
+
return { kind: 'constructor-family', members, abi };
|
|
1903
|
+
};
|
|
1904
|
+
/**
|
|
1905
|
+
* `(...args: never[]) => R` -- a function value with NO calling convention.
|
|
1906
|
+
*
|
|
1907
|
+
* `never` is uninhabited, so no call through this slot can ever supply an
|
|
1908
|
+
* argument, and the type is TypeScript's way of writing "some function,
|
|
1909
|
+
* which nobody here calls": it is `AnyFunction` in tsc's own `core.ts`, and
|
|
1910
|
+
* every use of it there ends at `Error.captureStackTrace`. Giving it a frame
|
|
1911
|
+
* is where the silent miscompile lives -- a concrete `f(a, b, c)` converted
|
|
1912
|
+
* into a zero-argument frame compiles and then runs with garbage the first
|
|
1913
|
+
* time anyone does call it -- so the truthful carrier is the identity half,
|
|
1914
|
+
* and a call through it is refused rather than invented.
|
|
1915
|
+
*
|
|
1916
|
+
* Asked of the DECLARED type, not the widened slot, and through the
|
|
1917
|
+
* deriver's own `isNeverType` rather than a shape test of this file's own:
|
|
1918
|
+
* by the time `abiOf` has built a carrier, `never` and `undefined` are both
|
|
1919
|
+
* physically nothing (`primitives.ts`), and telling them apart down there
|
|
1920
|
+
* would be the second authority this compiler exists to avoid.
|
|
1921
|
+
*/
|
|
1922
|
+
const isIdentityOnlySignature = (signature) => {
|
|
1923
|
+
const parameter = signature.parameters[0];
|
|
1924
|
+
if (signature.parameters.length !== 1 || parameter === undefined || !parameter.rest)
|
|
1925
|
+
return false;
|
|
1926
|
+
const declared = shapeOf(parameter.type);
|
|
1927
|
+
return declared?.kind === 'array' && isNeverType(declared.element);
|
|
1928
|
+
};
|
|
1929
|
+
const deriveSignature = (shape) => {
|
|
1930
|
+
if (shape.construct.length > 0) {
|
|
1931
|
+
// A construct signature with no class anchor -- `new () => Component` --
|
|
1932
|
+
// is a constructor whose class is not proven. That is a complete answer,
|
|
1933
|
+
// not a gap: the convention is what a construction goes through, exactly
|
|
1934
|
+
// as an unproven callable is called through its own. A value that is both
|
|
1935
|
+
// callable and constructable keeps both conventions, because `Number(x)`
|
|
1936
|
+
// and `new Number(x)` do genuinely different things.
|
|
1937
|
+
const shared = sharedAbiOf(shape.construct, 'construct');
|
|
1938
|
+
if (typeof shared === 'string')
|
|
1939
|
+
return unresolved(shared);
|
|
1940
|
+
// `[[Construct]]` MANUFACTURES its receiver -- ECMA-262 10.2.2 creates
|
|
1941
|
+
// the object from the constructor's `prototype` and only then enters the
|
|
1942
|
+
// body with it -- so a construct convention never has one to declare,
|
|
1943
|
+
// whatever the interned signature says. It can say something: a JS
|
|
1944
|
+
// constructor function's call and construct signatures share one
|
|
1945
|
+
// declaration, so `structural-receiver.ts`'s implicit receiver (which
|
|
1946
|
+
// exists for the BODY's sake -- see its `jsConstructorReceiverOf`)
|
|
1947
|
+
// arrives on both. Dropping it here, at the one place that knows which
|
|
1948
|
+
// convention is which, keeps the two answers from becoming two
|
|
1949
|
+
// authorities: a construction site would otherwise have to push a
|
|
1950
|
+
// receiver argument nothing evaluates, and `emit-callable.ts`'s
|
|
1951
|
+
// construct thunk is the code that actually allocates it.
|
|
1952
|
+
const constructAbi = shared.receiver === null ? shared : { ...shared, receiver: null };
|
|
1953
|
+
if (shape.call.length === 0)
|
|
1954
|
+
return { kind: 'constructor-value-dispatch', abi: constructAbi };
|
|
1955
|
+
const callAbi = sharedAbiOf(shape.call, 'overload', true);
|
|
1956
|
+
return typeof callAbi === 'string'
|
|
1957
|
+
? unresolved(callAbi)
|
|
1958
|
+
: { kind: 'function-and-constructor', call: callAbi, construct: constructAbi };
|
|
1959
|
+
}
|
|
1960
|
+
if (shape.call.length === 0)
|
|
1961
|
+
return unresolved('callable shape with no call signature');
|
|
1962
|
+
// The OPEN type of a generic source function is not a callable the
|
|
1963
|
+
// runtime can hold -- there is no frame until a call instantiates it --
|
|
1964
|
+
// it is a choice of which generic function a cell holds. See
|
|
1965
|
+
// `generic-function-set` (model.ts).
|
|
1966
|
+
if (shape.generic)
|
|
1967
|
+
return { kind: 'generic-function-set', members: [shape.generic] };
|
|
1968
|
+
if (shape.call.every(isIdentityOnlySignature))
|
|
1969
|
+
return { kind: 'callable-identity' };
|
|
1970
|
+
const abi = sharedAbiOf(shape.call, 'overload', true);
|
|
1971
|
+
// The target set of a first-class function value is not a structural fact,
|
|
1972
|
+
// so the carrier is the dispatching one. Naming a single `function` carrier
|
|
1973
|
+
// here would claim a proof the shape does not contain.
|
|
1974
|
+
if (typeof abi !== 'string')
|
|
1975
|
+
return { kind: 'function-value-dispatch', abi };
|
|
1976
|
+
// Incompatible declared overloads are missing a native storage contract,
|
|
1977
|
+
// not a dynamic source boundary. Normalization must publish the stored
|
|
1978
|
+
// implementation's signature when it can prove one; otherwise the value
|
|
1979
|
+
// has no calling convention -- which is a fact about it, not a gap.
|
|
1980
|
+
if (dynamicFallback)
|
|
1981
|
+
return { kind: 'dynamic', reason: 'opt-in-fallback' };
|
|
1982
|
+
// `Array.from` is four overloads that genuinely disagree at parameter 0,
|
|
1983
|
+
// and `Object.getOwnPropertyDescriptor(Array.from, 'name')` never calls
|
|
1984
|
+
// it. Refusing the whole program said "I cannot name the frame" about a
|
|
1985
|
+
// read that asks for no frame; joining the overloads would invent one.
|
|
1986
|
+
// The identity half is what the shape actually contains, and it is the
|
|
1987
|
+
// SAME answer `isIdentityOnlySignature` above reaches by the other route
|
|
1988
|
+
// -- a call through it is refused by name at emission
|
|
1989
|
+
// (`call-abi:no-invoke-path:callable-identity`), so nothing here is
|
|
1990
|
+
// fail-open.
|
|
1991
|
+
return { kind: 'callable-identity' };
|
|
1992
|
+
};
|
|
1993
|
+
// `isNeverType` is declared below; the union deriver only calls it later,
|
|
1994
|
+
// per arm, so the closure is what is handed over rather than the value.
|
|
1995
|
+
const deriveUnion = createUnionDeriver({ shapeOf, derive, isNeverType: (id) => isNeverType(id) });
|
|
1996
|
+
const deriveUnionShape = (shape) => {
|
|
1997
|
+
// A choice among generic source functions is ONE set, tagged by
|
|
1998
|
+
// member, not a sum of markers: `cond ? identity : setOriginalNode`.
|
|
1999
|
+
const genericMembers = genericFunctionSetMembersOf(shapeOf, shape);
|
|
2000
|
+
if (genericMembers)
|
|
2001
|
+
return { kind: 'generic-function-set', members: genericMembers };
|
|
2002
|
+
return deriveUnion(shape);
|
|
2003
|
+
};
|
|
2004
|
+
function deriveShape(id, shape) {
|
|
2005
|
+
// A host namespace ROOT is answered before the shape is looked at, and it
|
|
2006
|
+
// is the only policy here that has to be. The other four -- `binding`,
|
|
2007
|
+
// `elements`, `promise`, `collections` -- are consulted inside `'declared'`
|
|
2008
|
+
// (and `binding` also inside the two class cases) because each answers a
|
|
2009
|
+
// question about a declared TYPE, so the declaration the checker resolved
|
|
2010
|
+
// is both available and the right key. This one answers a question about a
|
|
2011
|
+
// VALUE the host owns, whose type is routinely not `'declared'` at all:
|
|
2012
|
+
// `window`'s is the intersection `Window & typeof globalThis`. Reaching
|
|
2013
|
+
// the switch first would flatten that intersection into a record of
|
|
2014
|
+
// lib.dom's `Window`, which is the answer this exists to displace; see
|
|
2015
|
+
// `HostNamespaceRootPolicy` (policies.ts) for
|
|
2016
|
+
// the whole of why, and for why the carrier is a stated-native
|
|
2017
|
+
// `native-record-ref` rather than a handle or a refusal.
|
|
2018
|
+
//
|
|
2019
|
+
// `owned`, matching the stated-native record the `'declared'` case below
|
|
2020
|
+
// already builds for a host's data-only type: the host holds one object
|
|
2021
|
+
// (`inline constexpr WindowFacade window{}`), so a value of it is a copy
|
|
2022
|
+
// of that object rather than a share of it. `borrowed` -- the other
|
|
2023
|
+
// reading of "an external owner" -- spells `T&`, and the host's object is
|
|
2024
|
+
// `constexpr`, so a non-const reference to it would not bind.
|
|
2025
|
+
const namespaceRoot = namespaceRoots.forType(id);
|
|
2026
|
+
if (namespaceRoot !== null)
|
|
2027
|
+
return { kind: 'native-record-ref', shapeId: id, ownership: 'owned', native: namespaceRoot };
|
|
2028
|
+
switch (shape.kind) {
|
|
2029
|
+
case 'primitive': {
|
|
2030
|
+
const carrier = primitiveCarrier(shape.primitive);
|
|
2031
|
+
// A symbol is a value the language creates, compares by identity, and
|
|
2032
|
+
// uses as a property key. None of the carriers model that, and boxing it
|
|
2033
|
+
// would be the forbidden shortcut, so the gap is stated instead.
|
|
2034
|
+
return carrier ?? unresolved(`no primitive for a ${shape.primitive}-valued carrier`);
|
|
2035
|
+
}
|
|
2036
|
+
case 'literal': {
|
|
2037
|
+
const carrier = primitiveCarrier(shape.primitive);
|
|
2038
|
+
return carrier ?? unresolved(`no primitive for a ${shape.primitive} literal carrier`);
|
|
2039
|
+
}
|
|
2040
|
+
case 'unique-symbol':
|
|
2041
|
+
// A `unique symbol`'s whole purpose is to be its own TYPE, so that one
|
|
2042
|
+
// framework key is not assignable where another is declared. That is a
|
|
2043
|
+
// checking fact; physically every one of them is one interned id, which
|
|
2044
|
+
// is the symbol carrier.
|
|
2045
|
+
return { kind: 'symbol' };
|
|
2046
|
+
case 'declared': {
|
|
2047
|
+
// A typed array is core ECMAScript, not a host protocol: `Uint8Array`
|
|
2048
|
+
// and its seven siblings are declared ambiently by the standard lib
|
|
2049
|
+
// (no body this compiler can derive a layout from) but are not
|
|
2050
|
+
// something any host installs -- so they are resolved by their own
|
|
2051
|
+
// policy, checked first, rather than falling into `binding` (host
|
|
2052
|
+
// protocols) or the ambient-with-no-protocol refusal below.
|
|
2053
|
+
const element = elements.forDeclaration(shape.declaration);
|
|
2054
|
+
if (element)
|
|
2055
|
+
return { kind: 'typed-array', element, buffer: typedArrayBufferKindOf(shape), ownership: ownership.forShape(shape, id) };
|
|
2056
|
+
// `ArrayBuffer`/`DataView`, checked here with the typed arrays because
|
|
2057
|
+
// they are the same family and reach the same trap: both are declared
|
|
2058
|
+
// ambiently with no body this compiler can lay out, both are core
|
|
2059
|
+
// ECMAScript rather than anything a host installs, and both are
|
|
2060
|
+
// ALREADY bound as opaque host protocols by the ambient-value census
|
|
2061
|
+
// (`ArrayBuffer` through `Uint8ArrayConstructor`'s own
|
|
2062
|
+
// `Uint8Array<ArrayBuffer>` return type). Falling through to `binding`
|
|
2063
|
+
// is what made every ArrayBuffer in three.js an opaque handle with no
|
|
2064
|
+
// bytes behind it. See `StandardBufferPolicy`.
|
|
2065
|
+
const buffer = buffers.forDeclaration(shape.declaration);
|
|
2066
|
+
if (buffer)
|
|
2067
|
+
return { kind: buffer, ownership: ownership.forShape(shape, id) };
|
|
2068
|
+
// `Promise<T>` is checked immediately after, for the identical
|
|
2069
|
+
// reason and ahead of `binding`/the ambient-body walk below: run
|
|
2070
|
+
// through `declaredBodyOf`'s data-only member stripping, the ambient
|
|
2071
|
+
// `Promise` interface's body is NOT empty (`then`/`catch`/`finally`
|
|
2072
|
+
// are methods, stripped, but other symbol-keyed members can survive)
|
|
2073
|
+
// -- so without this check, `Promise<T>` would silently derive as a
|
|
2074
|
+
// `native-record-ref` to a bogus struct instead of refusing or
|
|
2075
|
+
// deriving `T` at all. See design.md and citations.md finding 3 for
|
|
2076
|
+
// the concrete miscompile this produced before this check existed
|
|
2077
|
+
// (a `Promise<number>` parameter derived as a one-field struct while
|
|
2078
|
+
// the matching call result derived as plain `double`, and the two
|
|
2079
|
+
// disagreeing answers reached clang as a hard `no viable overloaded
|
|
2080
|
+
// '='` error). `shape.typeArguments[0]` reads `T` directly off the
|
|
2081
|
+
// `'declared'` shape's own field -- the same field `representationKey`
|
|
2082
|
+
// already prints for a declared shape -- never off the interface's
|
|
2083
|
+
// member list, which this check is precisely what keeps unconsulted.
|
|
2084
|
+
if (promise.forDeclaration(shape.declaration)) {
|
|
2085
|
+
const payload = shape.typeArguments[0];
|
|
2086
|
+
return payload
|
|
2087
|
+
? { kind: 'promise', value: derive(payload) }
|
|
2088
|
+
: unresolved('Promise<T> reached representation with no type argument');
|
|
2089
|
+
}
|
|
2090
|
+
// `Map`/`Set`/`WeakMap`/`WeakSet`, checked here for the same two
|
|
2091
|
+
// reasons `Promise<T>` is checked immediately above: their ambient
|
|
2092
|
+
// bodies are not empty after `declaredBodyOf`'s method stripping (a
|
|
2093
|
+
// `Map` keeps `size` and `[Symbol.toStringTag]`), so falling through
|
|
2094
|
+
// would seal a struct of leftovers; and the ambient-value census has
|
|
2095
|
+
// ALREADY bound `Map` as an opaque host protocol through
|
|
2096
|
+
// `MapConstructor.groupBy`'s return type, so falling through to
|
|
2097
|
+
// `binding` below would carry every `Map<K, V>` as a handle with no
|
|
2098
|
+
// key or value at all. See `KeyedCollectionPolicy`'s own comment.
|
|
2099
|
+
// `Generator<T, TReturn, TNext>`, checked here for the same two reasons
|
|
2100
|
+
// `Promise<T>` is checked immediately above: its ambient body is not
|
|
2101
|
+
// empty after `declaredBodyOf`'s method stripping, so falling through
|
|
2102
|
+
// would seal a struct of leftovers a generator value has none of; and
|
|
2103
|
+
// the carrier it needs is not a layout at all but the CURSOR
|
|
2104
|
+
// `gea::Iterator<T>` -- which is the same carrier the language itself
|
|
2105
|
+
// says a generator is, since `%GeneratorPrototype%[@@iterator]` returns
|
|
2106
|
+
// `this`. One carrier, `iterator(T)`, for a value that is both the
|
|
2107
|
+
// coroutine and the iterator over it.
|
|
2108
|
+
//
|
|
2109
|
+
// `TReturn`/`TNext` are carried when the checker resolved them to a
|
|
2110
|
+
// concrete, native carrier -- a `return 23` inside the body settles
|
|
2111
|
+
// `TReturn` to `number` the same way any other unannotated function's
|
|
2112
|
+
// inferred return settles, and an explicit `Generator<Y, R, N>`
|
|
2113
|
+
// annotation settles `N` the identical way a declared parameter does.
|
|
2114
|
+
// Neither is ever boxed to get there: a `TReturn`/`TNext` that
|
|
2115
|
+
// resolves to `dynamic`/`unresolved` (an unannotated generator's
|
|
2116
|
+
// implicit `TNext = unknown`, most commonly) collapses to
|
|
2117
|
+
// `{ kind: 'undefined' }` instead -- the cursor's own honest "stores
|
|
2118
|
+
// nothing here" carrier, matching what its default-constructed
|
|
2119
|
+
// `TReturn`/`TNext` slot already is at the C++ layer
|
|
2120
|
+
// (`runtime/gea_runtime.h`'s `Iterator<E, TReturn, TNext>`). A
|
|
2121
|
+
// generator whose resume value or completion value is actually READ
|
|
2122
|
+
// reaches its own refusal downstream, by name, exactly like any other
|
|
2123
|
+
// read through an `undefined` carrier already does -- never a widened
|
|
2124
|
+
// claim this compiler cannot back with real storage.
|
|
2125
|
+
if (generator.forDeclaration(shape.declaration)) {
|
|
2126
|
+
const yielded = shape.typeArguments[0];
|
|
2127
|
+
if (!yielded)
|
|
2128
|
+
return unresolved('Generator<T, TReturn, TNext> reached representation with no type argument');
|
|
2129
|
+
const nativeOrUndefined = (typeArgument) => {
|
|
2130
|
+
if (!typeArgument)
|
|
2131
|
+
return { kind: 'undefined' };
|
|
2132
|
+
const derived = deriveStored(typeArgument);
|
|
2133
|
+
return derived.kind === 'dynamic' || derived.kind === 'unresolved' ? { kind: 'undefined' } : derived;
|
|
2134
|
+
};
|
|
2135
|
+
return {
|
|
2136
|
+
kind: 'iterator',
|
|
2137
|
+
element: deriveStored(yielded),
|
|
2138
|
+
completion: nativeOrUndefined(shape.typeArguments[1]),
|
|
2139
|
+
resume: nativeOrUndefined(shape.typeArguments[2]),
|
|
2140
|
+
source: 'generator'
|
|
2141
|
+
};
|
|
2142
|
+
}
|
|
2143
|
+
const family = collections.forDeclaration(shape.declaration);
|
|
2144
|
+
if (family)
|
|
2145
|
+
return deriveKeyedCollection(family, shape, id, deriveStored, ownership);
|
|
2146
|
+
// `Date`, checked here for the same two reasons `Promise<T>` and the
|
|
2147
|
+
// keyed collections are checked above it. Its ambient body survives
|
|
2148
|
+
// `declaredBodyOf`'s method stripping as an EMPTY object shape, so
|
|
2149
|
+
// falling through would seal a layout of nothing and every member
|
|
2150
|
+
// access would then emit as a struct field that is not there; and the
|
|
2151
|
+
// carrier is the runtime's own `gea::runtime::Date`, which is a
|
|
2152
|
+
// STATED native type rather than one this compiler lays out --
|
|
2153
|
+
// `native` is what says so, and `records.ts` emits no struct for it.
|
|
2154
|
+
//
|
|
2155
|
+
// `native-record-ref` and not `native-handle`, on evidence: a
|
|
2156
|
+
// `native-handle` "carries absence" (types.ts's `carriesAbsence`), so
|
|
2157
|
+
// `representation/optional.ts` would collapse `Date | null` onto the
|
|
2158
|
+
// handle itself and spell `null` as an empty Date. A Date has no such
|
|
2159
|
+
// empty value. The shape id is the body's, so a program that reaches a
|
|
2160
|
+
// Date dynamically still finds the same sealed entry every other
|
|
2161
|
+
// record does.
|
|
2162
|
+
const dateNative = date.forDeclaration(shape.declaration);
|
|
2163
|
+
if (dateNative !== null && shape.body) {
|
|
2164
|
+
dateNatives.add(dateNative);
|
|
2165
|
+
return { kind: 'native-record-ref', shapeId: shape.body, ownership: ownership.forShape(shape, id), native: dateNative };
|
|
2166
|
+
}
|
|
2167
|
+
// `RegExp`, `RegExpExecArray` and `RegExpMatchArray`, checked here for
|
|
2168
|
+
// the same two reasons the three policies above are, both of which
|
|
2169
|
+
// hold for these as measured facts rather than by analogy.
|
|
2170
|
+
//
|
|
2171
|
+
// Their bodies survive `declaredBodyOf`'s method stripping: `RegExp`
|
|
2172
|
+
// keeps exactly ten data members (`source`, `global`, `ignoreCase`,
|
|
2173
|
+
// `multiline`, `lastIndex`, `flags`, `sticky`, `unicode`, `dotAll`,
|
|
2174
|
+
// `hasIndices`), and the two result interfaces keep
|
|
2175
|
+
// `index`/`input`/`groups`/`length` plus a number index signature. So
|
|
2176
|
+
// falling through would seal a plausible-looking struct for each and
|
|
2177
|
+
// emit a program that compiles and is not a regular expression.
|
|
2178
|
+
//
|
|
2179
|
+
// And the ambient-value census has ALREADY bound `RegExp` as an opaque
|
|
2180
|
+
// host protocol -- `lib.es5.d.ts` declares `var RegExp: RegExpConstructor`,
|
|
2181
|
+
// and the constructor's own `new (...): RegExp` result carries the
|
|
2182
|
+
// INTERFACE into the closure. Falling through to `binding` below would
|
|
2183
|
+
// give every pattern in the program a `native-handle` with no layout,
|
|
2184
|
+
// so `re.source` would have nowhere to go. The constructor's own handle
|
|
2185
|
+
// (`RegExpConstructor@1`) is untouched and stays a host boundary, which
|
|
2186
|
+
// is correct: `RegExp` the value really is an ambient constructor object.
|
|
2187
|
+
//
|
|
2188
|
+
// `shared-refcount` rather than the `owned` the bound data-only case
|
|
2189
|
+
// below uses, and that is not a default: a pattern is MUTABLE STATE
|
|
2190
|
+
// shared by reference. `re.lastIndex` advances across `exec` calls, and
|
|
2191
|
+
// `s.replace(re, ...)` resets it -- so two copies of one pattern would
|
|
2192
|
+
// silently drift apart. The ownership policy is not consulted for the
|
|
2193
|
+
// same reason: this is a fact about what a regular expression IS, not a
|
|
2194
|
+
// preference about how records are held.
|
|
2195
|
+
const pattern = regexp.forDeclaration(shape.declaration);
|
|
2196
|
+
if (pattern) {
|
|
2197
|
+
return shape.body
|
|
2198
|
+
? { kind: 'native-record-ref', shapeId: shape.body, ownership: 'shared-refcount', native: pattern.native }
|
|
2199
|
+
: unresolved(`the standard ${pattern.kind} declaration reached representation with no structural body`);
|
|
2200
|
+
}
|
|
2201
|
+
// `String`, the wrapper OBJECT (`new String(x)`), checked here for the
|
|
2202
|
+
// identical two reasons `RegExp` immediately above is -- see
|
|
2203
|
+
// `StringObjectDeclarationPolicy`'s own doc comment for both in full.
|
|
2204
|
+
// `shared-refcount` for the same reason a pattern is: this is an
|
|
2205
|
+
// object with identity, not a value, and a program that stores a
|
|
2206
|
+
// dynamic property on one (hono's `escapedString.isEscaped = true`)
|
|
2207
|
+
// must see that write from every reference to the same object.
|
|
2208
|
+
const stringObjectNative = stringObject.forDeclaration(shape.declaration);
|
|
2209
|
+
if (stringObjectNative !== null) {
|
|
2210
|
+
return shape.body
|
|
2211
|
+
? { kind: 'native-record-ref', shapeId: shape.body, ownership: 'shared-refcount', native: stringObjectNative }
|
|
2212
|
+
: unresolved('the standard String declaration reached representation with no structural body');
|
|
2213
|
+
}
|
|
2214
|
+
const errorNative = errors.forDeclaration(shape.declaration);
|
|
2215
|
+
if (errorNative !== null) {
|
|
2216
|
+
return shape.body
|
|
2217
|
+
? { kind: 'native-record-ref', shapeId: shape.body, ownership: 'shared-refcount', native: errorNative }
|
|
2218
|
+
: unresolved('a standard Error declaration reached representation with no structural body');
|
|
2219
|
+
}
|
|
2220
|
+
// The bare `Function` interface, checked here for the same first
|
|
2221
|
+
// reason every policy above it is -- the ambient-value census has
|
|
2222
|
+
// already bound it as an opaque host protocol through
|
|
2223
|
+
// `FunctionConstructor`'s own `new (...): Function` result, so falling
|
|
2224
|
+
// through to `binding` mints `native-boundary:Function@1`, which no
|
|
2225
|
+
// target can register because there is no C++ type for "some callable,
|
|
2226
|
+
// signature unknown" -- and for one reason none of them share: the
|
|
2227
|
+
// answer is not a carrier at all. `Function` states callability and
|
|
2228
|
+
// nothing else, so there is no frame to choose, and the honest carrier
|
|
2229
|
+
// is the box. See `'untyped-callable'` (model.ts) for why that is a
|
|
2230
|
+
// genuine dynamic boundary rather than a lowering not yet written, and
|
|
2231
|
+
// `FunctionDeclarationPolicy` (policies.ts) for why the body is not
|
|
2232
|
+
// sealed into a `name`/`length`/`prototype` struct instead.
|
|
2233
|
+
if (functionType.forDeclaration(shape.declaration))
|
|
2234
|
+
return { kind: 'dynamic', reason: 'untyped-callable' };
|
|
2235
|
+
// An interface the classes of this program declare themselves the
|
|
2236
|
+
// implementations of. Nothing constructs an interface, so a slot typed
|
|
2237
|
+
// by one holds one of those classes and nothing else -- see
|
|
2238
|
+
// `InterfaceImplementorPolicy` and the census behind it. One class is
|
|
2239
|
+
// the class; several are their tagged sum, which dispatches a member
|
|
2240
|
+
// call per arm exactly as a written class union does. All or nothing:
|
|
2241
|
+
// an implementor whose instantiation this cannot find would leave the
|
|
2242
|
+
// sum missing an arm the program can store, and a missing arm is a
|
|
2243
|
+
// miscompile, not a narrower answer, so the interface keeps its own
|
|
2244
|
+
// layout below and the store refuses by name instead. Checked after
|
|
2245
|
+
// every standard-library policy above (all of which answer for
|
|
2246
|
+
// ambient interfaces no program implements) and before `binding` and
|
|
2247
|
+
// the structural-body path below, which are the two that would
|
|
2248
|
+
// otherwise give the interface a layout of its own.
|
|
2249
|
+
// An implementor the sealed table holds NO instance shape for is a
|
|
2250
|
+
// class the program never constructs and never names as a type -- a
|
|
2251
|
+
// `PatternRouter` compiled in from a package file nothing imports a
|
|
2252
|
+
// value from -- and a class that is never constructed cannot be what
|
|
2253
|
+
// the slot holds, so it contributes no arm. That is different from an
|
|
2254
|
+
// implementor with instantiations none of which this reference's
|
|
2255
|
+
// arguments select: that one CAN be stored, and leaving it out is the
|
|
2256
|
+
// miscompile the all-or-nothing below refuses.
|
|
2257
|
+
const implementorDeclarations = implementors
|
|
2258
|
+
.forDeclaration(shape.declaration)
|
|
2259
|
+
.filter((implementor) => instanceShapesOf(implementor).length > 0);
|
|
2260
|
+
if (implementorDeclarations.length > 0) {
|
|
2261
|
+
const instances = [];
|
|
2262
|
+
for (const implementor of implementorDeclarations) {
|
|
2263
|
+
const instance = implementorShapeFor(implementor, shape.typeArguments);
|
|
2264
|
+
if (instance !== null)
|
|
2265
|
+
instances.push(instance);
|
|
2266
|
+
}
|
|
2267
|
+
if (instances.length === implementorDeclarations.length) {
|
|
2268
|
+
const sole = instances.length === 1 ? instances[0] : undefined;
|
|
2269
|
+
return sole !== undefined ? derive(sole) : deriveUnionShape({ kind: 'union', members: instances });
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
// A bound declaration is a host handle, full stop: the protocol is its
|
|
2273
|
+
// complete definition, and neither an empty structural body (a JSX
|
|
2274
|
+
// `Element` interface with no members) nor a missing one changes that.
|
|
2275
|
+
// "Host handle" is not "data-only handle": `declaredBodyOf` (structural.ts)
|
|
2276
|
+
// gives a call/construct-bearing type `signature` kind unconditionally,
|
|
2277
|
+
// dropping members it also has (`DateConstructor` keeps `now`/`parse`/`UTC`
|
|
2278
|
+
// out alongside its `new` overloads). Reading `call`/`construct` off that
|
|
2279
|
+
// shape is the checker's answer to "invoke path?" -- never a protocol check.
|
|
2280
|
+
const bound = binding.forDeclaration(shape.declaration);
|
|
2281
|
+
// ...with one exception the checker itself states. A bound declaration
|
|
2282
|
+
// whose body is DATA ONLY is not opaque -- the program builds one, and a
|
|
2283
|
+
// handle states a protocol and NO layout, so its keys have nowhere to
|
|
2284
|
+
// go. A body with methods stays a handle, which is what keeps
|
|
2285
|
+
// `GeaEmbeddedImage`/`FetchResponse` where they were. The record carrier
|
|
2286
|
+
// spells the host's own struct, so members emit BY NAME and clang
|
|
2287
|
+
// rejects any the C++ type lacks; `owned` because the host returns by
|
|
2288
|
+
// value (`isDataOnlyObjectShape`, object-shape.ts, states the rule).
|
|
2289
|
+
if (bound?.native && !bound.opaque && shape.body && isDataOnlyBody(shape.body)) {
|
|
2290
|
+
return { kind: 'native-record-ref', shapeId: shape.body, ownership: 'owned', native: bound.native };
|
|
2291
|
+
}
|
|
2292
|
+
// A binding that names NO C++ type, over a data-only body, is not a
|
|
2293
|
+
// claim -- it is a gap, and a handle is the one carrier that cannot
|
|
2294
|
+
// say so. `host-protocols.ts`'s closure walk binds whatever a host
|
|
2295
|
+
// MEMBER or CALL hands back, and its own `native` comes from the
|
|
2296
|
+
// plugin's `nativeTypes` keyed by name, so a host method returning an
|
|
2297
|
+
// ordinary data interface the plugin never named (`createOffer():
|
|
2298
|
+
// Promise<RTCSessionDescriptionInit>`) registered a protocol with a
|
|
2299
|
+
// null carrier. Read as a handle, that demands
|
|
2300
|
+
// `native-boundary:RTCSessionDescriptionInit@1` -- an obligation the
|
|
2301
|
+
// manifest can never satisfy, because nothing ever claimed a C++ type
|
|
2302
|
+
// for it -- and refuses the whole program (`examples/dialer`, every
|
|
2303
|
+
// one of its twelve rows). It is not opaque either: the app writes
|
|
2304
|
+
// `{ type, sdp }` object literals of it and reads their fields, which
|
|
2305
|
+
// is the definition of a layout this compiler owns. So it falls
|
|
2306
|
+
// through to the record path below, exactly as it did before anything
|
|
2307
|
+
// handed it across a boundary.
|
|
2308
|
+
//
|
|
2309
|
+
// A bound body with METHODS keeps the handle, carrier or not: its
|
|
2310
|
+
// operations belong to the host whether or not this compiler was told
|
|
2311
|
+
// the type's spelling, and inventing a layout for it would be the
|
|
2312
|
+
// guess this rule exists to prevent.
|
|
2313
|
+
const boundWithoutCarrier = bound !== null && !bound.native && shape.body !== null && isDataOnlyBody(shape.body);
|
|
2314
|
+
if (bound && !boundWithoutCarrier) {
|
|
2315
|
+
const invocable = shape.body ? shapeOf(shape.body) : null;
|
|
2316
|
+
const call = invocable?.kind === 'signature' ? hostInvocationAbiOf(invocable.call, 'overload') : null;
|
|
2317
|
+
const construct = invocable?.kind === 'signature' ? hostInvocationAbiOf(invocable.construct, 'construct') : null;
|
|
2318
|
+
return {
|
|
2319
|
+
kind: 'native-handle',
|
|
2320
|
+
protocol: bound.protocol,
|
|
2321
|
+
version: bound.version,
|
|
2322
|
+
native: bound.native,
|
|
2323
|
+
bases: binding.basesOf(bound.native),
|
|
2324
|
+
call,
|
|
2325
|
+
construct
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
// No body means the declaration is ambient: it declares a shape the
|
|
2329
|
+
// compiler did not define, so its carrier has to come from an installed
|
|
2330
|
+
// host protocol rather than from a layout guessed here.
|
|
2331
|
+
if (!shape.body)
|
|
2332
|
+
return unresolved(`declared type ${shape.declaration} is ambient and has no installed host protocol`);
|
|
2333
|
+
const body = shapeOf(shape.body);
|
|
2334
|
+
if (body?.kind === 'signature')
|
|
2335
|
+
return deriveSignature(body);
|
|
2336
|
+
// A name for a structure with no layout of its own IS that structure.
|
|
2337
|
+
// `type Result<T> = [...] | [...]` carries whatever the union carries;
|
|
2338
|
+
// there is nothing nominal to hold, and holding it as a
|
|
2339
|
+
// `native-record-ref` over a union shape would name a record layout
|
|
2340
|
+
// the sealed table never built. Only an `object` body has a layout of
|
|
2341
|
+
// its own, which is why that is the one kind that falls through to the
|
|
2342
|
+
// dictionary/record routing below.
|
|
2343
|
+
if (body !== null && body.kind !== 'object')
|
|
2344
|
+
return derive(shape.body);
|
|
2345
|
+
// A named declaration answers the identical "does this body have a
|
|
2346
|
+
// record layout" question `deriveObject` answers for an anonymous one,
|
|
2347
|
+
// read structurally off the body's own `index`/`members` keys -- never
|
|
2348
|
+
// by deriving the body wholesale, which would walk every member and
|
|
2349
|
+
// trip the recursion guard on the ordinary self-referential case this
|
|
2350
|
+
// carrier exists to support. A symbol-keyed member (an ambient
|
|
2351
|
+
// interface's `[Symbol.toStringTag]`) is an ordinary member here, the
|
|
2352
|
+
// same as it is for `deriveObject`: `recordFieldsOf` gives it a field
|
|
2353
|
+
// keyed by its own declaration identity rather than refusing the body
|
|
2354
|
+
// over it. A body that mixes named members with a string- or
|
|
2355
|
+
// number-keyed index signature is *not* refused either: it stays
|
|
2356
|
+
// nominal like any other record body, and `targets/cpp/records.ts`
|
|
2357
|
+
// derives the body's own shape again at emission, landing on the same
|
|
2358
|
+
// `record-with-index` carrier `deriveObject` would produce for it
|
|
2359
|
+
// directly -- a named declaration and an anonymous object ask the
|
|
2360
|
+
// identical layout question here, they just answer it at different
|
|
2361
|
+
// times.
|
|
2362
|
+
if (body?.kind === 'object') {
|
|
2363
|
+
const dictionaryIndex = dictionaryIndexOf(body);
|
|
2364
|
+
if (dictionaryIndex) {
|
|
2365
|
+
return {
|
|
2366
|
+
kind: 'dictionary',
|
|
2367
|
+
key: dictionaryIndex.key,
|
|
2368
|
+
value: deriveStored(dictionaryIndex.value),
|
|
2369
|
+
ownership: ownership.forShape(shape, id)
|
|
2370
|
+
};
|
|
2371
|
+
}
|
|
2372
|
+
const indexes = recordIndexesOf(body);
|
|
2373
|
+
if (typeof indexes === 'string')
|
|
2374
|
+
return unresolved(indexes);
|
|
2375
|
+
}
|
|
2376
|
+
// A name for a VALUE record is that record. Expanding a name is what
|
|
2377
|
+
// `native-record-ref` exists to avoid -- `interface Node { next: Node }`
|
|
2378
|
+
// has no finite by-value carrier -- but a value record has no reference
|
|
2379
|
+
// field at all by construction, so the body is finite and expanding it
|
|
2380
|
+
// is what lets `type Point = { x: number }` be a struct rather than a
|
|
2381
|
+
// handle. Delegating (rather than minting a second carrier here) keeps
|
|
2382
|
+
// the name and the body one answer, which is what `publish.ts` seals.
|
|
2383
|
+
if (valueRecords.forType(shape.body))
|
|
2384
|
+
return derive(shape.body);
|
|
2385
|
+
// Otherwise a declared name is carried nominally: its layout is
|
|
2386
|
+
// resolved from the sealed table by shape id at emission. Expanding it
|
|
2387
|
+
// here is what would make `interface Node { next: Node }` an infinite
|
|
2388
|
+
// carrier.
|
|
2389
|
+
return { kind: 'native-record-ref', shapeId: shape.body, ownership: ownership.forShape(shape, id), native: null };
|
|
2390
|
+
}
|
|
2391
|
+
case 'object-anchor': {
|
|
2392
|
+
// A callable-bearing object literal's nominal anchor (`structural.ts`).
|
|
2393
|
+
// Unlike `declared`, this shape never comes from an ambient/host
|
|
2394
|
+
// declaration -- an object literal is always defined in-program, so
|
|
2395
|
+
// there is no host-protocol branch to consult, and `shape.body` is
|
|
2396
|
+
// always built by `objectShapeOf` and therefore always `kind: 'object'`,
|
|
2397
|
+
// never `'signature'`. What DOES carry over from `declared`'s tail is
|
|
2398
|
+
// the dictionary/record-with-index routing: an object literal can
|
|
2399
|
+
// combine a method or accessor with a string- or number-keyed index
|
|
2400
|
+
// signature (`{ [k: string]: number; bump() {...} }`), and that
|
|
2401
|
+
// combination is answered the identical way a named declaration's body
|
|
2402
|
+
// answers it -- read structurally off the body's own shape, never by
|
|
2403
|
+
// deriving the body wholesale (which would walk `bump` again and trip
|
|
2404
|
+
// the recursion guard the anchor exists to avoid).
|
|
2405
|
+
const body = shapeOf(shape.body);
|
|
2406
|
+
if (body?.kind === 'object') {
|
|
2407
|
+
const dictionaryIndex = dictionaryIndexOf(body);
|
|
2408
|
+
if (dictionaryIndex) {
|
|
2409
|
+
return {
|
|
2410
|
+
kind: 'dictionary',
|
|
2411
|
+
key: dictionaryIndex.key,
|
|
2412
|
+
value: deriveStored(dictionaryIndex.value),
|
|
2413
|
+
ownership: ownership.forShape(shape, id)
|
|
2414
|
+
};
|
|
2415
|
+
}
|
|
2416
|
+
const indexes = recordIndexesOf(body);
|
|
2417
|
+
if (typeof indexes === 'string')
|
|
2418
|
+
return unresolved(indexes);
|
|
2419
|
+
}
|
|
2420
|
+
// The literal is carried nominally, exactly as `declared` carries an
|
|
2421
|
+
// interface or class: its layout is resolved from the sealed table by
|
|
2422
|
+
// shape id at emission (`targets/cpp/records.ts`'s `recordLayoutOfShape`),
|
|
2423
|
+
// never expanded here.
|
|
2424
|
+
return { kind: 'native-record-ref', shapeId: shape.body, ownership: ownership.forShape(shape, id), native: null };
|
|
2425
|
+
}
|
|
2426
|
+
case 'class-instance': {
|
|
2427
|
+
// Checked before `shape.body`, the same order the `declared` case
|
|
2428
|
+
// above already uses: `classInstanceBodyOf` (structural.ts)
|
|
2429
|
+
// enumerates a class's DATA properties in `data-only` mode whether or
|
|
2430
|
+
// not the class is ambient, so an ambient class with at least one
|
|
2431
|
+
// declared property (`UIScreen.bounds`, `UIScreen.scale`) already has
|
|
2432
|
+
// a non-null `shape.body` -- checking `!shape.body` first would route
|
|
2433
|
+
// it to `class-ref` regardless of being bound, and `class-ref`'s own
|
|
2434
|
+
// recipe is claimed flatly (`manifest.ts`) with no per-declaration
|
|
2435
|
+
// censused-check the way `constructor-family` has one
|
|
2436
|
+
// (`preflight/run.ts`'s `constructorFamilyIsCensused`) -- certifying,
|
|
2437
|
+
// then refusing at emission with "no class evaluation published" for
|
|
2438
|
+
// a class `class-lifecycle` never censused.
|
|
2439
|
+
const bound = binding.forDeclaration(shape.declaration);
|
|
2440
|
+
if (bound) {
|
|
2441
|
+
return {
|
|
2442
|
+
kind: 'native-handle',
|
|
2443
|
+
protocol: bound.protocol,
|
|
2444
|
+
version: bound.version,
|
|
2445
|
+
native: bound.native,
|
|
2446
|
+
bases: binding.basesOf(bound.native),
|
|
2447
|
+
call: null,
|
|
2448
|
+
construct: null
|
|
2449
|
+
};
|
|
2450
|
+
}
|
|
2451
|
+
// No body means the class was declared and not defined -- its instances
|
|
2452
|
+
// are built by something outside this program, and their layout belongs
|
|
2453
|
+
// to that host protocol rather than to a struct enumerated here.
|
|
2454
|
+
if (!shape.body) {
|
|
2455
|
+
return unresolved(`class ${shape.declaration} is declared without a body and has no installed host protocol`);
|
|
2456
|
+
}
|
|
2457
|
+
return {
|
|
2458
|
+
kind: 'class-ref',
|
|
2459
|
+
declaration: physicalClassDeclarationOf(shape),
|
|
2460
|
+
shapeId: shape.body,
|
|
2461
|
+
ownership: ownership.forShape(shape, id),
|
|
2462
|
+
ancestors: heritage.forDeclaration(shape.declaration)
|
|
2463
|
+
};
|
|
2464
|
+
}
|
|
2465
|
+
case 'class-constructor':
|
|
2466
|
+
return deriveClassConstructor(shape);
|
|
2467
|
+
case 'object':
|
|
2468
|
+
return deriveObject(id, shape);
|
|
2469
|
+
case 'array':
|
|
2470
|
+
// Always the observable Array, never the dense buffer: holes, index key
|
|
2471
|
+
// domain, and `length` semantics are observable, and a private buffer
|
|
2472
|
+
// has none of them. Selecting a buffer is a separate, proven decision.
|
|
2473
|
+
const extension = arrayExtensionFieldsOf(shape.extension);
|
|
2474
|
+
if (typeof extension === 'string')
|
|
2475
|
+
return unresolved(extension);
|
|
2476
|
+
return { kind: 'array-object', element: deriveStored(shape.element), ownership: ownership.forShape(shape, id), extension };
|
|
2477
|
+
case 'tuple':
|
|
2478
|
+
return deriveTuple(id, shape);
|
|
2479
|
+
case 'union':
|
|
2480
|
+
return deriveUnionShape(shape);
|
|
2481
|
+
case 'intersection':
|
|
2482
|
+
return deriveIntersection(id, shape);
|
|
2483
|
+
case 'signature':
|
|
2484
|
+
return deriveSignature(shape);
|
|
2485
|
+
case 'type-parameter':
|
|
2486
|
+
if (dynamicFallback)
|
|
2487
|
+
return { kind: 'dynamic', reason: 'opt-in-fallback' };
|
|
2488
|
+
return unresolved(`type parameter ${shape.declaration} reached representation without monomorphization`);
|
|
2489
|
+
case 'unresolved':
|
|
2490
|
+
if (dynamicFallback && shape.fallback === 'erased-type-expression')
|
|
2491
|
+
return { kind: 'dynamic', reason: 'opt-in-fallback' };
|
|
2492
|
+
// Bottom propagates. Substituting any carrier here would turn a stated
|
|
2493
|
+
// gap into a silently wrong answer.
|
|
2494
|
+
return unresolved(shape.reason);
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
const isNeverType = (id) => {
|
|
2498
|
+
const shape = shapeOf(id);
|
|
2499
|
+
if (shape?.kind === 'primitive')
|
|
2500
|
+
return shape.primitive === 'never';
|
|
2501
|
+
// An intersection of two classes neither of which descends from the other
|
|
2502
|
+
// is `never` in every sense this predicate is asked about -- unreachable,
|
|
2503
|
+
// no value, nothing to load -- even though TypeScript leaves the pair
|
|
2504
|
+
// unreduced and the shape therefore still says `intersection`. The
|
|
2505
|
+
// deriver's own intersection case answers the carrier half of this same
|
|
2506
|
+
// fact; consumers asking about REACHABILITY have to be told too, or a
|
|
2507
|
+
// provably dead branch keeps owing conversions for loads it never performs.
|
|
2508
|
+
if (shape?.kind !== 'intersection')
|
|
2509
|
+
return false;
|
|
2510
|
+
return isUninhabitedIntersection(substantiveMembersOf(shape.members));
|
|
2511
|
+
};
|
|
2512
|
+
// An OPEN tuple derives `array-object` already and is answered by its kind;
|
|
2513
|
+
// only the closed one lands in a record and needs the shape consulted.
|
|
2514
|
+
const isTupleShape = (id) => bodyShapeOf(id)?.kind === 'tuple';
|
|
2515
|
+
/**
|
|
2516
|
+
* The `[[Call]]`/`[[Construct]]` convention of one exact source function
|
|
2517
|
+
* whose semantic allocation was registered in `dynamicCallableShapes`.
|
|
2518
|
+
* The lookup starts with FunctionId, not a structural signature id: two
|
|
2519
|
+
* unrelated functions may share the latter, while only one may own the
|
|
2520
|
+
* mutable `.prototype`/expando table that required boxing.
|
|
2521
|
+
*
|
|
2522
|
+
* Calling `deriveSignature` directly, rather than going through the
|
|
2523
|
+
* memoized `derive`, is what bypasses the override without touching it:
|
|
2524
|
+
* `derive`'s own short-circuit remains the general type answer. This narrow
|
|
2525
|
+
* path returns `null` for an unjoinable overload and, critically, for a
|
|
2526
|
+
* construct-only signature: `[[Construct]]` has no caller-supplied receiver,
|
|
2527
|
+
* but its BODY does. Publishing that receiver-less construct ABI as an
|
|
2528
|
+
* ordinary call frame would enter the body with a slot nobody supplied.
|
|
2529
|
+
*/
|
|
2530
|
+
const nativeCallableConventions = (functionId) => {
|
|
2531
|
+
const id = dynamicCallableShapes.get(functionId);
|
|
2532
|
+
if (id === undefined)
|
|
2533
|
+
return null;
|
|
2534
|
+
const shape = shapeOf(id);
|
|
2535
|
+
if (shape?.kind !== 'signature')
|
|
2536
|
+
return null;
|
|
2537
|
+
const native = deriveSignature(shape);
|
|
2538
|
+
if (native.kind === 'function-value-dispatch')
|
|
2539
|
+
return { call: native.abi, construct: null };
|
|
2540
|
+
if (native.kind === 'function-and-constructor')
|
|
2541
|
+
return { call: native.call, construct: native.construct };
|
|
2542
|
+
return null;
|
|
2543
|
+
};
|
|
2544
|
+
const isDateCarrier = (representation) => representation.kind === 'native-record-ref' && representation.native !== null && dateNatives.has(representation.native);
|
|
2545
|
+
return { derive, layoutOf, abiOf, deriveStored, isNeverType, isTupleShape, nativeCallableConventions, isDateCarrier, dynamicFallback };
|
|
2546
|
+
};
|