@scriptc/compiler 0.2.7 → 0.2.9
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 +3 -0
- package/dist/backend/cycle-analysis.js +50 -17
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +138 -14
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +31 -6
- package/dist/backend/cycle-mutability.js +120 -18
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +16 -3
- package/dist/backend/llvm/alloc.js +78 -23
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +5 -5
- package/dist/backend/llvm/alloc.test.js.map +1 -1
- 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/byte-numbers.js +2 -3
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +4 -1
- package/dist/backend/llvm/call-lifetimes.js +14 -3
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +8 -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 +13 -1
- package/dist/backend/llvm/classes.js +32 -23
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +32 -3
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +17 -0
- package/dist/backend/llvm/common.js +28 -0
- package/dist/backend/llvm/common.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.js +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +89 -0
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +8 -4
- package/dist/backend/llvm/dyn.js +58 -31
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +227 -12
- package/dist/backend/llvm/emitter.js +1492 -169
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +54 -1
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +4 -4
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +1 -1
- package/dist/backend/llvm/expr-bytes.js +116 -32
- 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 +55 -10
- 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 +231 -28
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +2 -0
- package/dist/backend/llvm/expr-control.js +70 -14
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +75 -21
- 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.js +41 -12
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +50 -2
- package/dist/backend/llvm/expr-primitives.test.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +28 -14
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +3 -0
- package/dist/backend/llvm/expr-stream-bridges.js +114 -42
- package/dist/backend/llvm/expr-stream-bridges.js.map +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/layouts.d.ts +2 -1
- package/dist/backend/llvm/layouts.js +2 -2
- package/dist/backend/llvm/layouts.js.map +1 -1
- 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 +25 -13
- 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 +2 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +17 -6
- package/dist/backend/llvm/local-array-reads.js +223 -51
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +7 -3
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.js +10 -6
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +3 -2
- 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 +38 -19
- package/dist/backend/llvm/map-read-lifetimes.test.js.map +1 -1
- 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 +140 -17
- 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/shapes.d.ts +58 -19
- package/dist/backend/llvm/shapes.js +171 -62
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +36 -11
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/stack-unions.test.js +5 -2
- 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-key-hash.d.ts +9 -2
- package/dist/backend/llvm/string-key-hash.js +20 -3
- package/dist/backend/llvm/string-key-hash.js.map +1 -1
- package/dist/backend/llvm/string-key-hash.test.js +14 -3
- package/dist/backend/llvm/string-key-hash.test.js.map +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +24 -11
- 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 +79 -0
- package/dist/backend/llvm/string-reads.js.map +1 -0
- package/dist/backend/llvm/string-slices.js +1 -1
- package/dist/backend/llvm/switch-dispatch.test.js +1 -1
- 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/trunc.d.ts +8 -0
- package/dist/backend/llvm/trunc.js +28 -0
- package/dist/backend/llvm/trunc.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/loop-polls.d.ts +14 -0
- package/dist/backend/loop-polls.js +100 -0
- package/dist/backend/loop-polls.js.map +1 -0
- package/dist/backend/loop-polls.test.d.ts +1 -0
- package/dist/backend/loop-polls.test.js +86 -0
- package/dist/backend/loop-polls.test.js.map +1 -0
- package/dist/backend/may-throw.d.ts +29 -1
- package/dist/backend/may-throw.js +365 -3
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +136 -1
- package/dist/backend/may-throw.test.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +7 -5
- 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 +2 -0
- package/dist/backend/native-codegen.js +21 -2
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +41 -10
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-tools.d.ts +2 -0
- package/dist/backend/native-tools.js +3 -0
- package/dist/backend/native-tools.js.map +1 -1
- 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-abi.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +1 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/cli/command.js +78 -8
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/output-options.d.ts +1 -0
- package/dist/cli/output-options.js +3 -0
- package/dist/cli/output-options.js.map +1 -1
- package/dist/cli/usage.d.ts +8 -1
- package/dist/cli/usage.js +14 -1
- package/dist/cli/usage.js.map +1 -1
- package/dist/compile-types.d.ts +17 -3
- 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 +74 -4
- 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 -0
- package/dist/executable/executable-cache.js +3 -0
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +1 -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/array-values.d.ts +7 -0
- package/dist/frontend/lowering/array-values.js +157 -5
- package/dist/frontend/lowering/array-values.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 +4 -0
- package/dist/frontend/lowering/builtins/process.js +10 -0
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/strings.js +4 -1
- package/dist/frontend/lowering/builtins/strings.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/call-arguments.js +96 -4
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/class-assertions.d.ts +8 -0
- package/dist/frontend/lowering/class-assertions.js +217 -1
- package/dist/frontend/lowering/class-assertions.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +8 -5
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.js +88 -0
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- 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/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/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-callbacks.js +81 -44
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-construction.js +15 -2
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.js +231 -12
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +15 -4
- package/dist/frontend/lowering/containers/bytes.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/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 +6 -1
- package/dist/frontend/lowering/cycle-initialization.js +59 -33
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
- 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/object-literals.js +40 -2
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.d.ts +19 -0
- package/dist/frontend/lowering/expressions/union-fields.js +236 -0
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -0
- package/dist/frontend/lowering/lower-calls.d.ts +5 -0
- package/dist/frontend/lowering/lower-calls.js +237 -158
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +4 -0
- package/dist/frontend/lowering/lower-classes.js +72 -22
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +19 -0
- package/dist/frontend/lowering/lower-exprs.js +592 -109
- package/dist/frontend/lowering/lower-exprs.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 +3 -2
- 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 +10 -7
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +90 -1
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +47 -7
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +83 -2
- package/dist/frontend/lowering/lowerer.js +1158 -79
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/nan-coded-reads.d.ts +161 -0
- package/dist/frontend/lowering/nan-coded-reads.js +1342 -0
- package/dist/frontend/lowering/nan-coded-reads.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-bounds.d.ts +31 -0
- package/dist/frontend/lowering/runtime-optional-bounds.js +360 -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 +94 -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 +2 -1
- package/dist/frontend/lowering/runtime-optional-provenance.js +2 -1
- package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -1
- 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 +8 -0
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- 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 +25 -0
- package/dist/frontend/program.js +613 -17
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +64 -1
- 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 +3 -0
- package/dist/frontend/type-mapper.js +72 -6
- package/dist/frontend/type-mapper.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 +7 -2
- package/dist/index.js +67 -17
- package/dist/index.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 -0
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-globals.d.ts +14 -0
- package/dist/ir/constant-globals.js +81 -0
- package/dist/ir/constant-globals.js.map +1 -0
- package/dist/ir/constant-globals.test.d.ts +1 -0
- package/dist/ir/constant-globals.test.js +97 -0
- package/dist/ir/constant-globals.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +35 -0
- package/dist/ir/final-fields.js +187 -0
- package/dist/ir/final-fields.js.map +1 -0
- package/dist/ir/final-fields.test.d.ts +1 -0
- package/dist/ir/final-fields.test.js +106 -0
- package/dist/ir/final-fields.test.js.map +1 -0
- package/dist/ir/int32-slots.d.ts +81 -0
- package/dist/ir/int32-slots.js +850 -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 +249 -0
- package/dist/ir/int32-slots.test.js.map +1 -0
- package/dist/ir/integer-loops.d.ts +5 -0
- package/dist/ir/integer-loops.js +20 -4
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +17 -0
- package/dist/ir/integer-loops.test.js.map +1 -1
- 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 +30 -7
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/serialize.d.ts +12 -2
- package/dist/ir/serialize.js +190 -39
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.js +65 -1
- package/dist/ir/serialize.test.js.map +1 -1
- package/dist/ir/validate.js +21 -2
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +39 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/native/cache.d.ts +11 -1
- package/dist/native/cache.js +87 -2
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +32 -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 +55 -7
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/prepare.d.ts +7 -1
- package/dist/native/prepare.js +65 -29
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/prepare.test.js +23 -1
- package/dist/native/prepare.test.js.map +1 -1
- package/dist/native/text-file.d.ts +10 -0
- package/dist/native/text-file.js +41 -0
- package/dist/native/text-file.js.map +1 -0
- package/dist/startup-cache.d.ts +2 -0
- package/dist/startup-cache.js +2 -0
- package/dist/startup-cache.js.map +1 -1
- package/dist/text-parts.d.ts +5 -0
- package/dist/text-parts.js +36 -0
- package/dist/text-parts.js.map +1 -0
- package/package.json +20 -20
- package/surface-manifest.json +7 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +0 -8
- package/dist/frontend/lowering/expressions/union-field-write.js +0 -108
- package/dist/frontend/lowering/expressions/union-field-write.js.map +0 -1
|
@@ -2,6 +2,7 @@ import { generatorDrain } from "./iterator-adapters.js";
|
|
|
2
2
|
import { lowerUnionEquality, tagEqualityMayMissAlias } from "./strict-equality.js";
|
|
3
3
|
import { isOptionalProcessStreamProperty } from "./builtins/process.js";
|
|
4
4
|
import { lowerWorkerMetadata } from "./builtins/workers.js";
|
|
5
|
+
import { threadsImportOf } from "../threads-import.js";
|
|
5
6
|
import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../ir/build.js";
|
|
6
7
|
import { InternalCompilerError } from "../../errors.js";
|
|
7
8
|
import { SYMBOL_T } from "../../ir/ir.js";
|
|
@@ -17,9 +18,9 @@ import * as ts from "../ts7/adapter.js";
|
|
|
17
18
|
import { constituentTypes } from "../ts7/checker.js";
|
|
18
19
|
import { dirname } from "node:path";
|
|
19
20
|
import * as posix from "node:path/posix";
|
|
20
|
-
import { checkedClassAssertion } from "./class-assertions.js";
|
|
21
|
+
import { checkedClassAssertion, checkedClassUnionAssertion } from "./class-assertions.js";
|
|
21
22
|
import { narrowClassUnion, narrowStoredClassValue } from "./class-unions.js";
|
|
22
|
-
import { lowerUnionFieldWrite } from "./expressions/union-
|
|
23
|
+
import { lowerUnionFieldRead, lowerUnionFieldWrite } from "./expressions/union-fields.js";
|
|
23
24
|
import { captureContextArguments } from "./function-context.js";
|
|
24
25
|
import { OBJECT_CALLABLE_VALUES } from "./surfaces.js";
|
|
25
26
|
import { wasiGuestPath } from "../../wasi-paths.js";
|
|
@@ -29,7 +30,7 @@ import { ARRAY_METHODS, builtinConstLit, builtinFenceHintOf, builtinModuleConstO
|
|
|
29
30
|
import { UNSUPPORTED, blockedBindingUseDiag, requiresDynamicPackageDiag, unsupportedDiag, } from "../../diagnostics/diagnostic.js";
|
|
30
31
|
import { PoisonError, dynFallbackType, jsFuncNameOf, neverTaintedJsType, own } from "./lowerer.js";
|
|
31
32
|
import { lowerCollectionSpread } from "./containers/collection-methods.js";
|
|
32
|
-
import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, } from "./array-values.js";
|
|
33
|
+
import { arrayValueRead, arrayValueStore, arrayValueType, lowerSafeIndexRead, tryLowerIndexTruthiness, tryLowerNumericIndexRead, lowerSafeBytesRead, } from "./array-values.js";
|
|
33
34
|
import { strCharsCall } from "./containers/array-construction.js";
|
|
34
35
|
import { lowerOptionalStringIndex } from "./string-index.js";
|
|
35
36
|
import { tryLowerIndexedComparison } from "./indexed-comparison.js";
|
|
@@ -166,7 +167,14 @@ export function lowerExpr(lowerer, expr) {
|
|
|
166
167
|
}
|
|
167
168
|
lowerExprDepth++;
|
|
168
169
|
try {
|
|
169
|
-
|
|
170
|
+
let lowered = lowerExprInner(lowerer, expr);
|
|
171
|
+
const nanCoded = lowerer.nanCodedReads;
|
|
172
|
+
if (nanCoded) {
|
|
173
|
+
if (lowered.type.kind === "f64" && nanCoded.reboxes(expr))
|
|
174
|
+
lowered = reboxNanCoded(lowerer, lowered, locOf(expr));
|
|
175
|
+
else if (lowered.type.kind === "union" && nanCoded.convertsSource(expr))
|
|
176
|
+
lowered = lowerOptionalNumber(lowerer, lowered, locOf(expr));
|
|
177
|
+
}
|
|
170
178
|
if (lowered.type.kind === "void" && (lowerer.typeOf(expr).flags & ts.TypeFlags.Never) !== 0)
|
|
171
179
|
lowerer.neverValued.add(lowered);
|
|
172
180
|
return lowered;
|
|
@@ -175,6 +183,27 @@ export function lowerExpr(lowerer, expr) {
|
|
|
175
183
|
lowerExprDepth--;
|
|
176
184
|
}
|
|
177
185
|
}
|
|
186
|
+
/** `number | undefined` from a NaN-coded double whose slot never holds a
|
|
187
|
+
* genuine NaN (nan-coded-reads.ts): NaN is exactly undefined. */
|
|
188
|
+
function reboxNanCoded(lowerer, value, loc) {
|
|
189
|
+
const optional = lowerer.withUndefinedArm(F64);
|
|
190
|
+
const stmts = [];
|
|
191
|
+
let stable = value;
|
|
192
|
+
if (value.kind !== "varRef") {
|
|
193
|
+
const tmp = lowerer.declareHiddenLocal("%nanCoded", F64);
|
|
194
|
+
stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
|
|
195
|
+
stable = varRef(tmp.id, F64, loc);
|
|
196
|
+
}
|
|
197
|
+
const result = {
|
|
198
|
+
kind: "ternary",
|
|
199
|
+
cond: { kind: "libCall", fn: "num.isNaN", args: [stable], type: BOOL, loc },
|
|
200
|
+
then: lowerer.wrappedUndefined(optional, loc),
|
|
201
|
+
else_: lowerer.coerceToExpected(stable, optional),
|
|
202
|
+
type: optional,
|
|
203
|
+
loc,
|
|
204
|
+
};
|
|
205
|
+
return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: optional, loc };
|
|
206
|
+
}
|
|
178
207
|
function lowerExprInner(lowerer, expr) {
|
|
179
208
|
const loc = locOf(expr);
|
|
180
209
|
// An optional chain's guarded receiver: already evaluated by the
|
|
@@ -294,6 +323,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
294
323
|
// traps. Sub-union assertions and non-union inners keep their
|
|
295
324
|
// historic erasure (the widening sites re-tag with traps already).
|
|
296
325
|
if (ts.isNonNullExpression(expr)) {
|
|
326
|
+
// An asserted element read forwarded into a slot that holds undefined
|
|
327
|
+
// (see analyzeRuntimeOptionalArrayReads) reads without the bounds trap.
|
|
328
|
+
if (lowerer.runtimeOptionalAssertions.has(expr) &&
|
|
329
|
+
ts.isElementAccessExpression(expr.expression)) {
|
|
330
|
+
const probe = lowerAbsenceProbe(lowerer, expr.expression);
|
|
331
|
+
if (probe?.type.kind === "union")
|
|
332
|
+
return probe;
|
|
333
|
+
}
|
|
297
334
|
const inner = lowerer.lowerExpr(expr.expression);
|
|
298
335
|
if (inner.type.kind === "union") {
|
|
299
336
|
// `!` performs no runtime check: a missing array element stays
|
|
@@ -301,14 +338,20 @@ function lowerExprInner(lowerer, expr) {
|
|
|
301
338
|
if (ts.isElementAccessExpression(expr.expression) &&
|
|
302
339
|
assertedElementKeepsUndefined(lowerer, expr))
|
|
303
340
|
return inner;
|
|
341
|
+
// A forwarded assertion whose destination was promoted to hold
|
|
342
|
+
// undefined (see analyzeRuntimeOptionalArrayReads), or an equality
|
|
343
|
+
// operand, keeps the value: `!` performs no runtime check.
|
|
344
|
+
const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
345
|
+
if (lowerer.runtimeOptionalAssertions.has(expr) ||
|
|
346
|
+
(target?.kind === "object" && isEqualityOperand(expr)))
|
|
347
|
+
return inner;
|
|
304
348
|
const use = runtimeOptionalUseOf(expr);
|
|
305
349
|
if (runtimeOptionalAssertionErases(lowerer, expr, inner, use))
|
|
306
350
|
return inner;
|
|
307
|
-
const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
308
351
|
if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
|
|
309
352
|
const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc);
|
|
310
353
|
if (helper) {
|
|
311
|
-
return
|
|
354
|
+
return lowerer.checkedNarrowCall(helper, inner, target, loc);
|
|
312
355
|
}
|
|
313
356
|
}
|
|
314
357
|
return inner;
|
|
@@ -730,7 +773,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
730
773
|
// A known static result type fixes typeof's answer, but its producer
|
|
731
774
|
// still evaluates: calls, getters, and checked reads can have effects
|
|
732
775
|
// or throw. Only trivial operands may disappear.
|
|
733
|
-
let operand = lowerer.lowerExpr(expr.expression);
|
|
776
|
+
let operand = deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.expression) ?? lowerer.lowerExpr(expr.expression));
|
|
734
777
|
if (operand.type.kind === "jsval") {
|
|
735
778
|
return { kind: "jsOp", op: "typeof", args: [operand], type: STRING, loc };
|
|
736
779
|
}
|
|
@@ -949,13 +992,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
949
992
|
? lowerer.narrowedArmHelper(local.type.unionId, narrowed, loc)
|
|
950
993
|
: null;
|
|
951
994
|
if (helper) {
|
|
952
|
-
return
|
|
953
|
-
kind: "call",
|
|
954
|
-
callee: helper,
|
|
955
|
-
args: [varRef(local.id, local.type, loc)],
|
|
956
|
-
type: narrowed,
|
|
957
|
-
loc,
|
|
958
|
-
};
|
|
995
|
+
return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
|
|
959
996
|
}
|
|
960
997
|
}
|
|
961
998
|
}
|
|
@@ -993,7 +1030,10 @@ function lowerExprInner(lowerer, expr) {
|
|
|
993
1030
|
// that does not exist. The blocked-binding cascade names the use;
|
|
994
1031
|
// without this the validator's registration check ICEs on the live
|
|
995
1032
|
// reference (`@this {T}` inference — signature 07).
|
|
996
|
-
|
|
1033
|
+
const unregistered = lowerer.unregisteredClassOf(g.type, new Set());
|
|
1034
|
+
if (unregistered !== null) {
|
|
1035
|
+
// The class's own rejection is the root cause the cascade names.
|
|
1036
|
+
lowerer.flushDeferredClass(unregistered);
|
|
997
1037
|
lowerer.pushDiag(blockedBindingUseDiag(expr.text, loc));
|
|
998
1038
|
throw new PoisonError();
|
|
999
1039
|
}
|
|
@@ -1026,7 +1066,7 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1026
1066
|
lowerer.armTag(g.type.unionId, narrowed) >= 0) {
|
|
1027
1067
|
const helper = lowerer.narrowedArmHelper(g.type.unionId, narrowed, loc);
|
|
1028
1068
|
if (helper)
|
|
1029
|
-
return
|
|
1069
|
+
return lowerer.checkedNarrowCall(helper, ref, narrowed, loc);
|
|
1030
1070
|
}
|
|
1031
1071
|
const use = runtimeOptionalUseOf(expr);
|
|
1032
1072
|
// The enclosing logical/conditional expression consumes the union
|
|
@@ -1124,6 +1164,14 @@ function lowerExprInner(lowerer, expr) {
|
|
|
1124
1164
|
// as interned string literals; functions have no closure
|
|
1125
1165
|
// representation (they lower to libCall at call sites only); members
|
|
1126
1166
|
// with no lowering at all fence with the module-qualified name.
|
|
1167
|
+
{
|
|
1168
|
+
const member = threadsImportOf(lowerer.program, expr);
|
|
1169
|
+
// scriptc delivers published graphs by reference.
|
|
1170
|
+
if (member === "sharesPublishedGraphs")
|
|
1171
|
+
return { kind: "boolLit", value: true, type: BOOL, loc };
|
|
1172
|
+
if (member === "publish")
|
|
1173
|
+
lowerer.noLowering("publish (@scriptc/threads) as a value", expr, "call publish(value) directly");
|
|
1174
|
+
}
|
|
1127
1175
|
{
|
|
1128
1176
|
const bi = lowerer.builtinImportOf(expr);
|
|
1129
1177
|
if (bi) {
|
|
@@ -2189,6 +2237,11 @@ function lowerExprInner(lowerer, expr) {
|
|
|
2189
2237
|
handled.kind === "recordGet" &&
|
|
2190
2238
|
lowerer.isRuntimeOptionalField(handled.shapeId, handled.field))
|
|
2191
2239
|
return handled;
|
|
2240
|
+
// A class field assigned a missing read: the checker narrows this
|
|
2241
|
+
// read to the assigned value's bare type, but the stored undefined
|
|
2242
|
+
// arm is real (`obj.n = bytes[i]; obj.n` is undefined in Node).
|
|
2243
|
+
if (runtimeOptionalClassField(lowerer, handled, expr))
|
|
2244
|
+
return handled;
|
|
2192
2245
|
return lowerer.maybeNarrow(handled, expr);
|
|
2193
2246
|
}
|
|
2194
2247
|
// `globalThis.<name>` that no lowering above claimed
|
|
@@ -3299,13 +3352,7 @@ function runtimeOptionalReceiverRead(lowerer, expr, local, property, loc) {
|
|
|
3299
3352
|
if (!helper) {
|
|
3300
3353
|
lowerer.unsupported("SC1090", expr, "a direct read from a runtime-optional capture with multiple value arms");
|
|
3301
3354
|
}
|
|
3302
|
-
return
|
|
3303
|
-
kind: "call",
|
|
3304
|
-
callee: helper,
|
|
3305
|
-
args: [varRef(local.id, local.type, loc)],
|
|
3306
|
-
type: narrowed,
|
|
3307
|
-
loc,
|
|
3308
|
-
};
|
|
3355
|
+
return lowerer.checkedNarrowCall(helper, varRef(local.id, local.type, loc), narrowed, loc);
|
|
3309
3356
|
}
|
|
3310
3357
|
// A predicate can strengthen a record's fields or narrow a base class
|
|
3311
3358
|
// to a subclass without changing the slot's stored value arm. Extract
|
|
@@ -3438,6 +3485,18 @@ function runtimeOptionalElementKey(expr) {
|
|
|
3438
3485
|
return expr.text;
|
|
3439
3486
|
return null;
|
|
3440
3487
|
}
|
|
3488
|
+
/** An operand of `===`, `!==`, `==` or `!=` (through parentheses). */
|
|
3489
|
+
function isEqualityOperand(node) {
|
|
3490
|
+
let outer = node;
|
|
3491
|
+
while (ts.isParenthesizedExpression(outer.parent))
|
|
3492
|
+
outer = outer.parent;
|
|
3493
|
+
const parent = outer.parent;
|
|
3494
|
+
return (ts.isBinaryExpression(parent) &&
|
|
3495
|
+
(parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
3496
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
3497
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsToken ||
|
|
3498
|
+
parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken));
|
|
3499
|
+
}
|
|
3441
3500
|
/** Whether `xs[i]!` lands where an absent element's undefined is
|
|
3442
3501
|
* representable: array storage (a literal element, a push/unshift
|
|
3443
3502
|
* argument, an element assignment — arrays record the undefined state),
|
|
@@ -3505,6 +3564,17 @@ export function lowerUnitComparison(lowerer, left, right, negated, loc) {
|
|
|
3505
3564
|
// Two unit literals (`undefined === undefined`): statically decided.
|
|
3506
3565
|
return { kind: "boolLit", value: (other.unit === unit.unit) !== negated, type: BOOL, loc };
|
|
3507
3566
|
}
|
|
3567
|
+
const slot = lowerer.deferredFieldSlot(other);
|
|
3568
|
+
if (slot)
|
|
3569
|
+
return lowerUnitComparison(lowerer, slot, unit, negated, loc);
|
|
3570
|
+
// A binding the checker narrowed past the unit can still hold it at
|
|
3571
|
+
// runtime when its value came from an unassigned deferred-init field;
|
|
3572
|
+
// the stored tag answers either way.
|
|
3573
|
+
if (other.kind === "unionNarrow" &&
|
|
3574
|
+
other.value.kind === "varRef" &&
|
|
3575
|
+
other.value.type.kind === "union" &&
|
|
3576
|
+
lowerer.armTag(other.value.type.unionId, unit.type) >= 0)
|
|
3577
|
+
return lowerUnitComparison(lowerer, other.value, unit, negated, loc);
|
|
3508
3578
|
if (other.type.kind === "union") {
|
|
3509
3579
|
const tag = lowerer.armTag(other.type.unionId, unit.type);
|
|
3510
3580
|
if (tag < 0) {
|
|
@@ -3612,7 +3682,7 @@ function lowerLooseNullCompare(lowerer, expr, loc) {
|
|
|
3612
3682
|
if (!leftIsNull && right.kind !== ts.SyntaxKind.NullKeyword)
|
|
3613
3683
|
return null;
|
|
3614
3684
|
const otherNode = leftIsNull ? right : left;
|
|
3615
|
-
const other = lowerer
|
|
3685
|
+
const other = lowerPresenceOperand(lowerer, otherNode);
|
|
3616
3686
|
if (isUnitType(other.type)) {
|
|
3617
3687
|
// `null == null`, `undefined == null`: units are mutually loose-equal.
|
|
3618
3688
|
return { kind: "boolLit", value: !negated, type: BOOL, loc };
|
|
@@ -3717,13 +3787,84 @@ export function lowerNullishCoalesce(lowerer, expr, loc) {
|
|
|
3717
3787
|
parents.push(first);
|
|
3718
3788
|
first = first.left;
|
|
3719
3789
|
}
|
|
3720
|
-
let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first),
|
|
3790
|
+
let result = lowerNullishPair(lowerer, first, first === expr ? loc : locOf(first), assertedPresenceOperand(lowerer, first.left));
|
|
3721
3791
|
for (let i = parents.length - 1; i >= 0; i--) {
|
|
3722
3792
|
const parent = parents[i];
|
|
3723
3793
|
result = lowerNullishPair(lowerer, parent, parent === expr ? loc : locOf(parent), result);
|
|
3724
3794
|
}
|
|
3725
3795
|
return result;
|
|
3726
3796
|
}
|
|
3797
|
+
/** The left side of `??` (see lowerPresenceOperand). The absence probe
|
|
3798
|
+
* reads optional storage beneath erased assertions; a union assertion that
|
|
3799
|
+
* narrows a stored class arm still applies its checked class view, so
|
|
3800
|
+
* `(node.parent as Sub | undefined) ?? node` sees the asserted arm on both
|
|
3801
|
+
* sides of the default. */
|
|
3802
|
+
function assertedPresenceOperand(lowerer, node) {
|
|
3803
|
+
const probe = lowerAbsenceProbe(lowerer, node);
|
|
3804
|
+
if (probe === null)
|
|
3805
|
+
return runtimeOptionalStorageOperand(lowerer, node) ?? lowerer.lowerExpr(node);
|
|
3806
|
+
if (probe.type.kind !== "union" && probe.type.kind !== "object")
|
|
3807
|
+
return probe;
|
|
3808
|
+
let outer = node;
|
|
3809
|
+
while (ts.isParenthesizedExpression(outer))
|
|
3810
|
+
outer = outer.expression;
|
|
3811
|
+
if (!ts.isAsExpression(outer) && !ts.isTypeAssertion(outer))
|
|
3812
|
+
return probe;
|
|
3813
|
+
const target = lowerer.mapTypeOf(lowerer.checker.getTypeFromTypeNode(outer.type));
|
|
3814
|
+
if (target?.kind !== "union" || typeEquals(target, probe.type))
|
|
3815
|
+
return probe;
|
|
3816
|
+
return checkedClassUnionAssertion(lowerer, probe, target, locOf(outer)) ?? probe;
|
|
3817
|
+
}
|
|
3818
|
+
/** Read-modify-write updates read the member first: an unassigned
|
|
3819
|
+
* deferred-init receiver throws Node's member-read TypeError. */
|
|
3820
|
+
function checkDeferredMemberReceiver(lowerer, target, access) {
|
|
3821
|
+
if (target.container !== "class" ||
|
|
3822
|
+
!ts.isPropertyAccessExpression(access) ||
|
|
3823
|
+
target.obj.type.kind !== "object" ||
|
|
3824
|
+
lowerer.deferredFieldSlot(target.obj) === null)
|
|
3825
|
+
return;
|
|
3826
|
+
target.obj =
|
|
3827
|
+
lowerer.runtimeOptionalPropertyReceiver(access.expression, target.obj, target.obj.type, target.field) ?? target.obj;
|
|
3828
|
+
}
|
|
3829
|
+
/** Whether evaluating `expr` cannot store anything or run other code:
|
|
3830
|
+
* reads, arithmetic, tests and checked extractions (which at most throw). */
|
|
3831
|
+
function writeFree(expr) {
|
|
3832
|
+
switch (expr.kind) {
|
|
3833
|
+
case "numLit":
|
|
3834
|
+
case "strLit":
|
|
3835
|
+
case "boolLit":
|
|
3836
|
+
case "unitLit":
|
|
3837
|
+
case "varRef":
|
|
3838
|
+
return true;
|
|
3839
|
+
case "fieldGet":
|
|
3840
|
+
case "recordGet":
|
|
3841
|
+
return writeFree(expr.obj);
|
|
3842
|
+
case "bin":
|
|
3843
|
+
case "logical":
|
|
3844
|
+
return writeFree(expr.left) && writeFree(expr.right);
|
|
3845
|
+
case "unary":
|
|
3846
|
+
case "toBool":
|
|
3847
|
+
return writeFree(expr.operand);
|
|
3848
|
+
case "ternary":
|
|
3849
|
+
return writeFree(expr.cond) && writeFree(expr.then) && writeFree(expr.else_);
|
|
3850
|
+
case "unionIsTag":
|
|
3851
|
+
case "unionNarrow":
|
|
3852
|
+
case "unionWrap":
|
|
3853
|
+
return writeFree(expr.value);
|
|
3854
|
+
case "libCall":
|
|
3855
|
+
return expr.fn === "error.nodeThrow";
|
|
3856
|
+
default:
|
|
3857
|
+
return false;
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
/** The TypeError of a deferred-init field read that finds the field
|
|
3861
|
+
* unassigned where its declared type cannot hold undefined. */
|
|
3862
|
+
export const DEFERRED_READ_MESSAGE = "undefined is not representable in the target union (a value narrowed or asserted past it still held it)";
|
|
3863
|
+
/** The undefined-armed slot behind a checked deferred-init field read, or
|
|
3864
|
+
* the value itself (Lowerer.deferredFieldSlot). */
|
|
3865
|
+
function deferredSlotOr(lowerer, value) {
|
|
3866
|
+
return lowerer.deferredFieldSlot(value) ?? value;
|
|
3867
|
+
}
|
|
3727
3868
|
/** A plain value read that may be runtime-optional: an unchecked element
|
|
3728
3869
|
* read, or a binding, member or call that carries one. Lowering these
|
|
3729
3870
|
* without a destination type is the same as lowering them into one. */
|
|
@@ -3844,6 +3985,24 @@ function lowerNullishPair(lowerer, expr, loc, left) {
|
|
|
3844
3985
|
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({ kind: "call", callee: helper, args: [stable], type, loc }));
|
|
3845
3986
|
}
|
|
3846
3987
|
}
|
|
3988
|
+
// A subclass value defaulted to a base-class value (`circle ?? shape`):
|
|
3989
|
+
// the present arm upcasts after the original nullish test, and the
|
|
3990
|
+
// default lowers lazily into the base-class result.
|
|
3991
|
+
const present = rest.length === 1 ? rest[0] : null;
|
|
3992
|
+
if (present?.kind === "object" &&
|
|
3993
|
+
type.kind === "object" &&
|
|
3994
|
+
present.className !== type.className &&
|
|
3995
|
+
lowerer.isSubclassOf(present.className, type.className)) {
|
|
3996
|
+
const helper = lowerer.narrowedArmHelper(left.type.unionId, present, loc);
|
|
3997
|
+
if (helper !== null) {
|
|
3998
|
+
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({
|
|
3999
|
+
kind: "upcast",
|
|
4000
|
+
value: { kind: "call", callee: helper, args: [stable], type: present, loc },
|
|
4001
|
+
type,
|
|
4002
|
+
loc,
|
|
4003
|
+
}));
|
|
4004
|
+
}
|
|
4005
|
+
}
|
|
3847
4006
|
// A default may change the union or widen its records. Test the
|
|
3848
4007
|
// original tag before coercing: converting the whole left first can
|
|
3849
4008
|
// lose nullish arms, and evaluating the default eagerly loses laziness.
|
|
@@ -3957,7 +4116,7 @@ export function lowerCondition(lowerer, expr) {
|
|
|
3957
4116
|
};
|
|
3958
4117
|
}
|
|
3959
4118
|
}
|
|
3960
|
-
const value =
|
|
4119
|
+
const value = lowerPresenceOperand(lowerer, expr);
|
|
3961
4120
|
return (tryLowerIndexTruthiness(lowerer, value, expr, locOf(expr)) ?? lowerer.ensureBool(value, expr));
|
|
3962
4121
|
}
|
|
3963
4122
|
function lowerPromiseThenPresence(lowerer, access, result) {
|
|
@@ -3997,13 +4156,7 @@ function lowerPromiseThenPresence(lowerer, access, result) {
|
|
|
3997
4156
|
const helper = lowerer.narrowedArmHelper(receiver.type.unionId, promiseType, receiver.loc);
|
|
3998
4157
|
if (helper === null)
|
|
3999
4158
|
return null;
|
|
4000
|
-
receiver =
|
|
4001
|
-
kind: "call",
|
|
4002
|
-
callee: helper,
|
|
4003
|
-
args: [receiver],
|
|
4004
|
-
type: promiseType,
|
|
4005
|
-
loc: receiver.loc,
|
|
4006
|
-
};
|
|
4159
|
+
receiver = lowerer.checkedNarrowCall(helper, receiver, promiseType, receiver.loc);
|
|
4007
4160
|
}
|
|
4008
4161
|
}
|
|
4009
4162
|
if (receiver.type.kind === "dyn") {
|
|
@@ -4691,13 +4844,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
4691
4844
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
4692
4845
|
: null;
|
|
4693
4846
|
receiver = helper
|
|
4694
|
-
?
|
|
4695
|
-
kind: "call",
|
|
4696
|
-
callee: helper,
|
|
4697
|
-
args: [receiver],
|
|
4698
|
-
type: present,
|
|
4699
|
-
loc: locOf(expr.expression),
|
|
4700
|
-
}
|
|
4847
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
4701
4848
|
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
4702
4849
|
}
|
|
4703
4850
|
// An island handle behind a typed-array .d.ts surface: the engine
|
|
@@ -4791,13 +4938,7 @@ export function lowerIntrinsicProperty(lowerer, expr) {
|
|
|
4791
4938
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
4792
4939
|
: null;
|
|
4793
4940
|
receiver = helper
|
|
4794
|
-
?
|
|
4795
|
-
kind: "call",
|
|
4796
|
-
callee: helper,
|
|
4797
|
-
args: [receiver],
|
|
4798
|
-
type: present,
|
|
4799
|
-
loc: locOf(expr.expression),
|
|
4800
|
-
}
|
|
4941
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
4801
4942
|
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
4802
4943
|
}
|
|
4803
4944
|
// An island handle behind an array-typed .d.ts surface
|
|
@@ -5097,7 +5238,30 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
5097
5238
|
}
|
|
5098
5239
|
lowerer.badType(expr, tsType);
|
|
5099
5240
|
}
|
|
5100
|
-
|
|
5241
|
+
let type = mapped;
|
|
5242
|
+
// An inferred array of records takes the layout of an element literal
|
|
5243
|
+
// whose fields widened for missing-element reads; the other elements
|
|
5244
|
+
// build that layout directly. An explicit destination keeps its own.
|
|
5245
|
+
if (!expected && type.elem.kind === "record") {
|
|
5246
|
+
let variant = null;
|
|
5247
|
+
for (const candidate of expr.elements) {
|
|
5248
|
+
let x = candidate;
|
|
5249
|
+
while (ts.isParenthesizedExpression(x))
|
|
5250
|
+
x = x.expression;
|
|
5251
|
+
if (!ts.isObjectLiteralExpression(x))
|
|
5252
|
+
continue;
|
|
5253
|
+
const probe = tryLowerExpression(lowerer, x);
|
|
5254
|
+
if (!probe || !lowerer.isRuntimeOptionalRecordVariant(probe.type, type.elem))
|
|
5255
|
+
continue;
|
|
5256
|
+
if (variant !== null && !typeEquals(variant, probe.type)) {
|
|
5257
|
+
variant = null;
|
|
5258
|
+
break;
|
|
5259
|
+
}
|
|
5260
|
+
variant = probe.type;
|
|
5261
|
+
}
|
|
5262
|
+
if (variant !== null)
|
|
5263
|
+
type = arrayOf(variant);
|
|
5264
|
+
}
|
|
5101
5265
|
// Keep the array payload type fixed. Optional reads are stored through
|
|
5102
5266
|
// arrayValueStore, which records UNDEFINED in the state byte while the
|
|
5103
5267
|
// payload remains number/string/etc.; widening the array element here
|
|
@@ -5262,8 +5426,21 @@ export function lowerArrayLiteral(lowerer, expr, expected) {
|
|
|
5262
5426
|
}
|
|
5263
5427
|
const out = lowerer.declareHiddenLocal("%arrayLit", type);
|
|
5264
5428
|
const outRef = varRef(out.id, type, loc);
|
|
5429
|
+
// Dense capacity for the elements the statements below store.
|
|
5430
|
+
const capacity = Math.min(elems.length - spreads.length, 1024);
|
|
5265
5431
|
const body = [
|
|
5266
|
-
{
|
|
5432
|
+
{
|
|
5433
|
+
kind: "varDecl",
|
|
5434
|
+
localId: out.id,
|
|
5435
|
+
init: {
|
|
5436
|
+
kind: "arrayLit",
|
|
5437
|
+
elems: [],
|
|
5438
|
+
...(capacity > 0 ? { capacity } : {}),
|
|
5439
|
+
type,
|
|
5440
|
+
loc,
|
|
5441
|
+
},
|
|
5442
|
+
loc,
|
|
5443
|
+
},
|
|
5267
5444
|
];
|
|
5268
5445
|
const spreadSet = new Set(spreads);
|
|
5269
5446
|
const currentLength = () => ({
|
|
@@ -5438,6 +5615,34 @@ export function lowerOptionalNumber(lowerer, operand, loc, narrowedNode) {
|
|
|
5438
5615
|
? value
|
|
5439
5616
|
: { kind: "seqExpr", stmts: prefix, result: value, type: F64, loc };
|
|
5440
5617
|
}
|
|
5618
|
+
/** A number argument of a builtin that converts it with ToNumber (Math
|
|
5619
|
+
* functions, String.fromCharCode, the global isNaN/isFinite, DataView
|
|
5620
|
+
* offsets and values). ToNumber(undefined) is NaN, so a missing value — an
|
|
5621
|
+
* out-of-range read, a local or field holding one, or a hole — converts to
|
|
5622
|
+
* NaN instead of trusting the checker's number type. */
|
|
5623
|
+
export function lowerToNumberArgument(lowerer, node) {
|
|
5624
|
+
let inner = node;
|
|
5625
|
+
while (ts.isParenthesizedExpression(inner))
|
|
5626
|
+
inner = inner.expression;
|
|
5627
|
+
const loc = locOf(inner);
|
|
5628
|
+
const isOptionalNumber = (value) => value.type.kind === "union" &&
|
|
5629
|
+
lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0 &&
|
|
5630
|
+
lowerer.stripUndefinedArm(value.type).kind === "f64";
|
|
5631
|
+
const optional = ts.isIdentifier(inner)
|
|
5632
|
+
? runtimeOptionalStorageOperand(lowerer, inner)
|
|
5633
|
+
: ts.isElementAccessExpression(inner)
|
|
5634
|
+
? lowerAbsenceProbe(lowerer, inner)
|
|
5635
|
+
: null;
|
|
5636
|
+
if (optional && isOptionalNumber(optional))
|
|
5637
|
+
return lowerOptionalNumber(lowerer, optional, loc, inner);
|
|
5638
|
+
// A conditional builds each branch for the destination.
|
|
5639
|
+
if (ts.isConditionalExpression(inner))
|
|
5640
|
+
return lowerer.lowerExprExpecting(node, F64);
|
|
5641
|
+
const value = lowerer.lowerExpr(node);
|
|
5642
|
+
if (isOptionalNumber(value))
|
|
5643
|
+
return lowerOptionalNumber(lowerer, value, loc, inner);
|
|
5644
|
+
return lowerer.coerceInto(node, value, F64);
|
|
5645
|
+
}
|
|
5441
5646
|
/** `a[i]` reads. Only f64 indices into array receivers are modeled; JS
|
|
5442
5647
|
* string-key element access (`a["length"]`) and string indexing (`s[0]`
|
|
5443
5648
|
* typechecks against the lib's index signature; use .charAt) stay out. */
|
|
@@ -5686,7 +5891,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5686
5891
|
? lowerer.narrowedArmHelper(recv.type.unionId, present, locOf(expr.expression))
|
|
5687
5892
|
: null;
|
|
5688
5893
|
recv = helper
|
|
5689
|
-
?
|
|
5894
|
+
? lowerer.checkedNarrowCall(helper, recv, present, locOf(expr.expression))
|
|
5690
5895
|
: lowerer.maybeNarrow(recv, expr.expression);
|
|
5691
5896
|
}
|
|
5692
5897
|
// A typed-array .d.ts surface whose VALUE is an island handle
|
|
@@ -5719,14 +5924,24 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5719
5924
|
if (index.type.kind !== "f64") {
|
|
5720
5925
|
lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys");
|
|
5721
5926
|
}
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5927
|
+
// `t[i]!` asserts presence: the numeric element read (NaN when
|
|
5928
|
+
// invalid). Every other read answers undefined for an invalid index,
|
|
5929
|
+
// like Node.
|
|
5930
|
+
// A read whose every consumer treats undefined like NaN (see
|
|
5931
|
+
// nan-coded-reads.ts) is the same plain numeric read.
|
|
5932
|
+
if ((ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) ||
|
|
5933
|
+
lowerer.nanCodedReads?.isNumericRead(expr) === true) {
|
|
5934
|
+
return {
|
|
5935
|
+
kind: "bytesIntrinsic",
|
|
5936
|
+
method: "get",
|
|
5937
|
+
receiver: recv,
|
|
5938
|
+
args: [index],
|
|
5939
|
+
type: F64,
|
|
5940
|
+
loc: locOf(expr),
|
|
5941
|
+
invalidNaN: true,
|
|
5942
|
+
};
|
|
5943
|
+
}
|
|
5944
|
+
return lowerSafeBytesRead(lowerer, recv, index, locOf(expr));
|
|
5730
5945
|
}
|
|
5731
5946
|
// Tuple element read `t[0]`: a positional-field read of the tuple's
|
|
5732
5947
|
// record shape — LITERAL indices only (the checker's per-index types
|
|
@@ -5769,13 +5984,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5769
5984
|
? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(expr.expression))
|
|
5770
5985
|
: null;
|
|
5771
5986
|
obj = helper
|
|
5772
|
-
?
|
|
5773
|
-
kind: "call",
|
|
5774
|
-
callee: helper,
|
|
5775
|
-
args: [obj],
|
|
5776
|
-
type: present,
|
|
5777
|
-
loc: locOf(expr.expression),
|
|
5778
|
-
}
|
|
5987
|
+
? lowerer.checkedNarrowCall(helper, obj, present, locOf(expr.expression))
|
|
5779
5988
|
: lowerer.maybeNarrow(obj, expr.expression);
|
|
5780
5989
|
}
|
|
5781
5990
|
const idx = tupleLiteralIndex(expr.argumentExpression);
|
|
@@ -5957,6 +6166,17 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
5957
6166
|
const recv = lowerer.lowerExpr(expr.expression);
|
|
5958
6167
|
const index = lowerOptionalNumber(lowerer, lowerer.lowerExpr(expr.argumentExpression), locOf(expr.argumentExpression), expr.argumentExpression);
|
|
5959
6168
|
if (index.type.kind === "f64" && recv.type.kind === "string") {
|
|
6169
|
+
// A proven in-bounds integer index always names a code unit, where
|
|
6170
|
+
// charAt and the property read agree.
|
|
6171
|
+
if (lowerer.stringIndexBounds.inBounds(expr))
|
|
6172
|
+
return {
|
|
6173
|
+
kind: "strIntrinsic",
|
|
6174
|
+
method: "charAt",
|
|
6175
|
+
receiver: recv,
|
|
6176
|
+
args: [index],
|
|
6177
|
+
type: STRING,
|
|
6178
|
+
loc: locOf(expr),
|
|
6179
|
+
};
|
|
5960
6180
|
return lowerOptionalStringIndex(lowerer, recv, index, lowerer.withUndefinedArm(STRING), locOf(expr));
|
|
5961
6181
|
}
|
|
5962
6182
|
lowerer.unsupported("SC1090", expr, "string indexing with this index/result shape (expected a number index and a string or string | undefined result)");
|
|
@@ -6020,7 +6240,7 @@ export function lowerElementAccess(lowerer, expr) {
|
|
|
6020
6240
|
? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(expr.expression))
|
|
6021
6241
|
: null;
|
|
6022
6242
|
arr = helper
|
|
6023
|
-
?
|
|
6243
|
+
? lowerer.checkedNarrowCall(helper, arr, present, locOf(expr.expression))
|
|
6024
6244
|
: lowerer.maybeNarrow(arr, expr.expression);
|
|
6025
6245
|
}
|
|
6026
6246
|
// The checker sees an array but the VALUE is an island handle (an
|
|
@@ -6330,6 +6550,74 @@ function lowerRecordPropertyKey(lowerer, key, node) {
|
|
|
6330
6550
|
}
|
|
6331
6551
|
return key;
|
|
6332
6552
|
}
|
|
6553
|
+
/** The stored value of an identifier whose storage holds an undefined arm
|
|
6554
|
+
* that the checker's type at this use has dropped. An assignment from an
|
|
6555
|
+
* unchecked indexed read narrows the declared type even though the value
|
|
6556
|
+
* can be absent at runtime, so presence tests (`=== undefined`, `== null`,
|
|
6557
|
+
* truthiness, `??`, `typeof`) read the storage tag instead of trusting
|
|
6558
|
+
* that narrowing. A guard-proven use answers the same way at runtime. */
|
|
6559
|
+
export function runtimeOptionalStorageOperand(lowerer, node) {
|
|
6560
|
+
let expr = node;
|
|
6561
|
+
while (ts.isParenthesizedExpression(expr))
|
|
6562
|
+
expr = expr.expression;
|
|
6563
|
+
if (!ts.isIdentifier(expr))
|
|
6564
|
+
return null;
|
|
6565
|
+
// Only storage that can actually receive an absent value without the
|
|
6566
|
+
// checker seeing it qualifies; other declared-optional bindings keep the
|
|
6567
|
+
// checker's assignment and guard narrowing.
|
|
6568
|
+
const symbol = lowerer.resolveValueSymbol(expr);
|
|
6569
|
+
const local = lowerer.resolveLocal(expr);
|
|
6570
|
+
const global = local ? undefined : lowerer.globalOf(expr);
|
|
6571
|
+
const root = local ? lowerer.runtimeOptionalRootOf(local) : null;
|
|
6572
|
+
if (root && lowerer.runtimeOptionalStorageLocals.has(root)) {
|
|
6573
|
+
// These locals track guards: a branch that proved presence removes
|
|
6574
|
+
// the binding from the active set, and its reads stay narrowed. A
|
|
6575
|
+
// captured binding can be reassigned between calls, so a capture
|
|
6576
|
+
// never inherits a guard (the identifier read's own rule).
|
|
6577
|
+
const captured = local.boxed === true ||
|
|
6578
|
+
(!!symbol && lowerer.ctx.captureBySymbol.get(symbol) === local) ||
|
|
6579
|
+
root !== local;
|
|
6580
|
+
if (!captured && !lowerer.runtimeOptionalLocals.has(root))
|
|
6581
|
+
return null;
|
|
6582
|
+
}
|
|
6583
|
+
else if (!(symbol && lowerer.runtimeOptionalAssignedSymbols.has(symbol)) &&
|
|
6584
|
+
!(symbol && lowerer.runtimeOptionalBindingTypes.has(symbol)) &&
|
|
6585
|
+
!(global && lowerer.isRuntimeOptionalGlobal(global)))
|
|
6586
|
+
return null;
|
|
6587
|
+
const optional = lowerer.runtimeOptionalIdentifierValue(expr);
|
|
6588
|
+
if (optional === null)
|
|
6589
|
+
return null;
|
|
6590
|
+
const checked = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
6591
|
+
if (checked === null ||
|
|
6592
|
+
(checked.kind === "union" && lowerer.armTag(checked.unionId, UNDEFINED_T) >= 0))
|
|
6593
|
+
return null;
|
|
6594
|
+
return optional.value;
|
|
6595
|
+
}
|
|
6596
|
+
/** A `T | undefined` class field read that the checker narrowed to `T`
|
|
6597
|
+
* where the field was assigned a value that may be missing (an unchecked
|
|
6598
|
+
* indexed read). TypeScript's assignment narrowing is not a runtime fact
|
|
6599
|
+
* there, so the read keeps the stored union instead of extracting `T`. */
|
|
6600
|
+
function runtimeOptionalClassField(lowerer, value, node) {
|
|
6601
|
+
if (value.kind !== "fieldGet" || value.type.kind !== "union")
|
|
6602
|
+
return false;
|
|
6603
|
+
if (lowerer.armTag(value.type.unionId, UNDEFINED_T) < 0)
|
|
6604
|
+
return false;
|
|
6605
|
+
if ((lowerer.unions.get(value.type.unionId)?.arms.length ?? 0) !== 2)
|
|
6606
|
+
return false;
|
|
6607
|
+
const symbol = lowerer.checker.getSymbolAtLocation(node.name);
|
|
6608
|
+
if (!symbol || !lowerer.runtimeOptionalAssignedSymbols.has(symbol))
|
|
6609
|
+
return false;
|
|
6610
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
6611
|
+
return narrowed !== null && typeEquals(narrowed, lowerer.stripUndefinedArm(value.type));
|
|
6612
|
+
}
|
|
6613
|
+
/** A presence-test operand: an absence-aware element or field read, an
|
|
6614
|
+
* identifier's runtime-optional storage, or the ordinary lowering. */
|
|
6615
|
+
export function lowerPresenceOperand(lowerer, node) {
|
|
6616
|
+
// An unassigned deferred-init field observes its undefined slot too.
|
|
6617
|
+
return deferredSlotOr(lowerer, lowerAbsenceProbe(lowerer, node) ??
|
|
6618
|
+
runtimeOptionalStorageOperand(lowerer, node) ??
|
|
6619
|
+
lowerer.lowerExpr(node));
|
|
6620
|
+
}
|
|
6333
6621
|
/** A keyed read used only to observe absence (`if (map[k])`, or the left
|
|
6334
6622
|
* side of `||`/`??`). JavaScript answers undefined for missing record keys
|
|
6335
6623
|
* and array indices even when noUncheckedIndexedAccess is disabled. Keep
|
|
@@ -6542,13 +6830,7 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
6542
6830
|
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(target.expression))
|
|
6543
6831
|
: null;
|
|
6544
6832
|
if (helper)
|
|
6545
|
-
receiver =
|
|
6546
|
-
kind: "call",
|
|
6547
|
-
callee: helper,
|
|
6548
|
-
args: [receiver],
|
|
6549
|
-
type: present,
|
|
6550
|
-
loc: locOf(target.expression),
|
|
6551
|
-
};
|
|
6833
|
+
receiver = lowerer.checkedNarrowCall(helper, receiver, present, locOf(target.expression));
|
|
6552
6834
|
}
|
|
6553
6835
|
if (receiver.type.kind !== receiverType.kind) {
|
|
6554
6836
|
lowerer.unsupported("SC1090", target.expression, "compound assignment through a non-native array or byte view");
|
|
@@ -6563,12 +6845,15 @@ export function lowerElementCompound(lowerer, expr, op) {
|
|
|
6563
6845
|
const oldValue = receiver.type.kind === "array"
|
|
6564
6846
|
? arrayValueRead(lowerer, receiverRef(), indexRef(), receiver.type.elem, locOf(target))
|
|
6565
6847
|
: {
|
|
6848
|
+
// An invalid index reads undefined in Node, which every numeric
|
|
6849
|
+
// compound operator turns into NaN; the write is then ignored.
|
|
6566
6850
|
kind: "bytesIntrinsic",
|
|
6567
6851
|
method: "get",
|
|
6568
6852
|
receiver: receiverRef(),
|
|
6569
6853
|
args: [indexRef()],
|
|
6570
6854
|
type: F64,
|
|
6571
6855
|
loc: locOf(target),
|
|
6856
|
+
invalidNaN: true,
|
|
6572
6857
|
};
|
|
6573
6858
|
const oldLocal = lowerer.declareHiddenLocal("%compoundOld", oldValue.type);
|
|
6574
6859
|
const oldRef = () => varRef(oldLocal.id, oldValue.type, loc);
|
|
@@ -7184,13 +7469,7 @@ export function lowerElementWrite(lowerer, expr) {
|
|
|
7184
7469
|
? lowerer.narrowedArmHelper(arr.type.unionId, present, locOf(target.expression))
|
|
7185
7470
|
: null;
|
|
7186
7471
|
if (helper) {
|
|
7187
|
-
arr =
|
|
7188
|
-
kind: "call",
|
|
7189
|
-
callee: helper,
|
|
7190
|
-
args: [arr],
|
|
7191
|
-
type: present,
|
|
7192
|
-
loc: locOf(target.expression),
|
|
7193
|
-
};
|
|
7472
|
+
arr = lowerer.checkedNarrowCall(helper, arr, present, locOf(target.expression));
|
|
7194
7473
|
}
|
|
7195
7474
|
}
|
|
7196
7475
|
if (arr.type.kind !== "array") {
|
|
@@ -7308,7 +7587,7 @@ export function ensureString(lowerer, e, node) {
|
|
|
7308
7587
|
narrowed.kind === "bigint")) {
|
|
7309
7588
|
const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
|
|
7310
7589
|
if (helper) {
|
|
7311
|
-
return ensureString(lowerer,
|
|
7590
|
+
return ensureString(lowerer, lowerer.checkedNarrowCall(helper, e, narrowed, e.loc), node);
|
|
7312
7591
|
}
|
|
7313
7592
|
}
|
|
7314
7593
|
if (narrowed?.kind === "union" &&
|
|
@@ -7581,10 +7860,20 @@ export function lowerAsExpression(lowerer, expr) {
|
|
|
7581
7860
|
if (target && target.kind !== "union" && !typeEquals(target, inner.type)) {
|
|
7582
7861
|
const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, locOf(expr));
|
|
7583
7862
|
if (helper) {
|
|
7584
|
-
return
|
|
7863
|
+
return lowerer.checkedNarrowCall(helper, inner, target, locOf(expr));
|
|
7585
7864
|
}
|
|
7586
7865
|
}
|
|
7587
7866
|
}
|
|
7867
|
+
// `node.parent as Sub | undefined`: a union target whose class arm is
|
|
7868
|
+
// narrower than the stored class gets the same checked class view as
|
|
7869
|
+
// `node.parent as Sub`; the other arms keep their identical tags.
|
|
7870
|
+
if (target?.kind === "union" &&
|
|
7871
|
+
(inner.type.kind === "union" || inner.type.kind === "object") &&
|
|
7872
|
+
!typeEquals(target, inner.type)) {
|
|
7873
|
+
const asserted = checkedClassUnionAssertion(lowerer, inner, target, locOf(expr));
|
|
7874
|
+
if (asserted)
|
|
7875
|
+
return asserted;
|
|
7876
|
+
}
|
|
7588
7877
|
return inner; // erasure, unchanged
|
|
7589
7878
|
}
|
|
7590
7879
|
if (inner.type.kind === "jsval") {
|
|
@@ -7711,7 +8000,7 @@ export function lowerPrefixUnary(lowerer, expr) {
|
|
|
7711
8000
|
}
|
|
7712
8001
|
case ts.SyntaxKind.ExclamationToken: {
|
|
7713
8002
|
// `!x` is ToBoolean-then-negate: f64/string operands go through toBool.
|
|
7714
|
-
const operand = lowerer.ensureBool(lowerer.lowerExpr(expr.operand), expr.operand);
|
|
8003
|
+
const operand = lowerer.ensureBool(deferredSlotOr(lowerer, runtimeOptionalStorageOperand(lowerer, expr.operand) ?? lowerer.lowerExpr(expr.operand)), expr.operand);
|
|
7715
8004
|
return { kind: "unary", op: "!", operand, type: BOOL, loc };
|
|
7716
8005
|
}
|
|
7717
8006
|
case ts.SyntaxKind.TildeToken: {
|
|
@@ -7816,7 +8105,15 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7816
8105
|
const type = raw.type;
|
|
7817
8106
|
const read = type.kind === "array"
|
|
7818
8107
|
? arrayValueRead(lowerer, receiver, index, type.elem, loc)
|
|
7819
|
-
: {
|
|
8108
|
+
: {
|
|
8109
|
+
kind: "bytesIntrinsic",
|
|
8110
|
+
method: "get",
|
|
8111
|
+
receiver,
|
|
8112
|
+
args: [index],
|
|
8113
|
+
type: F64,
|
|
8114
|
+
loc,
|
|
8115
|
+
invalidNaN: true,
|
|
8116
|
+
};
|
|
7820
8117
|
return finish(read, (value) => type.kind === "array"
|
|
7821
8118
|
? arrayValueStore(lowerer, receiver, index, lowerer.coerceInto(access, value, type.elem), type.elem, loc)
|
|
7822
8119
|
: {
|
|
@@ -7848,6 +8145,7 @@ export function lowerIncDec(lowerer, expr, prefix) {
|
|
|
7848
8145
|
? lowerer.fieldTarget(access)
|
|
7849
8146
|
: symbolFieldTarget(lowerer, access);
|
|
7850
8147
|
if (target && lowerer.dynConvertible(target.fieldType)) {
|
|
8148
|
+
checkDeferredMemberReceiver(lowerer, target, access);
|
|
7851
8149
|
target.obj = save(target.obj, "%incrementReceiver");
|
|
7852
8150
|
return finish(lowerer.fieldGetExpr(target, loc, access), (value) => lowerer.fieldSetStmt(target, lowerer.coerceInto(access, value, target.fieldType), loc, access));
|
|
7853
8151
|
}
|
|
@@ -8081,12 +8379,75 @@ export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
|
|
|
8081
8379
|
}
|
|
8082
8380
|
lowerer.unsupported("SC1043", expr);
|
|
8083
8381
|
}
|
|
8382
|
+
/** Equality of two NaN-coded values (nan-coded-reads.ts), each of which may
|
|
8383
|
+
* stand for undefined and never holds a genuine NaN: Node's undefined equals
|
|
8384
|
+
* undefined, so two NaNs compare equal here. Operands evaluate once, in
|
|
8385
|
+
* order. */
|
|
8386
|
+
function lowerNanCodedEquality(lowerer, expr) {
|
|
8387
|
+
const loc = locOf(expr);
|
|
8388
|
+
const left = lowerer.lowerExpr(expr.left);
|
|
8389
|
+
const right = lowerer.lowerExpr(expr.right);
|
|
8390
|
+
if (left.type.kind !== "f64" || right.type.kind !== "f64") {
|
|
8391
|
+
throw new InternalCompilerError("NaN-coded equality operand is not a plain number");
|
|
8392
|
+
}
|
|
8393
|
+
const stmts = [];
|
|
8394
|
+
const stable = (value, name) => {
|
|
8395
|
+
if (value.kind === "varRef" || value.kind === "numLit")
|
|
8396
|
+
return value;
|
|
8397
|
+
const tmp = lowerer.declareHiddenLocal(name, F64);
|
|
8398
|
+
stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
|
|
8399
|
+
return varRef(tmp.id, F64, loc);
|
|
8400
|
+
};
|
|
8401
|
+
const a = stable(left, "%eqLeft");
|
|
8402
|
+
const b = stable(right, "%eqRight");
|
|
8403
|
+
const isNaN = (value) => ({
|
|
8404
|
+
kind: "libCall",
|
|
8405
|
+
fn: "num.isNaN",
|
|
8406
|
+
args: [value],
|
|
8407
|
+
type: BOOL,
|
|
8408
|
+
loc,
|
|
8409
|
+
});
|
|
8410
|
+
const bothUndefined = {
|
|
8411
|
+
kind: "logical",
|
|
8412
|
+
op: "&&",
|
|
8413
|
+
left: isNaN(a),
|
|
8414
|
+
right: isNaN(b),
|
|
8415
|
+
type: BOOL,
|
|
8416
|
+
loc,
|
|
8417
|
+
};
|
|
8418
|
+
const op = expr.operatorToken.kind;
|
|
8419
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
8420
|
+
op === ts.SyntaxKind.ExclamationEqualsToken;
|
|
8421
|
+
const result = negated
|
|
8422
|
+
? {
|
|
8423
|
+
kind: "logical",
|
|
8424
|
+
op: "&&",
|
|
8425
|
+
left: { kind: "bin", op: "!==", left: a, right: b, type: BOOL, loc },
|
|
8426
|
+
right: { kind: "unary", op: "!", operand: bothUndefined, type: BOOL, loc },
|
|
8427
|
+
type: BOOL,
|
|
8428
|
+
loc,
|
|
8429
|
+
}
|
|
8430
|
+
: {
|
|
8431
|
+
kind: "logical",
|
|
8432
|
+
op: "||",
|
|
8433
|
+
left: { kind: "bin", op: "===", left: a, right: b, type: BOOL, loc },
|
|
8434
|
+
right: bothUndefined,
|
|
8435
|
+
type: BOOL,
|
|
8436
|
+
loc,
|
|
8437
|
+
};
|
|
8438
|
+
return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
8439
|
+
}
|
|
8084
8440
|
export function lowerBinary(lowerer, expr) {
|
|
8085
8441
|
const loc = locOf(expr);
|
|
8086
8442
|
const op = expr.operatorToken.kind;
|
|
8087
8443
|
const cacheHas = lowerRequireCacheHas(lowerer, expr);
|
|
8088
8444
|
if (cacheHas)
|
|
8089
8445
|
return cacheHas;
|
|
8446
|
+
if (lowerer.nanCodedReads?.needsUndefinedEquality(expr)) {
|
|
8447
|
+
const undefinedEquality = lowerNanCodedEquality(lowerer, expr);
|
|
8448
|
+
if (undefinedEquality)
|
|
8449
|
+
return undefinedEquality;
|
|
8450
|
+
}
|
|
8090
8451
|
if (op === ts.SyntaxKind.EqualsToken ||
|
|
8091
8452
|
(op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment)) {
|
|
8092
8453
|
const urlWrite = lowerUrlAssignment(lowerer, expr);
|
|
@@ -8362,7 +8723,7 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8362
8723
|
const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
|
|
8363
8724
|
if (nullTest)
|
|
8364
8725
|
return nullTest;
|
|
8365
|
-
const loose = lowerAbstractEquality(lowerer, lowerer.lowerExpr(expr.left), lowerer.lowerExpr(expr.right), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
8726
|
+
const loose = lowerAbstractEquality(lowerer, deferredSlotOr(lowerer, lowerer.lowerExpr(expr.left)), deferredSlotOr(lowerer, lowerer.lowerExpr(expr.right)), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
8366
8727
|
if (loose)
|
|
8367
8728
|
return loose;
|
|
8368
8729
|
lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
|
|
@@ -8409,12 +8770,26 @@ export function lowerBinary(lowerer, expr) {
|
|
|
8409
8770
|
}
|
|
8410
8771
|
const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
8411
8772
|
op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
8773
|
+
// An identifier whose storage is runtime-optional is compared by its
|
|
8774
|
+
// stored value: the checker's narrowing to the present arm is not a
|
|
8775
|
+
// runtime proof. Identifier reads are pure, so taking the stored value
|
|
8776
|
+
// after both operands lowered keeps the evaluation order. A union on
|
|
8777
|
+
// the other side keeps the narrowed read (union-to-union comparison
|
|
8778
|
+
// has no lowering).
|
|
8412
8779
|
let left = strictEquality
|
|
8413
8780
|
? (lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left))
|
|
8414
8781
|
: lowerer.lowerExpr(expr.left);
|
|
8415
8782
|
let right = strictEquality
|
|
8416
8783
|
? (lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right))
|
|
8417
8784
|
: lowerer.lowerExpr(expr.right);
|
|
8785
|
+
if (strictEquality) {
|
|
8786
|
+
const storedLeft = runtimeOptionalStorageOperand(lowerer, expr.left);
|
|
8787
|
+
const storedRight = runtimeOptionalStorageOperand(lowerer, expr.right);
|
|
8788
|
+
if (storedLeft !== null && right.type.kind !== "union")
|
|
8789
|
+
left = storedLeft;
|
|
8790
|
+
if (storedRight !== null && left.type.kind !== "union")
|
|
8791
|
+
right = storedRight;
|
|
8792
|
+
}
|
|
8418
8793
|
if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
|
|
8419
8794
|
if (left.type.kind === "caught")
|
|
8420
8795
|
left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
|
|
@@ -9266,7 +9641,9 @@ function lowerLogicalChain(lowerer, expr) {
|
|
|
9266
9641
|
current = left;
|
|
9267
9642
|
continue;
|
|
9268
9643
|
}
|
|
9269
|
-
result = lowerLogicalPair(lowerer, current,
|
|
9644
|
+
result = lowerLogicalPair(lowerer, current, current.operatorToken.kind === ts.SyntaxKind.BarBarToken
|
|
9645
|
+
? lowerPresenceOperand(lowerer, left)
|
|
9646
|
+
: (lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left)));
|
|
9270
9647
|
break;
|
|
9271
9648
|
}
|
|
9272
9649
|
for (let i = parents.length - 1; i >= 0; i--) {
|
|
@@ -9921,11 +10298,12 @@ function lowerUnionTypeofTest(lowerer, expr, loc) {
|
|
|
9921
10298
|
for (const [a, b] of operandPairs(expr)) {
|
|
9922
10299
|
if (!ts.isTypeOfExpression(a))
|
|
9923
10300
|
continue;
|
|
9924
|
-
|
|
10301
|
+
const stored = runtimeOptionalStorageOperand(lowerer, a.expression);
|
|
10302
|
+
if (stored === null && lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
|
|
9925
10303
|
continue;
|
|
9926
10304
|
if (!ts.isStringLiteral(b))
|
|
9927
10305
|
continue; // bare-typeof + strEq handles pure operands
|
|
9928
|
-
const value = lowerer.lowerExpr(a.expression);
|
|
10306
|
+
const value = stored ?? lowerer.lowerExpr(a.expression);
|
|
9929
10307
|
if (value.type.kind !== "union")
|
|
9930
10308
|
continue; // defensive: an already-narrowed use
|
|
9931
10309
|
const unionId = value.type.unionId;
|
|
@@ -12012,6 +12390,11 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
12012
12390
|
const helper = lowerer.narrowedRetagHelper(expr.expression, value.type.unionId, receiverIr.unionId, locOf(expr));
|
|
12013
12391
|
if (helper)
|
|
12014
12392
|
value = { kind: "call", callee: helper, args: [value], type: receiverIr, loc: locOf(expr) };
|
|
12393
|
+
// Optional storage of a base class (a runtime-optional binding holding
|
|
12394
|
+
// `Base | undefined`) that `instanceof` narrowed to several subclasses:
|
|
12395
|
+
// extract the instance and test its class, as typed slots do.
|
|
12396
|
+
else
|
|
12397
|
+
value = narrowStoredClassValue(lowerer, value, receiverIr) ?? value;
|
|
12015
12398
|
}
|
|
12016
12399
|
// A checker-union receiver whose VALUE lowered to a plain RECORD (the
|
|
12017
12400
|
// merged-signature fiction — `runner(cmd, args)` where runner joined
|
|
@@ -12088,13 +12471,7 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
12088
12471
|
if (receiver === null) {
|
|
12089
12472
|
const helper = lowerer.narrowedArmHelper(value.type.unionId, objectType, locOf(expr.expression));
|
|
12090
12473
|
if (helper !== null)
|
|
12091
|
-
receiver =
|
|
12092
|
-
kind: "call",
|
|
12093
|
-
callee: helper,
|
|
12094
|
-
args: [value],
|
|
12095
|
-
type: objectType,
|
|
12096
|
-
loc: locOf(expr.expression),
|
|
12097
|
-
};
|
|
12474
|
+
receiver = lowerer.checkedNarrowCall(helper, value, objectType, locOf(expr.expression));
|
|
12098
12475
|
}
|
|
12099
12476
|
if (receiver !== null) {
|
|
12100
12477
|
return {
|
|
@@ -12140,6 +12517,11 @@ export function lowerUnionProperty(lowerer, expr) {
|
|
|
12140
12517
|
const keyed = lowerUnionKeyedRead(lowerer, expr, value.type.unionId, value, key, field);
|
|
12141
12518
|
if (keyed)
|
|
12142
12519
|
return keyed;
|
|
12520
|
+
// Class arms declaring the field with compatible but different types
|
|
12521
|
+
// (`T | undefined` beside `T`): per-arm slot reads widened to one type.
|
|
12522
|
+
const widened = lowerUnionFieldRead(lowerer, expr, value);
|
|
12523
|
+
if (widened)
|
|
12524
|
+
return widened;
|
|
12143
12525
|
// JavaScript overloads commonly inspect a class brand on a scalar-or-
|
|
12144
12526
|
// instance argument (e.g. Matrix4.makeTranslation). Preserve primitive
|
|
12145
12527
|
// missing-property semantics and dispatch class data through its native
|
|
@@ -12304,15 +12686,14 @@ function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved)
|
|
|
12304
12686
|
const lowerObjectReceiver = () => {
|
|
12305
12687
|
let obj = represented;
|
|
12306
12688
|
if (obj.type.kind === "union") {
|
|
12689
|
+
// A receiver that may hold a missing value (a field assigned an
|
|
12690
|
+
// unchecked read): Node's member-read TypeError for the unit arm.
|
|
12691
|
+
const present = lowerer.runtimeOptionalPropertyReceiver(receiverNode, obj, receiverType, fieldName);
|
|
12692
|
+
if (present)
|
|
12693
|
+
return present;
|
|
12307
12694
|
const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
|
|
12308
12695
|
obj = helper
|
|
12309
|
-
?
|
|
12310
|
-
kind: "call",
|
|
12311
|
-
callee: helper,
|
|
12312
|
-
args: [obj],
|
|
12313
|
-
type: receiverType,
|
|
12314
|
-
loc: locOf(receiverNode),
|
|
12315
|
-
}
|
|
12696
|
+
? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
|
|
12316
12697
|
: lowerer.maybeNarrow(obj, receiverNode);
|
|
12317
12698
|
}
|
|
12318
12699
|
return lowerer.coerceInto(receiverNode, obj, receiverType);
|
|
@@ -12476,13 +12857,7 @@ export function fieldTarget(lowerer, access) {
|
|
|
12476
12857
|
? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression))
|
|
12477
12858
|
: null;
|
|
12478
12859
|
obj = helper
|
|
12479
|
-
?
|
|
12480
|
-
kind: "call",
|
|
12481
|
-
callee: helper,
|
|
12482
|
-
args: [obj],
|
|
12483
|
-
type: present,
|
|
12484
|
-
loc: locOf(access.expression),
|
|
12485
|
-
}
|
|
12860
|
+
? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression))
|
|
12486
12861
|
: lowerer.maybeNarrow(obj, access.expression);
|
|
12487
12862
|
}
|
|
12488
12863
|
if (obj.type.kind !== "record")
|
|
@@ -12689,6 +13064,16 @@ function symbolFieldTarget(lowerer, expr) {
|
|
|
12689
13064
|
* tsc-clean (the property types as the setter's param), but Node yields
|
|
12690
13065
|
* undefined, which these property types cannot represent. */
|
|
12691
13066
|
export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
13067
|
+
// A member read through an unassigned deferred-init field throws Node's
|
|
13068
|
+
// member-read TypeError instead of the generic checked extraction.
|
|
13069
|
+
if (target.container === "class" &&
|
|
13070
|
+
ts.isPropertyAccessExpression(blame) &&
|
|
13071
|
+
target.obj.type.kind === "object" &&
|
|
13072
|
+
lowerer.deferredFieldSlot(target.obj) !== null) {
|
|
13073
|
+
const checked = lowerer.runtimeOptionalPropertyReceiver(blame.expression, target.obj, target.obj.type, target.field);
|
|
13074
|
+
if (checked)
|
|
13075
|
+
target = { ...target, obj: checked };
|
|
13076
|
+
}
|
|
12692
13077
|
if (target.container === "dynamic")
|
|
12693
13078
|
return lowerer.coerceInto(blame, {
|
|
12694
13079
|
kind: "dynKeyGet",
|
|
@@ -12812,6 +13197,34 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
12812
13197
|
if (lowerer.classes.get(target.className)?.deferredInitFields?.has(target.field) === true &&
|
|
12813
13198
|
target.fieldType.kind === "union") {
|
|
12814
13199
|
const inner = lowerer.stripUndefinedArm(target.fieldType);
|
|
13200
|
+
// Reference arms over a stable receiver check inline: the present
|
|
13201
|
+
// arm is a plain projection of the slot, so ordinary reads keep their
|
|
13202
|
+
// borrowed form and only an unassigned slot reaches the throw.
|
|
13203
|
+
const unionId = target.fieldType.unionId;
|
|
13204
|
+
const presentTag = lowerer.armTag(unionId, inner);
|
|
13205
|
+
const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
|
|
13206
|
+
if (inner.kind === "object" &&
|
|
13207
|
+
presentTag >= 0 &&
|
|
13208
|
+
undefTag >= 0 &&
|
|
13209
|
+
lowerer.unions.get(unionId)?.arms.length === 2 &&
|
|
13210
|
+
isSafeToRepeat(read)) {
|
|
13211
|
+
return {
|
|
13212
|
+
kind: "ternary",
|
|
13213
|
+
cond: {
|
|
13214
|
+
kind: "unionIsTag",
|
|
13215
|
+
unionId,
|
|
13216
|
+
tag: undefTag,
|
|
13217
|
+
negated: false,
|
|
13218
|
+
value: read,
|
|
13219
|
+
type: BOOL,
|
|
13220
|
+
loc,
|
|
13221
|
+
},
|
|
13222
|
+
then: nodeThrowExpr(1, "", DEFERRED_READ_MESSAGE, inner, loc),
|
|
13223
|
+
else_: { kind: "unionNarrow", unionId, tag: presentTag, value: read, type: inner, loc },
|
|
13224
|
+
type: inner,
|
|
13225
|
+
loc,
|
|
13226
|
+
};
|
|
13227
|
+
}
|
|
12815
13228
|
const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc);
|
|
12816
13229
|
if (helper)
|
|
12817
13230
|
return { kind: "call", callee: helper, args: [read], type: inner, loc };
|
|
@@ -12831,6 +13244,75 @@ export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
|
12831
13244
|
* call). A write to a getter-only property never gets here in a clean
|
|
12832
13245
|
* program (tsc's TS2540 is the fence); the rejection is the backstop. */
|
|
12833
13246
|
export function fieldSetStmt(lowerer, target, value, loc, blame) {
|
|
13247
|
+
// A member write through an unassigned deferred-init field: the value
|
|
13248
|
+
// still evaluates first, then the write throws Node's TypeError.
|
|
13249
|
+
const deferredSlot = target.container === "class" &&
|
|
13250
|
+
!((target.field === "message" || target.field === "name") &&
|
|
13251
|
+
(target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
13252
|
+
? lowerer.deferredFieldSlot(target.obj)
|
|
13253
|
+
: null;
|
|
13254
|
+
if (target.container === "class" && deferredSlot?.type.kind === "union") {
|
|
13255
|
+
const unionId = deferredSlot.type.unionId;
|
|
13256
|
+
const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
|
|
13257
|
+
const presentTag = lowerer.armTag(unionId, target.obj.type);
|
|
13258
|
+
if (undefTag >= 0 && presentTag >= 0) {
|
|
13259
|
+
// A value that cannot write anything leaves the field unchanged, so
|
|
13260
|
+
// the field is read after it (no snapshot of the slot).
|
|
13261
|
+
const late = isSafeToRepeat(deferredSlot) && writeFree(value);
|
|
13262
|
+
const receiver = late
|
|
13263
|
+
? null
|
|
13264
|
+
: lowerer.declareHiddenLocal("%deferredWriteObject", deferredSlot.type);
|
|
13265
|
+
const stored = lowerer.declareHiddenLocal("%deferredWriteValue", value.type);
|
|
13266
|
+
const receiverRef = receiver ? varRef(receiver.id, receiver.type, loc) : deferredSlot;
|
|
13267
|
+
const result = varRef(stored.id, stored.type, loc);
|
|
13268
|
+
const write = {
|
|
13269
|
+
kind: "fieldSet",
|
|
13270
|
+
obj: {
|
|
13271
|
+
kind: "unionNarrow",
|
|
13272
|
+
unionId,
|
|
13273
|
+
tag: presentTag,
|
|
13274
|
+
value: receiverRef,
|
|
13275
|
+
type: target.obj.type,
|
|
13276
|
+
loc,
|
|
13277
|
+
},
|
|
13278
|
+
className: target.className,
|
|
13279
|
+
field: target.field,
|
|
13280
|
+
value: result,
|
|
13281
|
+
loc,
|
|
13282
|
+
};
|
|
13283
|
+
return {
|
|
13284
|
+
kind: "exprStmt",
|
|
13285
|
+
expr: {
|
|
13286
|
+
kind: "seqExpr",
|
|
13287
|
+
stmts: [
|
|
13288
|
+
...(receiver
|
|
13289
|
+
? [{ kind: "varDecl", localId: receiver.id, init: deferredSlot, loc }]
|
|
13290
|
+
: []),
|
|
13291
|
+
{ kind: "varDecl", localId: stored.id, init: value, loc },
|
|
13292
|
+
],
|
|
13293
|
+
result: {
|
|
13294
|
+
kind: "ternary",
|
|
13295
|
+
cond: {
|
|
13296
|
+
kind: "unionIsTag",
|
|
13297
|
+
unionId,
|
|
13298
|
+
tag: undefTag,
|
|
13299
|
+
value: receiverRef,
|
|
13300
|
+
negated: false,
|
|
13301
|
+
type: BOOL,
|
|
13302
|
+
loc,
|
|
13303
|
+
},
|
|
13304
|
+
then: nodeThrowExpr(1, "", `Cannot set properties of undefined (setting '${target.field}')`, result.type, loc),
|
|
13305
|
+
else_: { kind: "seqExpr", stmts: [write], result, type: result.type, loc },
|
|
13306
|
+
type: result.type,
|
|
13307
|
+
loc,
|
|
13308
|
+
},
|
|
13309
|
+
type: result.type,
|
|
13310
|
+
loc,
|
|
13311
|
+
},
|
|
13312
|
+
loc,
|
|
13313
|
+
};
|
|
13314
|
+
}
|
|
13315
|
+
}
|
|
12834
13316
|
if (target.container === "dynamic")
|
|
12835
13317
|
return {
|
|
12836
13318
|
kind: "exprStmt",
|
|
@@ -13148,6 +13630,7 @@ function lowerFieldCompoundValue(lowerer, access, op, rhsNode, loc) {
|
|
|
13148
13630
|
const target = targetOf();
|
|
13149
13631
|
if (!target)
|
|
13150
13632
|
lowerer.unsupported("SC1090", access, "compound assignment to unsupported field targets");
|
|
13633
|
+
checkDeferredMemberReceiver(lowerer, target, access);
|
|
13151
13634
|
target.obj = save(target.obj, "%compoundReceiver");
|
|
13152
13635
|
// Accessors observe getter, RHS side effects, then setter, all through
|
|
13153
13636
|
// the saved receiver.
|