@scriptc/compiler 0.2.6 → 0.2.8
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/ambient/scriptc-node-fallback.d.ts +7 -18
- package/dist/backend/cycle-analysis.d.ts +21 -9
- package/dist/backend/cycle-analysis.js +139 -67
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +283 -3
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +39 -0
- package/dist/backend/cycle-mutability.js +205 -0
- package/dist/backend/cycle-mutability.js.map +1 -0
- package/dist/backend/link-plan-core.d.ts +2 -1
- package/dist/backend/link-plan-core.js +15 -3
- package/dist/backend/link-plan-core.js.map +1 -1
- package/dist/backend/link-plan.d.ts +2 -1
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +43 -0
- package/dist/backend/llvm/alloc.js +246 -0
- package/dist/backend/llvm/alloc.js.map +1 -0
- package/dist/backend/llvm/alloc.test.d.ts +1 -0
- package/dist/backend/llvm/alloc.test.js +102 -0
- package/dist/backend/llvm/alloc.test.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +9 -0
- package/dist/backend/llvm/blocks.js +9 -0
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/borrowed-receivers.d.ts +7 -0
- package/dist/backend/llvm/borrowed-receivers.js +39 -0
- package/dist/backend/llvm/borrowed-receivers.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +18 -3
- package/dist/backend/llvm/call-lifetimes.js +54 -19
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +178 -3
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/checked-narrows.d.ts +24 -0
- package/dist/backend/llvm/checked-narrows.js +108 -0
- package/dist/backend/llvm/checked-narrows.js.map +1 -0
- package/dist/backend/llvm/checked-narrows.test.d.ts +1 -0
- package/dist/backend/llvm/checked-narrows.test.js +208 -0
- package/dist/backend/llvm/checked-narrows.test.js.map +1 -0
- package/dist/backend/llvm/classes.d.ts +16 -1
- package/dist/backend/llvm/classes.js +60 -49
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +68 -6
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +13 -0
- package/dist/backend/llvm/common.js +30 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +19 -3
- package/dist/backend/llvm/constant-callbacks.js +289 -52
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +140 -3
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/debug-info.d.ts +6 -2
- package/dist/backend/llvm/debug-info.js +11 -1
- package/dist/backend/llvm/debug-info.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +29 -0
- package/dist/backend/llvm/dense-array-access.js +335 -0
- package/dist/backend/llvm/dense-array-access.js.map +1 -0
- package/dist/backend/llvm/dense-array-access.test.d.ts +1 -0
- package/dist/backend/llvm/dense-array-access.test.js +238 -0
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +38 -0
- package/dist/backend/llvm/dyn.js +213 -14
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +308 -15
- package/dist/backend/llvm/emitter.js +1788 -206
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +89 -7
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +62 -8
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-async.test.d.ts +1 -0
- package/dist/backend/llvm/expr-async.test.js +62 -0
- package/dist/backend/llvm/expr-async.test.js.map +1 -0
- package/dist/backend/llvm/expr-bytes.d.ts +1 -1
- package/dist/backend/llvm/expr-bytes.js +85 -8
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.js +29 -21
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +5 -0
- package/dist/backend/llvm/expr-calls.js +118 -15
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +7 -1
- package/dist/backend/llvm/expr-containers.js +246 -32
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +113 -8
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +2 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +244 -44
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-island.js +3 -8
- package/dist/backend/llvm/expr-island.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +93 -36
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +51 -3
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +31 -17
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +96 -29
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.js +6 -3
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/integer-remainder.d.ts +11 -0
- package/dist/backend/llvm/integer-remainder.js +91 -0
- package/dist/backend/llvm/integer-remainder.js.map +1 -1
- package/dist/backend/llvm/layouts.d.ts +3 -1
- package/dist/backend/llvm/layouts.js +3 -2
- package/dist/backend/llvm/layouts.js.map +1 -1
- package/dist/backend/llvm/lazy-captures.d.ts +16 -0
- package/dist/backend/llvm/lazy-captures.js +96 -0
- package/dist/backend/llvm/lazy-captures.js.map +1 -0
- package/dist/backend/llvm/lazy-captures.test.d.ts +1 -0
- package/dist/backend/llvm/lazy-captures.test.js +78 -0
- package/dist/backend/llvm/lazy-captures.test.js.map +1 -0
- package/dist/backend/llvm/lib-abi.js +10 -0
- package/dist/backend/llvm/lib-abi.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +10 -15
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +8 -8
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +1 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +5 -1
- package/dist/backend/llvm/local-array-reads.js +147 -26
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +85 -4
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.d.ts +5 -1
- package/dist/backend/llvm/local-union-storage.js +54 -8
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +94 -6
- package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.d.ts +18 -0
- package/dist/backend/llvm/map-number-lookup.js +62 -0
- package/dist/backend/llvm/map-number-lookup.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +6 -0
- package/dist/backend/llvm/map-read-lifetimes.js +24 -3
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +39 -20
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/nullable-fields.d.ts +28 -0
- package/dist/backend/llvm/nullable-fields.js +45 -0
- package/dist/backend/llvm/nullable-fields.js.map +1 -0
- package/dist/backend/llvm/nullable-fields.test.d.ts +1 -0
- package/dist/backend/llvm/nullable-fields.test.js +48 -0
- package/dist/backend/llvm/nullable-fields.test.js.map +1 -0
- package/dist/backend/llvm/nullable-unions.d.ts +68 -0
- package/dist/backend/llvm/nullable-unions.js +132 -0
- package/dist/backend/llvm/nullable-unions.js.map +1 -0
- package/dist/backend/llvm/publish.d.ts +58 -0
- package/dist/backend/llvm/publish.js +286 -0
- package/dist/backend/llvm/publish.js.map +1 -0
- package/dist/backend/llvm/rebound-parameters.d.ts +12 -0
- package/dist/backend/llvm/rebound-parameters.js +72 -0
- package/dist/backend/llvm/rebound-parameters.js.map +1 -0
- package/dist/backend/llvm/rebound-parameters.test.d.ts +1 -0
- package/dist/backend/llvm/rebound-parameters.test.js +67 -0
- package/dist/backend/llvm/rebound-parameters.test.js.map +1 -0
- package/dist/backend/llvm/reference-effects.d.ts +18 -2
- package/dist/backend/llvm/reference-effects.js +106 -16
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/reference-effects.test.js +52 -1
- package/dist/backend/llvm/reference-effects.test.js.map +1 -1
- package/dist/backend/llvm/serialized-ir-emission.test.d.ts +1 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js +52 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +104 -9
- package/dist/backend/llvm/shapes.js +356 -46
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +139 -5
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/stack-callbacks.js +2 -3
- package/dist/backend/llvm/stack-callbacks.js.map +1 -1
- package/dist/backend/llvm/stack-captures.d.ts +3 -1
- package/dist/backend/llvm/stack-captures.js +5 -3
- package/dist/backend/llvm/stack-captures.js.map +1 -1
- package/dist/backend/llvm/stack-unions.test.js +43 -3
- package/dist/backend/llvm/stack-unions.test.js.map +1 -1
- package/dist/backend/llvm/string-construction.d.ts +10 -0
- package/dist/backend/llvm/string-construction.js +42 -0
- package/dist/backend/llvm/string-construction.js.map +1 -1
- package/dist/backend/llvm/string-construction.test.js +1 -1
- package/dist/backend/llvm/string-key-hash.d.ts +15 -0
- package/dist/backend/llvm/string-key-hash.js +76 -0
- package/dist/backend/llvm/string-key-hash.js.map +1 -0
- package/dist/backend/llvm/string-key-hash.test.d.ts +1 -0
- package/dist/backend/llvm/string-key-hash.test.js +45 -0
- package/dist/backend/llvm/string-key-hash.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +65 -15
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-reads.d.ts +7 -0
- package/dist/backend/llvm/string-reads.js +76 -0
- package/dist/backend/llvm/string-reads.js.map +1 -0
- package/dist/backend/llvm/switch-dispatch.js +1 -1
- package/dist/backend/llvm/switch-dispatch.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.test.js +3 -3
- package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
- package/dist/backend/llvm/test-boxed-unions.d.ts +5 -0
- package/dist/backend/llvm/test-boxed-unions.js +13 -0
- package/dist/backend/llvm/test-boxed-unions.js.map +1 -0
- package/dist/backend/llvm/union-repr.d.ts +15 -0
- package/dist/backend/llvm/union-repr.js +89 -0
- package/dist/backend/llvm/union-repr.js.map +1 -0
- package/dist/backend/llvm/virtual-borrows.d.ts +31 -0
- package/dist/backend/llvm/virtual-borrows.js +82 -0
- package/dist/backend/llvm/virtual-borrows.js.map +1 -0
- package/dist/backend/llvm/walk-borrows.d.ts +43 -0
- package/dist/backend/llvm/walk-borrows.js +150 -0
- package/dist/backend/llvm/walk-borrows.js.map +1 -0
- package/dist/backend/llvm/walk-borrows.test.d.ts +1 -0
- package/dist/backend/llvm/walk-borrows.test.js +119 -0
- package/dist/backend/llvm/walk-borrows.test.js.map +1 -0
- package/dist/backend/llvm/walkers.d.ts +5 -1
- package/dist/backend/llvm/walkers.js +24 -21
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.d.ts +29 -1
- package/dist/backend/may-throw.js +349 -3
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +114 -2
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native/cache-warm.d.ts +2 -1
- package/dist/backend/native/cache-warm.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +3 -2
- package/dist/backend/native/contracts.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +2 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +7 -4
- package/dist/backend/native-codegen-core.js +14 -9
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +9 -0
- package/dist/backend/native-codegen.js +53 -2
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +64 -10
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +3 -2
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-link-info.d.ts +2 -1
- package/dist/backend/native-link-info.js.map +1 -1
- package/dist/backend/native-link-info.test.js +2 -2
- package/dist/backend/native-link-info.test.js.map +1 -1
- package/dist/backend/native-tools.d.ts +5 -1
- package/dist/backend/native-tools.js +3 -1
- package/dist/backend/native-tools.js.map +1 -1
- package/dist/backend/optimization.d.ts +25 -0
- package/dist/backend/optimization.js +21 -0
- package/dist/backend/optimization.js.map +1 -0
- package/dist/backend/optimization.test.d.ts +1 -0
- package/dist/backend/optimization.test.js +24 -0
- package/dist/backend/optimization.test.js.map +1 -0
- package/dist/backend/publication.d.ts +28 -0
- package/dist/backend/publication.js +155 -0
- package/dist/backend/publication.js.map +1 -0
- package/dist/backend/publication.test.d.ts +1 -0
- package/dist/backend/publication.test.js +72 -0
- package/dist/backend/publication.test.js.map +1 -0
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +15 -4
- package/dist/backend/runtime-pack-core.js +23 -12
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-native.d.ts +7 -3
- package/dist/backend/runtime-pack-native.js +0 -3
- package/dist/backend/runtime-pack-native.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.d.ts +20 -2
- package/dist/backend/runtime-pack.js +23 -0
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +115 -2
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/backend/targets.d.ts +2 -1
- package/dist/backend/targets.js +1 -1
- package/dist/backend/targets.js.map +1 -1
- package/dist/cli/command.js +75 -11
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/host.d.ts +2 -1
- package/dist/cli/usage.d.ts +4 -1
- package/dist/cli/usage.js +13 -3
- package/dist/cli/usage.js.map +1 -1
- package/dist/compile-types.d.ts +17 -5
- package/dist/coverage/report.d.ts +25 -2
- package/dist/coverage/report.js +161 -33
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/verdict-cache.d.ts +63 -0
- package/dist/coverage/verdict-cache.js +193 -0
- package/dist/coverage/verdict-cache.js.map +1 -0
- package/dist/coverage/verdict-cache.test.d.ts +1 -0
- package/dist/coverage/verdict-cache.test.js +52 -0
- package/dist/coverage/verdict-cache.test.js.map +1 -0
- package/dist/coverage/verdict-semantic.d.ts +2 -0
- package/dist/coverage/verdict-semantic.js +24 -0
- package/dist/coverage/verdict-semantic.js.map +1 -0
- package/dist/coverage/verdict-startup.d.ts +15 -0
- package/dist/coverage/verdict-startup.js +66 -0
- package/dist/coverage/verdict-startup.js.map +1 -0
- package/dist/diagnostics/diagnostic.d.ts +29 -1
- package/dist/diagnostics/diagnostic.js +84 -12
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/envelope.d.ts +130 -0
- package/dist/diagnostics/envelope.js +257 -0
- package/dist/diagnostics/envelope.js.map +1 -0
- package/dist/diagnostics/envelope.test.d.ts +1 -0
- package/dist/diagnostics/envelope.test.js +91 -0
- package/dist/diagnostics/envelope.test.js.map +1 -0
- package/dist/diagnostics/render.d.ts +3 -0
- package/dist/diagnostics/render.js +13 -2
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +2 -2
- package/dist/executable/executable-cache.js +7 -4
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +20 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.d.ts +4 -0
- package/dist/executable/prepare.js +7 -1
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/analysis.js +1 -0
- package/dist/frontend/analysis.js.map +1 -1
- package/dist/frontend/lowering/abstract-equality.js +5 -49
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +30 -0
- package/dist/frontend/lowering/array-values.js +246 -1
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +17 -2
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/numbers.js +29 -1
- package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.d.ts +10 -17
- package/dist/frontend/lowering/builtins/process.js +66 -29
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.js +4 -2
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/caught-value-dispatch.d.ts +11 -0
- package/dist/frontend/lowering/caught-value-dispatch.js +87 -0
- package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -0
- package/dist/frontend/lowering/class-assertions.d.ts +12 -0
- package/dist/frontend/lowering/class-assertions.js +229 -5
- package/dist/frontend/lowering/class-assertions.js.map +1 -1
- package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
- package/dist/frontend/lowering/class-callbacks.js +18 -5
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +12 -6
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.d.ts +5 -0
- package/dist/frontend/lowering/class-method-mutations.js +472 -0
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -0
- package/dist/frontend/lowering/class-method-values.js +25 -5
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.js +8 -2
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-unions.d.ts +16 -0
- package/dist/frontend/lowering/class-unions.js +127 -0
- package/dist/frontend/lowering/class-unions.js.map +1 -0
- package/dist/frontend/lowering/coercions/builders.js +8 -1
- package/dist/frontend/lowering/coercions/builders.js.map +1 -1
- package/dist/frontend/lowering/coercions/function-adapters.js +2 -0
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/identity.d.ts +7 -0
- package/dist/frontend/lowering/coercions/identity.js +26 -0
- package/dist/frontend/lowering/coercions/identity.js.map +1 -0
- package/dist/frontend/lowering/coercions/state.d.ts +6 -0
- package/dist/frontend/lowering/coercions/state.js +2 -0
- package/dist/frontend/lowering/coercions/state.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +9 -6
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/coercions/unions.d.ts +8 -0
- package/dist/frontend/lowering/coercions/unions.js +67 -2
- package/dist/frontend/lowering/coercions/unions.js.map +1 -1
- package/dist/frontend/lowering/collation-repertoire.d.ts +1 -0
- package/dist/frontend/lowering/collation-repertoire.js +19 -0
- package/dist/frontend/lowering/collation-repertoire.js.map +1 -0
- package/dist/frontend/lowering/collection-narrowing.d.ts +6 -0
- package/dist/frontend/lowering/collection-narrowing.js +31 -0
- package/dist/frontend/lowering/collection-narrowing.js.map +1 -0
- package/dist/frontend/lowering/construction-escapes.d.ts +38 -0
- package/dist/frontend/lowering/construction-escapes.js +146 -0
- package/dist/frontend/lowering/construction-escapes.js.map +1 -0
- package/dist/frontend/lowering/construction-escapes.test.d.ts +1 -0
- package/dist/frontend/lowering/construction-escapes.test.js +150 -0
- package/dist/frontend/lowering/construction-escapes.test.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callback-call.d.ts +7 -0
- package/dist/frontend/lowering/containers/array-callback-call.js +52 -0
- package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callbacks.d.ts +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +416 -65
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-concat.d.ts +7 -0
- package/dist/frontend/lowering/containers/array-concat.js +130 -0
- package/dist/frontend/lowering/containers/array-concat.js.map +1 -0
- package/dist/frontend/lowering/containers/array-construction.d.ts +2 -0
- package/dist/frontend/lowering/containers/array-construction.js +110 -5
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.d.ts +1 -11
- package/dist/frontend/lowering/containers/array-methods.js +274 -144
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/callback-arguments.js +43 -1
- package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +10 -1
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +56 -70
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +7 -63
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/cycle-initialization.d.ts +46 -0
- package/dist/frontend/lowering/cycle-initialization.js +303 -0
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -0
- package/dist/frontend/lowering/divergences.d.ts +9 -0
- package/dist/frontend/lowering/divergences.js +630 -0
- package/dist/frontend/lowering/divergences.js.map +1 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +178 -34
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +4 -4
- package/dist/frontend/lowering/expressions/union-field-write.js +54 -44
- package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
- package/dist/frontend/lowering/iterator-adapters.d.ts +20 -0
- package/dist/frontend/lowering/iterator-adapters.js +605 -0
- package/dist/frontend/lowering/iterator-adapters.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
- package/dist/frontend/lowering/lower-array-sort.js +44 -5
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-array-sort.test.js +31 -0
- package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js +7 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.js +1 -0
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +8 -3
- package/dist/frontend/lowering/lower-calls.js +388 -278
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +6 -0
- package/dist/frontend/lowering/lower-classes.js +117 -65
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +22 -2
- package/dist/frontend/lowering/lower-exprs.js +811 -254
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +32 -19
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +19 -13
- package/dist/frontend/lowering/lower-generators.js +67 -44
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +29 -4
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +1 -1
- package/dist/frontend/lowering/lower-island.js +24 -7
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +100 -3
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +82 -64
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +115 -2
- package/dist/frontend/lowering/lowerer.js +1266 -88
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/native-ffi.js +3 -1
- package/dist/frontend/lowering/native-ffi.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-bounds.d.ts +19 -0
- package/dist/frontend/lowering/runtime-optional-bounds.js +354 -0
- package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-bounds.test.d.ts +1 -0
- package/dist/frontend/lowering/runtime-optional-bounds.test.js +66 -0
- package/dist/frontend/lowering/runtime-optional-bounds.test.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-elements.d.ts +117 -0
- package/dist/frontend/lowering/runtime-optional-elements.js +738 -0
- package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-guards.d.ts +36 -0
- package/dist/frontend/lowering/runtime-optional-guards.js +375 -0
- package/dist/frontend/lowering/runtime-optional-guards.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-guards.test.d.ts +1 -0
- package/dist/frontend/lowering/runtime-optional-guards.test.js +92 -0
- package/dist/frontend/lowering/runtime-optional-guards.test.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-ownership.d.ts +63 -0
- package/dist/frontend/lowering/runtime-optional-ownership.js +382 -0
- package/dist/frontend/lowering/runtime-optional-ownership.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-provenance.d.ts +16 -0
- package/dist/frontend/lowering/runtime-optional-provenance.js +41 -0
- package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -0
- package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
- package/dist/frontend/lowering/strict-equality.d.ts +9 -0
- package/dist/frontend/lowering/strict-equality.js +116 -0
- package/dist/frontend/lowering/strict-equality.js.map +1 -0
- package/dist/frontend/lowering/string-index-bounds.d.ts +36 -0
- package/dist/frontend/lowering/string-index-bounds.js +537 -0
- package/dist/frontend/lowering/string-index-bounds.js.map +1 -0
- package/dist/frontend/lowering/string-index-bounds.test.d.ts +1 -0
- package/dist/frontend/lowering/string-index-bounds.test.js +223 -0
- package/dist/frontend/lowering/string-index-bounds.test.js.map +1 -0
- package/dist/frontend/lowering/surfaces.js +3 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/union-comparison.d.ts +5 -0
- package/dist/frontend/lowering/union-comparison.js +47 -0
- package/dist/frontend/lowering/union-comparison.js.map +1 -0
- package/dist/frontend/lowering/union-narrow.d.ts +2 -0
- package/dist/frontend/lowering/union-narrow.js +10 -6
- package/dist/frontend/lowering/union-narrow.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +10 -0
- package/dist/frontend/program-analysis.js +7 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.d.ts +63 -2
- package/dist/frontend/program.js +1038 -61
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +122 -6
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/resolve.d.ts +6 -0
- package/dist/frontend/resolve.js +14 -0
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/threads-import.d.ts +5 -0
- package/dist/frontend/threads-import.js +21 -0
- package/dist/frontend/threads-import.js.map +1 -0
- package/dist/frontend/type-mapper.d.ts +4 -1
- package/dist/frontend/type-mapper.js +161 -20
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.js +15 -3
- package/dist/frontend/type-mapper.test.js.map +1 -1
- package/dist/frontend/worker-target.d.ts +4 -0
- package/dist/frontend/worker-target.js +8 -1
- package/dist/frontend/worker-target.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +70 -16
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +3 -1
- package/dist/ir/analysis.js +4 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/build.d.ts +5 -0
- package/dist/ir/build.js +7 -0
- package/dist/ir/build.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +5 -3
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/initializer-bindings.test.js +1 -1
- package/dist/ir/int32-slots.d.ts +72 -0
- package/dist/ir/int32-slots.js +837 -0
- package/dist/ir/int32-slots.js.map +1 -0
- package/dist/ir/int32-slots.test.d.ts +1 -0
- package/dist/ir/int32-slots.test.js +222 -0
- package/dist/ir/int32-slots.test.js.map +1 -0
- package/dist/ir/integer-ranges.d.ts +19 -3
- package/dist/ir/integer-ranges.js +168 -23
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +74 -2
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +101 -20
- package/dist/ir/ir.js +20 -6
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +3 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/traverse.js +8 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +139 -22
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +308 -8
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/fence-eval.test.js +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/library-cache.test.js +5 -5
- package/dist/library/library-profile.d.ts +2 -1
- package/dist/library/library-profile.js +4 -3
- package/dist/library/library-profile.js.map +1 -1
- package/dist/native/cache.d.ts +3 -0
- package/dist/native/cache.js +49 -1
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +21 -1
- package/dist/native/cache.test.js.map +1 -1
- package/dist/native/cli.js +1 -1
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.d.ts +5 -0
- package/dist/native/compiler.js +51 -4
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +2 -2
- package/dist/native/library.d.ts +2 -1
- package/dist/native/library.js.map +1 -1
- package/dist/native/prepare.d.ts +4 -0
- package/dist/native/prepare.js +28 -3
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.d.ts +3 -2
- package/dist/native/sanitizer.js +3 -13
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/startup-cache.d.ts +2 -0
- package/dist/startup-cache.js +2 -0
- package/dist/startup-cache.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +8 -2
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { generatorDrain } from "./iterator-adapters.js";
|
|
2
|
+
import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js";
|
|
3
|
+
import { isOptionalProcessStreamProperty } from "./builtins/process.js";
|
|
1
4
|
import { lowerWorkerMetadata } from "./builtins/workers.js";
|
|
2
|
-
import {
|
|
5
|
+
import { threadsImportOf } from "../threads-import.js";
|
|
6
|
+
import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js";
|
|
3
7
|
import { InternalCompilerError } from "../../errors.js";
|
|
4
8
|
import { SYMBOL_T } from "../../ir/ir.js";
|
|
5
9
|
import { literalValues } from "../literal-values.js";
|
|
@@ -11,9 +15,12 @@ import { literalUnionArm } from "../union-discriminants.js";
|
|
|
11
15
|
* ToBoolean/ToString coercion helpers, and field/element reads and writes
|
|
12
16
|
* (FieldTarget). */
|
|
13
17
|
import * as ts from "../ts7/adapter.js";
|
|
18
|
+
import { constituentTypes } from "../ts7/checker.js";
|
|
14
19
|
import { dirname } from "node:path";
|
|
15
20
|
import * as posix from "node:path/posix";
|
|
16
|
-
import { checkedClassAssertion } from "./class-assertions.js";
|
|
21
|
+
import { checkedClassAssertion, checkedClassUnionAssertion } from "./class-assertions.js";
|
|
22
|
+
import { narrowClassUnion, narrowStoredClassValue } from "./class-unions.js";
|
|
23
|
+
import { lowerUnionFieldWrite } from "./expressions/union-field-write.js";
|
|
17
24
|
import { captureContextArguments } from "./function-context.js";
|
|
18
25
|
import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
|
|
19
26
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
@@ -23,9 +30,8 @@ import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstO
|
|
|
23
30
|
import { UNSUPPORTED, blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag, } from "../../diagnostics/diagnostic.js";
|
|
24
31
|
import { PoisonError, dynFallbackType, jsFuncNameOf, neverTaintedJsType, own } from "./lowerer.js";
|
|
25
32
|
import { lowerCollectionSpread } from "./containers/collection-methods.js";
|
|
26
|
-
import {
|
|
33
|
+
import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, lowerSafeBytesRead, } from "./array-values.js";
|
|
27
34
|
import { strCharsCall } from "./containers/array-construction.js";
|
|
28
|
-
import { arrayValueRead, arrayValueStore, arrayValueType } from "./array-values.js";
|
|
29
35
|
import { lowerOptionalStringIndex } from "./string-index.js";
|
|
30
36
|
import { tryLowerIndexedComparison } from "./indexed-comparison.js";
|
|
31
37
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
@@ -98,8 +104,8 @@ export function templateRawTextOf(node) {
|
|
|
98
104
|
const LOWER_EXPR_MAX_DEPTH = 200;
|
|
99
105
|
let lowerExprDepth = 0;
|
|
100
106
|
/** True when a property access names an ABSTRACT property declaration
|
|
101
|
-
* (`abstract p: number` — a PropertyDeclaration, not an accessor)
|
|
102
|
-
*
|
|
107
|
+
* (`abstract p: number` — a PropertyDeclaration, not an accessor).
|
|
108
|
+
* These uses need concrete property dispatch because the base has no slot. */
|
|
103
109
|
export function abstractPropertyDeclOf(lowerer, expr) {
|
|
104
110
|
const sym = lowerer.checker.getSymbolAtLocation(expr.name);
|
|
105
111
|
if (!sym)
|
|
@@ -161,7 +167,10 @@ export function lowerExpr(lowerer, expr) {
|
|
|
161
167
|
}
|
|
162
168
|
lowerExprDepth++;
|
|
163
169
|
try {
|
|
164
|
-
|
|
170
|
+
const lowered = lowerExprInner(lowerer, expr);
|
|
171
|
+
if (lowered.type.kind === "void" && (lowerer.typeOf(expr).flags & ts.TypeFlags.Never) !== 0)
|
|
172
|
+
lowerer.neverValued.add(lowered);
|
|
173
|
+
return lowered;
|
|
165
174
|
}
|
|
166
175
|
finally {
|
|
167
176
|
lowerExprDepth--;
|
|
@@ -286,16 +295,35 @@ function lowerExprInner(lowerer, expr) {
|
|
|
286
295
|
// traps. Sub-union assertions and non-union inners keep their
|
|
287
296
|
// historic erasure (the widening sites re-tag with traps already).
|
|
288
297
|
if (ts.isNonNullExpression(expr)) {
|
|
298
|
+
// An asserted element read forwarded into a slot that holds undefined
|
|
299
|
+
// (see analyzeRuntimeOptionalArrayReads) reads without the bounds trap.
|
|
300
|
+
if (lowerer.runtimeOptionalAssertions.has(expr) &&
|
|
301
|
+
ts.isElementAccessExpression(expr.expression)) {
|
|
302
|
+
const probe = lowerAbsenceProbe(lowerer, expr.expression);
|
|
303
|
+
if (probe?.type.kind === "union")
|
|
304
|
+
return probe;
|
|
305
|
+
}
|
|
289
306
|
const inner = lowerer.lowerExpr(expr.expression);
|
|
290
307
|
if (inner.type.kind === "union") {
|
|
308
|
+
// `!` performs no runtime check: a missing array element stays
|
|
309
|
+
// undefined where its destination can hold it.
|
|
310
|
+
if (ts.isElementAccessExpression(expr.expression) &&
|
|
311
|
+
assertedElementKeepsUndefined(lowerer, expr))
|
|
312
|
+
return inner;
|
|
313
|
+
// A forwarded assertion whose destination was promoted to hold
|
|
314
|
+
// undefined (see analyzeRuntimeOptionalArrayReads), or an equality
|
|
315
|
+
// operand, keeps the value: `!` performs no runtime check.
|
|
316
|
+
const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
317
|
+
if (lowerer.runtimeOptionalAssertions.has(expr) ||
|
|
318
|
+
(target?.kind === "object" && isEqualityOperand(expr)))
|
|
319
|
+
return inner;
|
|
291
320
|
const use = runtimeOptionalUseOf(expr);
|
|
292
321
|
if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
|
|
293
322
|
return inner;
|
|
294
|
-
const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
295
323
|
if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
|
|
296
324
|
const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc);
|
|
297
325
|
if (helper) {
|
|
298
|
-
return
|
|
326
|
+
return lowerer.checkedNarrowCall(helper, inner, target, loc);
|
|
299
327
|
}
|
|
300
328
|
}
|
|
301
329
|
return inner;
|
|
@@ -717,7 +745,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
717
745
|
// A known static result type fixes typeof's answer, but its producer
|
|
718
746
|
// still evaluates: calls, getters, and checked reads can have effects
|
|
719
747
|
// or throw. Only trivial operands may disappear.
|
|
720
|
-
let operand = lowerer.lowerExpr(expr.expression);
|
|
748
|
+
let operand = deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.expression) ?? lowerer.lowerExpr(expr.expression));
|
|
721
749
|
if (operand.type.kind === "jsval") {
|
|
722
750
|
return { kind: "jsOp", op: "typeof", args: [operand], type: STRING, loc };
|
|
723
751
|
}
|
|
@@ -936,13 +964,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
936
964
|
? lowerer.narrowedArmHelper(local.type.unionId, narrowed, loc)
|
|
937
965
|
: null;
|
|
938
966
|
if (helper) {
|
|
939
|
-
return
|
|
940
|
-
kind: "call",
|
|
941
|
-
callee: helper,
|
|
942
|
-
args: [varRef(local.id, local.type, loc)],
|
|
943
|
-
type: narrowed,
|
|
944
|
-
loc,
|
|
945
|
-
};
|
|
967
|
+
return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
|
|
946
968
|
}
|
|
947
969
|
}
|
|
948
970
|
}
|
|
@@ -980,7 +1002,10 @@ function lowerExprInner(lowerer, expr) {
|
|
|
980
1002
|
// that does not exist. The blocked-binding cascade names the use;
|
|
981
1003
|
// without this the validator's registration check ICEs on the live
|
|
982
1004
|
// reference (`@this {T}` inference — signature 07).
|
|
983
|
-
|
|
1005
|
+
const unregistered = lowerer.unregisteredClassOf(g.type, new Set());
|
|
1006
|
+
if (unregistered !== null) {
|
|
1007
|
+
// The class's own rejection is the root cause the cascade names.
|
|
1008
|
+
lowerer.flushDeferredClass(unregistered);
|
|
984
1009
|
lowerer.pushDiag(blockedBindingUseDiag(expr.text, loc));
|
|
985
1010
|
throw new PoisonError();
|
|
986
1011
|
}
|
|
@@ -1013,7 +1038,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1013
1038
|
lowerer.armTag(g.type.unionId, narrowed) >= 0) {
|
|
1014
1039
|
const helper = lowerer.narrowedArmHelper(g.type.unionId, narrowed, loc);
|
|
1015
1040
|
if (helper)
|
|
1016
|
-
return
|
|
1041
|
+
return lowerer.checkedNarrowCall(helper, ref, narrowed, loc);
|
|
1017
1042
|
}
|
|
1018
1043
|
const use = runtimeOptionalUseOf(expr);
|
|
1019
1044
|
// The enclosing logical/conditional expression consumes the union
|
|
@@ -1111,6 +1136,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1111
1136
|
// as interned string literals; functions have no closure
|
|
1112
1137
|
// representation (they lower to libCall at call sites only); members
|
|
1113
1138
|
// with no lowering at all fence with the module-qualified name.
|
|
1139
|
+
{
|
|
1140
|
+
const member = threadsImportOf(lowerer.program, expr);
|
|
1141
|
+
// scriptc delivers published graphs by reference.
|
|
1142
|
+
if (member === "sharesPublishedGraphs")
|
|
1143
|
+
return { kind: "boolLit", value: true, type: BOOL, loc };
|
|
1144
|
+
if (member === "publish")
|
|
1145
|
+
lowerer.noLowering("publish (@scriptc/threads) as a value", expr, "call publish(value) directly");
|
|
1146
|
+
}
|
|
1114
1147
|
{
|
|
1115
1148
|
const bi = lowerer.builtinImportOf(expr);
|
|
1116
1149
|
if (bi) {
|
|
@@ -3075,6 +3108,11 @@ export function maybeNarrow(lowerer, expr, node) {
|
|
|
3075
3108
|
// same trust-the-checker contract as the union bridge below.
|
|
3076
3109
|
if (expr.type.kind === "object") {
|
|
3077
3110
|
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
3111
|
+
if (narrowed?.kind === "union") {
|
|
3112
|
+
const union = narrowClassUnion(lowerer, expr, narrowed);
|
|
3113
|
+
if (union)
|
|
3114
|
+
return union;
|
|
3115
|
+
}
|
|
3078
3116
|
if (narrowed?.kind === "object" &&
|
|
3079
3117
|
narrowed.className !== expr.type.className &&
|
|
3080
3118
|
lowerer.isSubclassOf(narrowed.className, expr.type.className)) {
|
|
@@ -3084,6 +3122,8 @@ export function maybeNarrow(lowerer, expr, node) {
|
|
|
3084
3122
|
}
|
|
3085
3123
|
if (expr.type.kind !== "union")
|
|
3086
3124
|
return expr;
|
|
3125
|
+
if (ts.isPropertyAccessExpression(node) && isOptionalProcessStreamProperty(lowerer, node))
|
|
3126
|
+
return expr;
|
|
3087
3127
|
// Represented fields and index values can include undefined even when
|
|
3088
3128
|
// checker inference or lib.d.ts declares strings (RegExp captures).
|
|
3089
3129
|
// Only a declaration that represents the optional arm can provide a
|
|
@@ -3228,6 +3268,9 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
3228
3268
|
lowerer.unsupported("SC1090", expr, "a runtime-optional capture whose narrowed value type is not representable");
|
|
3229
3269
|
}
|
|
3230
3270
|
if (narrowed.kind === "union") {
|
|
3271
|
+
const classView = narrowStoredClassValue(lowerer, varRef(local.id, local.type, loc), narrowed);
|
|
3272
|
+
if (classView)
|
|
3273
|
+
return classView;
|
|
3231
3274
|
// The checker may keep the receiver at the storage union unchanged
|
|
3232
3275
|
// (`string | undefined` on a JS `.match()` call). There is no
|
|
3233
3276
|
// sub-union to re-tag: preserve the value for the downstream
|
|
@@ -3254,6 +3297,13 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
3254
3297
|
loc,
|
|
3255
3298
|
};
|
|
3256
3299
|
}
|
|
3300
|
+
if (narrowed.kind === "object") {
|
|
3301
|
+
const view = checkedClassAssertion(lowerer, varRef(local.id, local.type, loc), narrowed, loc);
|
|
3302
|
+
// Preserve the member-specific missing-value error on the two-arm
|
|
3303
|
+
// path below; mixed storage also needs to validate its concrete class.
|
|
3304
|
+
if (view && (lowerer.unions.get(local.type.unionId)?.arms.length ?? 0) > 2)
|
|
3305
|
+
return view;
|
|
3306
|
+
}
|
|
3257
3307
|
const undefTag = lowerer.armTag(local.type.unionId, UNDEFINED_T);
|
|
3258
3308
|
const def = lowerer.unions.get(local.type.unionId);
|
|
3259
3309
|
if (!def || undefTag < 0)
|
|
@@ -3269,13 +3319,7 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
3269
3319
|
if (!helper) {
|
|
3270
3320
|
lowerer.unsupported("SC1090", expr, "a direct read from a runtime-optional capture with multiple value arms");
|
|
3271
3321
|
}
|
|
3272
|
-
return
|
|
3273
|
-
kind: "call",
|
|
3274
|
-
callee: helper,
|
|
3275
|
-
args: [varRef(local.id, local.type, loc)],
|
|
3276
|
-
type: narrowed,
|
|
3277
|
-
loc,
|
|
3278
|
-
};
|
|
3322
|
+
return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
|
|
3279
3323
|
}
|
|
3280
3324
|
// A predicate can strengthen a record's fields or narrow a base class
|
|
3281
3325
|
// to a subclass without changing the slot's stored value arm. Extract
|
|
@@ -3408,6 +3452,57 @@ function runtimeOptionalElementKey(expr) {
|
|
|
3408
3452
|
return expr.text;
|
|
3409
3453
|
return null;
|
|
3410
3454
|
}
|
|
3455
|
+
/** An operand of `===`, `!==`, `==` or `!=` (through parentheses). */
|
|
3456
|
+
function isEqualityOperand(node) {
|
|
3457
|
+
let outer = node;
|
|
3458
|
+
while (ts.isParenthesizedExpression(outer.parent))
|
|
3459
|
+
outer = outer.parent;
|
|
3460
|
+
const parent = outer.parent;
|
|
3461
|
+
return (ts.isBinaryExpression(parent) &&
|
|
3462
|
+
(parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
3463
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
3464
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
|
|
3465
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken));
|
|
3466
|
+
}
|
|
3467
|
+
/** Whether `xs[i]!` lands where an absent element's undefined is
|
|
3468
|
+
* representable: array storage (a literal element, a push/unshift
|
|
3469
|
+
* argument, an element assignment — arrays record the undefined state),
|
|
3470
|
+
* an equality operand, or a slot whose contextual type admits undefined.
|
|
3471
|
+
* TypeScript's `!` has no runtime effect, so such reads stay optional. */
|
|
3472
|
+
function assertedElementKeepsUndefined(lowerer, node) {
|
|
3473
|
+
let outer = node;
|
|
3474
|
+
while (ts.isParenthesizedExpression(outer.parent))
|
|
3475
|
+
outer = outer.parent;
|
|
3476
|
+
const parent = outer.parent;
|
|
3477
|
+
if (ts.isArrayLiteralExpression(parent))
|
|
3478
|
+
return true;
|
|
3479
|
+
// An equality test observes the missing element itself.
|
|
3480
|
+
if (ts.isBinaryExpression(parent) &&
|
|
3481
|
+
(parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
3482
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
3483
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
|
|
3484
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken))
|
|
3485
|
+
return true;
|
|
3486
|
+
const isArray = (receiver) => lowerer.checker.isArrayType(lowerer.typeOf(receiver));
|
|
3487
|
+
if (ts.isCallExpression(parent) &&
|
|
3488
|
+
parent.arguments.includes(outer) &&
|
|
3489
|
+
ts.isPropertyAccessExpression(parent.expression) &&
|
|
3490
|
+
(parent.expression.name.text === "push" || parent.expression.name.text === "unshift") &&
|
|
3491
|
+
isArray(parent.expression.expression))
|
|
3492
|
+
return true;
|
|
3493
|
+
if (ts.isBinaryExpression(parent) &&
|
|
3494
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
3495
|
+
parent.right === outer &&
|
|
3496
|
+
ts.isElementAccessExpression(parent.left) &&
|
|
3497
|
+
isArray(parent.left.expression))
|
|
3498
|
+
return true;
|
|
3499
|
+
const contextual = lowerer.checker.getContextualType(outer);
|
|
3500
|
+
if (!contextual)
|
|
3501
|
+
return false;
|
|
3502
|
+
const admits = (type) => (type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.Undefined)) !== 0;
|
|
3503
|
+
return (admits(contextual) ||
|
|
3504
|
+
((contextual.flags & ts.TypeFlags.Union) !== 0 && constituentTypes(contextual).some(admits)));
|
|
3505
|
+
}
|
|
3411
3506
|
function runtimeOptionalAssertionErases(lowerer, expr, inner, use) {
|
|
3412
3507
|
if (inner.type.kind !== "union" ||
|
|
3413
3508
|
!use?.optional ||
|
|
@@ -3436,6 +3531,17 @@ export function lowerUnitComparison(lowerer, left, right, negated, loc) {
|
|
|
3436
3531
|
// Two unit literals (`undefined === undefined`): statically decided.
|
|
3437
3532
|
return { kind: "boolLit", value: (other.unit === unit.unit) !== negated, type: BOOL, loc };
|
|
3438
3533
|
}
|
|
3534
|
+
const slot = lowerer.deferredFieldSlot(other);
|
|
3535
|
+
if (slot)
|
|
3536
|
+
return lowerUnitComparison(lowerer, slot, unit, negated, loc);
|
|
3537
|
+
// A binding the checker narrowed past the unit can still hold it at
|
|
3538
|
+
// runtime when its value came from an unassigned deferred-init field;
|
|
3539
|
+
// the stored tag answers either way.
|
|
3540
|
+
if (other.kind === "unionNarrow" &&
|
|
3541
|
+
other.value.kind === "varRef" &&
|
|
3542
|
+
other.value.type.kind === "union" &&
|
|
3543
|
+
lowerer.armTag(other.value.type.unionId, unit.type) >= 0)
|
|
3544
|
+
return lowerUnitComparison(lowerer, other.value, unit, negated, loc);
|
|
3439
3545
|
if (other.type.kind === "union") {
|
|
3440
3546
|
const tag = lowerer.armTag(other.type.unionId, unit.type);
|
|
3441
3547
|
if (tag < 0) {
|
|
@@ -3543,7 +3649,7 @@ function lowerLooseNullCompare(lowerer, expr, loc) {
|
|
|
3543
3649
|
if (!leftIsNull && right.kind !== ts.SyntaxKind.NullKeyword)
|
|
3544
3650
|
return null;
|
|
3545
3651
|
const otherNode = leftIsNull ? right : left;
|
|
3546
|
-
const other = lowerer
|
|
3652
|
+
const other = lowerPresenceOperand(lowerer, otherNode);
|
|
3547
3653
|
if (isUnitType(other.type)) {
|
|
3548
3654
|
// `null == null`, `undefined == null`: units are mutually loose-equal.
|
|
3549
3655
|
return { kind: "boolLit", value: !negated, type: BOOL, loc };
|
|
@@ -3648,13 +3754,110 @@ export function lowerNullishCoalesce(lowerer, expr, loc) {
|
|
|
3648
3754
|
parents.push(first);
|
|
3649
3755
|
first = first.left;
|
|
3650
3756
|
}
|
|
3651
|
-
let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first),
|
|
3757
|
+
let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), assertedPresenceOperand(lowerer, first.left));
|
|
3652
3758
|
for (let i = parents.length - 1; i >= 0; i--) {
|
|
3653
3759
|
const parent = parents[i];
|
|
3654
3760
|
result = lowerNullishPair(lowerer, parent, parent === expr ? loc : locOf(parent), result);
|
|
3655
3761
|
}
|
|
3656
3762
|
return result;
|
|
3657
3763
|
}
|
|
3764
|
+
/** The left side of `??` (see lowerPresenceOperand). The absence probe
|
|
3765
|
+
* reads optional storage beneath erased assertions; a union assertion that
|
|
3766
|
+
* narrows a stored class arm still applies its checked class view, so
|
|
3767
|
+
* `(node.parent as Sub | undefined) ?? node` sees the asserted arm on both
|
|
3768
|
+
* sides of the default. */
|
|
3769
|
+
function assertedPresenceOperand(lowerer, node) {
|
|
3770
|
+
const probe = lowerAbsenceProbe(lowerer, node);
|
|
3771
|
+
if (probe === null)
|
|
3772
|
+
return runtimeOptionalStorageOperand(lowerer, node) ?? lowerer.lowerExpr(node);
|
|
3773
|
+
if (probe.type.kind !== "union" && probe.type.kind !== "object")
|
|
3774
|
+
return probe;
|
|
3775
|
+
let outer = node;
|
|
3776
|
+
while (ts.isParenthesizedExpression(outer))
|
|
3777
|
+
outer = outer.expression;
|
|
3778
|
+
if (!ts.isAsExpression(outer) && !ts.isTypeAssertion(outer))
|
|
3779
|
+
return probe;
|
|
3780
|
+
const target = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(outer.type));
|
|
3781
|
+
if (target?.kind !== "union" || typeEquals(target, probe.type))
|
|
3782
|
+
return probe;
|
|
3783
|
+
return checkedClassUnionAssertion(lowerer, probe, target, locOf(outer)) ?? probe;
|
|
3784
|
+
}
|
|
3785
|
+
/** Read-modify-write updates read the member first: an unassigned
|
|
3786
|
+
* deferred-init receiver throws Node's member-read TypeError. */
|
|
3787
|
+
function checkDeferredMemberReceiver(lowerer, target, access) {
|
|
3788
|
+
if (target.container !== "class" ||
|
|
3789
|
+
!ts.isPropertyAccessExpression(access) ||
|
|
3790
|
+
target.obj.type.kind !== "object" ||
|
|
3791
|
+
lowerer.deferredFieldSlot(target.obj) === null)
|
|
3792
|
+
return;
|
|
3793
|
+
target.obj =
|
|
3794
|
+
lowerer.runtimeOptionalPropertyReceiver(access.expression, target.obj, target.obj.type, target.field) ?? target.obj;
|
|
3795
|
+
}
|
|
3796
|
+
/** Whether evaluating `expr` cannot store anything or run other code:
|
|
3797
|
+
* reads, arithmetic, tests and checked extractions (which at most throw). */
|
|
3798
|
+
function writeFree(expr) {
|
|
3799
|
+
switch (expr.kind) {
|
|
3800
|
+
case "numLit":
|
|
3801
|
+
case "strLit":
|
|
3802
|
+
case "boolLit":
|
|
3803
|
+
case "unitLit":
|
|
3804
|
+
case "varRef":
|
|
3805
|
+
return true;
|
|
3806
|
+
case "fieldGet":
|
|
3807
|
+
case "recordGet":
|
|
3808
|
+
return writeFree(expr.obj);
|
|
3809
|
+
case "bin":
|
|
3810
|
+
case "logical":
|
|
3811
|
+
return writeFree(expr.left) && writeFree(expr.right);
|
|
3812
|
+
case "unary":
|
|
3813
|
+
case "toBool":
|
|
3814
|
+
return writeFree(expr.operand);
|
|
3815
|
+
case "ternary":
|
|
3816
|
+
return writeFree(expr.cond) && writeFree(expr.then) && writeFree(expr.else_);
|
|
3817
|
+
case "unionIsTag":
|
|
3818
|
+
case "unionNarrow":
|
|
3819
|
+
case "unionWrap":
|
|
3820
|
+
return writeFree(expr.value);
|
|
3821
|
+
case "libCall":
|
|
3822
|
+
return expr.fn === "error.nodeThrow";
|
|
3823
|
+
default:
|
|
3824
|
+
return false;
|
|
3825
|
+
}
|
|
3826
|
+
}
|
|
3827
|
+
/** The TypeError of a deferred-init field read that finds the field
|
|
3828
|
+
* unassigned where its declared type cannot hold undefined. */
|
|
3829
|
+
export const DEFERRED_READ_MESSAGE = "undefined is not representable in the target union (a value narrowed or asserted past it still held it)";
|
|
3830
|
+
/** The undefined-armed slot behind a checked deferred-init field read, or
|
|
3831
|
+
* the value itself (Lowerer.deferredFieldSlot). */
|
|
3832
|
+
function deferredSlotOr(lowerer, value) {
|
|
3833
|
+
return lowerer.deferredFieldSlot(value) ?? value;
|
|
3834
|
+
}
|
|
3835
|
+
/** A plain value read that may be runtime-optional: an unchecked element
|
|
3836
|
+
* read, or a binding, member or call that carries one. Lowering these
|
|
3837
|
+
* without a destination type is the same as lowering them into one. */
|
|
3838
|
+
function isPlainValueRead(node) {
|
|
3839
|
+
while (ts.isParenthesizedExpression(node))
|
|
3840
|
+
node = node.expression;
|
|
3841
|
+
return (ts.isElementAccessExpression(node) ||
|
|
3842
|
+
ts.isIdentifier(node) ||
|
|
3843
|
+
ts.isPropertyAccessExpression(node) ||
|
|
3844
|
+
ts.isCallExpression(node));
|
|
3845
|
+
}
|
|
3846
|
+
/** A member access or call receiver needs the present value itself (JS
|
|
3847
|
+
* throws a TypeError reading a member of undefined). */
|
|
3848
|
+
function isMemberReceiver(node) {
|
|
3849
|
+
let child = node;
|
|
3850
|
+
let parent = node.parent;
|
|
3851
|
+
while (ts.isParenthesizedExpression(parent)) {
|
|
3852
|
+
child = parent;
|
|
3853
|
+
parent = parent.parent;
|
|
3854
|
+
}
|
|
3855
|
+
return (((ts.isPropertyAccessExpression(parent) ||
|
|
3856
|
+
ts.isElementAccessExpression(parent) ||
|
|
3857
|
+
ts.isCallExpression(parent)) &&
|
|
3858
|
+
parent.expression === child) ||
|
|
3859
|
+
(ts.isTaggedTemplateExpression(parent) && parent.tag === child));
|
|
3860
|
+
}
|
|
3658
3861
|
function lowerNullishPair(lowerer, expr, loc, left) {
|
|
3659
3862
|
if (left.type.kind === "dyn") {
|
|
3660
3863
|
// `a ?? b` on a CHECKED-DYNAMIC left: the deciding test is the
|
|
@@ -3691,7 +3894,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
|
|
|
3691
3894
|
const fresh = rest.length === 1 ? lowerer.emptyCollectionFor(expr.right, rest[0]) : null;
|
|
3692
3895
|
if (fresh)
|
|
3693
3896
|
return { kind: "nullish", left, right: fresh, type: fresh.type, loc };
|
|
3694
|
-
|
|
3897
|
+
let type = lowerer.irTypeOf(expr);
|
|
3898
|
+
// A runtime-optional read can reach the default even when declarations
|
|
3899
|
+
// call the left side present. Preserve a differently typed primitive
|
|
3900
|
+
// fallback rather than checking it against that incomplete result type.
|
|
3901
|
+
const rightType = lowerer.mapTypeOf(lowerer.typeOf(expr.right));
|
|
3902
|
+
const primitive = (t) => t.kind === "f64" || t.kind === "string" || t.kind === "bool";
|
|
3903
|
+
if (rightType &&
|
|
3904
|
+
primitive(type) &&
|
|
3905
|
+
primitive(rightType) &&
|
|
3906
|
+
!typeEquals(type, rightType) &&
|
|
3907
|
+
rest.every(primitive)) {
|
|
3908
|
+
const arms = [...rest];
|
|
3909
|
+
if (!arms.some((arm) => typeEquals(arm, rightType)))
|
|
3910
|
+
arms.push(rightType);
|
|
3911
|
+
arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
|
|
3912
|
+
type = { kind: "union", unionId: lowerer.unions.intern(arms) };
|
|
3913
|
+
lowerer.runtimeOptionalArithmeticTypes.set(expr, type);
|
|
3914
|
+
}
|
|
3695
3915
|
if (type.kind === "dyn" && lowerer.dynConvertible(left.type)) {
|
|
3696
3916
|
return {
|
|
3697
3917
|
kind: "nullish",
|
|
@@ -3701,6 +3921,27 @@ function lowerNullishPair(lowerer, expr, loc, left) {
|
|
|
3701
3921
|
loc,
|
|
3702
3922
|
};
|
|
3703
3923
|
}
|
|
3924
|
+
// A runtime-optional default (`name ?? names[0]`): the checker types an
|
|
3925
|
+
// unchecked element read as the bare element type, but an out-of-range
|
|
3926
|
+
// read is undefined at runtime. When the default shares the left's
|
|
3927
|
+
// optional union, that union is the result, so the undefined state
|
|
3928
|
+
// reaches the consumer (an optional return or parameter takes it as its
|
|
3929
|
+
// undefined arm; a plain slot still extracts the element with its
|
|
3930
|
+
// checked narrow).
|
|
3931
|
+
if (rest.length === 1 &&
|
|
3932
|
+
typeEquals(type, rest[0]) &&
|
|
3933
|
+
isPlainValueRead(expr.right) &&
|
|
3934
|
+
!isMemberReceiver(expr)) {
|
|
3935
|
+
const raw = lowerer.lowerExpr(expr.right);
|
|
3936
|
+
if (typeEquals(raw.type, left.type))
|
|
3937
|
+
return { kind: "nullish", left, right: raw, type: left.type, loc };
|
|
3938
|
+
// `names[0] ?? undefined`: an explicit unit default stays the left's arm.
|
|
3939
|
+
if (isUnitType(raw.type) && lowerer.armTag(left.type.unionId, raw.type) >= 0) {
|
|
3940
|
+
const right = lowerer.coerceInto(expr.right, raw, left.type);
|
|
3941
|
+
return { kind: "nullish", left, right, type: left.type, loc };
|
|
3942
|
+
}
|
|
3943
|
+
return { kind: "nullish", left, right: lowerer.coerceInto(expr.right, raw, type), type, loc };
|
|
3944
|
+
}
|
|
3704
3945
|
if (typeEquals(type, left.type) || (rest.length === 1 && typeEquals(type, rest[0]))) {
|
|
3705
3946
|
const right = lowerer.lowerExprExpecting(expr.right, type);
|
|
3706
3947
|
return { kind: "nullish", left, right, type, loc };
|
|
@@ -3711,6 +3952,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
|
|
|
3711
3952
|
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({ kind: "call", callee: helper, args: [stable], type, loc }));
|
|
3712
3953
|
}
|
|
3713
3954
|
}
|
|
3955
|
+
// A subclass value defaulted to a base-class value (`circle ?? shape`):
|
|
3956
|
+
// the present arm upcasts after the original nullish test, and the
|
|
3957
|
+
// default lowers lazily into the base-class result.
|
|
3958
|
+
const present = rest.length === 1 ? rest[0] : null;
|
|
3959
|
+
if (present?.kind === "object" &&
|
|
3960
|
+
type.kind === "object" &&
|
|
3961
|
+
present.className !== type.className &&
|
|
3962
|
+
lowerer.isSubclassOf(present.className, type.className)) {
|
|
3963
|
+
const helper = lowerer.narrowedArmHelper(left.type.unionId, present, loc);
|
|
3964
|
+
if (helper !== null) {
|
|
3965
|
+
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({
|
|
3966
|
+
kind: "upcast",
|
|
3967
|
+
value: { kind: "call", callee: helper, args: [stable], type: present, loc },
|
|
3968
|
+
type,
|
|
3969
|
+
loc,
|
|
3970
|
+
}));
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3714
3973
|
// A default may change the union or widen its records. Test the
|
|
3715
3974
|
// original tag before coercing: converting the whole left first can
|
|
3716
3975
|
// lose nullish arms, and evaluating the default eagerly loses laziness.
|
|
@@ -3824,7 +4083,8 @@ export function lowerCondition(lowerer, expr) {
|
|
|
3824
4083
|
};
|
|
3825
4084
|
}
|
|
3826
4085
|
}
|
|
3827
|
-
|
|
4086
|
+
const value = lowerPresenceOperand(lowerer, expr);
|
|
4087
|
+
return (tryLowerIndexTruthiness(lowerer, value, expr, locOf(expr)) ?? lowerer.ensureBool(value, expr));
|
|
3828
4088
|
}
|
|
3829
4089
|
function lowerPromiseThenPresence(lowerer, access, result) {
|
|
3830
4090
|
if (access.name.text !== "then")
|
|
@@ -3863,13 +4123,7 @@ function lowerPromiseThenPresence(lowerer, access, result) {
|
|
|
3863
4123
|
const helper = lowerer.narrowedArmHelper(receiver.type.unionId, promiseType, receiver.loc);
|
|
3864
4124
|
if (helper === null)
|
|
3865
4125
|
return null;
|
|
3866
|
-
receiver =
|
|
3867
|
-
kind: "call",
|
|
3868
|
-
callee: helper,
|
|
3869
|
-
args: [receiver],
|
|
3870
|
-
type: promiseType,
|
|
3871
|
-
loc: receiver.loc,
|
|
3872
|
-
};
|
|
4126
|
+
receiver = lowerer.checkedNarrowCall(helper, receiver, promiseType, receiver.loc);
|
|
3873
4127
|
}
|
|
3874
4128
|
}
|
|
3875
4129
|
if (receiver.type.kind === "dyn") {
|
|
@@ -4557,13 +4811,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
4557
4811
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
4558
4812
|
: null;
|
|
4559
4813
|
receiver = helper
|
|
4560
|
-
?
|
|
4561
|
-
kind: "call",
|
|
4562
|
-
callee: helper,
|
|
4563
|
-
args: [receiver],
|
|
4564
|
-
type: present,
|
|
4565
|
-
loc: locOf(expr.expression),
|
|
4566
|
-
}
|
|
4814
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
4567
4815
|
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
4568
4816
|
}
|
|
4569
4817
|
// An island handle behind a typed-array .d.ts surface: the engine
|
|
@@ -4657,13 +4905,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
4657
4905
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
4658
4906
|
: null;
|
|
4659
4907
|
receiver = helper
|
|
4660
|
-
?
|
|
4661
|
-
kind: "call",
|
|
4662
|
-
callee: helper,
|
|
4663
|
-
args: [receiver],
|
|
4664
|
-
type: present,
|
|
4665
|
-
loc: locOf(expr.expression),
|
|
4666
|
-
}
|
|
4908
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
4667
4909
|
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
4668
4910
|
}
|
|
4669
4911
|
// An island handle behind an array-typed .d.ts surface
|
|
@@ -4963,7 +5205,30 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
4963
5205
|
}
|
|
4964
5206
|
lowerer.badType(expr, tsType);
|
|
4965
5207
|
}
|
|
4966
|
-
|
|
5208
|
+
let type = mapped;
|
|
5209
|
+
// An inferred array of records takes the layout of an element literal
|
|
5210
|
+
// whose fields widened for missing-element reads; the other elements
|
|
5211
|
+
// build that layout directly. An explicit destination keeps its own.
|
|
5212
|
+
if (!expected && type.elem.kind === "record") {
|
|
5213
|
+
let variant = null;
|
|
5214
|
+
for (const candidate of expr.elements) {
|
|
5215
|
+
let x = candidate;
|
|
5216
|
+
while (ts.isParenthesizedExpression(x))
|
|
5217
|
+
x = x.expression;
|
|
5218
|
+
if (!ts.isObjectLiteralExpression(x))
|
|
5219
|
+
continue;
|
|
5220
|
+
const probe = tryLowerExpression(lowerer, x);
|
|
5221
|
+
if (!probe || !lowerer.isRuntimeOptionalRecordVariant(probe.type, type.elem))
|
|
5222
|
+
continue;
|
|
5223
|
+
if (variant !== null && !typeEquals(variant, probe.type)) {
|
|
5224
|
+
variant = null;
|
|
5225
|
+
break;
|
|
5226
|
+
}
|
|
5227
|
+
variant = probe.type;
|
|
5228
|
+
}
|
|
5229
|
+
if (variant !== null)
|
|
5230
|
+
type = arrayOf(variant);
|
|
5231
|
+
}
|
|
4967
5232
|
// Keep the array payload type fixed. Optional reads are stored through
|
|
4968
5233
|
// arrayValueStore, which records UNDEFINED in the state byte while the
|
|
4969
5234
|
// payload remains number/string/etc.; widening the array element here
|
|
@@ -5031,6 +5296,13 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
5031
5296
|
loc: locOf(el),
|
|
5032
5297
|
};
|
|
5033
5298
|
}
|
|
5299
|
+
// `[...it]` over a generator (or an iterator adapted into one):
|
|
5300
|
+
// drain it once, in order, into a fresh element array.
|
|
5301
|
+
if (src.type.kind === "generator") {
|
|
5302
|
+
const drained = generatorDrain(lowerer, src, type.elem, locOf(el));
|
|
5303
|
+
if (drained)
|
|
5304
|
+
src = drained;
|
|
5305
|
+
}
|
|
5034
5306
|
// A native checked iterable can supply scalar elements even when
|
|
5035
5307
|
// the checker inferred a typed array from its producer. Drain once
|
|
5036
5308
|
// and validate the elements before the ordinary spread copy.
|
|
@@ -5121,8 +5393,21 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
5121
5393
|
}
|
|
5122
5394
|
const out = lowerer.declareHiddenLocal("%arrayLit", type);
|
|
5123
5395
|
const outRef = varRef(out.id, type, loc);
|
|
5396
|
+
// Dense capacity for the elements the statements below store.
|
|
5397
|
+
const capacity = Math.min(elems.length - spreads.length, 1024);
|
|
5124
5398
|
const body = [
|
|
5125
|
-
{
|
|
5399
|
+
{
|
|
5400
|
+
kind: "varDecl",
|
|
5401
|
+
localId: out.id,
|
|
5402
|
+
init: {
|
|
5403
|
+
kind: "arrayLit",
|
|
5404
|
+
elems: [],
|
|
5405
|
+
...(capacity > 0 ? { capacity } : {}),
|
|
5406
|
+
type,
|
|
5407
|
+
loc,
|
|
5408
|
+
},
|
|
5409
|
+
loc,
|
|
5410
|
+
},
|
|
5126
5411
|
];
|
|
5127
5412
|
const spreadSet = new Set(spreads);
|
|
5128
5413
|
const currentLength = () => ({
|
|
@@ -5545,7 +5830,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5545
5830
|
? lowerer.narrowedArmHelper(recv.type.unionId, present, locOf(expr.expression))
|
|
5546
5831
|
: null;
|
|
5547
5832
|
recv = helper
|
|
5548
|
-
?
|
|
5833
|
+
? lowerer.checkedNarrowCall(helper, recv, present, locOf(expr.expression))
|
|
5549
5834
|
: lowerer.maybeNarrow(recv, expr.expression);
|
|
5550
5835
|
}
|
|
5551
5836
|
// A typed-array .d.ts surface whose VALUE is an island handle
|
|
@@ -5554,7 +5839,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5554
5839
|
// declared number type.
|
|
5555
5840
|
if (recv.type.kind === "jsval")
|
|
5556
5841
|
return islandElementRead(lowerer, expr, recv);
|
|
5557
|
-
const index = lowerer.lowerExpr(expr.argumentExpression);
|
|
5842
|
+
const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
|
|
5558
5843
|
if (isJsSourceFile(expr.getSourceFile()) && recv.type.kind === "bytes") {
|
|
5559
5844
|
return {
|
|
5560
5845
|
kind: "dynKeyGet",
|
|
@@ -5578,14 +5863,21 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5578
5863
|
if (index.type.kind !== "f64") {
|
|
5579
5864
|
lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys");
|
|
5580
5865
|
}
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5866
|
+
// `t[i]!` asserts presence: the numeric element read (NaN when
|
|
5867
|
+
// invalid). Every other read answers undefined for an invalid index,
|
|
5868
|
+
// like Node.
|
|
5869
|
+
if (ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) {
|
|
5870
|
+
return {
|
|
5871
|
+
kind: "bytesIntrinsic",
|
|
5872
|
+
method: "get",
|
|
5873
|
+
receiver: recv,
|
|
5874
|
+
args: [index],
|
|
5875
|
+
type: F64,
|
|
5876
|
+
loc: locOf(expr),
|
|
5877
|
+
invalidNaN: true,
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
return lowerSafeBytesRead(lowerer, recv, index, locOf(expr));
|
|
5589
5881
|
}
|
|
5590
5882
|
// Tuple element read `t[0]`: a positional-field read of the tuple's
|
|
5591
5883
|
// record shape — LITERAL indices only (the checker's per-index types
|
|
@@ -5628,13 +5920,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5628
5920
|
? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(expr.expression))
|
|
5629
5921
|
: null;
|
|
5630
5922
|
obj = helper
|
|
5631
|
-
?
|
|
5632
|
-
kind: "call",
|
|
5633
|
-
callee: helper,
|
|
5634
|
-
args: [obj],
|
|
5635
|
-
type: present,
|
|
5636
|
-
loc: locOf(expr.expression),
|
|
5637
|
-
}
|
|
5923
|
+
? lowerer.checkedNarrowCall(helper, obj, present, locOf(expr.expression))
|
|
5638
5924
|
: lowerer.maybeNarrow(obj, expr.expression);
|
|
5639
5925
|
}
|
|
5640
5926
|
const idx = tupleLiteralIndex(expr.argumentExpression);
|
|
@@ -5811,19 +6097,14 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5811
6097
|
}
|
|
5812
6098
|
}
|
|
5813
6099
|
if (receiverIr?.kind === "string") {
|
|
5814
|
-
//
|
|
5815
|
-
//
|
|
5816
|
-
// noUncheckedIndexedAccess the checker types the read `string`,
|
|
5817
|
-
// and charAt's "" is the only string-typed answer for an
|
|
5818
|
-
// out-of-range or fractional index where JS reads `undefined` —
|
|
5819
|
-
// SEMANTICS.md documents the divergence; in-range integer reads
|
|
5820
|
-
// (the loop pattern) are JS-exact. Optional results instead retain
|
|
5821
|
-
// undefined for missing string properties.
|
|
6100
|
+
// An indexed string property is absent for non-integer and missing
|
|
6101
|
+
// indexes. charAt has different coercion and out-of-range semantics.
|
|
5822
6102
|
const recv = lowerer.lowerExpr(expr.expression);
|
|
5823
|
-
const index = lowerer.lowerExpr(expr.argumentExpression);
|
|
5824
|
-
const resultType = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
6103
|
+
const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
|
|
5825
6104
|
if (index.type.kind === "f64" && recv.type.kind === "string") {
|
|
5826
|
-
|
|
6105
|
+
// A proven in-bounds integer index always names a code unit, where
|
|
6106
|
+
// charAt and the property read agree.
|
|
6107
|
+
if (lowerer.stringIndexBounds.inBounds(expr))
|
|
5827
6108
|
return {
|
|
5828
6109
|
kind: "strIntrinsic",
|
|
5829
6110
|
method: "charAt",
|
|
@@ -5832,15 +6113,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5832
6113
|
type: STRING,
|
|
5833
6114
|
loc: locOf(expr),
|
|
5834
6115
|
};
|
|
5835
|
-
|
|
5836
|
-
if (resultType?.kind === "union") {
|
|
5837
|
-
const arms = lowerer.unions.get(resultType.unionId)?.arms;
|
|
5838
|
-
if (arms?.length === 2 &&
|
|
5839
|
-
lowerer.armTag(resultType.unionId, STRING) >= 0 &&
|
|
5840
|
-
lowerer.armTag(resultType.unionId, UNDEFINED_T) >= 0) {
|
|
5841
|
-
return lowerOptionalStringIndex(lowerer, recv, index, resultType, locOf(expr));
|
|
5842
|
-
}
|
|
5843
|
-
}
|
|
6116
|
+
return lowerOptionalStringIndex(lowerer, recv, index, lowerer.withUndefinedArm(STRING), locOf(expr));
|
|
5844
6117
|
}
|
|
5845
6118
|
lowerer.unsupported("SC1090", expr, "string indexing with this index/result shape (expected a number index and a string or string | undefined result)");
|
|
5846
6119
|
}
|
|
@@ -5903,7 +6176,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5903
6176
|
? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(expr.expression))
|
|
5904
6177
|
: null;
|
|
5905
6178
|
arr = helper
|
|
5906
|
-
?
|
|
6179
|
+
? lowerer.checkedNarrowCall(helper, arr, present, locOf(expr.expression))
|
|
5907
6180
|
: lowerer.maybeNarrow(arr, expr.expression);
|
|
5908
6181
|
}
|
|
5909
6182
|
// The checker sees an array but the VALUE is an island handle (an
|
|
@@ -5962,10 +6235,13 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5962
6235
|
// change the storage representation or the low-level getter itself.
|
|
5963
6236
|
if (arr.type.kind === "array") {
|
|
5964
6237
|
// A non-null assertion is the explicit proven-present form. Preserve
|
|
5965
|
-
// the dense getter's established bounds trap
|
|
5966
|
-
//
|
|
5967
|
-
//
|
|
5968
|
-
|
|
6238
|
+
// the dense getter's established bounds trap where the asserted value
|
|
6239
|
+
// must be the element type (library ABI checks and the catchable
|
|
6240
|
+
// RangeError contract for an out-of-bounds assert). Where undefined is
|
|
6241
|
+
// representable, the assertion keeps JavaScript's unchecked read.
|
|
6242
|
+
const provenPresent = ts.isNonNullExpression(expr.parent) &&
|
|
6243
|
+
expr.parent.expression === expr &&
|
|
6244
|
+
!assertedElementKeepsUndefined(lowerer, expr.parent);
|
|
5969
6245
|
if (provenPresent) {
|
|
5970
6246
|
return lowerer.maybeNarrow({ kind: "arrayGet", arr, index, type: elemT, loc: locOf(expr) }, expr);
|
|
5971
6247
|
}
|
|
@@ -5979,7 +6255,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5979
6255
|
arr.kind === "arrIntrinsic" &&
|
|
5980
6256
|
arr.method === "slice" &&
|
|
5981
6257
|
npmStaticPackageOfPath(expr.getSourceFile().fileName) !== null) {
|
|
5982
|
-
const safe =
|
|
6258
|
+
const safe = lowerSafeIndexRead(lowerer, arr, index, locOf(expr));
|
|
5983
6259
|
if (safe)
|
|
5984
6260
|
return safe;
|
|
5985
6261
|
}
|
|
@@ -6210,6 +6486,57 @@ function lowerRecordPropertyKey(lowerer, key, node) {
|
|
|
6210
6486
|
}
|
|
6211
6487
|
return key;
|
|
6212
6488
|
}
|
|
6489
|
+
/** The stored value of an identifier whose storage holds an undefined arm
|
|
6490
|
+
* that the checker's type at this use has dropped. An assignment from an
|
|
6491
|
+
* unchecked indexed read narrows the declared type even though the value
|
|
6492
|
+
* can be absent at runtime, so presence tests (`=== undefined`, `== null`,
|
|
6493
|
+
* truthiness, `??`, `typeof`) read the storage tag instead of trusting
|
|
6494
|
+
* that narrowing. A guard-proven use answers the same way at runtime. */
|
|
6495
|
+
export function runtimeOptionalStorageOperand(lowerer, node) {
|
|
6496
|
+
let expr = node;
|
|
6497
|
+
while (ts.isParenthesizedExpression(expr))
|
|
6498
|
+
expr = expr.expression;
|
|
6499
|
+
if (!ts.isIdentifier(expr))
|
|
6500
|
+
return null;
|
|
6501
|
+
// Only storage that can actually receive an absent value without the
|
|
6502
|
+
// checker seeing it qualifies; other declared-optional bindings keep the
|
|
6503
|
+
// checker's assignment and guard narrowing.
|
|
6504
|
+
const symbol = lowerer.resolveValueSymbol(expr);
|
|
6505
|
+
const local = lowerer.resolveLocal(expr);
|
|
6506
|
+
const global = local ? undefined : lowerer.globalOf(expr);
|
|
6507
|
+
const root = local ? lowerer.runtimeOptionalRootOf(local) : null;
|
|
6508
|
+
if (root && lowerer.runtimeOptionalStorageLocals.has(root)) {
|
|
6509
|
+
// These locals track guards: a branch that proved presence removes
|
|
6510
|
+
// the binding from the active set, and its reads stay narrowed. A
|
|
6511
|
+
// captured binding can be reassigned between calls, so a capture
|
|
6512
|
+
// never inherits a guard (the identifier read's own rule).
|
|
6513
|
+
const captured = local.boxed === true ||
|
|
6514
|
+
(!!symbol && lowerer.ctx.captureBySymbol.get(symbol) === local) ||
|
|
6515
|
+
root !== local;
|
|
6516
|
+
if (!captured && !lowerer.runtimeOptionalLocals.has(root))
|
|
6517
|
+
return null;
|
|
6518
|
+
}
|
|
6519
|
+
else if (!(symbol && lowerer.runtimeOptionalAssignedSymbols.has(symbol)) &&
|
|
6520
|
+
!(symbol && lowerer.runtimeOptionalBindingTypes.has(symbol)) &&
|
|
6521
|
+
!(global && lowerer.isRuntimeOptionalGlobal(global)))
|
|
6522
|
+
return null;
|
|
6523
|
+
const optional = lowerer.runtimeOptionalIdentifierValue(expr);
|
|
6524
|
+
if (optional === null)
|
|
6525
|
+
return null;
|
|
6526
|
+
const checked = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
6527
|
+
if (checked === null ||
|
|
6528
|
+
(checked.kind === "union" && lowerer.armTag(checked.unionId, UNDEFINED_T) >= 0))
|
|
6529
|
+
return null;
|
|
6530
|
+
return optional.value;
|
|
6531
|
+
}
|
|
6532
|
+
/** A presence-test operand: an absence-aware element or field read, an
|
|
6533
|
+
* identifier's runtime-optional storage, or the ordinary lowering. */
|
|
6534
|
+
export function lowerPresenceOperand(lowerer, node) {
|
|
6535
|
+
// An unassigned deferred-init field observes its undefined slot too.
|
|
6536
|
+
return deferredSlotOr(lowerer, lowerAbsenceProbe(lowerer, node) ??
|
|
6537
|
+
runtimeOptionalStorageOperand(lowerer, node) ??
|
|
6538
|
+
lowerer.lowerExpr(node));
|
|
6539
|
+
}
|
|
6213
6540
|
/** A keyed read used only to observe absence (`if (map[k])`, or the left
|
|
6214
6541
|
* side of `||`/`??`). JavaScript answers undefined for missing record keys
|
|
6215
6542
|
* and array indices even when noUncheckedIndexedAccess is disabled. Keep
|
|
@@ -6225,6 +6552,10 @@ export function lowerAbsenceProbe(lowerer, node) {
|
|
|
6225
6552
|
expr = expr.expression;
|
|
6226
6553
|
}
|
|
6227
6554
|
if (ts.isPropertyAccessExpression(expr)) {
|
|
6555
|
+
// Namespace members are bindings, not fields of a runtime namespace
|
|
6556
|
+
// object. Their ordinary read already preserves optional storage.
|
|
6557
|
+
if (!expr.questionDotToken && nsMemberIdentOf(lowerer, expr))
|
|
6558
|
+
return null;
|
|
6228
6559
|
const target = lowerer.fieldTarget(expr);
|
|
6229
6560
|
if (target?.container === "class" &&
|
|
6230
6561
|
target.fieldType.kind === "union" &&
|
|
@@ -6418,13 +6749,7 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
6418
6749
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(target.expression))
|
|
6419
6750
|
: null;
|
|
6420
6751
|
if (helper)
|
|
6421
|
-
receiver =
|
|
6422
|
-
kind: "call",
|
|
6423
|
-
callee: helper,
|
|
6424
|
-
args: [receiver],
|
|
6425
|
-
type: present,
|
|
6426
|
-
loc: locOf(target.expression),
|
|
6427
|
-
};
|
|
6752
|
+
receiver = lowerer.checkedNarrowCall(helper, receiver, present, locOf(target.expression));
|
|
6428
6753
|
}
|
|
6429
6754
|
if (receiver.type.kind !== receiverType.kind) {
|
|
6430
6755
|
lowerer.unsupported("SC1090", target.expression, "compound assignment through a non-native array or byte view");
|
|
@@ -6439,12 +6764,15 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
6439
6764
|
const oldValue = receiver.type.kind === "array"
|
|
6440
6765
|
? arrayValueRead(lowerer, receiverRef(), indexRef(), receiver.type.elem, locOf(target))
|
|
6441
6766
|
: {
|
|
6767
|
+
// An invalid index reads undefined in Node, which every numeric
|
|
6768
|
+
// compound operator turns into NaN; the write is then ignored.
|
|
6442
6769
|
kind: "bytesIntrinsic",
|
|
6443
6770
|
method: "get",
|
|
6444
6771
|
receiver: receiverRef(),
|
|
6445
6772
|
args: [indexRef()],
|
|
6446
6773
|
type: F64,
|
|
6447
6774
|
loc: locOf(target),
|
|
6775
|
+
invalidNaN: true,
|
|
6448
6776
|
};
|
|
6449
6777
|
const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
|
|
6450
6778
|
const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
|
|
@@ -7060,13 +7388,7 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
7060
7388
|
? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(target.expression))
|
|
7061
7389
|
: null;
|
|
7062
7390
|
if (helper) {
|
|
7063
|
-
arr =
|
|
7064
|
-
kind: "call",
|
|
7065
|
-
callee: helper,
|
|
7066
|
-
args: [arr],
|
|
7067
|
-
type: present,
|
|
7068
|
-
loc: locOf(target.expression),
|
|
7069
|
-
};
|
|
7391
|
+
arr = lowerer.checkedNarrowCall(helper, arr, present, locOf(target.expression));
|
|
7070
7392
|
}
|
|
7071
7393
|
}
|
|
7072
7394
|
if (arr.type.kind !== "array") {
|
|
@@ -7184,8 +7506,21 @@ export function ensureString(lowerer, e, node) {
|
|
|
7184
7506
|
narrowed.kind === "bigint")) {
|
|
7185
7507
|
const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
|
|
7186
7508
|
if (helper) {
|
|
7509
|
+
return ensureString(lowerer, lowerer.checkedNarrowCall(helper, e, narrowed, e.loc), node);
|
|
7510
|
+
}
|
|
7511
|
+
}
|
|
7512
|
+
if (narrowed?.kind === "union" &&
|
|
7513
|
+
!typeEquals(narrowed, e.type) &&
|
|
7514
|
+
lowerer.unions
|
|
7515
|
+
.get(narrowed.unionId)
|
|
7516
|
+
?.arms.every((arm) => isUnitType(arm) ||
|
|
7517
|
+
arm.kind === "string" ||
|
|
7518
|
+
arm.kind === "f64" ||
|
|
7519
|
+
arm.kind === "bool" ||
|
|
7520
|
+
arm.kind === "bigint")) {
|
|
7521
|
+
const helper = lowerer.narrowedRetagHelper(node, e.type.unionId, narrowed.unionId, e.loc);
|
|
7522
|
+
if (helper)
|
|
7187
7523
|
return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
|
|
7188
|
-
}
|
|
7189
7524
|
}
|
|
7190
7525
|
lowerer.unsupported("SC1090", node, `string conversions of unions with object arms (${NARROW_FIRST})`);
|
|
7191
7526
|
}
|
|
@@ -7360,20 +7695,16 @@ export function lowerAsExpression(lowerer, expr) {
|
|
|
7360
7695
|
};
|
|
7361
7696
|
}
|
|
7362
7697
|
}
|
|
7363
|
-
//
|
|
7364
|
-
//
|
|
7365
|
-
//
|
|
7366
|
-
// (`/** @type {T} */ (e)` — JS has no `as`); 5.9.3 parsed that as a
|
|
7367
|
-
// plain parenthesized read, which lowered caught→dyn and met the
|
|
7368
|
-
// target through the ordinary checked-cast coercion — so the dyn
|
|
7369
|
-
// bridge stays open here exactly for that shape.
|
|
7698
|
+
// Structural assertions use the ordinary checked dynamic bridge. It
|
|
7699
|
+
// retains primitive values and native class identity before validating
|
|
7700
|
+
// the requested shape; an assertion does not bypass runtime checks.
|
|
7370
7701
|
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
7371
7702
|
const bridged = narrowed &&
|
|
7372
7703
|
(narrowed.kind === "f64" ||
|
|
7373
7704
|
narrowed.kind === "bool" ||
|
|
7374
7705
|
narrowed.kind === "string" ||
|
|
7375
7706
|
narrowed.kind === "object" ||
|
|
7376
|
-
|
|
7707
|
+
narrowed.kind === "dyn");
|
|
7377
7708
|
if (!bridged)
|
|
7378
7709
|
lowerer.unsupported("SC1063", expr);
|
|
7379
7710
|
}
|
|
@@ -7448,10 +7779,20 @@ export function lowerAsExpression(lowerer, expr) {
|
|
|
7448
7779
|
if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
|
|
7449
7780
|
const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, locOf(expr));
|
|
7450
7781
|
if (helper) {
|
|
7451
|
-
return
|
|
7782
|
+
return lowerer.checkedNarrowCall(helper, inner, target, locOf(expr));
|
|
7452
7783
|
}
|
|
7453
7784
|
}
|
|
7454
7785
|
}
|
|
7786
|
+
// `node.parent as Sub | undefined`: a union target whose class arm is
|
|
7787
|
+
// narrower than the stored class gets the same checked class view as
|
|
7788
|
+
// `node.parent as Sub`; the other arms keep their identical tags.
|
|
7789
|
+
if (target?.kind === "union" &&
|
|
7790
|
+
(inner.type.kind === "union" || inner.type.kind === "object") &&
|
|
7791
|
+
!typeEquals(target, inner.type)) {
|
|
7792
|
+
const asserted = checkedClassUnionAssertion(lowerer, inner, target, locOf(expr));
|
|
7793
|
+
if (asserted)
|
|
7794
|
+
return asserted;
|
|
7795
|
+
}
|
|
7455
7796
|
return inner; // erasure, unchanged
|
|
7456
7797
|
}
|
|
7457
7798
|
if (inner.type.kind === "jsval") {
|
|
@@ -7578,7 +7919,7 @@ export function lowerPrefixUnary(lowerer, expr) {
|
|
|
7578
7919
|
}
|
|
7579
7920
|
case ts.SyntaxKind.ExclamationToken: {
|
|
7580
7921
|
// `!x` is ToBoolean-then-negate: f64/string operands go through toBool.
|
|
7581
|
-
const operand = lowerer.ensureBool(lowerer.lowerExpr(expr.operand), expr.operand);
|
|
7922
|
+
const operand = lowerer.ensureBool(deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.operand) ?? lowerer.lowerExpr(expr.operand)), expr.operand);
|
|
7582
7923
|
return { kind: "unary", op: "!", operand, type: BOOL, loc };
|
|
7583
7924
|
}
|
|
7584
7925
|
case ts.SyntaxKind.TildeToken: {
|
|
@@ -7625,11 +7966,11 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7625
7966
|
}
|
|
7626
7967
|
fenceNodeModuleMutation(lowerer, access, "assignment");
|
|
7627
7968
|
if (ts.isPropertyAccessExpression(access)) {
|
|
7628
|
-
const target = staticFieldWriteTarget(lowerer, access)
|
|
7969
|
+
const target = staticFieldWriteTarget(lowerer, access) ??
|
|
7970
|
+
expandoWritableTarget(lowerer, access) ??
|
|
7971
|
+
nsWritableTarget(lowerer, access);
|
|
7629
7972
|
if (target) {
|
|
7630
|
-
|
|
7631
|
-
lowerer.unsupported("SC1043", expr);
|
|
7632
|
-
return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
|
|
7973
|
+
return lowerIncDecTarget(lowerer, expr, target, prefix);
|
|
7633
7974
|
}
|
|
7634
7975
|
}
|
|
7635
7976
|
const stmts = [];
|
|
@@ -7683,7 +8024,15 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7683
8024
|
const type = raw.type;
|
|
7684
8025
|
const read = type.kind === "array"
|
|
7685
8026
|
? arrayValueRead(lowerer, receiver, index, type.elem, loc)
|
|
7686
|
-
: {
|
|
8027
|
+
: {
|
|
8028
|
+
kind: "bytesIntrinsic",
|
|
8029
|
+
method: "get",
|
|
8030
|
+
receiver,
|
|
8031
|
+
args: [index],
|
|
8032
|
+
type: F64,
|
|
8033
|
+
loc,
|
|
8034
|
+
invalidNaN: true,
|
|
8035
|
+
};
|
|
7687
8036
|
return finish(read, (value) => type.kind === "array"
|
|
7688
8037
|
? arrayValueStore(lowerer, receiver, index, lowerer.coerceInto(access, value, type.elem), type.elem, loc)
|
|
7689
8038
|
: {
|
|
@@ -7715,6 +8064,7 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7715
8064
|
? lowerer.fieldTarget(access)
|
|
7716
8065
|
: symbolFieldTarget(lowerer, access);
|
|
7717
8066
|
if (target && lowerer.dynConvertible(target.fieldType)) {
|
|
8067
|
+
checkDeferredMemberReceiver(lowerer, target, access);
|
|
7718
8068
|
target.obj = save(target.obj, "%incrementReceiver");
|
|
7719
8069
|
return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt(target, lowerer.coerceInto(access, value, target.fieldType), loc, access));
|
|
7720
8070
|
}
|
|
@@ -7741,10 +8091,18 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7741
8091
|
if (!target) {
|
|
7742
8092
|
lowerer.rejectUnresolved(expr.operand, `increment/decrement of '${expr.operand.text}' (not a writable local or module global)`);
|
|
7743
8093
|
}
|
|
8094
|
+
return lowerIncDecTarget(lowerer, expr, target, prefix);
|
|
8095
|
+
}
|
|
8096
|
+
/** Numeric updates read the represented slot once and write the computed
|
|
8097
|
+
* value back in that same representation. In particular, an unchecked
|
|
8098
|
+
* indexed initializer can leave undefined in an otherwise numeric binding. */
|
|
8099
|
+
export function lowerIncDecTarget(lowerer, expr, target, prefix) {
|
|
8100
|
+
const loc = locOf(expr);
|
|
8101
|
+
const op = expr.operator === ts.SyntaxKind.PlusPlusToken ? "+" : "-";
|
|
7744
8102
|
if (target.type.kind === "dyn") {
|
|
7745
8103
|
const old = lowerer.declareHiddenLocal("%numericOld", DYN);
|
|
7746
8104
|
const next = lowerer.declareHiddenLocal("%numericNext", DYN);
|
|
7747
|
-
const read =
|
|
8105
|
+
const read = varRef(target.id, target.type, loc);
|
|
7748
8106
|
return {
|
|
7749
8107
|
kind: "seqExpr",
|
|
7750
8108
|
stmts: [
|
|
@@ -7776,6 +8134,42 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7776
8134
|
loc,
|
|
7777
8135
|
};
|
|
7778
8136
|
}
|
|
8137
|
+
if (target.type.kind === "union") {
|
|
8138
|
+
const read = lowerOptionalNumber(lowerer, varRef(target.id, target.type, loc), loc, expr.operand);
|
|
8139
|
+
if (read.type.kind === "f64") {
|
|
8140
|
+
const old = lowerer.declareHiddenLocal("%numericOld", F64);
|
|
8141
|
+
const next = lowerer.declareHiddenLocal("%numericNext", F64);
|
|
8142
|
+
const result = varRef(prefix ? next.id : old.id, F64, loc);
|
|
8143
|
+
return {
|
|
8144
|
+
kind: "seqExpr",
|
|
8145
|
+
stmts: [
|
|
8146
|
+
{ kind: "varDecl", localId: old.id, init: read, loc },
|
|
8147
|
+
{
|
|
8148
|
+
kind: "varDecl",
|
|
8149
|
+
localId: next.id,
|
|
8150
|
+
init: {
|
|
8151
|
+
kind: "bin",
|
|
8152
|
+
op,
|
|
8153
|
+
left: varRef(old.id, F64, loc),
|
|
8154
|
+
right: numLit(1, loc),
|
|
8155
|
+
type: F64,
|
|
8156
|
+
loc,
|
|
8157
|
+
},
|
|
8158
|
+
loc,
|
|
8159
|
+
},
|
|
8160
|
+
{
|
|
8161
|
+
kind: "assign",
|
|
8162
|
+
localId: target.id,
|
|
8163
|
+
value: lowerer.coerceInto(expr.operand, varRef(next.id, F64, loc), target.type),
|
|
8164
|
+
loc,
|
|
8165
|
+
},
|
|
8166
|
+
],
|
|
8167
|
+
result,
|
|
8168
|
+
type: F64,
|
|
8169
|
+
loc,
|
|
8170
|
+
};
|
|
8171
|
+
}
|
|
8172
|
+
}
|
|
7779
8173
|
if (target.type.kind !== "f64")
|
|
7780
8174
|
lowerer.unsupported("SC1043", expr);
|
|
7781
8175
|
return { kind: "incDec", op, prefix, localId: target.id, type: F64, loc };
|
|
@@ -8136,6 +8530,9 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8136
8530
|
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
|
8137
8531
|
if (recv && recv.type.kind === "dyn")
|
|
8138
8532
|
return lowerDynMemberAssignment(lowerer, expr, recv);
|
|
8533
|
+
const unionWrite = lowerUnionFieldWrite(lowerer, expr.left, expr.right);
|
|
8534
|
+
if (unionWrite)
|
|
8535
|
+
return unionWrite;
|
|
8139
8536
|
const field = lowerer.fieldTarget(expr.left);
|
|
8140
8537
|
if (field) {
|
|
8141
8538
|
const recvTmp = lowerer.declareHiddenLocal("%setReceiver", field.obj.type);
|
|
@@ -8182,7 +8579,7 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8182
8579
|
const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
|
|
8183
8580
|
if (nullTest)
|
|
8184
8581
|
return nullTest;
|
|
8185
|
-
const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
8582
|
+
const loose = lowerAbstractEquality(lowerer, deferredSlotOr(lowerer, lowerer.lowerExpr(expr.left)), deferredSlotOr(lowerer, lowerer.lowerExpr(expr.right)), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
8186
8583
|
if (loose)
|
|
8187
8584
|
return loose;
|
|
8188
8585
|
lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
|
|
@@ -8229,12 +8626,26 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8229
8626
|
}
|
|
8230
8627
|
const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
8231
8628
|
op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
8629
|
+
// An identifier whose storage is runtime-optional is compared by its
|
|
8630
|
+
// stored value: the checker's narrowing to the present arm is not a
|
|
8631
|
+
// runtime proof. Identifier reads are pure, so taking the stored value
|
|
8632
|
+
// after both operands lowered keeps the evaluation order. A union on
|
|
8633
|
+
// the other side keeps the narrowed read (union-to-union comparison
|
|
8634
|
+
// has no lowering).
|
|
8232
8635
|
let left = strictEquality
|
|
8233
8636
|
? (lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left))
|
|
8234
8637
|
: lowerer.lowerExpr(expr.left);
|
|
8235
8638
|
let right = strictEquality
|
|
8236
8639
|
? (lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right))
|
|
8237
8640
|
: lowerer.lowerExpr(expr.right);
|
|
8641
|
+
if (strictEquality) {
|
|
8642
|
+
const storedLeft = runtimeOptionalStorageOperand(lowerer, expr.left);
|
|
8643
|
+
const storedRight = runtimeOptionalStorageOperand(lowerer, expr.right);
|
|
8644
|
+
if (storedLeft !== null && right.type.kind !== "union")
|
|
8645
|
+
left = storedLeft;
|
|
8646
|
+
if (storedRight !== null && left.type.kind !== "union")
|
|
8647
|
+
right = storedRight;
|
|
8648
|
+
}
|
|
8238
8649
|
if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
|
|
8239
8650
|
if (left.type.kind === "caught")
|
|
8240
8651
|
left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
|
|
@@ -8721,7 +9132,7 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8721
9132
|
const optionalStringPlus = lowerOptionalStringPlus();
|
|
8722
9133
|
if (optionalStringPlus)
|
|
8723
9134
|
return optionalStringPlus;
|
|
8724
|
-
|
|
9135
|
+
{
|
|
8725
9136
|
const primitive = (type) => type.kind === "f64" ||
|
|
8726
9137
|
type.kind === "string" ||
|
|
8727
9138
|
type.kind === "bool" ||
|
|
@@ -8827,6 +9238,13 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8827
9238
|
if (unitTest)
|
|
8828
9239
|
return unitTest;
|
|
8829
9240
|
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
9241
|
+
const compared = lowerUnionEquality(lowerer, left, right, negated, false, loc);
|
|
9242
|
+
if (compared)
|
|
9243
|
+
return compared;
|
|
9244
|
+
const aliasRefusal = (type) => {
|
|
9245
|
+
if (tagEqualityMayMissAlias(lowerer, type))
|
|
9246
|
+
lowerer.unsupported("SC1090", expr, `comparisons of related class values beside structural union members (${NARROW_FIRST})`);
|
|
9247
|
+
};
|
|
8830
9248
|
// JS strict equality of the ARM values, per union tag (a
|
|
8831
9249
|
// per-union helper): equal tags compare payloads (f64 ==, string
|
|
8832
9250
|
// bytes, bool ==, ref-arm POINTER identity), different tags are
|
|
@@ -8862,6 +9280,7 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8862
9280
|
};
|
|
8863
9281
|
}
|
|
8864
9282
|
if ((sameUnion || !bothUnion) && lowerer.eqComparableUnion(ut.unionId)) {
|
|
9283
|
+
aliasRefusal(ut);
|
|
8865
9284
|
return {
|
|
8866
9285
|
kind: "unionEq",
|
|
8867
9286
|
unionId: ut.unionId,
|
|
@@ -8892,6 +9311,7 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8892
9311
|
kind: "union",
|
|
8893
9312
|
unionId: lowerer.unions.intern(arms),
|
|
8894
9313
|
};
|
|
9314
|
+
aliasRefusal(common);
|
|
8895
9315
|
return {
|
|
8896
9316
|
kind: "unionEq",
|
|
8897
9317
|
unionId: common.unionId,
|
|
@@ -9077,7 +9497,9 @@ function lowerLogicalChain(lowerer, expr) {
|
|
|
9077
9497
|
current = left;
|
|
9078
9498
|
continue;
|
|
9079
9499
|
}
|
|
9080
|
-
result = lowerLogicalPair(lowerer, current,
|
|
9500
|
+
result = lowerLogicalPair(lowerer, current, current.operatorToken.kind === ts.SyntaxKind.BarBarToken
|
|
9501
|
+
? lowerPresenceOperand(lowerer, left)
|
|
9502
|
+
: (lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left)));
|
|
9081
9503
|
break;
|
|
9082
9504
|
}
|
|
9083
9505
|
for (let i = parents.length - 1; i >= 0; i--) {
|
|
@@ -9732,11 +10154,12 @@ function lowerUnionTypeofTest(lowerer, expr, loc) {
|
|
|
9732
10154
|
for (const [a, b] of operandPairs(expr)) {
|
|
9733
10155
|
if (!ts.isTypeOfExpression(a))
|
|
9734
10156
|
continue;
|
|
9735
|
-
|
|
10157
|
+
const stored = runtimeOptionalStorageOperand(lowerer, a.expression);
|
|
10158
|
+
if (stored === null && lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
|
|
9736
10159
|
continue;
|
|
9737
10160
|
if (!ts.isStringLiteral(b))
|
|
9738
10161
|
continue; // bare-typeof + strEq handles pure operands
|
|
9739
|
-
const value = lowerer.lowerExpr(a.expression);
|
|
10162
|
+
const value = stored ?? lowerer.lowerExpr(a.expression);
|
|
9740
10163
|
if (value.type.kind !== "union")
|
|
9741
10164
|
continue; // defensive: an already-narrowed use
|
|
9742
10165
|
const unionId = value.type.unionId;
|
|
@@ -10037,17 +10460,30 @@ export function caughtRead(lowerer, node, local, loc) {
|
|
|
10037
10460
|
}
|
|
10038
10461
|
if (narrowed?.kind === "object") {
|
|
10039
10462
|
const info = lowerer.classes.get(narrowed.className);
|
|
10040
|
-
if (info
|
|
10041
|
-
|
|
10463
|
+
if (info) {
|
|
10464
|
+
const value = { kind: "caughtNarrow", value: ref, type: narrowed, loc };
|
|
10465
|
+
if (lowerer.inHierarchy(info))
|
|
10466
|
+
return value;
|
|
10467
|
+
return {
|
|
10468
|
+
kind: "ternary",
|
|
10469
|
+
cond: {
|
|
10470
|
+
kind: "caughtTest",
|
|
10471
|
+
value: ref,
|
|
10472
|
+
test: "instanceof",
|
|
10473
|
+
className: info.def.name,
|
|
10474
|
+
type: BOOL,
|
|
10475
|
+
loc,
|
|
10476
|
+
},
|
|
10477
|
+
then: value,
|
|
10478
|
+
else_: lowerer.coerceInto(node, { kind: "caughtToDyn", value: ref, type: DYN, loc }, narrowed),
|
|
10479
|
+
type: narrowed,
|
|
10480
|
+
loc,
|
|
10481
|
+
};
|
|
10042
10482
|
}
|
|
10043
10483
|
}
|
|
10044
|
-
//
|
|
10045
|
-
//
|
|
10046
|
-
//
|
|
10047
|
-
// extended to exception payloads. Error payloads keep their
|
|
10048
|
-
// observability (instanceof Error / .message / String() — the checked-dynamic tree's
|
|
10049
|
-
// error encoding); other object payloads are type-erased at runtime and
|
|
10050
|
-
// convert to the "[object Object]" approximation — SEMANTICS.md 67.
|
|
10484
|
+
// Unnarrowed reads cross into unknown. The caught-value dispatch pass
|
|
10485
|
+
// retains known native class payloads through live identity capsules;
|
|
10486
|
+
// other payload kinds use the runtime's ordinary conversion.
|
|
10051
10487
|
if (narrowed?.kind === "dyn") {
|
|
10052
10488
|
return { kind: "caughtToDyn", value: ref, type: DYN, loc };
|
|
10053
10489
|
}
|
|
@@ -10113,6 +10549,38 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
10113
10549
|
(lowerer.isStdlibGlobal(expr.right, "Set") || lowerer.isStdlibGlobal(expr.right, "Map"))) {
|
|
10114
10550
|
const collection = lowerer.isStdlibGlobal(expr.right, "Map") ? "map" : "set";
|
|
10115
10551
|
const value = lowerer.lowerExpr(expr.left);
|
|
10552
|
+
if (value.type.kind === "union") {
|
|
10553
|
+
const union = lowerer.unions.get(value.type.unionId);
|
|
10554
|
+
if (union) {
|
|
10555
|
+
const local = lowerer.declareHiddenLocal("%collectionTest", value.type);
|
|
10556
|
+
const reference = varRef(local.id, value.type, loc);
|
|
10557
|
+
let result = { kind: "boolLit", value: false, type: BOOL, loc };
|
|
10558
|
+
union.arms.forEach((arm, tag) => {
|
|
10559
|
+
if (arm.kind !== collection)
|
|
10560
|
+
return;
|
|
10561
|
+
const test = {
|
|
10562
|
+
kind: "unionIsTag",
|
|
10563
|
+
unionId: union.id,
|
|
10564
|
+
value: reference,
|
|
10565
|
+
tag,
|
|
10566
|
+
negated: false,
|
|
10567
|
+
type: BOOL,
|
|
10568
|
+
loc,
|
|
10569
|
+
};
|
|
10570
|
+
result =
|
|
10571
|
+
result.kind === "boolLit"
|
|
10572
|
+
? test
|
|
10573
|
+
: { kind: "logical", op: "||", left: result, right: test, type: BOOL, loc };
|
|
10574
|
+
});
|
|
10575
|
+
return {
|
|
10576
|
+
kind: "seqExpr",
|
|
10577
|
+
stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }],
|
|
10578
|
+
result,
|
|
10579
|
+
type: BOOL,
|
|
10580
|
+
loc,
|
|
10581
|
+
};
|
|
10582
|
+
}
|
|
10583
|
+
}
|
|
10116
10584
|
if (value.type.kind === "dyn")
|
|
10117
10585
|
return {
|
|
10118
10586
|
kind: "libCall",
|
|
@@ -10390,8 +10858,22 @@ export function lowerInstanceOf(lowerer, expr, loc) {
|
|
|
10390
10858
|
const caughtLocal = lowerer.caughtLocalOf(expr.left);
|
|
10391
10859
|
if (caughtLocal) {
|
|
10392
10860
|
if (!lowerer.inHierarchy(target)) {
|
|
10393
|
-
|
|
10394
|
-
|
|
10861
|
+
const value = varRef(caughtLocal.id, CAUGHT, loc);
|
|
10862
|
+
return {
|
|
10863
|
+
kind: "ternary",
|
|
10864
|
+
cond: {
|
|
10865
|
+
kind: "caughtTest",
|
|
10866
|
+
value,
|
|
10867
|
+
test: "instanceof",
|
|
10868
|
+
className: target.def.name,
|
|
10869
|
+
type: BOOL,
|
|
10870
|
+
loc,
|
|
10871
|
+
},
|
|
10872
|
+
then: { kind: "boolLit", value: true, type: BOOL, loc },
|
|
10873
|
+
else_: classInstanceOf(lowerer, { kind: "caughtToDyn", value, type: DYN, loc }, target, loc),
|
|
10874
|
+
type: BOOL,
|
|
10875
|
+
loc,
|
|
10876
|
+
};
|
|
10395
10877
|
}
|
|
10396
10878
|
return {
|
|
10397
10879
|
kind: "caughtTest",
|
|
@@ -10689,11 +11171,10 @@ function lowerPrivateIn(lowerer, expr, priv, loc) {
|
|
|
10689
11171
|
* type-directed: a declared non-optional field is a compile-time `true`,
|
|
10690
11172
|
* a missing field (no index signature) a compile-time `false` — both
|
|
10691
11173
|
* folds limited to side-effect-free receivers, the lowerInstanceOf rule —
|
|
10692
|
-
* and an OPTIONAL field (undefined-armed union) is a runtime
|
|
10693
|
-
* the slot:
|
|
10694
|
-
*
|
|
10695
|
-
*
|
|
10696
|
-
* false here; SEMANTICS.md 55). Union receivers (the `in`-narrowing
|
|
11174
|
+
* and an OPTIONAL field (undefined-armed union) is a runtime presence
|
|
11175
|
+
* test on the slot: an omitted or deleted property is absent, while a
|
|
11176
|
+
* property explicitly holding `undefined` is present, as in JS
|
|
11177
|
+
* (`"a" in {a: undefined}` is true). Union receivers (the `in`-narrowing
|
|
10697
11178
|
* idiom over multiple shapes), index-signature keys, class instances,
|
|
10698
11179
|
* and dyn/unknown stay fenced. Keys are literal strings — a computed key
|
|
10699
11180
|
* over a shape would need the runtime key table. */
|
|
@@ -10737,13 +11218,42 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
10737
11218
|
}
|
|
10738
11219
|
}
|
|
10739
11220
|
}
|
|
11221
|
+
// A RUNTIME numeric key over an ARRAY receiver (`if (i in arr)` in a
|
|
11222
|
+
// loop) asks the same slot/property presence query as the literal fold
|
|
11223
|
+
// above and `Object.hasOwn`. The checked-dynamic fallback below would
|
|
11224
|
+
// box the receiver and materialize every element on each evaluation,
|
|
11225
|
+
// which makes such loops quadratic. A Number key never names an
|
|
11226
|
+
// inherited property: neither Array.prototype nor Object.prototype has
|
|
11227
|
+
// index-like or numeric-string keys. JS evaluates the key before the
|
|
11228
|
+
// receiver, so the key is stabilized in a hidden local first.
|
|
11229
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(expr.left))?.kind === "f64" &&
|
|
11230
|
+
lowerer.mapTypeOf(lowerer.typeOf(expr.right))?.kind === "array") {
|
|
11231
|
+
const k = lowerer.lowerExpr(expr.left);
|
|
11232
|
+
const recvArr = lowerer.lowerExpr(expr.right);
|
|
11233
|
+
if (k.type.kind === "f64" && recvArr.type.kind === "array") {
|
|
11234
|
+
const keyLocal = lowerer.declareHiddenLocal("%inIndex", F64);
|
|
11235
|
+
return {
|
|
11236
|
+
kind: "seqExpr",
|
|
11237
|
+
stmts: [{ kind: "varDecl", localId: keyLocal.id, init: k, loc }],
|
|
11238
|
+
result: {
|
|
11239
|
+
kind: "arrayHas",
|
|
11240
|
+
arr: recvArr,
|
|
11241
|
+
index: varRef(keyLocal.id, F64, loc),
|
|
11242
|
+
type: BOOL,
|
|
11243
|
+
loc,
|
|
11244
|
+
},
|
|
11245
|
+
type: BOOL,
|
|
11246
|
+
loc,
|
|
11247
|
+
};
|
|
11248
|
+
}
|
|
11249
|
+
}
|
|
10740
11250
|
const key = foldedStringKeyOf(lowerer, expr.left);
|
|
10741
11251
|
if (key === null) {
|
|
10742
11252
|
// A RUNTIME string key over an INDEX-SIGNATURE record receiver (the
|
|
10743
11253
|
// `names.filter((k) => k in config)` idiom): the interned key-
|
|
10744
11254
|
// presence helper — declared fields answer statically per name
|
|
10745
|
-
// (optional slots
|
|
10746
|
-
//
|
|
11255
|
+
// (optional slots by their runtime presence), then the overflow
|
|
11256
|
+
// map's live keys. Other receivers keep the
|
|
10747
11257
|
// fence: fixed shapes want the literal folds above, and there is no
|
|
10748
11258
|
// runtime key table to ask.
|
|
10749
11259
|
const rIn = lowerRuntimeKeyIn(lowerer, expr, loc);
|
|
@@ -10986,24 +11496,9 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
10986
11496
|
const field = shape.fields.find((f) => f.name === key);
|
|
10987
11497
|
if (field) {
|
|
10988
11498
|
if (field.type.kind === "union" && lowerer.armTag(field.type.unionId, UNDEFINED_T) >= 0) {
|
|
10989
|
-
// Optional slot: the key is present
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
obj: recv,
|
|
10993
|
-
shapeId: recv.type.shapeId,
|
|
10994
|
-
field: key,
|
|
10995
|
-
type: field.type,
|
|
10996
|
-
loc,
|
|
10997
|
-
};
|
|
10998
|
-
return {
|
|
10999
|
-
kind: "unionIsTag",
|
|
11000
|
-
unionId: field.type.unionId,
|
|
11001
|
-
tag: lowerer.armTag(field.type.unionId, UNDEFINED_T),
|
|
11002
|
-
negated: true,
|
|
11003
|
-
value: read,
|
|
11004
|
-
type: BOOL,
|
|
11005
|
-
loc,
|
|
11006
|
-
};
|
|
11499
|
+
// Optional slot: the key is present unless the field is absent
|
|
11500
|
+
// (omitted or deleted); an explicit undefined is present.
|
|
11501
|
+
return lowerer.recordFieldPresent(recv, recv.type.shapeId, key, loc);
|
|
11007
11502
|
}
|
|
11008
11503
|
// A declared non-optional field always exists on every value of the
|
|
11009
11504
|
// shape — statically true, but folding may only drop a
|
|
@@ -11043,9 +11538,9 @@ function lowerInExpression(lowerer, expr, loc) {
|
|
|
11043
11538
|
* runtime string and r an index-signature record — an interned
|
|
11044
11539
|
* `%rec.haskey.<n>(k, r)` walks the declared names (a string-equality
|
|
11045
11540
|
* chain: non-optional fields and accessor slots answer true, optional
|
|
11046
|
-
* slots answer their per-value tag test) and then the overflow
|
|
11047
|
-
*
|
|
11048
|
-
* its fence). */
|
|
11541
|
+
* slots answer their per-value tag test) and then probes the overflow
|
|
11542
|
+
* map's hashed key set. Null when the pair is outside that shape (the
|
|
11543
|
+
* caller keeps its fence). */
|
|
11049
11544
|
function lowerRuntimeKeyIn(lowerer, expr, loc) {
|
|
11050
11545
|
if (lowerer.mapTypeOf(lowerer.typeOf(expr.left))?.kind !== "string")
|
|
11051
11546
|
return null;
|
|
@@ -11080,62 +11575,15 @@ function lowerRuntimeKeyIn(lowerer, expr, loc) {
|
|
|
11080
11575
|
type: BOOL,
|
|
11081
11576
|
loc,
|
|
11082
11577
|
};
|
|
11083
|
-
const
|
|
11084
|
-
|
|
11085
|
-
|
|
11086
|
-
kind: "unionIsTag",
|
|
11087
|
-
unionId: f.type.unionId,
|
|
11088
|
-
tag: utag,
|
|
11089
|
-
negated: true,
|
|
11090
|
-
value: {
|
|
11091
|
-
kind: "recordGet",
|
|
11092
|
-
obj: r,
|
|
11093
|
-
shapeId: recvT.shapeId,
|
|
11094
|
-
field: f.name,
|
|
11095
|
-
type: f.type,
|
|
11096
|
-
loc,
|
|
11097
|
-
},
|
|
11098
|
-
type: BOOL,
|
|
11099
|
-
loc,
|
|
11100
|
-
}
|
|
11101
|
-
: { kind: "boolLit", value: true, type: BOOL, loc };
|
|
11578
|
+
const answer = accessor
|
|
11579
|
+
? { kind: "boolLit", value: true, type: BOOL, loc }
|
|
11580
|
+
: lowerer.recordFieldPresent(r, recvT.shapeId, f.name, loc);
|
|
11102
11581
|
body.push({ kind: "if", cond: eq, then: [ret(answer)], else_: null, loc });
|
|
11103
11582
|
}
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
init: { kind: "recordOvfKeys", obj: r, shapeId: recvT.shapeId, type: ksT, loc },
|
|
11109
|
-
loc,
|
|
11110
|
-
}, countedFor(loc, {
|
|
11111
|
-
kind: "arrIntrinsic",
|
|
11112
|
-
method: "length",
|
|
11113
|
-
receiver: varRef("ks.0", ksT, loc),
|
|
11114
|
-
args: [],
|
|
11115
|
-
type: F64,
|
|
11116
|
-
loc,
|
|
11117
|
-
}, () => [
|
|
11118
|
-
{
|
|
11119
|
-
kind: "if",
|
|
11120
|
-
cond: {
|
|
11121
|
-
kind: "strEq",
|
|
11122
|
-
negated: false,
|
|
11123
|
-
left: k,
|
|
11124
|
-
right: {
|
|
11125
|
-
kind: "arrayGet",
|
|
11126
|
-
arr: varRef("ks.0", ksT, loc),
|
|
11127
|
-
index: varRef("i.0", F64, loc),
|
|
11128
|
-
type: STRING,
|
|
11129
|
-
loc,
|
|
11130
|
-
},
|
|
11131
|
-
type: BOOL,
|
|
11132
|
-
loc,
|
|
11133
|
-
},
|
|
11134
|
-
then: [ret({ kind: "boolLit", value: true, type: BOOL, loc })],
|
|
11135
|
-
else_: null,
|
|
11136
|
-
loc,
|
|
11137
|
-
},
|
|
11138
|
-
]), ret({ kind: "boolLit", value: false, type: BOOL, loc }));
|
|
11583
|
+
// Overflow keys answer through the map's hashed presence probe (a
|
|
11584
|
+
// stored undefined value is still present), not a scan over a fresh
|
|
11585
|
+
// key snapshot, which made `k in dict` loops quadratic.
|
|
11586
|
+
body.push(ret({ kind: "recordOvfHas", obj: r, shapeId: recvT.shapeId, key: k, type: BOOL, loc }));
|
|
11139
11587
|
lowerer.liftedFns.push({
|
|
11140
11588
|
name: helper,
|
|
11141
11589
|
params: [
|
|
@@ -11146,8 +11594,6 @@ function lowerRuntimeKeyIn(lowerer, expr, loc) {
|
|
|
11146
11594
|
locals: [
|
|
11147
11595
|
{ id: "k.0", name: "k", type: STRING, mutable: true },
|
|
11148
11596
|
{ id: "r.0", name: "r", type: recT, mutable: true },
|
|
11149
|
-
{ id: "ks.0", name: "ks", type: ksT, mutable: false },
|
|
11150
|
-
{ id: "i.0", name: "i", type: F64, mutable: true },
|
|
11151
11597
|
],
|
|
11152
11598
|
body,
|
|
11153
11599
|
loc,
|
|
@@ -11835,7 +12281,7 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
11835
12281
|
return null;
|
|
11836
12282
|
}
|
|
11837
12283
|
if (value.type.kind !== "union") {
|
|
11838
|
-
|
|
12284
|
+
lowerer.unsupported("SC1090", expr, "shared property access without a represented union receiver");
|
|
11839
12285
|
}
|
|
11840
12286
|
const def = lowerer.unions.get(value.type.unionId);
|
|
11841
12287
|
if (!def)
|
|
@@ -11876,13 +12322,7 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
11876
12322
|
if (receiver === null) {
|
|
11877
12323
|
const helper = lowerer.narrowedArmHelper(value.type.unionId, objectType, locOf(expr.expression));
|
|
11878
12324
|
if (helper !== null)
|
|
11879
|
-
receiver =
|
|
11880
|
-
kind: "call",
|
|
11881
|
-
callee: helper,
|
|
11882
|
-
args: [value],
|
|
11883
|
-
type: objectType,
|
|
11884
|
-
loc: locOf(expr.expression),
|
|
11885
|
-
};
|
|
12325
|
+
receiver = lowerer.checkedNarrowCall(helper, value, objectType, locOf(expr.expression));
|
|
11886
12326
|
}
|
|
11887
12327
|
if (receiver !== null) {
|
|
11888
12328
|
return {
|
|
@@ -12094,13 +12534,7 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
|
|
|
12094
12534
|
if (obj.type.kind === "union") {
|
|
12095
12535
|
const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
|
|
12096
12536
|
obj = helper
|
|
12097
|
-
?
|
|
12098
|
-
kind: "call",
|
|
12099
|
-
callee: helper,
|
|
12100
|
-
args: [obj],
|
|
12101
|
-
type: receiverType,
|
|
12102
|
-
loc: locOf(receiverNode),
|
|
12103
|
-
}
|
|
12537
|
+
? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
|
|
12104
12538
|
: lowerer.maybeNarrow(obj, receiverNode);
|
|
12105
12539
|
}
|
|
12106
12540
|
return lowerer.coerceInto(receiverNode, obj, receiverType);
|
|
@@ -12212,11 +12646,32 @@ export function fieldTarget(lowerer, access) {
|
|
|
12212
12646
|
const stored = ts.isIdentifier(access.expression)
|
|
12213
12647
|
? (lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type)
|
|
12214
12648
|
: undefined;
|
|
12215
|
-
const
|
|
12649
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
12650
|
+
// Structural record views retain their storage layout, while a nominal
|
|
12651
|
+
// subclass guard proves a more specific layout of the same object.
|
|
12652
|
+
const receiverIr = stored?.kind === "record"
|
|
12216
12653
|
? stored
|
|
12217
|
-
:
|
|
12654
|
+
: stored?.kind === "object" &&
|
|
12655
|
+
!(narrowed?.kind === "object" &&
|
|
12656
|
+
lowerer.isSubclassOf(narrowed.className, stored.className))
|
|
12657
|
+
? stored
|
|
12658
|
+
: narrowed;
|
|
12218
12659
|
if (receiverIr?.kind === "object") {
|
|
12219
|
-
|
|
12660
|
+
const target = classFieldTarget(lowerer, access.expression, receiverIr, access.name.text);
|
|
12661
|
+
if (target)
|
|
12662
|
+
return target;
|
|
12663
|
+
// Abstract properties declare no base storage. Resolve the concrete
|
|
12664
|
+
// instance's live field or accessor through the existing class bridge;
|
|
12665
|
+
// inventing a shared field offset would misread subclass layouts.
|
|
12666
|
+
if (abstractPropertyDeclOf(lowerer, access)) {
|
|
12667
|
+
return {
|
|
12668
|
+
container: "dynamic",
|
|
12669
|
+
obj: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN),
|
|
12670
|
+
field: access.name.text,
|
|
12671
|
+
fieldType: lowerer.irTypeOf(access),
|
|
12672
|
+
};
|
|
12673
|
+
}
|
|
12674
|
+
return null;
|
|
12220
12675
|
}
|
|
12221
12676
|
if (receiverIr?.kind === "union" && hasClassPayload(lowerer, receiverIr)) {
|
|
12222
12677
|
return representedClassFieldTarget(lowerer, access.expression, access.name.text, lowerer.lowerExpr(access.expression));
|
|
@@ -12243,13 +12698,7 @@ export function fieldTarget(lowerer, access) {
|
|
|
12243
12698
|
? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression))
|
|
12244
12699
|
: null;
|
|
12245
12700
|
obj = helper
|
|
12246
|
-
?
|
|
12247
|
-
kind: "call",
|
|
12248
|
-
callee: helper,
|
|
12249
|
-
args: [obj],
|
|
12250
|
-
type: present,
|
|
12251
|
-
loc: locOf(access.expression),
|
|
12252
|
-
}
|
|
12701
|
+
? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression))
|
|
12253
12702
|
: lowerer.maybeNarrow(obj, access.expression);
|
|
12254
12703
|
}
|
|
12255
12704
|
if (obj.type.kind !== "record")
|
|
@@ -12456,14 +12905,24 @@ function symbolFieldTarget(lowerer, expr) {
|
|
|
12456
12905
|
* tsc-clean (the property types as the setter's param), but Node yields
|
|
12457
12906
|
* undefined, which these property types cannot represent. */
|
|
12458
12907
|
export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
12908
|
+
// A member read through an unassigned deferred-init field throws Node's
|
|
12909
|
+
// member-read TypeError instead of the generic checked extraction.
|
|
12910
|
+
if (target.container === "class" &&
|
|
12911
|
+
ts.isPropertyAccessExpression(blame) &&
|
|
12912
|
+
target.obj.type.kind === "object" &&
|
|
12913
|
+
lowerer.deferredFieldSlot(target.obj) !== null) {
|
|
12914
|
+
const checked = lowerer.runtimeOptionalPropertyReceiver(blame.expression, target.obj, target.obj.type, target.field);
|
|
12915
|
+
if (checked)
|
|
12916
|
+
target = { ...target, obj: checked };
|
|
12917
|
+
}
|
|
12459
12918
|
if (target.container === "dynamic")
|
|
12460
|
-
return {
|
|
12919
|
+
return lowerer.coerceInto(blame, {
|
|
12461
12920
|
kind: "dynKeyGet",
|
|
12462
12921
|
value: target.obj,
|
|
12463
12922
|
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
12464
12923
|
type: DYN,
|
|
12465
12924
|
loc,
|
|
12466
|
-
};
|
|
12925
|
+
}, target.fieldType);
|
|
12467
12926
|
if (target.container === "class" &&
|
|
12468
12927
|
(target.field === "message" || target.field === "name") &&
|
|
12469
12928
|
(target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
@@ -12579,6 +13038,34 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
12579
13038
|
if (lowerer.classes.get(target.className)?.deferredInitFields?.has(target.field) === true &&
|
|
12580
13039
|
target.fieldType.kind === "union") {
|
|
12581
13040
|
const inner = lowerer.stripUndefinedArm(target.fieldType);
|
|
13041
|
+
// Reference arms over a stable receiver check inline: the present
|
|
13042
|
+
// arm is a plain projection of the slot, so ordinary reads keep their
|
|
13043
|
+
// borrowed form and only an unassigned slot reaches the throw.
|
|
13044
|
+
const unionId = target.fieldType.unionId;
|
|
13045
|
+
const presentTag = lowerer.armTag(unionId, inner);
|
|
13046
|
+
const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
|
|
13047
|
+
if (inner.kind === "object" &&
|
|
13048
|
+
presentTag >= 0 &&
|
|
13049
|
+
undefTag >= 0 &&
|
|
13050
|
+
lowerer.unions.get(unionId)?.arms.length === 2 &&
|
|
13051
|
+
isSafeToRepeat(read)) {
|
|
13052
|
+
return {
|
|
13053
|
+
kind: "ternary",
|
|
13054
|
+
cond: {
|
|
13055
|
+
kind: "unionIsTag",
|
|
13056
|
+
unionId,
|
|
13057
|
+
tag: undefTag,
|
|
13058
|
+
negated: false,
|
|
13059
|
+
value: read,
|
|
13060
|
+
type: BOOL,
|
|
13061
|
+
loc,
|
|
13062
|
+
},
|
|
13063
|
+
then: nodeThrowExpr(1, "", DEFERRED_READ_MESSAGE, inner, loc),
|
|
13064
|
+
else_: { kind: "unionNarrow", unionId, tag: presentTag, value: read, type: inner, loc },
|
|
13065
|
+
type: inner,
|
|
13066
|
+
loc,
|
|
13067
|
+
};
|
|
13068
|
+
}
|
|
12582
13069
|
const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc);
|
|
12583
13070
|
if (helper)
|
|
12584
13071
|
return { kind: "call", callee: helper, args: [read], type: inner, loc };
|
|
@@ -12598,6 +13085,75 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
12598
13085
|
* call). A write to a getter-only property never gets here in a clean
|
|
12599
13086
|
* program (tsc's TS2540 is the fence); the rejection is the backstop. */
|
|
12600
13087
|
export function fieldSetStmt(lowerer, target, value, loc, blame) {
|
|
13088
|
+
// A member write through an unassigned deferred-init field: the value
|
|
13089
|
+
// still evaluates first, then the write throws Node's TypeError.
|
|
13090
|
+
const deferredSlot = target.container === "class" &&
|
|
13091
|
+
!((target.field === "message" || target.field === "name") &&
|
|
13092
|
+
(target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
13093
|
+
? lowerer.deferredFieldSlot(target.obj)
|
|
13094
|
+
: null;
|
|
13095
|
+
if (target.container === "class" && deferredSlot?.type.kind === "union") {
|
|
13096
|
+
const unionId = deferredSlot.type.unionId;
|
|
13097
|
+
const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
|
|
13098
|
+
const presentTag = lowerer.armTag(unionId, target.obj.type);
|
|
13099
|
+
if (undefTag >= 0 && presentTag >= 0) {
|
|
13100
|
+
// A value that cannot write anything leaves the field unchanged, so
|
|
13101
|
+
// the field is read after it (no snapshot of the slot).
|
|
13102
|
+
const late = isSafeToRepeat(deferredSlot) && writeFree(value);
|
|
13103
|
+
const receiver = late
|
|
13104
|
+
? null
|
|
13105
|
+
: lowerer.declareHiddenLocal("%deferredWriteObject", deferredSlot.type);
|
|
13106
|
+
const stored = lowerer.declareHiddenLocal("%deferredWriteValue", value.type);
|
|
13107
|
+
const receiverRef = receiver ? varRef(receiver.id, receiver.type, loc) : deferredSlot;
|
|
13108
|
+
const result = varRef(stored.id, stored.type, loc);
|
|
13109
|
+
const write = {
|
|
13110
|
+
kind: "fieldSet",
|
|
13111
|
+
obj: {
|
|
13112
|
+
kind: "unionNarrow",
|
|
13113
|
+
unionId,
|
|
13114
|
+
tag: presentTag,
|
|
13115
|
+
value: receiverRef,
|
|
13116
|
+
type: target.obj.type,
|
|
13117
|
+
loc,
|
|
13118
|
+
},
|
|
13119
|
+
className: target.className,
|
|
13120
|
+
field: target.field,
|
|
13121
|
+
value: result,
|
|
13122
|
+
loc,
|
|
13123
|
+
};
|
|
13124
|
+
return {
|
|
13125
|
+
kind: "exprStmt",
|
|
13126
|
+
expr: {
|
|
13127
|
+
kind: "seqExpr",
|
|
13128
|
+
stmts: [
|
|
13129
|
+
...(receiver
|
|
13130
|
+
? [{ kind: "varDecl", localId: receiver.id, init: deferredSlot, loc }]
|
|
13131
|
+
: []),
|
|
13132
|
+
{ kind: "varDecl", localId: stored.id, init: value, loc },
|
|
13133
|
+
],
|
|
13134
|
+
result: {
|
|
13135
|
+
kind: "ternary",
|
|
13136
|
+
cond: {
|
|
13137
|
+
kind: "unionIsTag",
|
|
13138
|
+
unionId,
|
|
13139
|
+
tag: undefTag,
|
|
13140
|
+
value: receiverRef,
|
|
13141
|
+
negated: false,
|
|
13142
|
+
type: BOOL,
|
|
13143
|
+
loc,
|
|
13144
|
+
},
|
|
13145
|
+
then: nodeThrowExpr(1, "", `Cannot set properties of undefined (setting '${target.field}')`, result.type, loc),
|
|
13146
|
+
else_: { kind: "seqExpr", stmts: [write], result, type: result.type, loc },
|
|
13147
|
+
type: result.type,
|
|
13148
|
+
loc,
|
|
13149
|
+
},
|
|
13150
|
+
type: result.type,
|
|
13151
|
+
loc,
|
|
13152
|
+
},
|
|
13153
|
+
loc,
|
|
13154
|
+
};
|
|
13155
|
+
}
|
|
13156
|
+
}
|
|
12601
13157
|
if (target.container === "dynamic")
|
|
12602
13158
|
return {
|
|
12603
13159
|
kind: "exprStmt",
|
|
@@ -12915,6 +13471,7 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
|
|
|
12915
13471
|
const target = targetOf();
|
|
12916
13472
|
if (!target)
|
|
12917
13473
|
lowerer.unsupported("SC1090", access, "compound assignment to unsupported field targets");
|
|
13474
|
+
checkDeferredMemberReceiver(lowerer, target, access);
|
|
12918
13475
|
target.obj = save(target.obj, "%compoundReceiver");
|
|
12919
13476
|
// Accessors observe getter, RHS side effects, then setter, all through
|
|
12920
13477
|
// the saved receiver.
|