@scriptc/compiler 0.3.6 → 0.4.0
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 +682 -50
- package/ambient/scriptc.d.ts +134 -0
- package/dist/backend/cycle-analysis.d.ts +1 -1
- package/dist/backend/cycle-analysis.js +1 -0
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +13 -1
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.js +16 -5
- package/dist/backend/cycle-mutability.js.map +1 -1
- package/dist/backend/executable-features.js +13 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/immutability.test.js +1 -1
- package/dist/backend/library-pack.js +6 -0
- package/dist/backend/library-pack.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +41 -4
- package/dist/backend/llvm/alloc.js +138 -7
- package/dist/backend/llvm/alloc.js.map +1 -1
- package/dist/backend/llvm/alloc.test.js +30 -1
- package/dist/backend/llvm/alloc.test.js.map +1 -1
- package/dist/backend/llvm/appended-array-literals.test.js +1 -1
- package/dist/backend/llvm/array-search.test.js +1 -1
- package/dist/backend/llvm/blocks.d.ts +8 -0
- package/dist/backend/llvm/blocks.js +43 -1
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/blocks.test.js +22 -1
- package/dist/backend/llvm/blocks.test.js.map +1 -1
- package/dist/backend/llvm/byte-numbers.js +15 -5
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/bytes-alias.d.ts +14 -0
- package/dist/backend/llvm/bytes-alias.js +20 -0
- package/dist/backend/llvm/bytes-alias.js.map +1 -0
- package/dist/backend/llvm/bytes-loop-versions.d.ts +86 -0
- package/dist/backend/llvm/bytes-loop-versions.js +506 -0
- package/dist/backend/llvm/bytes-loop-versions.js.map +1 -0
- package/dist/backend/llvm/bytes-loop-versions.test.d.ts +1 -0
- package/dist/backend/llvm/bytes-loop-versions.test.js +244 -0
- package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.js +50 -1
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +34 -0
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/checked-narrows.test.js +1 -1
- package/dist/backend/llvm/checked-value-lifetimes.js +4 -1
- package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +11 -0
- package/dist/backend/llvm/classes.js +71 -14
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +58 -8
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.js +1 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +5 -1
- package/dist/backend/llvm/constant-callbacks.js +55 -12
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +88 -1
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/counted-loops.d.ts +4 -0
- package/dist/backend/llvm/counted-loops.js +37 -0
- package/dist/backend/llvm/counted-loops.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +12 -3
- package/dist/backend/llvm/dense-array-access.js +72 -14
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +59 -3
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dense-array-loops.d.ts +51 -0
- package/dist/backend/llvm/dense-array-loops.js +162 -0
- package/dist/backend/llvm/dense-array-loops.js.map +1 -0
- package/dist/backend/llvm/dense-array-loops.test.d.ts +1 -0
- package/dist/backend/llvm/dense-array-loops.test.js +128 -0
- package/dist/backend/llvm/dense-array-loops.test.js.map +1 -0
- package/dist/backend/llvm/dyn-handle-tags.test.d.ts +1 -0
- package/dist/backend/llvm/dyn-handle-tags.test.js +38 -0
- package/dist/backend/llvm/dyn-handle-tags.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +28 -4
- package/dist/backend/llvm/dyn.js +293 -178
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emit-function.d.ts +64 -0
- package/dist/backend/llvm/emit-function.js +1190 -0
- package/dist/backend/llvm/emit-function.js.map +1 -0
- package/dist/backend/llvm/emit-module.d.ts +24 -0
- package/dist/backend/llvm/emit-module.js +1535 -0
- package/dist/backend/llvm/emit-module.js.map +1 -0
- package/dist/backend/llvm/emit-statements.d.ts +58 -0
- package/dist/backend/llvm/emit-statements.js +1964 -0
- package/dist/backend/llvm/emit-statements.js.map +1 -0
- package/dist/backend/llvm/emitter.d.ts +547 -283
- package/dist/backend/llvm/emitter.js +689 -4643
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +57 -3
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +73 -46
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-async.test.js +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +2 -0
- package/dist/backend/llvm/expr-bytes.js +76 -29
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +6 -2
- package/dist/backend/llvm/expr-callbacks.js +48 -11
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.d.ts +1 -1
- package/dist/backend/llvm/expr-calls.js +71 -53
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-calls.test.js +1 -1
- package/dist/backend/llvm/expr-containers.js +39 -15
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +16 -16
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.d.ts +3 -0
- package/dist/backend/llvm/expr-dynamic.js +67 -62
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +121 -25
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +2 -2
- package/dist/backend/llvm/expr-records.d.ts +1 -1
- package/dist/backend/llvm/expr-records.js +32 -11
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +54 -12
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +2 -2
- package/dist/backend/llvm/expr-stream-callbacks.js +22 -1
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/int32-abi.test.js +2 -2
- package/dist/backend/llvm/integer-clones.test.js +3 -3
- package/dist/backend/llvm/integer-remainder.d.ts +34 -13
- package/dist/backend/llvm/integer-remainder.js +156 -22
- package/dist/backend/llvm/integer-remainder.js.map +1 -1
- package/dist/backend/llvm/intern-tables.test.js +1 -1
- package/dist/backend/llvm/jsval-encoding.d.ts +21 -0
- package/dist/backend/llvm/jsval-encoding.js +20 -0
- package/dist/backend/llvm/jsval-encoding.js.map +1 -0
- package/dist/backend/llvm/jsval.d.ts +12 -0
- package/dist/backend/llvm/jsval.js +488 -0
- package/dist/backend/llvm/jsval.js.map +1 -0
- package/dist/backend/llvm/lazy-captures.d.ts +12 -2
- package/dist/backend/llvm/lazy-captures.js +39 -17
- package/dist/backend/llvm/lazy-captures.js.map +1 -1
- package/dist/backend/llvm/lib-abi.js +1 -1
- package/dist/backend/llvm/lib-abi.js.map +1 -1
- package/dist/backend/llvm/lib-connect.js +1 -1
- package/dist/backend/llvm/lib-connect.js.map +1 -1
- package/dist/backend/llvm/lib-datagram.js +14 -8
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +189 -23
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +42 -13
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-http2.js +3 -3
- package/dist/backend/llvm/lib-http2.js.map +1 -1
- package/dist/backend/llvm/lib-lookup.js +2 -2
- package/dist/backend/llvm/lib-lookup.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +56 -22
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +90 -50
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.d.ts +12 -0
- package/dist/backend/llvm/lib-shared.js +187 -6
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +46 -16
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +43 -7
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/lib-tls.js +4 -9
- package/dist/backend/llvm/lib-tls.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +2 -2
- package/dist/backend/llvm/local-array-reads.test.js +1 -1
- package/dist/backend/llvm/local-extents.d.ts +19 -0
- package/dist/backend/llvm/local-extents.js +169 -0
- package/dist/backend/llvm/local-extents.js.map +1 -0
- package/dist/backend/llvm/local-extents.test.d.ts +1 -0
- package/dist/backend/llvm/local-extents.test.js +92 -0
- package/dist/backend/llvm/local-extents.test.js.map +1 -0
- package/dist/backend/llvm/local-union-storage.js +7 -7
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +2 -2
- package/dist/backend/llvm/map-entry-fusion.test.js +1 -1
- package/dist/backend/llvm/map-number-lookup.js +2 -2
- package/dist/backend/llvm/map-number-lookup.test.js +2 -2
- package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
- package/dist/backend/llvm/narrow-guards.d.ts +38 -0
- package/dist/backend/llvm/narrow-guards.js +151 -0
- package/dist/backend/llvm/narrow-guards.js.map +1 -0
- package/dist/backend/llvm/nullable-unions.d.ts +64 -6
- package/dist/backend/llvm/nullable-unions.js +103 -6
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.test.d.ts +1 -0
- package/dist/backend/llvm/nullable-unions.test.js +65 -0
- package/dist/backend/llvm/nullable-unions.test.js.map +1 -0
- package/dist/backend/llvm/publish.d.ts +4 -0
- package/dist/backend/llvm/publish.js +14 -2
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/publish.test.js +1 -1
- package/dist/backend/llvm/receivers.d.ts +31 -0
- package/dist/backend/llvm/receivers.js +395 -0
- package/dist/backend/llvm/receivers.js.map +1 -0
- package/dist/backend/llvm/record-results.d.ts +12 -1
- package/dist/backend/llvm/record-results.js +64 -4
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/reference-effects.js +9 -0
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/reference-writes.d.ts +4 -0
- package/dist/backend/llvm/reference-writes.js +142 -6
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/reference-writes.test.d.ts +1 -0
- package/dist/backend/llvm/reference-writes.test.js +88 -0
- package/dist/backend/llvm/reference-writes.test.js.map +1 -0
- package/dist/backend/llvm/regex-matchers.d.ts +8 -0
- package/dist/backend/llvm/regex-matchers.js +33 -0
- package/dist/backend/llvm/regex-matchers.js.map +1 -1
- package/dist/backend/llvm/regex-matchers.test.js +23 -1
- package/dist/backend/llvm/regex-matchers.test.js.map +1 -1
- package/dist/backend/llvm/regions.d.ts +1 -1
- package/dist/backend/llvm/regions.js +9 -6
- package/dist/backend/llvm/regions.js.map +1 -1
- package/dist/backend/llvm/regions.test.js +1 -1
- package/dist/backend/llvm/shapes.d.ts +66 -43
- package/dist/backend/llvm/shapes.js +280 -21
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +37 -3
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/split-loops.js +2 -2
- package/dist/backend/llvm/split-loops.js.map +1 -1
- package/dist/backend/llvm/stack-objects.d.ts +26 -6
- package/dist/backend/llvm/stack-objects.js +133 -10
- package/dist/backend/llvm/stack-objects.js.map +1 -1
- package/dist/backend/llvm/stack-objects.test.js +55 -1
- package/dist/backend/llvm/stack-objects.test.js.map +1 -1
- package/dist/backend/llvm/stack-unions.test.js +1 -1
- package/dist/backend/llvm/string-construction.test.js +1 -1
- package/dist/backend/llvm/string-lifetimes.test.js +15 -14
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-slices.d.ts +25 -0
- package/dist/backend/llvm/string-slices.js +207 -1
- package/dist/backend/llvm/string-slices.js.map +1 -1
- package/dist/backend/llvm/string-slices.test.js +139 -2
- package/dist/backend/llvm/string-slices.test.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.test.js +2 -2
- package/dist/backend/llvm/thread-slots.d.ts +5 -0
- package/dist/backend/llvm/thread-slots.js +142 -0
- package/dist/backend/llvm/thread-slots.js.map +1 -0
- package/dist/backend/llvm/thread-slots.test.d.ts +1 -0
- package/dist/backend/llvm/thread-slots.test.js +110 -0
- package/dist/backend/llvm/thread-slots.test.js.map +1 -0
- package/dist/backend/llvm/union-repr.d.ts +7 -7
- package/dist/backend/llvm/union-repr.js +18 -2
- package/dist/backend/llvm/union-repr.js.map +1 -1
- package/dist/backend/llvm/union-retype.test.js +17 -3
- package/dist/backend/llvm/union-retype.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -2
- package/dist/backend/llvm/walkers.js +51 -26
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/llvm/wasm-modules.d.ts +16 -0
- package/dist/backend/llvm/wasm-modules.js +66 -0
- package/dist/backend/llvm/wasm-modules.js.map +1 -0
- package/dist/backend/llvm/wrapping-sums.d.ts +7 -0
- package/dist/backend/llvm/wrapping-sums.js +11 -3
- package/dist/backend/llvm/wrapping-sums.js.map +1 -1
- package/dist/backend/mangle.d.ts +7 -0
- package/dist/backend/mangle.js +11 -0
- package/dist/backend/mangle.js.map +1 -1
- package/dist/backend/may-throw.d.ts +3 -0
- package/dist/backend/may-throw.js +4 -2
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +1 -1
- package/dist/backend/native/contracts.d.ts +37 -0
- package/dist/backend/native/executable.js +192 -137
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/library.js +1 -0
- package/dist/backend/native/library.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-link-info-core.d.ts +30 -0
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/publication.test.js +1 -1
- package/dist/backend/runtime-pack-core.d.ts +9 -1
- package/dist/backend/runtime-pack-core.js +10 -1
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-native.js +1 -1
- package/dist/backend/runtime-pack-native.js.map +1 -1
- package/dist/backend/runtime-pack-native.test.d.ts +1 -0
- package/dist/backend/runtime-pack-native.test.js +31 -0
- package/dist/backend/runtime-pack-native.test.js.map +1 -0
- package/dist/backend/runtime-pack-targets.test.js +5 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +5 -0
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/stack-observations.d.ts +22 -0
- package/dist/backend/stack-observations.js +382 -0
- package/dist/backend/stack-observations.js.map +1 -0
- package/dist/backend/stack-observations.test.d.ts +1 -0
- package/dist/backend/stack-observations.test.js +233 -0
- package/dist/backend/stack-observations.test.js.map +1 -0
- package/dist/backend/target-diagnostics.js +8 -0
- package/dist/backend/target-diagnostics.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/backend/warm-cache.js +5 -0
- package/dist/backend/warm-cache.js.map +1 -1
- package/dist/backend/young-nursery.d.ts +7 -0
- package/dist/backend/young-nursery.js +10 -0
- package/dist/backend/young-nursery.js.map +1 -0
- package/dist/cli/command.js +44 -4
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/usage.d.ts +11 -1
- package/dist/cli/usage.js +20 -1
- package/dist/cli/usage.js.map +1 -1
- package/dist/compat/fetch-profile.js +10 -1
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/compile-types.d.ts +13 -0
- package/dist/contracts/check.js +24 -6
- package/dist/contracts/check.js.map +1 -1
- package/dist/contracts/int32-elements.d.ts +115 -0
- package/dist/contracts/int32-elements.js +1179 -0
- package/dist/contracts/int32-elements.js.map +1 -0
- package/dist/coverage/report.d.ts +16 -0
- package/dist/coverage/report.js +182 -1
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.js +16 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/coverage/verdict-cache.d.ts +2 -0
- package/dist/coverage/verdict-cache.js +12 -0
- package/dist/coverage/verdict-cache.js.map +1 -1
- package/dist/coverage/verdict-cache.test.js +2 -1
- package/dist/coverage/verdict-cache.test.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +10 -6
- package/dist/diagnostics/diagnostic.js +29 -21
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/envelope.d.ts +39 -2
- package/dist/diagnostics/envelope.js.map +1 -1
- package/dist/diagnostics/render.d.ts +7 -0
- package/dist/diagnostics/render.js +50 -13
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/diagnostics/render.test.d.ts +1 -0
- package/dist/diagnostics/render.test.js +49 -0
- package/dist/diagnostics/render.test.js.map +1 -0
- package/dist/executable/executable-cache.d.ts +17 -0
- package/dist/executable/executable-cache.js +13 -1
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +7 -1
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.js +2 -1
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/analysis.js +6 -1
- package/dist/frontend/analysis.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +16 -2
- package/dist/frontend/builtin-modules.js +40 -7
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/cjs-syntax.js +52 -51
- package/dist/frontend/cjs-syntax.js.map +1 -1
- package/dist/frontend/contract-types.d.ts +3 -0
- package/dist/frontend/contract-types.js +36 -7
- package/dist/frontend/contract-types.js.map +1 -1
- package/dist/frontend/experimental-import.d.ts +5 -1
- package/dist/frontend/experimental-import.js +26 -7
- package/dist/frontend/experimental-import.js.map +1 -1
- package/dist/frontend/fork-target.js +20 -22
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/fork-target.test.js +2 -1
- package/dist/frontend/fork-target.test.js.map +1 -1
- package/dist/frontend/function-completion.js +6 -6
- package/dist/frontend/function-completion.js.map +1 -1
- package/dist/frontend/helper-tokens.js +15 -3
- package/dist/frontend/helper-tokens.js.map +1 -1
- package/dist/frontend/helper-tokens.test.js +7 -1
- package/dist/frontend/helper-tokens.test.js.map +1 -1
- package/dist/frontend/inferred-js-diagnostics.js +14 -17
- package/dist/frontend/inferred-js-diagnostics.js.map +1 -1
- package/dist/frontend/input-tracker.d.ts +3 -0
- package/dist/frontend/input-tracker.js +32 -3
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/lib-contract.js +36 -32
- package/dist/frontend/lib-contract.js.map +1 -1
- package/dist/frontend/lib-exports.js +3 -3
- package/dist/frontend/lib-exports.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +8 -3
- package/dist/frontend/lowering/array-values.js +60 -11
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/assert-instances.js +4 -4
- package/dist/frontend/lowering/assert-instances.js.map +1 -1
- package/dist/frontend/lowering/assertion-identity.d.ts +12 -0
- package/dist/frontend/lowering/assertion-identity.js +70 -0
- package/dist/frontend/lowering/assertion-identity.js.map +1 -0
- package/dist/frontend/lowering/assertion-members.d.ts +28 -0
- package/dist/frontend/lowering/assertion-members.js +185 -0
- package/dist/frontend/lowering/assertion-members.js.map +1 -0
- package/dist/frontend/lowering/binding-analysis.js +27 -20
- package/dist/frontend/lowering/binding-analysis.js.map +1 -1
- package/dist/frontend/lowering/builtin-calls.js +63 -5
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtin-function-fences.d.ts +14 -0
- package/dist/frontend/lowering/builtin-function-fences.js +42 -0
- package/dist/frontend/lowering/builtin-function-fences.js.map +1 -0
- package/dist/frontend/lowering/builtins/arguments.js +1 -1
- package/dist/frontend/lowering/builtins/arguments.js.map +1 -1
- package/dist/frontend/lowering/builtins/async-context.js +53 -52
- package/dist/frontend/lowering/builtins/async-context.js.map +1 -1
- package/dist/frontend/lowering/builtins/atomics.js +6 -6
- package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
- package/dist/frontend/lowering/builtins/blob.js +8 -6
- package/dist/frontend/lowering/builtins/blob.js.map +1 -1
- package/dist/frontend/lowering/builtins/builtin-class-dyn.d.ts +23 -0
- package/dist/frontend/lowering/builtins/builtin-class-dyn.js +156 -0
- package/dist/frontend/lowering/builtins/builtin-class-dyn.js.map +1 -0
- package/dist/frontend/lowering/builtins/callable-aliases.js +16 -5
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-async.js +7 -7
- package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-methods.d.ts +6 -4
- package/dist/frontend/lowering/builtins/child-process-methods.js +310 -57
- package/dist/frontend/lowering/builtins/child-process-methods.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-sync.js +16 -10
- package/dist/frontend/lowering/builtins/child-process-sync.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process.d.ts +6 -4
- package/dist/frontend/lowering/builtins/child-process.js +85 -61
- package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
- package/dist/frontend/lowering/builtins/class-values.d.ts +60 -0
- package/dist/frontend/lowering/builtins/class-values.js +226 -0
- package/dist/frontend/lowering/builtins/class-values.js.map +1 -0
- package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
- package/dist/frontend/lowering/builtins/compression.js +107 -44
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/constants.d.ts +9 -1
- package/dist/frontend/lowering/builtins/constants.js +28 -7
- package/dist/frontend/lowering/builtins/constants.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.d.ts +19 -0
- package/dist/frontend/lowering/builtins/crypto.js +211 -37
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/dates.d.ts +7 -1
- package/dist/frontend/lowering/builtins/dates.js +92 -16
- package/dist/frontend/lowering/builtins/dates.js.map +1 -1
- package/dist/frontend/lowering/builtins/disposable-stack.d.ts +18 -0
- package/dist/frontend/lowering/builtins/disposable-stack.js +137 -0
- package/dist/frontend/lowering/builtins/disposable-stack.js.map +1 -0
- package/dist/frontend/lowering/builtins/environment.js +3 -3
- package/dist/frontend/lowering/builtins/environment.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.d.ts +14 -10
- package/dist/frontend/lowering/builtins/errors.js +169 -3
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.js +128 -116
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.js +77 -77
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-glob.js +3 -3
- package/dist/frontend/lowering/builtins/fs-glob.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-streams.js +10 -11
- package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -1
- package/dist/frontend/lowering/builtins/ipc.js +45 -8
- package/dist/frontend/lowering/builtins/ipc.js.map +1 -1
- package/dist/frontend/lowering/builtins/json.js +232 -24
- package/dist/frontend/lowering/builtins/json.js.map +1 -1
- package/dist/frontend/lowering/builtins/key-object.js +4 -4
- package/dist/frontend/lowering/builtins/key-object.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-bindings.d.ts +8 -0
- package/dist/frontend/lowering/builtins/module-bindings.js +71 -22
- package/dist/frontend/lowering/builtins/module-bindings.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-calls.js +55 -44
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-resolution.d.ts +4 -3
- package/dist/frontend/lowering/builtins/module-resolution.js +24 -23
- package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
- package/dist/frontend/lowering/builtins/navigator.d.ts +13 -0
- package/dist/frontend/lowering/builtins/navigator.js +40 -0
- package/dist/frontend/lowering/builtins/navigator.js.map +1 -0
- package/dist/frontend/lowering/builtins/net-address.d.ts +19 -0
- package/dist/frontend/lowering/builtins/net-address.js +156 -0
- package/dist/frontend/lowering/builtins/net-address.js.map +1 -0
- package/dist/frontend/lowering/builtins/numbers.js +25 -9
- package/dist/frontend/lowering/builtins/numbers.js.map +1 -1
- package/dist/frontend/lowering/builtins/operating-system.d.ts +4 -0
- package/dist/frontend/lowering/builtins/operating-system.js +25 -12
- package/dist/frontend/lowering/builtins/operating-system.js.map +1 -1
- package/dist/frontend/lowering/builtins/performance.d.ts +12 -0
- package/dist/frontend/lowering/builtins/performance.js +259 -8
- package/dist/frontend/lowering/builtins/performance.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.d.ts +32 -1
- package/dist/frontend/lowering/builtins/process.js +461 -99
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.d.ts +5 -1
- package/dist/frontend/lowering/builtins/promises.js +326 -43
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/promisify-callback.d.ts +37 -0
- package/dist/frontend/lowering/builtins/promisify-callback.js +320 -0
- package/dist/frontend/lowering/builtins/promisify-callback.js.map +1 -0
- package/dist/frontend/lowering/builtins/properties.js +37 -1
- package/dist/frontend/lowering/builtins/properties.js.map +1 -1
- package/dist/frontend/lowering/builtins/querystring.js +14 -14
- package/dist/frontend/lowering/builtins/querystring.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +12 -2
- package/dist/frontend/lowering/builtins/readline.js +136 -39
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/receiver-types.js +3 -5
- package/dist/frontend/lowering/builtins/receiver-types.js.map +1 -1
- package/dist/frontend/lowering/builtins/reflection.js +16 -14
- package/dist/frontend/lowering/builtins/reflection.js.map +1 -1
- package/dist/frontend/lowering/builtins/runtime-constructor.d.ts +26 -0
- package/dist/frontend/lowering/builtins/runtime-constructor.js +165 -0
- package/dist/frontend/lowering/builtins/runtime-constructor.js.map +1 -0
- package/dist/frontend/lowering/builtins/strings.js +101 -12
- package/dist/frontend/lowering/builtins/strings.js.map +1 -1
- package/dist/frontend/lowering/builtins/text-codecs.js +41 -38
- package/dist/frontend/lowering/builtins/text-codecs.js.map +1 -1
- package/dist/frontend/lowering/builtins/timers.js +75 -30
- package/dist/frontend/lowering/builtins/timers.js.map +1 -1
- package/dist/frontend/lowering/builtins/url.d.ts +3 -0
- package/dist/frontend/lowering/builtins/url.js +120 -17
- package/dist/frontend/lowering/builtins/url.js.map +1 -1
- package/dist/frontend/lowering/builtins/util-types.js +20 -4
- package/dist/frontend/lowering/builtins/util-types.js.map +1 -1
- package/dist/frontend/lowering/builtins/v8.d.ts +11 -0
- package/dist/frontend/lowering/builtins/v8.js +105 -0
- package/dist/frontend/lowering/builtins/v8.js.map +1 -0
- package/dist/frontend/lowering/builtins/webassembly.d.ts +33 -0
- package/dist/frontend/lowering/builtins/webassembly.js +388 -0
- package/dist/frontend/lowering/builtins/webassembly.js.map +1 -0
- package/dist/frontend/lowering/builtins/webcrypto.d.ts +20 -0
- package/dist/frontend/lowering/builtins/webcrypto.js +112 -0
- package/dist/frontend/lowering/builtins/webcrypto.js.map +1 -0
- package/dist/frontend/lowering/builtins/workers.d.ts +12 -0
- package/dist/frontend/lowering/builtins/workers.js +193 -8
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.js +69 -14
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/call-signatures.d.ts +19 -1
- package/dist/frontend/lowering/call-signatures.js +254 -47
- package/dist/frontend/lowering/call-signatures.js.map +1 -1
- package/dist/frontend/lowering/checked-promise-all.d.ts +3 -0
- package/dist/frontend/lowering/checked-promise-all.js +1 -1
- package/dist/frontend/lowering/checked-promise-all.js.map +1 -1
- package/dist/frontend/lowering/cjs-exports-object.d.ts +53 -0
- package/dist/frontend/lowering/cjs-exports-object.js +528 -0
- package/dist/frontend/lowering/cjs-exports-object.js.map +1 -0
- package/dist/frontend/lowering/cjs-inline-require.d.ts +86 -0
- package/dist/frontend/lowering/cjs-inline-require.js +314 -0
- package/dist/frontend/lowering/cjs-inline-require.js.map +1 -0
- package/dist/frontend/lowering/cjs-tsc-interop.d.ts +28 -0
- package/dist/frontend/lowering/cjs-tsc-interop.js +208 -0
- package/dist/frontend/lowering/cjs-tsc-interop.js.map +1 -0
- package/dist/frontend/lowering/class-attributes.d.ts +19 -0
- package/dist/frontend/lowering/class-attributes.js +378 -0
- package/dist/frontend/lowering/class-attributes.js.map +1 -0
- package/dist/frontend/lowering/class-callbacks.d.ts +3 -1
- package/dist/frontend/lowering/class-callbacks.js +21 -10
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-construction.js +49 -4
- package/dist/frontend/lowering/class-construction.js.map +1 -1
- package/dist/frontend/lowering/class-descriptors.d.ts +2 -0
- package/dist/frontend/lowering/class-descriptors.js +8 -8
- package/dist/frontend/lowering/class-descriptors.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +64 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +1115 -89
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js +1 -1
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -1
- package/dist/frontend/lowering/class-iterables.d.ts +11 -0
- package/dist/frontend/lowering/class-iterables.js +31 -0
- package/dist/frontend/lowering/class-iterables.js.map +1 -0
- package/dist/frontend/lowering/class-method-mutations.js +73 -35
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -1
- package/dist/frontend/lowering/class-method-values.js +56 -10
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-protocol-dispatch.js +24 -22
- package/dist/frontend/lowering/class-protocol-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.js +25 -44
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/class-prototypes.d.ts +6 -0
- package/dist/frontend/lowering/class-prototypes.js +80 -18
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-runtime-statics.js +1 -1
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -1
- package/dist/frontend/lowering/class-static-data.js +2 -2
- package/dist/frontend/lowering/class-static-data.js.map +1 -1
- package/dist/frontend/lowering/class-to-primitive.d.ts +25 -0
- package/dist/frontend/lowering/class-to-primitive.js +261 -0
- package/dist/frontend/lowering/class-to-primitive.js.map +1 -0
- package/dist/frontend/lowering/class-unions.d.ts +25 -0
- package/dist/frontend/lowering/class-unions.js +102 -1
- package/dist/frontend/lowering/class-unions.js.map +1 -1
- package/dist/frontend/lowering/code-generation.d.ts +14 -0
- package/dist/frontend/lowering/code-generation.js +127 -0
- package/dist/frontend/lowering/code-generation.js.map +1 -0
- package/dist/frontend/lowering/coercions/function-adapters.d.ts +16 -2
- package/dist/frontend/lowering/coercions/function-adapters.js +145 -3
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural-plans.js +25 -3
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +35 -3
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/coercions/unions.d.ts +15 -0
- package/dist/frontend/lowering/coercions/unions.js +57 -1
- package/dist/frontend/lowering/coercions/unions.js.map +1 -1
- package/dist/frontend/lowering/collection-ingestion.js +2 -2
- package/dist/frontend/lowering/collection-ingestion.js.map +1 -1
- package/dist/frontend/lowering/collection-narrowing.js +2 -4
- package/dist/frontend/lowering/collection-narrowing.js.map +1 -1
- package/dist/frontend/lowering/construction-escapes.js +8 -8
- package/dist/frontend/lowering/construction-escapes.js.map +1 -1
- package/dist/frontend/lowering/construction-escapes.test.js +4 -4
- package/dist/frontend/lowering/construction-escapes.test.js.map +1 -1
- package/dist/frontend/lowering/constructor-returns.d.ts +61 -0
- package/dist/frontend/lowering/constructor-returns.js +477 -0
- package/dist/frontend/lowering/constructor-returns.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callback-call.js +1 -1
- package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.d.ts +9 -0
- package/dist/frontend/lowering/containers/array-callbacks.js +266 -100
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-concat.js +1 -1
- package/dist/frontend/lowering/containers/array-concat.js.map +1 -1
- package/dist/frontend/lowering/containers/array-construction.d.ts +0 -1
- package/dist/frontend/lowering/containers/array-construction.js +51 -13
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-from-async.d.ts +6 -5
- package/dist/frontend/lowering/containers/array-from-async.js +159 -14
- package/dist/frontend/lowering/containers/array-from-async.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.js +89 -77
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/array-pipelines.js +1 -0
- package/dist/frontend/lowering/containers/array-pipelines.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +161 -101
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/callback-arguments.d.ts +9 -1
- package/dist/frontend/lowering/containers/callback-arguments.js +55 -5
- package/dist/frontend/lowering/containers/callback-arguments.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-grouping.d.ts +7 -8
- package/dist/frontend/lowering/containers/collection-grouping.js +217 -26
- package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +54 -25
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/dynamic-receivers.js +1 -1
- package/dist/frontend/lowering/containers/dynamic-receivers.js.map +1 -1
- package/dist/frontend/lowering/containers/exec-result-uses.js +2 -2
- package/dist/frontend/lowering/containers/exec-result-uses.js.map +1 -1
- package/dist/frontend/lowering/containers/for-of.d.ts +6 -0
- package/dist/frontend/lowering/containers/for-of.js +19 -19
- package/dist/frontend/lowering/containers/for-of.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +142 -57
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/containers/iterator-helpers.d.ts +53 -4
- package/dist/frontend/lowering/containers/iterator-helpers.js +1581 -462
- package/dist/frontend/lowering/containers/iterator-helpers.js.map +1 -1
- package/dist/frontend/lowering/containers/match-row-uses.d.ts +17 -0
- package/dist/frontend/lowering/containers/match-row-uses.js +264 -0
- package/dist/frontend/lowering/containers/match-row-uses.js.map +1 -0
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +14 -0
- package/dist/frontend/lowering/containers/string-and-regexp.js +419 -30
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/containers/string-replacement.js +1 -1
- package/dist/frontend/lowering/containers/string-replacement.js.map +1 -1
- package/dist/frontend/lowering/cycle-initialization.d.ts +4 -0
- package/dist/frontend/lowering/cycle-initialization.js +39 -0
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -1
- package/dist/frontend/lowering/deferred-module-initializers.js +47 -43
- package/dist/frontend/lowering/deferred-module-initializers.js.map +1 -1
- package/dist/frontend/lowering/devirtualize.d.ts +1 -1
- package/dist/frontend/lowering/devirtualize.js +27 -7
- package/dist/frontend/lowering/devirtualize.js.map +1 -1
- package/dist/frontend/lowering/divergences.d.ts +0 -5
- package/dist/frontend/lowering/divergences.js +62 -125
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/dyn-streams.d.ts +25 -0
- package/dist/frontend/lowering/dyn-streams.js +257 -0
- package/dist/frontend/lowering/dyn-streams.js.map +1 -0
- package/dist/frontend/lowering/error-methods.js +4 -1
- package/dist/frontend/lowering/error-methods.js.map +1 -1
- package/dist/frontend/lowering/error-name-order.d.ts +19 -0
- package/dist/frontend/lowering/error-name-order.js +93 -0
- package/dist/frontend/lowering/error-name-order.js.map +1 -0
- package/dist/frontend/lowering/expressions/array-literals.d.ts +21 -0
- package/dist/frontend/lowering/expressions/array-literals.js +703 -0
- package/dist/frontend/lowering/expressions/array-literals.js.map +1 -0
- package/dist/frontend/lowering/expressions/binary.d.ts +35 -0
- package/dist/frontend/lowering/expressions/binary.js +2483 -0
- package/dist/frontend/lowering/expressions/binary.js.map +1 -0
- package/dist/frontend/lowering/expressions/element-access.d.ts +31 -0
- package/dist/frontend/lowering/expressions/element-access.js +1797 -0
- package/dist/frontend/lowering/expressions/element-access.js.map +1 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -3
- package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
- package/dist/frontend/lowering/expressions/hosted-narrowing.d.ts +38 -0
- package/dist/frontend/lowering/expressions/hosted-narrowing.js +160 -0
- package/dist/frontend/lowering/expressions/hosted-narrowing.js.map +1 -0
- package/dist/frontend/lowering/expressions/identifiers.d.ts +4 -0
- package/dist/frontend/lowering/expressions/identifiers.js +830 -0
- package/dist/frontend/lowering/expressions/identifiers.js.map +1 -0
- package/dist/frontend/lowering/expressions/keyed-field-targets.d.ts +40 -0
- package/dist/frontend/lowering/expressions/keyed-field-targets.js +226 -0
- package/dist/frontend/lowering/expressions/keyed-field-targets.js.map +1 -0
- package/dist/frontend/lowering/expressions/narrowing.d.ts +37 -0
- package/dist/frontend/lowering/expressions/narrowing.js +1322 -0
- package/dist/frontend/lowering/expressions/narrowing.js.map +1 -0
- package/dist/frontend/lowering/expressions/native-proxy.js +4 -4
- package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -1
- package/dist/frontend/lowering/expressions/nullish-assignment.js +45 -0
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.d.ts +10 -0
- package/dist/frontend/lowering/expressions/object-literals.js +253 -85
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +2 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +91 -14
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/expressions/property-access.d.ts +110 -0
- package/dist/frontend/lowering/expressions/property-access.js +3544 -0
- package/dist/frontend/lowering/expressions/property-access.js.map +1 -0
- package/dist/frontend/lowering/expressions/relational.d.ts +28 -0
- package/dist/frontend/lowering/expressions/relational.js +1679 -0
- package/dist/frontend/lowering/expressions/relational.js.map +1 -0
- package/dist/frontend/lowering/expressions/typeof.d.ts +22 -0
- package/dist/frontend/lowering/expressions/typeof.js +538 -0
- package/dist/frontend/lowering/expressions/typeof.js.map +1 -0
- package/dist/frontend/lowering/expressions/union-fields.js +1 -1
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
- package/dist/frontend/lowering/expressions/updates.d.ts +21 -0
- package/dist/frontend/lowering/expressions/updates.js +780 -0
- package/dist/frontend/lowering/expressions/updates.js.map +1 -0
- package/dist/frontend/lowering/function-context.d.ts +10 -0
- package/dist/frontend/lowering/function-context.js +11 -1
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/function-returns.js +52 -28
- package/dist/frontend/lowering/function-returns.js.map +1 -1
- package/dist/frontend/lowering/general-streams.d.ts +25 -0
- package/dist/frontend/lowering/general-streams.js +108 -0
- package/dist/frontend/lowering/general-streams.js.map +1 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +7 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js +172 -69
- package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.d.ts +39 -0
- package/dist/frontend/lowering/generic-functions.js +393 -75
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/import-meta.js +2 -2
- package/dist/frontend/lowering/import-meta.js.map +1 -1
- package/dist/frontend/lowering/intern-tables.js +10 -9
- package/dist/frontend/lowering/intern-tables.js.map +1 -1
- package/dist/frontend/lowering/iterator-adapters.d.ts +19 -0
- package/dist/frontend/lowering/iterator-adapters.js +331 -3
- package/dist/frontend/lowering/iterator-adapters.js.map +1 -1
- package/dist/frontend/lowering/js-class-fields.d.ts +28 -0
- package/dist/frontend/lowering/js-class-fields.js +170 -0
- package/dist/frontend/lowering/js-class-fields.js.map +1 -0
- package/dist/frontend/lowering/js-dynamic-objects.d.ts +15 -0
- package/dist/frontend/lowering/js-dynamic-objects.js +299 -0
- package/dist/frontend/lowering/js-dynamic-objects.js.map +1 -0
- package/dist/frontend/lowering/js-dynamic-objects.test.d.ts +1 -0
- package/dist/frontend/lowering/js-dynamic-objects.test.js +35 -0
- package/dist/frontend/lowering/js-dynamic-objects.test.js.map +1 -0
- package/dist/frontend/lowering/json-require.d.ts +22 -0
- package/dist/frontend/lowering/json-require.js +131 -0
- package/dist/frontend/lowering/json-require.js.map +1 -0
- package/dist/frontend/lowering/key-order-witness.d.ts +44 -0
- package/dist/frontend/lowering/key-order-witness.js +641 -0
- package/dist/frontend/lowering/key-order-witness.js.map +1 -0
- package/dist/frontend/lowering/key-order-witness.test.d.ts +1 -0
- package/dist/frontend/lowering/key-order-witness.test.js +239 -0
- package/dist/frontend/lowering/key-order-witness.test.js.map +1 -0
- package/dist/frontend/lowering/lifetime-regions.js +7 -7
- package/dist/frontend/lowering/lifetime-regions.js.map +1 -1
- package/dist/frontend/lowering/lower-assert.js +61 -60
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.d.ts +10 -1
- package/dist/frontend/lowering/lower-async-iteration.js +34 -6
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +5 -0
- package/dist/frontend/lowering/lower-builtin-values.js +32 -3
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +1239 -442
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +50 -3
- package/dist/frontend/lowering/lower-classes.js +1473 -468
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.d.ts +4 -2
- package/dist/frontend/lowering/lower-comptime.js +111 -13
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-console.js +13 -11
- package/dist/frontend/lowering/lower-console.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.d.ts +10 -0
- package/dist/frontend/lowering/lower-dgram.js +179 -8
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-enums.js +113 -14
- package/dist/frontend/lowering/lower-enums.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +16 -7
- package/dist/frontend/lowering/lower-event-emitter.js +258 -70
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-event-target.js +2 -2
- package/dist/frontend/lowering/lower-event-target.js.map +1 -1
- package/dist/frontend/lowering/lower-expando.js +17 -13
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +188 -186
- package/dist/frontend/lowering/lower-exprs.js +1481 -12489
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +68 -22
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +6 -0
- package/dist/frontend/lowering/lower-generators.js +29 -16
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-global-value.js +5 -1
- package/dist/frontend/lowering/lower-global-value.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +331 -96
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.js +23 -20
- package/dist/frontend/lowering/lower-mixins.js.map +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +8 -1
- package/dist/frontend/lowering/lower-mock.js +185 -18
- package/dist/frontend/lowering/lower-mock.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +267 -61
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +6 -0
- package/dist/frontend/lowering/lower-namespaces.js +45 -33
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-node-module.d.ts +16 -0
- package/dist/frontend/lowering/lower-node-module.js +147 -14
- package/dist/frontend/lowering/lower-node-module.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +6 -6
- package/dist/frontend/lowering/lower-server.js +488 -100
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.d.ts +4 -0
- package/dist/frontend/lowering/lower-stdlib.js +151 -109
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +28 -2
- package/dist/frontend/lowering/lower-stmts.js +1541 -391
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +3 -0
- package/dist/frontend/lowering/lower-stream.js +398 -56
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.d.ts +3 -0
- package/dist/frontend/lowering/lower-test.js +437 -62
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lower-timers.js +80 -32
- package/dist/frontend/lowering/lower-timers.js.map +1 -1
- package/dist/frontend/lowering/lower-url.js +1 -1
- package/dist/frontend/lowering/lower-url.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +399 -26
- package/dist/frontend/lowering/lowerer.js +1910 -305
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.js +10 -4
- package/dist/frontend/lowering/lowerer.test.js.map +1 -1
- package/dist/frontend/lowering/maybe-promise.d.ts +46 -0
- package/dist/frontend/lowering/maybe-promise.js +249 -0
- package/dist/frontend/lowering/maybe-promise.js.map +1 -0
- package/dist/frontend/lowering/module-member-this.d.ts +3 -0
- package/dist/frontend/lowering/module-member-this.js +262 -0
- package/dist/frontend/lowering/module-member-this.js.map +1 -0
- package/dist/frontend/lowering/module-namespace-elements.js +1 -1
- package/dist/frontend/lowering/module-namespace-elements.js.map +1 -1
- package/dist/frontend/lowering/nan-coded-reads.d.ts +3 -0
- package/dist/frontend/lowering/nan-coded-reads.js +45 -32
- package/dist/frontend/lowering/nan-coded-reads.js.map +1 -1
- package/dist/frontend/lowering/narrowing-stability.d.ts +18 -3
- package/dist/frontend/lowering/narrowing-stability.js +104 -32
- package/dist/frontend/lowering/narrowing-stability.js.map +1 -1
- package/dist/frontend/lowering/native-ffi.js +11 -11
- package/dist/frontend/lowering/native-ffi.js.map +1 -1
- package/dist/frontend/lowering/object-factory-new.js +6 -8
- package/dist/frontend/lowering/object-factory-new.js.map +1 -1
- package/dist/frontend/lowering/private-brands.d.ts +46 -0
- package/dist/frontend/lowering/private-brands.js +265 -0
- package/dist/frontend/lowering/private-brands.js.map +1 -0
- package/dist/frontend/lowering/promise-executor-adapter.d.ts +11 -0
- package/dist/frontend/lowering/promise-executor-adapter.js +87 -0
- package/dist/frontend/lowering/promise-executor-adapter.js.map +1 -0
- package/dist/frontend/lowering/require-initialization.d.ts +32 -0
- package/dist/frontend/lowering/require-initialization.js +246 -0
- package/dist/frontend/lowering/require-initialization.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-bounds.js +7 -7
- package/dist/frontend/lowering/runtime-optional-bounds.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-elements.js +12 -12
- package/dist/frontend/lowering/runtime-optional-elements.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-guards.js +10 -10
- package/dist/frontend/lowering/runtime-optional-guards.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-guards.test.js +1 -1
- package/dist/frontend/lowering/runtime-optional-guards.test.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-ownership.js +10 -9
- package/dist/frontend/lowering/runtime-optional-ownership.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-provenance.js +2 -2
- package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-records.d.ts +35 -0
- package/dist/frontend/lowering/runtime-optional-records.js +205 -32
- package/dist/frontend/lowering/runtime-optional-records.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-records.test.js +19 -1
- package/dist/frontend/lowering/runtime-optional-records.test.js.map +1 -1
- package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
- package/dist/frontend/lowering/split-consumers.js +4 -4
- package/dist/frontend/lowering/split-consumers.js.map +1 -1
- package/dist/frontend/lowering/static-function-names.d.ts +28 -0
- package/dist/frontend/lowering/static-function-names.js +212 -0
- package/dist/frontend/lowering/static-function-names.js.map +1 -0
- package/dist/frontend/lowering/static-this.js +6 -6
- package/dist/frontend/lowering/static-this.js.map +1 -1
- package/dist/frontend/lowering/strict-mode.d.ts +5 -0
- package/dist/frontend/lowering/strict-mode.js +31 -0
- package/dist/frontend/lowering/strict-mode.js.map +1 -0
- package/dist/frontend/lowering/string-index-bounds.js +10 -10
- package/dist/frontend/lowering/string-index-bounds.js.map +1 -1
- package/dist/frontend/lowering/string-index.d.ts +12 -0
- package/dist/frontend/lowering/string-index.js +72 -1
- package/dist/frontend/lowering/string-index.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +12 -3
- package/dist/frontend/lowering/surfaces.js +252 -41
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/symbol-fields.d.ts +7 -0
- package/dist/frontend/lowering/symbol-fields.js +204 -36
- package/dist/frontend/lowering/symbol-fields.js.map +1 -1
- package/dist/frontend/lowering/symbol-methods.d.ts +2 -1
- package/dist/frontend/lowering/symbol-methods.js +24 -6
- package/dist/frontend/lowering/symbol-methods.js.map +1 -1
- package/dist/frontend/lowering/thread-slots.d.ts +13 -0
- package/dist/frontend/lowering/thread-slots.js +208 -0
- package/dist/frontend/lowering/thread-slots.js.map +1 -0
- package/dist/frontend/lowering/typed-arguments.d.ts +74 -0
- package/dist/frontend/lowering/typed-arguments.js +472 -0
- package/dist/frontend/lowering/typed-arguments.js.map +1 -0
- package/dist/frontend/lowering/union-retag.d.ts +8 -0
- package/dist/frontend/lowering/union-retag.js +27 -0
- package/dist/frontend/lowering/union-retag.js.map +1 -1
- package/dist/frontend/lowering/union-retag.test.js +24 -1
- package/dist/frontend/lowering/union-retag.test.js.map +1 -1
- package/dist/frontend/lowering/var-hoisting.js +6 -6
- package/dist/frontend/lowering/var-hoisting.js.map +1 -1
- package/dist/frontend/lowering/width-lift.d.ts +4 -0
- package/dist/frontend/mock-shapes.js +13 -6
- package/dist/frontend/mock-shapes.js.map +1 -1
- package/dist/frontend/module-source-candidates.js +1 -1
- package/dist/frontend/module-source-candidates.js.map +1 -1
- package/dist/frontend/module-source-candidates.test.js +2 -1
- package/dist/frontend/module-source-candidates.test.js.map +1 -1
- package/dist/frontend/module-syntax.js +8 -8
- package/dist/frontend/module-syntax.js.map +1 -1
- package/dist/frontend/npm-static-bundled-chunks.d.ts +51 -0
- package/dist/frontend/npm-static-bundled-chunks.js +810 -0
- package/dist/frontend/npm-static-bundled-chunks.js.map +1 -0
- package/dist/frontend/npm-static-bundled-chunks.test.d.ts +1 -0
- package/dist/frontend/npm-static-bundled-chunks.test.js +287 -0
- package/dist/frontend/npm-static-bundled-chunks.test.js.map +1 -0
- package/dist/frontend/npm-static-bundled-cjs.js +24 -23
- package/dist/frontend/npm-static-bundled-cjs.js.map +1 -1
- package/dist/frontend/npm-static-bundled-esm.d.ts +9 -0
- package/dist/frontend/npm-static-bundled-esm.js +768 -0
- package/dist/frontend/npm-static-bundled-esm.js.map +1 -0
- package/dist/frontend/npm-static-bundled-esm.test.d.ts +1 -0
- package/dist/frontend/npm-static-bundled-esm.test.js +207 -0
- package/dist/frontend/npm-static-bundled-esm.test.js.map +1 -0
- package/dist/frontend/npm-static-cjs-exports-alias.d.ts +2 -0
- package/dist/frontend/npm-static-cjs-exports-alias.js +186 -0
- package/dist/frontend/npm-static-cjs-exports-alias.js.map +1 -0
- package/dist/frontend/npm-static-cjs-exports-alias.test.d.ts +1 -0
- package/dist/frontend/npm-static-cjs-exports-alias.test.js +73 -0
- package/dist/frontend/npm-static-cjs-exports-alias.test.js.map +1 -0
- package/dist/frontend/npm-static-cjs-exports-var.d.ts +2 -0
- package/dist/frontend/npm-static-cjs-exports-var.js +236 -0
- package/dist/frontend/npm-static-cjs-exports-var.js.map +1 -0
- package/dist/frontend/npm-static-declaration-syntax.js +102 -101
- package/dist/frontend/npm-static-declaration-syntax.js.map +1 -1
- package/dist/frontend/npm-static-prune.js +36 -24
- package/dist/frontend/npm-static-prune.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-host.d.ts +4 -1
- package/dist/frontend/npm-static-rewrite-host.js +14 -3
- package/dist/frontend/npm-static-rewrite-host.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-syntax.d.ts +19 -0
- package/dist/frontend/npm-static-rewrite-syntax.js +274 -101
- package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -1
- package/dist/frontend/npm-static-subtyping.js +7 -9
- package/dist/frontend/npm-static-subtyping.js.map +1 -1
- package/dist/frontend/npm-static.d.ts +17 -1
- package/dist/frontend/npm-static.js +167 -16
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm-static.test.js +22 -1
- package/dist/frontend/npm-static.test.js.map +1 -1
- package/dist/frontend/pipeline.js +164 -26
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/pipeline.test.js +22 -1
- package/dist/frontend/pipeline.test.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +6 -1
- package/dist/frontend/program-analysis.js +7 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.d.ts +92 -2
- package/dist/frontend/program.js +1557 -255
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +76 -6
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/resolve.js +36 -2
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/resolve.test.js +49 -0
- package/dist/frontend/resolve.test.js.map +1 -1
- package/dist/frontend/services.d.ts +20 -1
- package/dist/frontend/services.js +40 -3
- package/dist/frontend/services.js.map +1 -1
- package/dist/frontend/services.test.js +2 -1
- package/dist/frontend/services.test.js.map +1 -1
- package/dist/frontend/threads-import.js +1 -1
- package/dist/frontend/threads-import.js.map +1 -1
- package/dist/frontend/tier-analysis.d.ts +71 -0
- package/dist/frontend/tier-analysis.js +522 -0
- package/dist/frontend/tier-analysis.js.map +1 -0
- package/dist/frontend/ts7/api-conformance.d.ts +234 -0
- package/dist/frontend/ts7/api-conformance.js +7 -0
- package/dist/frontend/ts7/api-conformance.js.map +1 -0
- package/dist/frontend/ts7/ast-guards.generated.js +2 -1
- package/dist/frontend/ts7/ast-guards.generated.js.map +1 -1
- package/dist/frontend/ts7/ast-node.d.ts +47 -25
- package/dist/frontend/ts7/ast-node.js +64 -18
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +36 -12
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/ts7/ast-types.d.ts +10 -3
- package/dist/frontend/ts7/ast-types.generated.d.ts +39 -39
- package/dist/frontend/ts7/ast.d.ts +1 -0
- package/dist/frontend/ts7/ast.js +3 -2
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/checker-backend.d.ts +23 -0
- package/dist/frontend/ts7/checker-backend.js +88 -0
- package/dist/frontend/ts7/checker-backend.js.map +1 -0
- package/dist/frontend/ts7/checker-backend.test.d.ts +1 -0
- package/dist/frontend/ts7/checker-backend.test.js +63 -0
- package/dist/frontend/ts7/checker-backend.test.js.map +1 -0
- package/dist/frontend/ts7/checker-cache.d.ts +0 -3
- package/dist/frontend/ts7/checker-cache.js +0 -6
- package/dist/frontend/ts7/checker-cache.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +18 -11
- package/dist/frontend/ts7/checker.js +42 -55
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.js +10 -7
- package/dist/frontend/ts7/checker.test.js.map +1 -1
- package/dist/frontend/ts7/diagnostic.d.ts +19 -0
- package/dist/frontend/ts7/diagnostic.js +22 -0
- package/dist/frontend/ts7/diagnostic.js.map +1 -0
- package/dist/frontend/ts7/node-functions.d.ts +8 -0
- package/dist/frontend/ts7/node-functions.js +18 -0
- package/dist/frontend/ts7/node-functions.js.map +1 -0
- package/dist/frontend/ts7/program-host.d.ts +5 -1
- package/dist/frontend/ts7/program-host.js +12 -0
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/rpc-api.d.ts +5 -1
- package/dist/frontend/ts7/rpc-api.js +8 -1
- package/dist/frontend/ts7/rpc-api.js.map +1 -1
- package/dist/frontend/ts7/semantic-checker.d.ts +13 -6
- package/dist/frontend/ts7/semantic-checker.js +26 -8
- package/dist/frontend/ts7/semantic-checker.js.map +1 -1
- package/dist/frontend/ts7/semantic-checker.test.js +12 -9
- package/dist/frontend/ts7/semantic-checker.test.js.map +1 -1
- package/dist/frontend/ts7/semantic-model.d.ts +54 -24
- package/dist/frontend/ts7/semantic-model.js +88 -16
- package/dist/frontend/ts7/semantic-model.js.map +1 -1
- package/dist/frontend/ts7/semantic-model.test.js +4 -4
- package/dist/frontend/ts7/semantic-model.test.js.map +1 -1
- package/dist/frontend/ts7/semantic-types.d.ts +7 -3
- package/dist/frontend/ts7/semantic-types.js +1 -1
- package/dist/frontend/ts7/semantic-types.js.map +1 -1
- package/dist/frontend/ts7/session.d.ts +11 -11
- package/dist/frontend/ts7/session.js +8 -5
- package/dist/frontend/ts7/session.js.map +1 -1
- package/dist/frontend/ts7/session.test.js +9 -5
- package/dist/frontend/ts7/session.test.js.map +1 -1
- package/dist/frontend/ts7/source-parser.d.ts +6 -2
- package/dist/frontend/ts7/source-parser.js +24 -3
- package/dist/frontend/ts7/source-parser.js.map +1 -1
- package/dist/frontend/ts7/source-parser.test.js +38 -17
- package/dist/frontend/ts7/source-parser.test.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +122 -2
- package/dist/frontend/type-mapper.js +2545 -719
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-only-imports.d.ts +28 -0
- package/dist/frontend/type-only-imports.js +122 -0
- package/dist/frontend/type-only-imports.js.map +1 -0
- package/dist/frontend/worker-target.js +8 -8
- package/dist/frontend/worker-target.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +29 -2
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.js +4 -2
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/api.d.ts +1 -1
- package/dist/ir/api.js +1 -1
- package/dist/ir/api.js.map +1 -1
- package/dist/ir/array-length-stability.d.ts +30 -0
- package/dist/ir/array-length-stability.js +236 -0
- package/dist/ir/array-length-stability.js.map +1 -0
- package/dist/ir/array-length-stability.test.d.ts +1 -0
- package/dist/ir/array-length-stability.test.js +113 -0
- package/dist/ir/array-length-stability.test.js.map +1 -0
- package/dist/ir/build.d.ts +2 -2
- package/dist/ir/build.js +1 -1
- package/dist/ir/build.js.map +1 -1
- package/dist/ir/builtin-effects.js +103 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +494 -25
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/byte-numbers.js +3 -0
- package/dist/ir/byte-numbers.js.map +1 -1
- package/dist/ir/callback-specialization.d.ts +37 -0
- package/dist/ir/callback-specialization.js +459 -0
- package/dist/ir/callback-specialization.js.map +1 -0
- package/dist/ir/callback-specialization.test.d.ts +1 -0
- package/dist/ir/callback-specialization.test.js +208 -0
- package/dist/ir/callback-specialization.test.js.map +1 -0
- package/dist/ir/capture-values.d.ts +0 -1
- package/dist/ir/capture-values.js +51 -40
- package/dist/ir/capture-values.js.map +1 -1
- package/dist/ir/constant-globals.test.js +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/field-values.test.js +1 -1
- package/dist/ir/final-fields.test.js +1 -1
- package/dist/ir/function-references.test.js +9 -1
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/init-only-globals.test.js +1 -1
- package/dist/ir/initializer-bindings.test.js +1 -1
- package/dist/ir/int32-slots.d.ts +14 -0
- package/dist/ir/int32-slots.js +97 -14
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +1 -1
- package/dist/ir/integer-loop-facts.d.ts +2 -0
- package/dist/ir/integer-loop-facts.js +24 -3
- package/dist/ir/integer-loop-facts.js.map +1 -1
- package/dist/ir/integer-loops.d.ts +1 -1
- package/dist/ir/integer-loops.js +39 -9
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +104 -0
- package/dist/ir/integer-loops.test.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +3 -0
- package/dist/ir/integer-ranges.js +3 -1
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +82 -1
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/intrinsic-signatures.js +6 -0
- package/dist/ir/intrinsic-signatures.js.map +1 -1
- package/dist/ir/ir.d.ts +221 -58
- package/dist/ir/ir.js +119 -12
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +10 -0
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/jsval.d.ts +8 -0
- package/dist/ir/jsval.js +365 -0
- package/dist/ir/jsval.js.map +1 -0
- package/dist/ir/jsval.test.d.ts +1 -0
- package/dist/ir/jsval.test.js +239 -0
- package/dist/ir/jsval.test.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +148 -33
- package/dist/ir/runtime-features.js +629 -386
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/self-captures.d.ts +33 -0
- package/dist/ir/self-captures.js +245 -0
- package/dist/ir/self-captures.js.map +1 -0
- package/dist/ir/self-captures.test.d.ts +1 -0
- package/dist/ir/self-captures.test.js +135 -0
- package/dist/ir/self-captures.test.js.map +1 -0
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +7 -4
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/tiers.d.ts +26 -0
- package/dist/ir/tiers.js +101 -0
- package/dist/ir/tiers.js.map +1 -0
- package/dist/ir/tiers.test.d.ts +1 -0
- package/dist/ir/tiers.test.js +140 -0
- package/dist/ir/tiers.test.js.map +1 -0
- package/dist/ir/traverse.js +103 -94
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/traverse.test.js +33 -30
- package/dist/ir/traverse.test.js.map +1 -1
- package/dist/ir/unshare.js +65 -3
- package/dist/ir/unshare.js.map +1 -1
- package/dist/ir/unshare.test.js +1 -1
- package/dist/ir/validate.js +175 -68
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +26 -9
- 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/ir-policy.js +13 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/library/library-cache.d.ts +1 -0
- package/dist/library/library-cache.js.map +1 -1
- package/dist/library/library-cache.test.js +5 -5
- package/dist/library/library-profile.d.ts +4 -4
- package/dist/library/library-profile.js +35 -7
- package/dist/library/library-profile.js.map +1 -1
- package/dist/library/prepare.js +13 -1
- package/dist/library/prepare.js.map +1 -1
- package/dist/native/cli.js +5 -0
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.js +2 -2
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +2 -2
- package/dist/native/prepare.js +7 -0
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.test.js +12 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/dist/native/toolchain.d.ts +2 -0
- package/dist/native/toolchain.js +10 -1
- package/dist/native/toolchain.js.map +1 -1
- package/dist/native/toolchain.test.js +39 -1
- package/dist/native/toolchain.test.js.map +1 -1
- package/dist/startup-cache.d.ts +1 -0
- package/dist/startup-cache.js +1 -0
- package/dist/startup-cache.js.map +1 -1
- package/dist/wasm/base64.d.ts +5 -0
- package/dist/wasm/base64.js +62 -0
- package/dist/wasm/base64.js.map +1 -0
- package/dist/wasm/binary.d.ts +36 -0
- package/dist/wasm/binary.js +1976 -0
- package/dist/wasm/binary.js.map +1 -0
- package/dist/wasm/binary.test.d.ts +1 -0
- package/dist/wasm/binary.test.js +190 -0
- package/dist/wasm/binary.test.js.map +1 -0
- package/dist/wasm/discover.d.ts +38 -0
- package/dist/wasm/discover.js +377 -0
- package/dist/wasm/discover.js.map +1 -0
- package/dist/wasm/discover.test.d.ts +1 -0
- package/dist/wasm/discover.test.js +24 -0
- package/dist/wasm/discover.test.js.map +1 -0
- package/dist/wasm/module.d.ts +151 -0
- package/dist/wasm/module.js +575 -0
- package/dist/wasm/module.js.map +1 -0
- package/dist/wasm/translate.d.ts +48 -0
- package/dist/wasm/translate.js +2129 -0
- package/dist/wasm/translate.js.map +1 -0
- package/dist/wasm/translate.test.d.ts +1 -0
- package/dist/wasm/translate.test.js +207 -0
- package/dist/wasm/translate.test.js.map +1 -0
- package/package.json +21 -20
- package/surface-manifest.json +303 -19
|
@@ -0,0 +1,2483 @@
|
|
|
1
|
+
/* Binary operators: arithmetic, comparisons and equality, logical and nullish pairs, and string conversion for concatenation. */
|
|
2
|
+
import * as ts from "../../ts7/adapter.js";
|
|
3
|
+
import { cleanFuncAdaptable } from "../coercions/function-adapters.js";
|
|
4
|
+
import { jsFuncNameOf } from "../lowerer.js";
|
|
5
|
+
import { BIGINT_T, BOOL, DYN, DYN_HANDLE_KINDS, F64, REF_TRUTHY_KINDS, STRING, UNDEFINED_T, VOID, canBoxFuncIntoDyn, isUnitType, typeEquals, typeKey, } from "../../../ir/ir.js";
|
|
6
|
+
import { isSafeToDiscard, isSafeToRepeat } from "./evaluation-safety.js";
|
|
7
|
+
import { bigintCompoundValue, compoundUnsupported, concatOperand, constructorGlobalTypeof, deferredSlotOr, dynCompoundValue, lowerAbsenceProbe, lowerDynMemberAssignment, lowerOptionalNumber, lowerPresenceOperand, nullishBranches, operandPairs, operatorUnsupported, runtimeOptionalStorageOperand, symbolFieldInfo, typeofAnswer, } from "../lower-exprs.js";
|
|
8
|
+
import { COMPOUND_ASSIGN_OPS, NARROW_FIRST } from "../surfaces.js";
|
|
9
|
+
import { lowerElementCompoundParts } from "./element-access.js";
|
|
10
|
+
import { InternalCompilerError } from "../../../errors.js";
|
|
11
|
+
import { isJsSourceFile, locOf } from "../../program.js";
|
|
12
|
+
import { storedClassValueType } from "../lower-classes.js";
|
|
13
|
+
import { hasRuntimeStatics } from "../class-runtime-statics.js";
|
|
14
|
+
import { tryLowerExpression } from "./try-lower-expression.js";
|
|
15
|
+
import { fenceNodeModuleMutation, lowerRequireCacheHas } from "../lower-node-module.js";
|
|
16
|
+
import { errorToStringCall } from "../error-methods.js";
|
|
17
|
+
import { classToStringConversion, classUnionToString } from "../class-to-primitive.js";
|
|
18
|
+
import { isPerfEntryType, perfEntryTag } from "../builtins/performance.js";
|
|
19
|
+
import { guardNullProto, nullProtoRecordShape } from "../null-prototype.js";
|
|
20
|
+
import { numLit, varRef } from "../../../ir/build.js";
|
|
21
|
+
import { lowerUrlAssignment } from "../builtins/url.js";
|
|
22
|
+
import { lowerClassPrototypeComputedAssignment } from "../class-prototypes.js";
|
|
23
|
+
import { lowerShortCircuitAssignment } from "./nullish-assignment.js";
|
|
24
|
+
import { lowerEventObjectPropertyWrite } from "../lower-event-target.js";
|
|
25
|
+
import { lowerFieldCompoundValue } from "./updates.js";
|
|
26
|
+
import { expandoWritableTarget } from "../lower-expando.js";
|
|
27
|
+
import { nsWritableTarget } from "../lower-namespaces.js";
|
|
28
|
+
import { arrayValueStore, tryLowerBytesReadNumberEquality } from "../array-values.js";
|
|
29
|
+
import { cjsExportMemberWriteGlobalOf, cjsInFileExportGlobalOf } from "../cjs-exports-object.js";
|
|
30
|
+
import { lowerUnionFieldWrite } from "./union-fields.js";
|
|
31
|
+
import { lowerAbstractEquality } from "../abstract-equality.js";
|
|
32
|
+
import { lowerInExpression } from "./relational.js";
|
|
33
|
+
import { lowerDynTypeofTest, lowerErrorCodeTypeofTest } from "./typeof.js";
|
|
34
|
+
import { builtinClassRefOf, sameBuiltinClass } from "../builtins/class-values.js";
|
|
35
|
+
import { lowerRuntimeConstructorIs, runtimeConstructorReceiver, } from "../builtins/runtime-constructor.js";
|
|
36
|
+
import { tryLowerIndexedComparison } from "../indexed-comparison.js";
|
|
37
|
+
import { lowerUnionEquality, tagEqualityMayMissAlias } from "../strict-equality.js";
|
|
38
|
+
import { withUnitArm } from "../../type-mapper.js";
|
|
39
|
+
import { npmStaticPackageOfPath } from "../../npm-static.js";
|
|
40
|
+
import { lowerWebAssemblyTypeof } from "../builtins/webassembly.js";
|
|
41
|
+
/** `v === undefined` / `v !== null` — the narrowing tests for unit-armed
|
|
42
|
+
* unions. A union operand compared with a unit literal lowers to a
|
|
43
|
+
* runtime TAG test (unionIsTag); afterwards tsc's control-flow narrowing
|
|
44
|
+
* types the branches and reads bridge through maybeNarrow as usual. When
|
|
45
|
+
* the checker already narrowed the non-literal side PAST the union
|
|
46
|
+
* (`w = 5; if (w !== null)`), the comparison is statically decided and
|
|
47
|
+
* folds to a bool literal — that drops only a side-effect-free read
|
|
48
|
+
* (flow narrowing applies to references, never to calls), and soundness
|
|
49
|
+
* rests on the same narrowing proof unionNarrow relies on. Null when
|
|
50
|
+
* neither side is a unit literal (not a unit comparison). */
|
|
51
|
+
export function lowerUnitComparison(lowerer, left, right, negated, loc) {
|
|
52
|
+
const unit = left.kind === "unitLit" ? left : right.kind === "unitLit" ? right : null;
|
|
53
|
+
if (!unit)
|
|
54
|
+
return null;
|
|
55
|
+
const other = unit === left ? right : left;
|
|
56
|
+
if (other.kind === "unitLit") {
|
|
57
|
+
// Two unit literals (`undefined === undefined`): statically decided.
|
|
58
|
+
return { kind: "boolLit", value: (other.unit === unit.unit) !== negated, type: BOOL, loc };
|
|
59
|
+
}
|
|
60
|
+
const slot = lowerer.deferredFieldSlot(other);
|
|
61
|
+
if (slot)
|
|
62
|
+
return lowerUnitComparison(lowerer, slot, unit, negated, loc);
|
|
63
|
+
// A binding the checker narrowed past the unit can still hold it at
|
|
64
|
+
// runtime when its value came from an unassigned deferred-init field;
|
|
65
|
+
// the stored tag answers either way.
|
|
66
|
+
if (other.kind === "unionNarrow" &&
|
|
67
|
+
other.value.kind === "varRef" &&
|
|
68
|
+
other.value.type.kind === "union" &&
|
|
69
|
+
lowerer.armTag(other.value.type.unionId, unit.type) >= 0)
|
|
70
|
+
return lowerUnitComparison(lowerer, other.value, unit, negated, loc);
|
|
71
|
+
if (other.type.kind === "union") {
|
|
72
|
+
const tag = lowerer.armTag(other.type.unionId, unit.type);
|
|
73
|
+
if (tag < 0) {
|
|
74
|
+
// A union WITHOUT that unit arm: legal TS (`miss === null` on a
|
|
75
|
+
// `number | undefined` — null/undefined guard comparisons are
|
|
76
|
+
// permitted against nullable-adjacent types), and === never
|
|
77
|
+
// coerces, so the answer is the constant `negated`. The literal
|
|
78
|
+
// must NOT flow into the union representation (the unionEq
|
|
79
|
+
// fallback would coerce it through the stranded-arm trap and
|
|
80
|
+
// throw where Node answers false). JS still evaluates the
|
|
81
|
+
// operand, so a non-droppable one (`xs.find(f) === null` — the
|
|
82
|
+
// callback's effects are observable) rides one throwaway tag
|
|
83
|
+
// test; droppable reads fold to the bare literal.
|
|
84
|
+
const answer = { kind: "boolLit", value: negated, type: BOOL, loc };
|
|
85
|
+
if (isSafeToDiscard(other))
|
|
86
|
+
return answer;
|
|
87
|
+
const evalOnce = {
|
|
88
|
+
kind: "unionIsTag",
|
|
89
|
+
unionId: other.type.unionId,
|
|
90
|
+
tag: 0,
|
|
91
|
+
negated: false,
|
|
92
|
+
value: other,
|
|
93
|
+
type: BOOL,
|
|
94
|
+
loc,
|
|
95
|
+
};
|
|
96
|
+
return {
|
|
97
|
+
kind: "logical",
|
|
98
|
+
op: negated ? "||" : "&&",
|
|
99
|
+
left: evalOnce,
|
|
100
|
+
right: answer,
|
|
101
|
+
type: BOOL,
|
|
102
|
+
loc,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
return {
|
|
106
|
+
kind: "unionIsTag",
|
|
107
|
+
unionId: other.type.unionId,
|
|
108
|
+
tag,
|
|
109
|
+
negated,
|
|
110
|
+
value: other,
|
|
111
|
+
type: BOOL,
|
|
112
|
+
loc,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// A process.env read tsc narrowed past its union (an earlier write to
|
|
116
|
+
// the same key): the environment is VOLATILE — `delete process.env.K`
|
|
117
|
+
// undoes the write the narrowing rode on — so folding would bake a
|
|
118
|
+
// stale answer. Compare the fresh read's union tag instead.
|
|
119
|
+
const envRead = volatileEnvRead(other);
|
|
120
|
+
if (envRead && envRead.type.kind === "union") {
|
|
121
|
+
const tag = lowerer.armTag(envRead.type.unionId, unit.type);
|
|
122
|
+
if (tag >= 0) {
|
|
123
|
+
return {
|
|
124
|
+
kind: "unionIsTag",
|
|
125
|
+
unionId: envRead.type.unionId,
|
|
126
|
+
tag,
|
|
127
|
+
negated,
|
|
128
|
+
value: envRead,
|
|
129
|
+
type: BOOL,
|
|
130
|
+
loc,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// A VOID-typed operand (`foo() === undefined` where foo's declared
|
|
135
|
+
// return is undefined/void — the mapping folds both to void): JS
|
|
136
|
+
// yields undefined from such a call, so the compare is TRUE-when-equal
|
|
137
|
+
// — the opposite of the never-holds-units fold below — and the IR has
|
|
138
|
+
// no value (nor a sequence form to keep the call's effects). Fall
|
|
139
|
+
// through to the caller's comparison fence instead of folding a lie.
|
|
140
|
+
if (other.type.kind === "void")
|
|
141
|
+
return null;
|
|
142
|
+
// Non-union operand: it can never hold undefined/null at runtime (the
|
|
143
|
+
// checker narrowed it to a concrete arm), so `=== unit` is false and
|
|
144
|
+
// `!== unit` is true.
|
|
145
|
+
return { kind: "boolLit", value: negated, type: BOOL, loc };
|
|
146
|
+
}
|
|
147
|
+
/** The union-typed process.envGet read inside a checker-narrowed operand,
|
|
148
|
+
* or null — the volatility escape above (and lowerLooseNullCompare's). */
|
|
149
|
+
function volatileEnvRead(e) {
|
|
150
|
+
if (e.kind === "libCall" && e.fn === "process.envGet")
|
|
151
|
+
return e;
|
|
152
|
+
if (e.kind === "unionNarrow" && e.value.kind === "libCall" && e.value.fn === "process.envGet") {
|
|
153
|
+
return e.value;
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
function lowerLooseNullCompare(lowerer, expr, loc) {
|
|
158
|
+
const negated = expr.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsToken;
|
|
159
|
+
const unwrap = (e) => ts.isParenthesizedExpression(e) ? unwrap(e.expression) : e;
|
|
160
|
+
const left = unwrap(expr.left);
|
|
161
|
+
const right = unwrap(expr.right);
|
|
162
|
+
const leftIsNull = left.kind === ts.SyntaxKind.NullKeyword;
|
|
163
|
+
if (!leftIsNull && right.kind !== ts.SyntaxKind.NullKeyword)
|
|
164
|
+
return null;
|
|
165
|
+
const otherNode = leftIsNull ? right : left;
|
|
166
|
+
const other = lowerPresenceOperand(lowerer, otherNode);
|
|
167
|
+
if (isUnitType(other.type)) {
|
|
168
|
+
// `null == null`, `undefined == null`: units are mutually loose-equal.
|
|
169
|
+
return { kind: "boolLit", value: !negated, type: BOOL, loc };
|
|
170
|
+
}
|
|
171
|
+
if (other.type.kind === "dyn") {
|
|
172
|
+
// `v != null` on unknown: one dyn kind test covers both units.
|
|
173
|
+
return {
|
|
174
|
+
kind: "dynTest",
|
|
175
|
+
test: "nullish",
|
|
176
|
+
...(negated ? { negated: true } : {}),
|
|
177
|
+
value: other,
|
|
178
|
+
type: BOOL,
|
|
179
|
+
loc,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
if (other.type.kind === "union") {
|
|
183
|
+
const ut = other.type;
|
|
184
|
+
const def = lowerer.unions.get(ut.unionId);
|
|
185
|
+
if (!def)
|
|
186
|
+
lowerer.badType(otherNode, lowerer.typeOf(otherNode));
|
|
187
|
+
const tags = def.arms.flatMap((a, i) => (isUnitType(a) ? [i] : []));
|
|
188
|
+
if (tags.length === 0) {
|
|
189
|
+
// No unit arms: never null-ish (defensive — the fold below).
|
|
190
|
+
return { kind: "boolLit", value: negated, type: BOOL, loc };
|
|
191
|
+
}
|
|
192
|
+
const isTag = (tag) => ({
|
|
193
|
+
kind: "unionIsTag",
|
|
194
|
+
unionId: ut.unionId,
|
|
195
|
+
tag,
|
|
196
|
+
negated,
|
|
197
|
+
value: other,
|
|
198
|
+
type: BOOL,
|
|
199
|
+
loc,
|
|
200
|
+
});
|
|
201
|
+
if (tags.length === 1)
|
|
202
|
+
return isTag(tags[0]);
|
|
203
|
+
// Both null AND undefined arms: tag-in-set as a short-circuit pair
|
|
204
|
+
// (De Morgan for `!=`). The operand IrExpr rides both tests, so the
|
|
205
|
+
// backend emits it per test — restricted to re-emittable pure reads;
|
|
206
|
+
// anything effectful gets its own actionable fence (the generic
|
|
207
|
+
// SC1040 hint would wrongly suggest `== null` as the fix).
|
|
208
|
+
if (!isSafeToRepeat(other)) {
|
|
209
|
+
lowerer.unsupported("SC1090", expr, `'== null' / '!= null' on a '${lowerer.fmt(ut)}' value that isn't a plain read ` +
|
|
210
|
+
`(both unit arms need the operand twice — bind it to a const first)`);
|
|
211
|
+
}
|
|
212
|
+
return {
|
|
213
|
+
kind: "logical",
|
|
214
|
+
op: negated ? "&&" : "||",
|
|
215
|
+
left: isTag(tags[0]),
|
|
216
|
+
right: isTag(tags[1]),
|
|
217
|
+
type: BOOL,
|
|
218
|
+
loc,
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
if (other.type.kind === "void") {
|
|
222
|
+
return null; // no static tag to test — keep the fence
|
|
223
|
+
}
|
|
224
|
+
// The env-volatility escape (see lowerUnitComparison): a narrowed
|
|
225
|
+
// process.env read compares its FRESH union tag instead of folding.
|
|
226
|
+
const envRead = volatileEnvRead(other);
|
|
227
|
+
if (envRead && envRead.type.kind === "union") {
|
|
228
|
+
const def = lowerer.unions.get(envRead.type.unionId);
|
|
229
|
+
const tag = def ? def.arms.findIndex((a) => isUnitType(a)) : -1;
|
|
230
|
+
if (tag >= 0) {
|
|
231
|
+
return {
|
|
232
|
+
kind: "unionIsTag",
|
|
233
|
+
unionId: envRead.type.unionId,
|
|
234
|
+
tag,
|
|
235
|
+
negated,
|
|
236
|
+
value: envRead,
|
|
237
|
+
type: BOOL,
|
|
238
|
+
loc,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
// A non-nullable operand (tsc allows the comparison as a guard):
|
|
243
|
+
// `== null` is statically false, `!= null` statically true.
|
|
244
|
+
return { kind: "boolLit", value: negated, type: BOOL, loc };
|
|
245
|
+
}
|
|
246
|
+
/** A plain value read that may be runtime-optional: an unchecked element
|
|
247
|
+
* read, or a binding, member or call that carries one. Lowering these
|
|
248
|
+
* without a destination type is the same as lowering them into one. */
|
|
249
|
+
function isPlainValueRead(node) {
|
|
250
|
+
while (ts.isParenthesizedExpression(node))
|
|
251
|
+
node = node.expression;
|
|
252
|
+
return (ts.isElementAccessExpression(node) ||
|
|
253
|
+
ts.isIdentifier(node) ||
|
|
254
|
+
ts.isPropertyAccessExpression(node) ||
|
|
255
|
+
ts.isCallExpression(node));
|
|
256
|
+
}
|
|
257
|
+
/** A member access or call receiver needs the present value itself (JS
|
|
258
|
+
* throws a TypeError reading a member of undefined). */
|
|
259
|
+
function isMemberReceiver(node) {
|
|
260
|
+
let child = node;
|
|
261
|
+
let parent = node.parent;
|
|
262
|
+
while (ts.isParenthesizedExpression(parent)) {
|
|
263
|
+
child = parent;
|
|
264
|
+
parent = parent.parent;
|
|
265
|
+
}
|
|
266
|
+
return (((ts.isPropertyAccessExpression(parent) ||
|
|
267
|
+
ts.isElementAccessExpression(parent) ||
|
|
268
|
+
ts.isCallExpression(parent)) &&
|
|
269
|
+
parent.expression === child) ||
|
|
270
|
+
(ts.isTaggedTemplateExpression(parent) && parent.tag === child));
|
|
271
|
+
}
|
|
272
|
+
export function lowerNullishPair(lowerer, expr, loc, left) {
|
|
273
|
+
if (left.type.kind === "dyn") {
|
|
274
|
+
// `a ?? b` on a CHECKED-DYNAMIC left: the deciding test is the
|
|
275
|
+
// runtime kind (scr_dyn_is_nullish — UNDEF/NULL take the default).
|
|
276
|
+
// Both sides live in the checked-dynamic tree — the right converts through
|
|
277
|
+
// the usual boundary and evaluates lazily in its branch; a default
|
|
278
|
+
// with no dyn representation keeps the fence.
|
|
279
|
+
const right = lowerer.coerceToExpected(lowerer.lowerExpr(expr.right), DYN);
|
|
280
|
+
if (right.type.kind !== "dyn") {
|
|
281
|
+
lowerer.unsupported("SC1100", expr, "nullish coalescing on 'unknown' values against defaults with no dynamic representation");
|
|
282
|
+
}
|
|
283
|
+
return { kind: "nullish", left, right, type: DYN, loc };
|
|
284
|
+
}
|
|
285
|
+
if (left.type.kind !== "union")
|
|
286
|
+
return left;
|
|
287
|
+
const def = lowerer.unions.get(left.type.unionId);
|
|
288
|
+
if (!def)
|
|
289
|
+
lowerer.badType(expr.left, lowerer.typeOf(expr.left));
|
|
290
|
+
if (!def.arms.some(isUnitType))
|
|
291
|
+
return left;
|
|
292
|
+
const rest = def.arms.filter((a) => !isUnitType(a));
|
|
293
|
+
// `optionalMap ?? new Map()` carries its element contract on the left;
|
|
294
|
+
// the empty fallback may use it without constructing a Map<any, any>
|
|
295
|
+
// arm that has no first-class union representation.
|
|
296
|
+
const fresh = rest.length === 1 ? lowerer.emptyCollectionFor(expr.right, rest[0]) : null;
|
|
297
|
+
if (fresh)
|
|
298
|
+
return { kind: "nullish", left, right: fresh, type: fresh.type, loc };
|
|
299
|
+
let type = lowerer.irTypeOf(expr);
|
|
300
|
+
// A runtime-optional read can reach the default even when declarations
|
|
301
|
+
// call the left side present. Preserve a differently typed primitive
|
|
302
|
+
// fallback rather than checking it against that incomplete result type.
|
|
303
|
+
const rightType = lowerer.mapTypeOf(lowerer.typeOf(expr.right));
|
|
304
|
+
const primitive = (t) => t.kind === "f64" || t.kind === "string" || t.kind === "bool";
|
|
305
|
+
if (rightType &&
|
|
306
|
+
primitive(type) &&
|
|
307
|
+
primitive(rightType) &&
|
|
308
|
+
!typeEquals(type, rightType) &&
|
|
309
|
+
rest.every(primitive)) {
|
|
310
|
+
const arms = [...rest];
|
|
311
|
+
if (!arms.some((arm) => typeEquals(arm, rightType)))
|
|
312
|
+
arms.push(rightType);
|
|
313
|
+
arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
|
|
314
|
+
type = { kind: "union", unionId: lowerer.unions.intern(arms) };
|
|
315
|
+
lowerer.runtimeOptionalArithmeticTypes.set(expr, type);
|
|
316
|
+
}
|
|
317
|
+
if (type.kind === "dyn" && lowerer.dynConvertible(left.type)) {
|
|
318
|
+
return {
|
|
319
|
+
kind: "nullish",
|
|
320
|
+
left: lowerer.coerceToExpected(left, DYN),
|
|
321
|
+
right: lowerer.lowerExprExpecting(expr.right, DYN),
|
|
322
|
+
type: DYN,
|
|
323
|
+
loc,
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
// A runtime-optional default (`name ?? names[0]`): the checker types an
|
|
327
|
+
// unchecked element read as the bare element type, but an out-of-range
|
|
328
|
+
// read is undefined at runtime. When the default shares the left's
|
|
329
|
+
// optional union, that union is the result, so the undefined state
|
|
330
|
+
// reaches the consumer (an optional return or parameter takes it as its
|
|
331
|
+
// undefined arm; a plain slot still extracts the element with its
|
|
332
|
+
// checked narrow).
|
|
333
|
+
if (rest.length === 1 &&
|
|
334
|
+
typeEquals(type, rest[0]) &&
|
|
335
|
+
isPlainValueRead(expr.right) &&
|
|
336
|
+
!isMemberReceiver(expr)) {
|
|
337
|
+
const raw = lowerer.lowerExpr(expr.right);
|
|
338
|
+
if (typeEquals(raw.type, left.type))
|
|
339
|
+
return { kind: "nullish", left, right: raw, type: left.type, loc };
|
|
340
|
+
// `names[0] ?? undefined`: an explicit unit default stays the left's arm.
|
|
341
|
+
if (isUnitType(raw.type) && lowerer.armTag(left.type.unionId, raw.type) >= 0) {
|
|
342
|
+
const right = lowerer.coerceInto(expr.right, raw, left.type);
|
|
343
|
+
return { kind: "nullish", left, right, type: left.type, loc };
|
|
344
|
+
}
|
|
345
|
+
return { kind: "nullish", left, right: lowerer.coerceInto(expr.right, raw, type), type, loc };
|
|
346
|
+
}
|
|
347
|
+
if (typeEquals(type, left.type) || (rest.length === 1 && typeEquals(type, rest[0]))) {
|
|
348
|
+
const right = lowerer.lowerExprExpecting(expr.right, type);
|
|
349
|
+
return { kind: "nullish", left, right, type, loc };
|
|
350
|
+
}
|
|
351
|
+
if (type.kind !== "union" && rest.length > 1 && rest.some((arm) => typeEquals(arm, type))) {
|
|
352
|
+
const helper = lowerer.narrowedArmHelper(left.type.unionId, type, loc);
|
|
353
|
+
if (helper !== null) {
|
|
354
|
+
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({ kind: "call", callee: helper, args: [stable], type, loc }));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
// A subclass value defaulted to a base-class value (`circle ?? shape`):
|
|
358
|
+
// the present arm upcasts after the original nullish test, and the
|
|
359
|
+
// default lowers lazily into the base-class result.
|
|
360
|
+
const present = rest.length === 1 ? rest[0] : null;
|
|
361
|
+
if (present?.kind === "object" &&
|
|
362
|
+
type.kind === "object" &&
|
|
363
|
+
present.className !== type.className &&
|
|
364
|
+
lowerer.isSubclassOf(present.className, type.className)) {
|
|
365
|
+
const helper = lowerer.narrowedArmHelper(left.type.unionId, present, loc);
|
|
366
|
+
if (helper !== null) {
|
|
367
|
+
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({
|
|
368
|
+
kind: "upcast",
|
|
369
|
+
value: { kind: "call", callee: helper, args: [stable], type: present, loc },
|
|
370
|
+
type,
|
|
371
|
+
loc,
|
|
372
|
+
}));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
// A default may change the union or widen its records. Test the
|
|
376
|
+
// original tag before coercing: converting the whole left first can
|
|
377
|
+
// lose nullish arms, and evaluating the default eagerly loses laziness.
|
|
378
|
+
if (type.kind === "union") {
|
|
379
|
+
const retag = lowerer.unionRetagHelper(left.type.unionId, type.unionId, loc) ??
|
|
380
|
+
lowerer.narrowedRetagHelper(expr.left, left.type.unionId, type.unionId, loc);
|
|
381
|
+
if (retag !== null) {
|
|
382
|
+
// Narrowing may exclude a record/class arm while storage retains
|
|
383
|
+
// it. The checked retag traps that impossible arm, but only AFTER
|
|
384
|
+
// the original nullish test: null/undefined must reach the lazy
|
|
385
|
+
// default even when neither is representable in the result.
|
|
386
|
+
return nullishBranches(lowerer, left, left.type, def.arms, type, loc, () => lowerer.lowerExprExpecting(expr.right, type), (stable) => ({ kind: "call", callee: retag, args: [stable], type, loc }));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// An optional callback defaulted to a function of another signature
|
|
390
|
+
// (`o.tags ?? (() => ({}))`, fewer parameters or a narrower result): the
|
|
391
|
+
// result is the callback's own function type, and the default adapts into
|
|
392
|
+
// it (JavaScript ignores surplus arguments). The checker's merged union
|
|
393
|
+
// signature would lose the callback's result shape.
|
|
394
|
+
if (present?.kind === "func" && present.rest !== true) {
|
|
395
|
+
const raw = lowerer.lowerExpr(expr.right);
|
|
396
|
+
if (raw.type.kind === "func" &&
|
|
397
|
+
(typeEquals(raw.type, present) || cleanFuncAdaptable(lowerer, raw.type, present))) {
|
|
398
|
+
const right = lowerer.coerceInto(expr.right, raw, present);
|
|
399
|
+
lowerer.nullishFuncResults.add(expr);
|
|
400
|
+
return { kind: "nullish", left, right, type: present, loc };
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
lowerer.unsupported("SC1090", expr, rest.length !== 1
|
|
404
|
+
? `'??' on '${lowerer.fmt(left.type)}' (the non-nullish result is a sub-union; check a discriminant field first)`
|
|
405
|
+
: `'??' where the default changes the result type (left is '${lowerer.fmt(left.type)}' but the whole expression is '${lowerer.fmt(type)}' — give both sides one type)`);
|
|
406
|
+
}
|
|
407
|
+
/** `a[i] op= rhs` over native arrays and byte views. A compound assignment
|
|
408
|
+
* evaluates the receiver and index, reads the old element, evaluates rhs,
|
|
409
|
+
* then writes. Capture each stage so a call in the index or rhs cannot
|
|
410
|
+
* change the target or the value used by the operator. The expression yields
|
|
411
|
+
* the computed value before a typed array or Buffer coerces it for storage. */
|
|
412
|
+
export function lowerElementCompound(lowerer, expr, op) {
|
|
413
|
+
const lowered = lowerElementCompoundParts(lowerer, expr, op, false);
|
|
414
|
+
if (!lowered.expr)
|
|
415
|
+
throw new InternalCompilerError("a compound element value lowered to statements");
|
|
416
|
+
return lowered.expr;
|
|
417
|
+
}
|
|
418
|
+
/** JavaScript callable members live on the closure, so aliases and chained
|
|
419
|
+
* writes share the same storage as Object.defineProperties. */
|
|
420
|
+
export function lowerNativeFunctionAssignment(lowerer, expr) {
|
|
421
|
+
const target = expr.left;
|
|
422
|
+
if (!isJsSourceFile(ts.getSourceFileOfNode(expr)) ||
|
|
423
|
+
(!ts.isPropertyAccessExpression(target) && !ts.isElementAccessExpression(target)) ||
|
|
424
|
+
target.questionDotToken)
|
|
425
|
+
return null;
|
|
426
|
+
// Checked constructors share the callable's live property descriptors.
|
|
427
|
+
const classType = storedClassValueType(lowerer, target.expression);
|
|
428
|
+
const staticClass = classType?.kind === "classval" ? lowerer.classes.get(classType.className) : undefined;
|
|
429
|
+
if (staticClass && hasRuntimeStatics(staticClass)) {
|
|
430
|
+
return lowerDynMemberAssignment(lowerer, expr, lowerer.lowerExprExpecting(target.expression, DYN));
|
|
431
|
+
}
|
|
432
|
+
// Other class statics and prototype tables have their own paths.
|
|
433
|
+
// Probing them as ordinary functions could materialize unused methods.
|
|
434
|
+
if (lowerer.exactClassOfReceiver(target.expression) ||
|
|
435
|
+
(ts.isPropertyAccessExpression(target.expression) &&
|
|
436
|
+
target.expression.name.text === "prototype" &&
|
|
437
|
+
lowerer.exactClassOfReceiver(target.expression.expression)))
|
|
438
|
+
return null;
|
|
439
|
+
const receiver = tryLowerExpression(lowerer, target.expression);
|
|
440
|
+
if (receiver?.type.kind !== "func" ||
|
|
441
|
+
!canBoxFuncIntoDyn(receiver.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
|
|
442
|
+
return null;
|
|
443
|
+
fenceNodeModuleMutation(lowerer, target, "assignment");
|
|
444
|
+
const fnName = jsFuncNameOf(target.expression);
|
|
445
|
+
const boxed = {
|
|
446
|
+
kind: "dynFrom",
|
|
447
|
+
value: receiver,
|
|
448
|
+
type: DYN,
|
|
449
|
+
loc: locOf(target.expression),
|
|
450
|
+
...(fnName !== null ? { fnName } : {}),
|
|
451
|
+
};
|
|
452
|
+
return lowerDynMemberAssignment(lowerer, expr, boxed);
|
|
453
|
+
}
|
|
454
|
+
/** `typeof globalThis.AbortSignal.any === "function"`: the comparison
|
|
455
|
+
* folds with constructorGlobalTypeof's answer. */
|
|
456
|
+
function lowerConstructorGlobalTypeofTest(lowerer, expr, loc) {
|
|
457
|
+
const negated = expr.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
458
|
+
for (const [a, b] of operandPairs(expr)) {
|
|
459
|
+
if (!ts.isTypeOfExpression(a) || !ts.isStringLiteral(b))
|
|
460
|
+
continue;
|
|
461
|
+
const answer = constructorGlobalTypeof(lowerer, a.expression);
|
|
462
|
+
if (answer !== null)
|
|
463
|
+
return { kind: "boolLit", value: (answer === b.text) !== negated, type: BOOL, loc };
|
|
464
|
+
}
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
export function ensureString(lowerer, e, node) {
|
|
468
|
+
if (e.type.kind === "string")
|
|
469
|
+
return e;
|
|
470
|
+
if (e.type.kind === "url")
|
|
471
|
+
return { kind: "libCall", fn: "url.href", args: [e], type: STRING, loc: e.loc };
|
|
472
|
+
// String(date) / `${date}` / "" + date: Date's ToPrimitive prefers
|
|
473
|
+
// toString().
|
|
474
|
+
if (e.type.kind === "date")
|
|
475
|
+
return { kind: "libCall", fn: "date.toString", args: [e], type: STRING, loc: e.loc };
|
|
476
|
+
if (e.type.kind === "regex") {
|
|
477
|
+
return {
|
|
478
|
+
kind: "regexIntrinsic",
|
|
479
|
+
method: "toString",
|
|
480
|
+
receiver: e,
|
|
481
|
+
args: [],
|
|
482
|
+
type: STRING,
|
|
483
|
+
loc: e.loc,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
if (e.type.kind === "bigint") {
|
|
487
|
+
return {
|
|
488
|
+
kind: "libCall",
|
|
489
|
+
fn: "bigint.toString",
|
|
490
|
+
args: [e, { kind: "numLit", value: 10, type: F64, loc: e.loc }],
|
|
491
|
+
type: STRING,
|
|
492
|
+
loc: e.loc,
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
if (e.type.kind === "dyn") {
|
|
496
|
+
// String(u) / `${u}`: a runtime dispatch over the dyn kind — Node's
|
|
497
|
+
// String() exactly (undefined/null texts, JS number formatting,
|
|
498
|
+
// strings verbatim, arrays via join, objects as "[object Object]").
|
|
499
|
+
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
500
|
+
}
|
|
501
|
+
if (e.type.kind === "bytes") {
|
|
502
|
+
// Preserve the runtime brand: typed arrays join numeric elements,
|
|
503
|
+
// while a Buffer stored in a Uint8Array slot decodes its bytes.
|
|
504
|
+
const boxed = { kind: "dynFrom", value: e, type: DYN, loc: e.loc };
|
|
505
|
+
return { kind: "toString", operand: boxed, type: STRING, loc: e.loc };
|
|
506
|
+
}
|
|
507
|
+
if (e.type.kind === "object") {
|
|
508
|
+
// String(err) / `${err}` uses the same dispatch as err.toString().
|
|
509
|
+
for (let c = lowerer.classes.get(e.type.className) ?? null; c; c = c.base) {
|
|
510
|
+
if (c.builtinError) {
|
|
511
|
+
return errorToStringCall(lowerer, e);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
// A program class instance converts through its own methods.
|
|
515
|
+
const converted = classToStringConversion(lowerer, e, "string", node);
|
|
516
|
+
if (converted)
|
|
517
|
+
return converted;
|
|
518
|
+
}
|
|
519
|
+
if (e.type.kind === "union") {
|
|
520
|
+
// `${u}` — the arm's ToString via a per-union interned helper
|
|
521
|
+
// (sc_us_*), Node-exact per arm kind: unit arms are the known texts
|
|
522
|
+
// "undefined"/"null", string arms pass through, f64/bool arms use the
|
|
523
|
+
// JS-exact formatters. Ref arms (records, arrays, ...) stay fenced:
|
|
524
|
+
// JS would print "[object Object]" and friends — narrow first.
|
|
525
|
+
const def = lowerer.unions.get(e.type.unionId);
|
|
526
|
+
const stringable = def?.arms.every((a) => a.kind === "undefinedT" ||
|
|
527
|
+
a.kind === "nullT" ||
|
|
528
|
+
a.kind === "string" ||
|
|
529
|
+
a.kind === "f64" ||
|
|
530
|
+
a.kind === "bigint" ||
|
|
531
|
+
a.kind === "bool");
|
|
532
|
+
if (stringable) {
|
|
533
|
+
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
534
|
+
}
|
|
535
|
+
// Runtime-optional locals can retain their stored union after the
|
|
536
|
+
// checker has narrowed this use to a primitive arm. Validate that
|
|
537
|
+
// arm before converting it; an unguarded object arm stays fenced.
|
|
538
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
539
|
+
if (narrowed &&
|
|
540
|
+
(narrowed.kind === "string" ||
|
|
541
|
+
narrowed.kind === "f64" ||
|
|
542
|
+
narrowed.kind === "bool" ||
|
|
543
|
+
narrowed.kind === "bigint")) {
|
|
544
|
+
const helper = lowerer.narrowedArmHelper(e.type.unionId, narrowed, e.loc);
|
|
545
|
+
if (helper) {
|
|
546
|
+
return ensureString(lowerer, lowerer.checkedNarrowCall(helper, e, narrowed, e.loc), node);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
if (narrowed?.kind === "union" &&
|
|
550
|
+
!typeEquals(narrowed, e.type) &&
|
|
551
|
+
lowerer.unions
|
|
552
|
+
.get(narrowed.unionId)
|
|
553
|
+
?.arms.every((arm) => isUnitType(arm) ||
|
|
554
|
+
arm.kind === "string" ||
|
|
555
|
+
arm.kind === "f64" ||
|
|
556
|
+
arm.kind === "bool" ||
|
|
557
|
+
arm.kind === "bigint")) {
|
|
558
|
+
const helper = lowerer.narrowedRetagHelper(node, e.type.unionId, narrowed.unionId, e.loc);
|
|
559
|
+
if (helper)
|
|
560
|
+
return ensureString(lowerer, { kind: "call", callee: helper, args: [e], type: narrowed, loc: e.loc }, node);
|
|
561
|
+
}
|
|
562
|
+
const viaClasses = classUnionToString(lowerer, e, "string", node);
|
|
563
|
+
if (viaClasses)
|
|
564
|
+
return viaClasses;
|
|
565
|
+
lowerer.unsupported("SC1090", node, `string conversions of unions with object arms (${NARROW_FIRST})`);
|
|
566
|
+
}
|
|
567
|
+
if (e.type.kind === "symbol") {
|
|
568
|
+
// JS splits here: `${sym}` and concatenation THROW a TypeError,
|
|
569
|
+
// String(sym) answers "Symbol(desc)". One shared lowering cannot
|
|
570
|
+
// honor both — fence with the sanctioned spelling instead of
|
|
571
|
+
// guessing the context.
|
|
572
|
+
lowerer.unsupported("SC1090", node, "string conversions of symbol values (template literals throw in JS — call .toString() explicitly)");
|
|
573
|
+
}
|
|
574
|
+
if (isUnitType(e.type)) {
|
|
575
|
+
if (e.kind === "unitLit") {
|
|
576
|
+
return { kind: "strLit", value: e.unit, type: STRING, loc: e.loc };
|
|
577
|
+
}
|
|
578
|
+
// Keep sequencing and branch effects even though the final unit's
|
|
579
|
+
// spelling is constant. Never turn an unknown producer into a literal.
|
|
580
|
+
if (e.kind === "seqExpr") {
|
|
581
|
+
return { ...e, result: lowerer.ensureString(e.result, node), type: STRING };
|
|
582
|
+
}
|
|
583
|
+
if (e.kind === "ternary") {
|
|
584
|
+
return {
|
|
585
|
+
...e,
|
|
586
|
+
then: lowerer.ensureString(e.then, node),
|
|
587
|
+
else_: lowerer.ensureString(e.else_, node),
|
|
588
|
+
type: STRING,
|
|
589
|
+
};
|
|
590
|
+
}
|
|
591
|
+
lowerer.unsupported("SC1090", node, `string conversions of '${e.type.kind === "undefinedT" ? "undefined" : "null"}' values`);
|
|
592
|
+
}
|
|
593
|
+
if (e.type.kind === "array") {
|
|
594
|
+
// `${[1,2,3]}` / String(arr): Array.prototype.toString IS join(",")
|
|
595
|
+
// — the SAME intrinsic the .join() lowering emits, fenced to the
|
|
596
|
+
// same element kinds (f64/string/bool, unions of those with unit
|
|
597
|
+
// arms printing empty). Nested arrays would need JS's recursive
|
|
598
|
+
// dispatch — the join fence already tells that story.
|
|
599
|
+
const elem = e.type.elem;
|
|
600
|
+
const joinableUnion = elem.kind === "union" &&
|
|
601
|
+
(lowerer.unions
|
|
602
|
+
.get(elem.unionId)
|
|
603
|
+
?.arms.every((a) => a.kind === "f64" || a.kind === "string" || a.kind === "bool" || isUnitType(a)) ??
|
|
604
|
+
false);
|
|
605
|
+
if (elem.kind === "f64" || elem.kind === "string" || elem.kind === "bool" || joinableUnion) {
|
|
606
|
+
const sep = { kind: "strLit", value: ",", type: STRING, loc: e.loc };
|
|
607
|
+
return {
|
|
608
|
+
kind: "arrIntrinsic",
|
|
609
|
+
method: "join",
|
|
610
|
+
receiver: e,
|
|
611
|
+
args: [sep],
|
|
612
|
+
type: STRING,
|
|
613
|
+
loc: e.loc,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (e.type.kind === "record") {
|
|
618
|
+
// `${obj}` / String(obj): a plain data record has no toString of its
|
|
619
|
+
// own (a func-typed `toString` FIELD would shadow the prototype's —
|
|
620
|
+
// JS would call it, so that shape keeps the fence), and a TUPLE
|
|
621
|
+
// prints its elements like an array (not lowered — fenced) — every
|
|
622
|
+
// other record is Object.prototype.toString's constant.
|
|
623
|
+
const shape = lowerer.shapes.get(e.type.shapeId);
|
|
624
|
+
if (isPerfEntryType(lowerer, e.type))
|
|
625
|
+
return perfEntryTag(lowerer, e, e.type, e.loc);
|
|
626
|
+
if (shape && !shape.tuple && !shape.fields.some((f) => f.name === "toString")) {
|
|
627
|
+
// A null-prototype record (Object.groupBy) has no toString or
|
|
628
|
+
// valueOf: ToPrimitive throws Node's TypeError.
|
|
629
|
+
const nullProtoT = nullProtoRecordShape(lowerer, e.type);
|
|
630
|
+
if (nullProtoT)
|
|
631
|
+
return nullProtoToString(lowerer, e, nullProtoT);
|
|
632
|
+
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (e.type.kind !== "f64" && e.type.kind !== "bool")
|
|
636
|
+
lowerer.badType(node, lowerer.typeOf(node));
|
|
637
|
+
return { kind: "toString", operand: e, type: STRING, loc: e.loc };
|
|
638
|
+
}
|
|
639
|
+
/** String(r) over a record that may have a null prototype: an interned
|
|
640
|
+
* helper that throws Node's TypeError for a null-prototype record and
|
|
641
|
+
* answers "[object Object]" otherwise. */
|
|
642
|
+
function nullProtoToString(lowerer, e, t) {
|
|
643
|
+
const loc = e.loc;
|
|
644
|
+
const key = `nullProtoToString:${t.shapeId}`;
|
|
645
|
+
let helper = lowerer.valueHelpers.get(key);
|
|
646
|
+
if (!helper) {
|
|
647
|
+
helper = `%rec.tostr.${lowerer.valueHelpers.size}`;
|
|
648
|
+
lowerer.valueHelpers.set(key, helper);
|
|
649
|
+
const r = varRef("r.0", t, loc);
|
|
650
|
+
lowerer.liftedFns.push({
|
|
651
|
+
name: helper,
|
|
652
|
+
params: [{ localId: "r.0", name: "r", type: t }],
|
|
653
|
+
returnType: STRING,
|
|
654
|
+
locals: [{ id: "r.0", name: "r", type: t, mutable: false }],
|
|
655
|
+
body: [
|
|
656
|
+
{
|
|
657
|
+
kind: "return",
|
|
658
|
+
value: guardNullProto(r, t.shapeId, "Cannot convert object to primitive value", { kind: "toString", operand: r, type: STRING, loc }, loc),
|
|
659
|
+
loc,
|
|
660
|
+
},
|
|
661
|
+
],
|
|
662
|
+
loc,
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
return { kind: "call", callee: helper, args: [e], type: STRING, loc };
|
|
666
|
+
}
|
|
667
|
+
/** Whether a lowered statement can live inside a seqExpr. These statements
|
|
668
|
+
* do not leave the expression through a jump; the native emitters can place
|
|
669
|
+
* their writes and local state branches before evaluating the final result.
|
|
670
|
+
* Blocks check their bodies recursively. */
|
|
671
|
+
function seqExprSafeStmt(s) {
|
|
672
|
+
switch (s.kind) {
|
|
673
|
+
case "varDecl":
|
|
674
|
+
case "assign":
|
|
675
|
+
case "exprStmt":
|
|
676
|
+
case "fieldSet":
|
|
677
|
+
case "recordSet":
|
|
678
|
+
case "recordKeySet":
|
|
679
|
+
case "arraySet":
|
|
680
|
+
case "arraySetLength":
|
|
681
|
+
case "bytesSet":
|
|
682
|
+
case "arraySetUndefined":
|
|
683
|
+
case "arrayDelete":
|
|
684
|
+
return true;
|
|
685
|
+
case "if":
|
|
686
|
+
return s.then.every(seqExprSafeStmt) && (s.else_?.every(seqExprSafeStmt) ?? true);
|
|
687
|
+
case "block":
|
|
688
|
+
return s.body.every(seqExprSafeStmt);
|
|
689
|
+
default:
|
|
690
|
+
return false;
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
export function lowerCompoundValueToTarget(lowerer, expr, compound, target) {
|
|
694
|
+
const loc = locOf(expr);
|
|
695
|
+
const read = {
|
|
696
|
+
kind: "varRef",
|
|
697
|
+
localId: target.id,
|
|
698
|
+
type: target.type,
|
|
699
|
+
loc: locOf(expr.left),
|
|
700
|
+
};
|
|
701
|
+
const rhs = lowerer.lowerExpr(expr.right);
|
|
702
|
+
const numericRead = lowerOptionalNumber(lowerer, read, loc);
|
|
703
|
+
const numericRhs = lowerOptionalNumber(lowerer, rhs, loc);
|
|
704
|
+
if (compound === "+" &&
|
|
705
|
+
(target.type.kind === "string" ||
|
|
706
|
+
(target.type.kind === "union" &&
|
|
707
|
+
lowerer.stripUndefinedArm(target.type).kind === "string" &&
|
|
708
|
+
rhs.type.kind === "string"))) {
|
|
709
|
+
return lowerer.coerceInto(expr, {
|
|
710
|
+
kind: "strConcat",
|
|
711
|
+
left: lowerer.ensureString(read, expr.left),
|
|
712
|
+
right: concatOperand(lowerer, rhs, expr.right),
|
|
713
|
+
type: STRING,
|
|
714
|
+
loc,
|
|
715
|
+
}, target.type);
|
|
716
|
+
}
|
|
717
|
+
if (numericRead.type.kind === "f64" && numericRhs.type.kind === "f64") {
|
|
718
|
+
return lowerer.coerceInto(expr, { kind: "bin", op: compound, left: numericRead, right: numericRhs, type: F64, loc }, target.type);
|
|
719
|
+
}
|
|
720
|
+
// An untyped operand: exactly the expanded `x = x op rhs` — the runtime
|
|
721
|
+
// operator on both values, then the checked conversion into the
|
|
722
|
+
// target's declared type (a string result for a number target throws the
|
|
723
|
+
// catchable TypeError, as the expanded assignment does).
|
|
724
|
+
if ((target.type.kind === "dyn" || rhs.type.kind === "dyn") &&
|
|
725
|
+
(isJsSourceFile(ts.getSourceFileOfNode(expr)) ||
|
|
726
|
+
(lowerer.dynConvertible(read.type) && lowerer.dynConvertible(rhs.type)))) {
|
|
727
|
+
const left = lowerer.coerceInto(expr.left, read, DYN);
|
|
728
|
+
const right = lowerer.coerceInto(expr.right, rhs, DYN);
|
|
729
|
+
return lowerer.coerceInto(expr, dynCompoundValue(compound, left, right, loc), target.type);
|
|
730
|
+
}
|
|
731
|
+
const bigint = bigintCompoundValue(compound, read, rhs, loc);
|
|
732
|
+
if (bigint)
|
|
733
|
+
return bigint;
|
|
734
|
+
compoundUnsupported(lowerer, expr, compound, read.type, rhs.type);
|
|
735
|
+
}
|
|
736
|
+
/** Equality of two NaN-coded values (nan-coded-reads.ts), each of which may
|
|
737
|
+
* stand for undefined and never holds a genuine NaN: Node's undefined equals
|
|
738
|
+
* undefined, so two NaNs compare equal here. Operands evaluate once, in
|
|
739
|
+
* order. */
|
|
740
|
+
function lowerNanCodedEquality(lowerer, expr) {
|
|
741
|
+
const loc = locOf(expr);
|
|
742
|
+
const left = lowerer.lowerExpr(expr.left);
|
|
743
|
+
const right = lowerer.lowerExpr(expr.right);
|
|
744
|
+
if (left.type.kind !== "f64" || right.type.kind !== "f64") {
|
|
745
|
+
throw new InternalCompilerError("NaN-coded equality operand is not a plain number");
|
|
746
|
+
}
|
|
747
|
+
const stmts = [];
|
|
748
|
+
const stable = (value, name) => {
|
|
749
|
+
if (value.kind === "varRef" || value.kind === "numLit")
|
|
750
|
+
return value;
|
|
751
|
+
const tmp = lowerer.declareHiddenLocal(name, F64);
|
|
752
|
+
stmts.push({ kind: "varDecl", localId: tmp.id, init: value, loc });
|
|
753
|
+
return varRef(tmp.id, F64, loc);
|
|
754
|
+
};
|
|
755
|
+
const a = stable(left, "%eqLeft");
|
|
756
|
+
const b = stable(right, "%eqRight");
|
|
757
|
+
const isNaN = (value) => ({
|
|
758
|
+
kind: "libCall",
|
|
759
|
+
fn: "num.isNaN",
|
|
760
|
+
args: [value],
|
|
761
|
+
type: BOOL,
|
|
762
|
+
loc,
|
|
763
|
+
});
|
|
764
|
+
const bothUndefined = {
|
|
765
|
+
kind: "logical",
|
|
766
|
+
op: "&&",
|
|
767
|
+
left: isNaN(a),
|
|
768
|
+
right: isNaN(b),
|
|
769
|
+
type: BOOL,
|
|
770
|
+
loc,
|
|
771
|
+
};
|
|
772
|
+
const op = expr.operatorToken.kind;
|
|
773
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken ||
|
|
774
|
+
op === ts.SyntaxKind.ExclamationEqualsToken;
|
|
775
|
+
const result = negated
|
|
776
|
+
? {
|
|
777
|
+
kind: "logical",
|
|
778
|
+
op: "&&",
|
|
779
|
+
left: { kind: "bin", op: "!==", left: a, right: b, type: BOOL, loc },
|
|
780
|
+
right: { kind: "unary", op: "!", operand: bothUndefined, type: BOOL, loc },
|
|
781
|
+
type: BOOL,
|
|
782
|
+
loc,
|
|
783
|
+
}
|
|
784
|
+
: {
|
|
785
|
+
kind: "logical",
|
|
786
|
+
op: "||",
|
|
787
|
+
left: { kind: "bin", op: "===", left: a, right: b, type: BOOL, loc },
|
|
788
|
+
right: bothUndefined,
|
|
789
|
+
type: BOOL,
|
|
790
|
+
loc,
|
|
791
|
+
};
|
|
792
|
+
return stmts.length === 0 ? result : { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
793
|
+
}
|
|
794
|
+
export function lowerBinary(lowerer, expr) {
|
|
795
|
+
const loc = locOf(expr);
|
|
796
|
+
const op = expr.operatorToken.kind;
|
|
797
|
+
const cacheHas = lowerRequireCacheHas(lowerer, expr);
|
|
798
|
+
if (cacheHas)
|
|
799
|
+
return cacheHas;
|
|
800
|
+
if (lowerer.nanCodedReads?.needsUndefinedEquality(expr)) {
|
|
801
|
+
const undefinedEquality = lowerNanCodedEquality(lowerer, expr);
|
|
802
|
+
if (undefinedEquality)
|
|
803
|
+
return undefinedEquality;
|
|
804
|
+
}
|
|
805
|
+
if (op === ts.SyntaxKind.EqualsToken ||
|
|
806
|
+
(op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment)) {
|
|
807
|
+
const urlWrite = lowerUrlAssignment(lowerer, expr);
|
|
808
|
+
if (urlWrite)
|
|
809
|
+
return urlWrite;
|
|
810
|
+
if (op === ts.SyntaxKind.EqualsToken) {
|
|
811
|
+
const prototypeWrite = lowerClassPrototypeComputedAssignment(lowerer, expr);
|
|
812
|
+
if (prototypeWrite)
|
|
813
|
+
return prototypeWrite;
|
|
814
|
+
const callableWrite = lowerNativeFunctionAssignment(lowerer, expr);
|
|
815
|
+
if (callableWrite)
|
|
816
|
+
return callableWrite;
|
|
817
|
+
}
|
|
818
|
+
if (op === ts.SyntaxKind.QuestionQuestionEqualsToken ||
|
|
819
|
+
op === ts.SyntaxKind.AmpersandAmpersandEqualsToken ||
|
|
820
|
+
op === ts.SyntaxKind.BarBarEqualsToken) {
|
|
821
|
+
return lowerShortCircuitAssignment(lowerer, expr);
|
|
822
|
+
}
|
|
823
|
+
if (ts.isPropertyAccessExpression(expr.left) || ts.isElementAccessExpression(expr.left)) {
|
|
824
|
+
fenceNodeModuleMutation(lowerer, expr.left, "assignment");
|
|
825
|
+
}
|
|
826
|
+
// The writable Event accessors on Event subclass instances, in value
|
|
827
|
+
// position (`const r = (event.returnValue = false)`).
|
|
828
|
+
if (op === ts.SyntaxKind.EqualsToken && ts.isPropertyAccessExpression(expr.left)) {
|
|
829
|
+
const eventWrite = lowerEventObjectPropertyWrite(lowerer, expr.left, expr.right);
|
|
830
|
+
if (eventWrite)
|
|
831
|
+
return eventWrite;
|
|
832
|
+
}
|
|
833
|
+
// `x = e` in EXPRESSION position (`while ((idx = s.indexOf("\n")) !== -1)`,
|
|
834
|
+
// `f(x = v)`): evaluate e once, write the binding, yield the assigned
|
|
835
|
+
// value — JS evaluation order. Variable targets only (locals and module
|
|
836
|
+
// globals, captured/boxed included); the RHS coerces into the binding's
|
|
837
|
+
// type exactly like statement position, and the expression's value is
|
|
838
|
+
// the coerced binding-typed value (representation change only — never
|
|
839
|
+
// observably different from JS's raw-RHS yield). Indexed compounds
|
|
840
|
+
// use a sequenced read/modify/write; other member targets and
|
|
841
|
+
// destructuring targets stay fenced.
|
|
842
|
+
if (op === ts.SyntaxKind.EqualsToken && ts.isIdentifier(expr.left)) {
|
|
843
|
+
const target = lowerer.resolveWritable(expr.left);
|
|
844
|
+
if (!target) {
|
|
845
|
+
lowerer.rejectUnresolved(expr.left, `assignment to '${expr.left.text}' (not a writable local or module global)`);
|
|
846
|
+
}
|
|
847
|
+
const value = lowerer.lowerExprExpecting(expr.right, target.type);
|
|
848
|
+
const runtimeOptionalRoot = lowerer.runtimeOptionalRootOf(target);
|
|
849
|
+
if (lowerer.runtimeOptionalStorageLocals.has(runtimeOptionalRoot))
|
|
850
|
+
lowerer.runtimeOptionalLocals.add(runtimeOptionalRoot);
|
|
851
|
+
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
852
|
+
}
|
|
853
|
+
const indexedCompound = COMPOUND_ASSIGN_OPS[op];
|
|
854
|
+
if (indexedCompound !== undefined && ts.isElementAccessExpression(expr.left)) {
|
|
855
|
+
if (symbolFieldInfo(lowerer, expr.left))
|
|
856
|
+
return lowerFieldCompoundValue(lowerer, expr.left, indexedCompound, expr.right, loc);
|
|
857
|
+
return lowerElementCompound(lowerer, expr, indexedCompound);
|
|
858
|
+
}
|
|
859
|
+
if (indexedCompound !== undefined && ts.isIdentifier(expr.left)) {
|
|
860
|
+
const target = lowerer.resolveWritable(expr.left);
|
|
861
|
+
if (!target) {
|
|
862
|
+
lowerer.rejectUnresolved(expr.left, "assignment to an unresolved variable");
|
|
863
|
+
}
|
|
864
|
+
const value = lowerCompoundValueToTarget(lowerer, expr, indexedCompound, target);
|
|
865
|
+
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
866
|
+
}
|
|
867
|
+
if (indexedCompound !== undefined &&
|
|
868
|
+
(ts.isPropertyAccessExpression(expr.left) || ts.isElementAccessExpression(expr.left)) &&
|
|
869
|
+
!(ts.isPropertyAccessExpression(expr.left) && expr.left.questionDotToken)) {
|
|
870
|
+
const target = expandoWritableTarget(lowerer, expr.left) ??
|
|
871
|
+
(ts.isPropertyAccessExpression(expr.left) ? nsWritableTarget(lowerer, expr.left) : null);
|
|
872
|
+
if (target) {
|
|
873
|
+
const value = lowerCompoundValueToTarget(lowerer, expr, indexedCompound, target);
|
|
874
|
+
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
875
|
+
}
|
|
876
|
+
return lowerFieldCompoundValue(lowerer, expr.left, indexedCompound, expr.right, loc);
|
|
877
|
+
}
|
|
878
|
+
// `events.defaultMaxListeners = v` — the module-property write
|
|
879
|
+
// Node validates (validateNumber(n, 'defaultMaxListeners', 0)):
|
|
880
|
+
// the value crosses into the checked-dynamic tree and the runtime ladder throws
|
|
881
|
+
// ERR_INVALID_ARG_TYPE / ERR_OUT_OF_RANGE with Node's exact slot
|
|
882
|
+
// name; valid numbers apply. The expression's value is the RHS
|
|
883
|
+
// (JS's assignment yield).
|
|
884
|
+
if (op === ts.SyntaxKind.EqualsToken &&
|
|
885
|
+
ts.isPropertyAccessExpression(expr.left) &&
|
|
886
|
+
!expr.left.questionDotToken &&
|
|
887
|
+
expr.left.name.text === "defaultMaxListeners") {
|
|
888
|
+
const bi = lowerer.builtinMemberOf(expr.left);
|
|
889
|
+
if (bi && bi.module === "events" && bi.member === "defaultMaxListeners") {
|
|
890
|
+
const rhs = lowerer.lowerExpr(expr.right);
|
|
891
|
+
if (rhs.type.kind === "dyn" || rhs.kind === "unitLit" || lowerer.dynConvertible(rhs.type)) {
|
|
892
|
+
const valTmp = lowerer.declareHiddenLocal("%setVal", rhs.type);
|
|
893
|
+
const valRef = () => ({
|
|
894
|
+
kind: "varRef",
|
|
895
|
+
localId: valTmp.id,
|
|
896
|
+
type: rhs.type,
|
|
897
|
+
loc,
|
|
898
|
+
});
|
|
899
|
+
const dynVal = rhs.type.kind === "dyn"
|
|
900
|
+
? valRef()
|
|
901
|
+
: { kind: "dynFrom", value: valRef(), type: DYN, loc };
|
|
902
|
+
return {
|
|
903
|
+
kind: "seqExpr",
|
|
904
|
+
stmts: [
|
|
905
|
+
{ kind: "varDecl", localId: valTmp.id, init: rhs, loc },
|
|
906
|
+
{
|
|
907
|
+
kind: "exprStmt",
|
|
908
|
+
expr: {
|
|
909
|
+
kind: "libCall",
|
|
910
|
+
fn: "emitter.setDefaultMaxChk",
|
|
911
|
+
args: [
|
|
912
|
+
dynVal,
|
|
913
|
+
{ kind: "strLit", value: "defaultMaxListeners", type: STRING, loc },
|
|
914
|
+
],
|
|
915
|
+
type: VOID,
|
|
916
|
+
loc,
|
|
917
|
+
},
|
|
918
|
+
loc,
|
|
919
|
+
},
|
|
920
|
+
],
|
|
921
|
+
result: valRef(),
|
|
922
|
+
type: rhs.type,
|
|
923
|
+
loc,
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
// Member targets whose storage IS a module global — namespace
|
|
929
|
+
// members (`N.x`) and expando function members (`Foo.baz`): the
|
|
930
|
+
// same assignExpr, since the "member" is a variable.
|
|
931
|
+
if (op === ts.SyntaxKind.EqualsToken &&
|
|
932
|
+
(ts.isPropertyAccessExpression(expr.left) || ts.isElementAccessExpression(expr.left)) &&
|
|
933
|
+
!(ts.isPropertyAccessExpression(expr.left) && expr.left.questionDotToken)) {
|
|
934
|
+
const target = expandoWritableTarget(lowerer, expr.left) ??
|
|
935
|
+
(ts.isPropertyAccessExpression(expr.left) ? nsWritableTarget(lowerer, expr.left) : null);
|
|
936
|
+
if (target) {
|
|
937
|
+
const value = lowerer.lowerExprExpecting(expr.right, target.type);
|
|
938
|
+
return { kind: "assignExpr", localId: target.id, value, type: target.type, loc };
|
|
939
|
+
}
|
|
940
|
+
// Bundled numeric enums use e[e["name"] = value] = "name".
|
|
941
|
+
// Capture the receiver and key before the RHS. PutValue coerces the
|
|
942
|
+
// key afterward, then yields the RHS without rereading the property.
|
|
943
|
+
if (ts.isElementAccessExpression(expr.left) && !expr.left.questionDotToken) {
|
|
944
|
+
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
|
945
|
+
if (recv &&
|
|
946
|
+
(recv.type.kind === "dyn" ||
|
|
947
|
+
(recv.type.kind === "array" &&
|
|
948
|
+
isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
949
|
+
lowerer.dynConvertible(recv.type)))) {
|
|
950
|
+
return lowerDynMemberAssignment(lowerer, expr, lowerer.coerceInto(expr.left.expression, recv, DYN));
|
|
951
|
+
}
|
|
952
|
+
if (recv?.type.kind === "array" || recv?.type.kind === "bytes") {
|
|
953
|
+
const receiver = lowerer.declareHiddenLocal("%setArray", recv.type);
|
|
954
|
+
const index = lowerer.lowerExpr(expr.left.argumentExpression);
|
|
955
|
+
if (index.type.kind !== "f64")
|
|
956
|
+
lowerer.unsupported("SC1090", expr.left.argumentExpression, "indexing with non-number keys");
|
|
957
|
+
const key = lowerer.declareHiddenLocal("%setIndex", F64);
|
|
958
|
+
const raw = lowerer.lowerExpr(expr.right);
|
|
959
|
+
const value = lowerer.declareHiddenLocal("%setValue", raw.type);
|
|
960
|
+
const result = varRef(value.id, raw.type, loc);
|
|
961
|
+
const arr = varRef(receiver.id, recv.type, loc);
|
|
962
|
+
const idx = varRef(key.id, F64, loc);
|
|
963
|
+
const write = recv.type.kind === "array"
|
|
964
|
+
? arrayValueStore(lowerer, arr, idx, result, recv.type.elem, loc)
|
|
965
|
+
: {
|
|
966
|
+
kind: "bytesSet",
|
|
967
|
+
arr,
|
|
968
|
+
index: idx,
|
|
969
|
+
value: lowerer.coerceInto(expr.right, result, F64),
|
|
970
|
+
loc,
|
|
971
|
+
};
|
|
972
|
+
return {
|
|
973
|
+
kind: "seqExpr",
|
|
974
|
+
stmts: [
|
|
975
|
+
{ kind: "varDecl", localId: receiver.id, init: recv, loc },
|
|
976
|
+
{ kind: "varDecl", localId: key.id, init: index, loc },
|
|
977
|
+
{ kind: "varDecl", localId: value.id, init: raw, loc },
|
|
978
|
+
write,
|
|
979
|
+
],
|
|
980
|
+
result,
|
|
981
|
+
type: result.type,
|
|
982
|
+
loc,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
// `h.k = v` on a CHECKED-DYNAMIC receiver in VALUE position
|
|
987
|
+
// (`var _ = module.exports = foo`): receiver first, then RHS
|
|
988
|
+
// (JS's reference-before-value order), the keyed write, and the
|
|
989
|
+
// RHS value is the expression's value — its OWN type, so the
|
|
990
|
+
// consumer sees exactly what the checker typed.
|
|
991
|
+
if (ts.isPropertyAccessExpression(expr.left) && !expr.left.questionDotToken) {
|
|
992
|
+
// `const src = exports.src = []`: an export member assigned in
|
|
993
|
+
// value position writes its export global and yields the value.
|
|
994
|
+
{
|
|
995
|
+
let inFunction = false;
|
|
996
|
+
for (let p = expr.parent; p !== undefined; p = p.parent) {
|
|
997
|
+
if (ts.isFunctionLike(p) || ts.isClassDeclaration(p) || ts.isClassExpression(p)) {
|
|
998
|
+
inFunction = true;
|
|
999
|
+
break;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
const g = inFunction
|
|
1003
|
+
? cjsExportMemberWriteGlobalOf(lowerer, expr.left)
|
|
1004
|
+
: cjsInFileExportGlobalOf(lowerer, expr.left);
|
|
1005
|
+
if (g) {
|
|
1006
|
+
const value = lowerer.lowerExprExpecting(expr.right, g.type);
|
|
1007
|
+
const tmp = lowerer.declareHiddenLocal("%exportValue", value.type);
|
|
1008
|
+
const result = varRef(tmp.id, value.type, loc);
|
|
1009
|
+
return {
|
|
1010
|
+
kind: "seqExpr",
|
|
1011
|
+
stmts: [
|
|
1012
|
+
{ kind: "varDecl", localId: tmp.id, init: value, loc },
|
|
1013
|
+
{ kind: "assign", localId: g.id, value: result, loc },
|
|
1014
|
+
],
|
|
1015
|
+
result,
|
|
1016
|
+
type: value.type,
|
|
1017
|
+
loc,
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
const recv = tryLowerExpression(lowerer, expr.left.expression);
|
|
1022
|
+
if (recv && recv.type.kind === "dyn")
|
|
1023
|
+
return lowerDynMemberAssignment(lowerer, expr, recv);
|
|
1024
|
+
const unionWrite = lowerUnionFieldWrite(lowerer, expr.left, expr.right);
|
|
1025
|
+
if (unionWrite)
|
|
1026
|
+
return unionWrite;
|
|
1027
|
+
const field = lowerer.fieldTarget(expr.left);
|
|
1028
|
+
if (field) {
|
|
1029
|
+
const recvTmp = lowerer.declareHiddenLocal("%setReceiver", field.obj.type);
|
|
1030
|
+
const receiver = field.obj;
|
|
1031
|
+
field.obj = varRef(recvTmp.id, receiver.type, loc);
|
|
1032
|
+
const value = lowerer.lowerExprExpecting(expr.right, field.fieldType);
|
|
1033
|
+
const valTmp = lowerer.declareHiddenLocal("%setValue", value.type);
|
|
1034
|
+
const result = varRef(valTmp.id, value.type, loc);
|
|
1035
|
+
return {
|
|
1036
|
+
kind: "seqExpr",
|
|
1037
|
+
stmts: [
|
|
1038
|
+
{ kind: "varDecl", localId: recvTmp.id, init: receiver, loc },
|
|
1039
|
+
{ kind: "varDecl", localId: valTmp.id, init: value, loc },
|
|
1040
|
+
lowerer.fieldSetStmt(field, result, loc, expr.left),
|
|
1041
|
+
],
|
|
1042
|
+
result,
|
|
1043
|
+
type: result.type,
|
|
1044
|
+
loc,
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
// Destructuring assignment in VALUE position (`(() => [i] = [i+1])()`,
|
|
1050
|
+
// `({} = {x} = a)`, `var d = ([] = src)`): the statement machinery's
|
|
1051
|
+
// parts under a seqExpr — the expression's value is the RHS value
|
|
1052
|
+
// (JS's GetValue of the right reference), which is exactly the
|
|
1053
|
+
// parts' hidden temp.
|
|
1054
|
+
if (op === ts.SyntaxKind.EqualsToken &&
|
|
1055
|
+
(ts.isObjectLiteralExpression(expr.left) || ts.isArrayLiteralExpression(expr.left))) {
|
|
1056
|
+
const parts = lowerer.lowerDestructuringAssignParts(expr.left, expr.right, loc);
|
|
1057
|
+
return {
|
|
1058
|
+
kind: "seqExpr",
|
|
1059
|
+
stmts: parts.stmts,
|
|
1060
|
+
result: parts.value,
|
|
1061
|
+
type: parts.value.type,
|
|
1062
|
+
loc,
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
lowerer.unsupported("SC1090", expr, op === ts.SyntaxKind.EqualsToken
|
|
1066
|
+
? "assignment to non-variables as an expression (only `x = e` over a variable yields a value; write property/destructuring assignments as statements)"
|
|
1067
|
+
: "compound assignment as an expression (write `x op= e` as a statement, or spell out `x = x op e`)");
|
|
1068
|
+
}
|
|
1069
|
+
if (op === ts.SyntaxKind.EqualsEqualsToken || op === ts.SyntaxKind.ExclamationEqualsToken) {
|
|
1070
|
+
const nullTest = lowerLooseNullCompare(lowerer, expr, loc);
|
|
1071
|
+
if (nullTest)
|
|
1072
|
+
return nullTest;
|
|
1073
|
+
const loose = lowerAbstractEquality(lowerer, deferredSlotOr(lowerer, lowerer.lowerExpr(expr.left)), deferredSlotOr(lowerer, lowerer.lowerExpr(expr.right)), op === ts.SyntaxKind.ExclamationEqualsToken, loc);
|
|
1074
|
+
if (loose)
|
|
1075
|
+
return loose;
|
|
1076
|
+
lowerer.unsupported("SC1040", expr, undefined, "object-to-primitive loose equality can call user-defined valueOf/toString methods — compare explicit primitive conversions instead");
|
|
1077
|
+
}
|
|
1078
|
+
if (op === ts.SyntaxKind.AmpersandAmpersandToken || op === ts.SyntaxKind.BarBarToken) {
|
|
1079
|
+
return lowerLogicalChain(lowerer, expr);
|
|
1080
|
+
}
|
|
1081
|
+
if (op === ts.SyntaxKind.QuestionQuestionToken) {
|
|
1082
|
+
return lowerer.lowerNullishCoalesce(expr, loc);
|
|
1083
|
+
}
|
|
1084
|
+
if (op === ts.SyntaxKind.CommaToken) {
|
|
1085
|
+
// Comma expression in VALUE position (`r = ({} = a, [] = a)` — the
|
|
1086
|
+
// conformance corpus's paired-destructuring idiom): the left operand
|
|
1087
|
+
// runs for EFFECT exactly as its statement lowering (JS discards its
|
|
1088
|
+
// value), the right operand is the expression's value — a seqExpr.
|
|
1089
|
+
// The validator restricts seqExpr statements to straight-line writes
|
|
1090
|
+
// (the lowering point is mid-expression), so a left operand whose
|
|
1091
|
+
// statement lowering needs real control flow keeps a pointed fence
|
|
1092
|
+
// instead of tripping the validator downstream.
|
|
1093
|
+
const effect = lowerer.lowerExprStatement(expr.left);
|
|
1094
|
+
if (!seqExprSafeStmt(effect)) {
|
|
1095
|
+
lowerer.unsupported("SC1090", expr.left, "comma expressions whose left operand needs control flow (run it as its own statement first)");
|
|
1096
|
+
}
|
|
1097
|
+
const result = lowerer.lowerExpr(expr.right);
|
|
1098
|
+
return { kind: "seqExpr", stmts: [effect], result, type: result.type, loc };
|
|
1099
|
+
}
|
|
1100
|
+
if (op === ts.SyntaxKind.InstanceOfKeyword)
|
|
1101
|
+
return lowerer.lowerInstanceOf(expr, loc);
|
|
1102
|
+
if (op === ts.SyntaxKind.InKeyword) {
|
|
1103
|
+
return lowerInExpression(lowerer, expr, loc);
|
|
1104
|
+
}
|
|
1105
|
+
// `typeof e === "string"` on a catch binding or an `unknown` value: a
|
|
1106
|
+
// runtime kind test — intercepted BEFORE the operands lower (a raw
|
|
1107
|
+
// read of the binding is the narrowness fence, and bare `typeof e`
|
|
1108
|
+
// has no lowering).
|
|
1109
|
+
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1110
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
1111
|
+
const test = lowerConstructorGlobalTypeofTest(lowerer, expr, loc) ??
|
|
1112
|
+
lowerWebAssemblyTypeofTest(lowerer, expr, loc) ??
|
|
1113
|
+
lowerErrorCodeTypeofTest(lowerer, expr, loc) ??
|
|
1114
|
+
lowerer.lowerCaughtTypeofTest(expr, loc) ??
|
|
1115
|
+
lowerDynTypeofTest(lowerer, expr, loc) ??
|
|
1116
|
+
lowerUnionTypeofTest(lowerer, expr, loc);
|
|
1117
|
+
if (test)
|
|
1118
|
+
return test;
|
|
1119
|
+
}
|
|
1120
|
+
// `x.constructor === Readable` for an instance of EventEmitter or a
|
|
1121
|
+
// stream class: the instance's own class, compared without a class value.
|
|
1122
|
+
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1123
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
1124
|
+
for (const [side, other] of [
|
|
1125
|
+
[expr.left, expr.right],
|
|
1126
|
+
[expr.right, expr.left],
|
|
1127
|
+
]) {
|
|
1128
|
+
const ctor = runtimeConstructorReceiver(lowerer, side);
|
|
1129
|
+
const target = ctor ? builtinClassRefOf(lowerer, other) : null;
|
|
1130
|
+
if (ctor && (target?.kind === "emitter" || target?.kind === "stream")) {
|
|
1131
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
1132
|
+
return lowerRuntimeConstructorIs(lowerer, ctor.receiver, target.info, negated, loc);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
// `C === EventEmitter` between two builtin class references: the
|
|
1137
|
+
// classes are compile-time values, so the answer folds.
|
|
1138
|
+
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1139
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
1140
|
+
const leftClass = builtinClassRefOf(lowerer, expr.left);
|
|
1141
|
+
const rightClass = leftClass === null ? null : builtinClassRefOf(lowerer, expr.right);
|
|
1142
|
+
if (leftClass !== null && rightClass !== null) {
|
|
1143
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
1144
|
+
const same = sameBuiltinClass(leftClass, rightClass);
|
|
1145
|
+
return { kind: "boolLit", value: same !== negated, type: BOOL, loc };
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
const strictEquality = op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1149
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
1150
|
+
// An identifier whose storage is runtime-optional is compared by its
|
|
1151
|
+
// stored value: the checker's narrowing to the present arm is not a
|
|
1152
|
+
// runtime proof. Identifier reads are pure, so taking the stored value
|
|
1153
|
+
// after both operands lowered keeps the evaluation order. A union on
|
|
1154
|
+
// the other side keeps the narrowed read (union-to-union comparison
|
|
1155
|
+
// has no lowering).
|
|
1156
|
+
let left = strictEquality
|
|
1157
|
+
? (lowerAbsenceProbe(lowerer, expr.left) ?? lowerer.lowerExpr(expr.left))
|
|
1158
|
+
: lowerer.lowerExpr(expr.left);
|
|
1159
|
+
let right = strictEquality
|
|
1160
|
+
? (lowerAbsenceProbe(lowerer, expr.right) ?? lowerer.lowerExpr(expr.right))
|
|
1161
|
+
: lowerer.lowerExpr(expr.right);
|
|
1162
|
+
if (strictEquality) {
|
|
1163
|
+
const storedLeft = runtimeOptionalStorageOperand(lowerer, expr.left);
|
|
1164
|
+
const storedRight = runtimeOptionalStorageOperand(lowerer, expr.right);
|
|
1165
|
+
if (storedLeft !== null && right.type.kind !== "union")
|
|
1166
|
+
left = storedLeft;
|
|
1167
|
+
if (storedRight !== null && left.type.kind !== "union")
|
|
1168
|
+
right = storedRight;
|
|
1169
|
+
// A typed-array read compared with a plain number needs no
|
|
1170
|
+
// `number | undefined` box.
|
|
1171
|
+
const fusedLeft = tryLowerBytesReadNumberEquality(lowerer, left, right, expr.right);
|
|
1172
|
+
if (fusedLeft)
|
|
1173
|
+
left = fusedLeft;
|
|
1174
|
+
else {
|
|
1175
|
+
const fusedRight = tryLowerBytesReadNumberEquality(lowerer, right, left, expr.left);
|
|
1176
|
+
if (fusedRight)
|
|
1177
|
+
right = fusedRight;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
if (strictEquality && (left.type.kind === "caught" || right.type.kind === "caught")) {
|
|
1181
|
+
if (left.type.kind === "caught")
|
|
1182
|
+
left = { kind: "caughtToDyn", value: left, type: DYN, loc: left.loc };
|
|
1183
|
+
if (right.type.kind === "caught")
|
|
1184
|
+
right = { kind: "caughtToDyn", value: right, type: DYN, loc: right.loc };
|
|
1185
|
+
}
|
|
1186
|
+
if (left.type.kind === "dyn" || right.type.kind === "dyn") {
|
|
1187
|
+
// The narrowing unit comparisons ARE answerable on unknown: `v ===
|
|
1188
|
+
// undefined` / `v !== null` test the dyn node's kind directly, and
|
|
1189
|
+
// tsc's control flow narrows the branches (reads then bridge through
|
|
1190
|
+
// maybeNarrow's validated extraction).
|
|
1191
|
+
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1192
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
1193
|
+
const negated = op === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
1194
|
+
const unit = left.kind === "unitLit" ? left : right.kind === "unitLit" ? right : null;
|
|
1195
|
+
const other = left.kind === "unitLit" ? right : left;
|
|
1196
|
+
if (unit && other.type.kind === "dyn") {
|
|
1197
|
+
return {
|
|
1198
|
+
kind: "dynTest",
|
|
1199
|
+
test: unit.unit,
|
|
1200
|
+
...(negated ? { negated: true } : {}),
|
|
1201
|
+
value: other,
|
|
1202
|
+
type: BOOL,
|
|
1203
|
+
loc,
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
// dyn vs SCALAR strict equality (`value !== ""`, `u === 5` — the
|
|
1207
|
+
// normalizePricing filter): a guarded kind test + payload compare,
|
|
1208
|
+
// JS-exact (strict equality never coerces; a non-matching dyn kind
|
|
1209
|
+
// answers false). dyn vs dyn keeps the fence below.
|
|
1210
|
+
const dynSide = left.type.kind === "dyn" ? left : right;
|
|
1211
|
+
const scalarSide = dynSide === left ? right : left;
|
|
1212
|
+
const reference = scalarSide.type;
|
|
1213
|
+
if ((reference.kind === "object" ||
|
|
1214
|
+
reference.kind === "record" ||
|
|
1215
|
+
reference.kind === "array" ||
|
|
1216
|
+
reference.kind === "bytes" ||
|
|
1217
|
+
reference.kind === "func" ||
|
|
1218
|
+
reference.kind === "classval" ||
|
|
1219
|
+
reference.kind === "regex" ||
|
|
1220
|
+
reference.kind === "url" ||
|
|
1221
|
+
reference.kind === "bigint" ||
|
|
1222
|
+
reference.kind === "symbol" ||
|
|
1223
|
+
reference.kind === "map" ||
|
|
1224
|
+
reference.kind === "set" ||
|
|
1225
|
+
reference.kind === "union" ||
|
|
1226
|
+
DYN_HANDLE_KINDS.has(reference.kind)) &&
|
|
1227
|
+
lowerer.dynConvertible(reference)) {
|
|
1228
|
+
// Records, arrays and byte views compare by the capsule identity
|
|
1229
|
+
// their dyn reads produce, including when they arrive through a
|
|
1230
|
+
// union (an optional array field read from a typed record).
|
|
1231
|
+
const liveArm = (type) => {
|
|
1232
|
+
if (type.kind === "array" || type.kind === "bytes")
|
|
1233
|
+
return true;
|
|
1234
|
+
const shape = type.kind === "record" ? lowerer.shapes.get(type.shapeId) : undefined;
|
|
1235
|
+
return !!shape && (shape.fields.length > 0 || shape.indexValue !== undefined);
|
|
1236
|
+
};
|
|
1237
|
+
const boxed = {
|
|
1238
|
+
kind: "dynFrom",
|
|
1239
|
+
value: scalarSide,
|
|
1240
|
+
type: DYN,
|
|
1241
|
+
loc: scalarSide.loc,
|
|
1242
|
+
...(reference.kind === "record" ||
|
|
1243
|
+
liveArm(reference) ||
|
|
1244
|
+
(reference.kind === "union" &&
|
|
1245
|
+
(lowerer.unions.get(reference.unionId)?.arms.some(liveArm) ?? false))
|
|
1246
|
+
? { liveRef: true }
|
|
1247
|
+
: {}),
|
|
1248
|
+
};
|
|
1249
|
+
return {
|
|
1250
|
+
kind: "dynScalarEq",
|
|
1251
|
+
left: scalarSide === left ? boxed : left,
|
|
1252
|
+
right: scalarSide === right ? boxed : right,
|
|
1253
|
+
...(negated ? { negated: true } : {}),
|
|
1254
|
+
type: BOOL,
|
|
1255
|
+
loc,
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
if (dynSide.type.kind === "dyn" &&
|
|
1259
|
+
(scalarSide.type.kind === "f64" ||
|
|
1260
|
+
scalarSide.type.kind === "string" ||
|
|
1261
|
+
scalarSide.type.kind === "bool" ||
|
|
1262
|
+
// dyn vs dyn (`context.actual !== context.exact` —
|
|
1263
|
+
// test/common's exit accounting): the runtime's whole-dyn
|
|
1264
|
+
// strict equality — scalars by value, units by kind,
|
|
1265
|
+
// reference kinds by identity (scr_dyn_strict_eq).
|
|
1266
|
+
scalarSide.type.kind === "dyn")) {
|
|
1267
|
+
return {
|
|
1268
|
+
kind: "dynScalarEq",
|
|
1269
|
+
left,
|
|
1270
|
+
right,
|
|
1271
|
+
...(negated ? { negated: true } : {}),
|
|
1272
|
+
type: BOOL,
|
|
1273
|
+
loc,
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
const bitwise = {
|
|
1278
|
+
[ts.SyntaxKind.AmpersandToken]: "&",
|
|
1279
|
+
[ts.SyntaxKind.BarToken]: "|",
|
|
1280
|
+
[ts.SyntaxKind.CaretToken]: "^",
|
|
1281
|
+
[ts.SyntaxKind.LessThanLessThanToken]: "<<",
|
|
1282
|
+
[ts.SyntaxKind.GreaterThanGreaterThanToken]: ">>",
|
|
1283
|
+
[ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken]: ">>>",
|
|
1284
|
+
};
|
|
1285
|
+
if (bitwise[op]) {
|
|
1286
|
+
const l = lowerer.coerceToExpected(left, DYN);
|
|
1287
|
+
const r = lowerer.coerceToExpected(right, DYN);
|
|
1288
|
+
if (l.type.kind === "dyn" && r.type.kind === "dyn") {
|
|
1289
|
+
const value = {
|
|
1290
|
+
kind: "libCall",
|
|
1291
|
+
fn: "dyn.bitwise",
|
|
1292
|
+
args: [l, r, { kind: "strLit", value: bitwise[op], type: STRING, loc }],
|
|
1293
|
+
type: DYN,
|
|
1294
|
+
loc,
|
|
1295
|
+
};
|
|
1296
|
+
return left.type.kind === "f64" || right.type.kind === "f64"
|
|
1297
|
+
? { kind: "dynCheck", value, type: F64, loc }
|
|
1298
|
+
: value;
|
|
1299
|
+
}
|
|
1300
|
+
}
|
|
1301
|
+
// Numeric operators dispatch on ToNumeric's actual Number/BigInt
|
|
1302
|
+
// result, including values flowing through native callable properties.
|
|
1303
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) ||
|
|
1304
|
+
op === ts.SyntaxKind.PlusToken ||
|
|
1305
|
+
[
|
|
1306
|
+
ts.SyntaxKind.LessThanToken,
|
|
1307
|
+
ts.SyntaxKind.LessThanEqualsToken,
|
|
1308
|
+
ts.SyntaxKind.GreaterThanToken,
|
|
1309
|
+
ts.SyntaxKind.GreaterThanEqualsToken,
|
|
1310
|
+
].includes(op) ||
|
|
1311
|
+
[
|
|
1312
|
+
ts.SyntaxKind.MinusToken,
|
|
1313
|
+
ts.SyntaxKind.AsteriskToken,
|
|
1314
|
+
ts.SyntaxKind.SlashToken,
|
|
1315
|
+
ts.SyntaxKind.PercentToken,
|
|
1316
|
+
ts.SyntaxKind.AsteriskAsteriskToken,
|
|
1317
|
+
].includes(op)) {
|
|
1318
|
+
const other = left.type.kind === "dyn" ? right : left;
|
|
1319
|
+
const NUM_BIN = {
|
|
1320
|
+
[ts.SyntaxKind.MinusToken]: "-",
|
|
1321
|
+
[ts.SyntaxKind.AsteriskToken]: "*",
|
|
1322
|
+
[ts.SyntaxKind.SlashToken]: "/",
|
|
1323
|
+
[ts.SyntaxKind.PercentToken]: "%",
|
|
1324
|
+
[ts.SyntaxKind.AsteriskAsteriskToken]: "**",
|
|
1325
|
+
};
|
|
1326
|
+
const NUM_CMP = {
|
|
1327
|
+
[ts.SyntaxKind.LessThanToken]: "<",
|
|
1328
|
+
[ts.SyntaxKind.LessThanEqualsToken]: "<=",
|
|
1329
|
+
[ts.SyntaxKind.GreaterThanToken]: ">",
|
|
1330
|
+
[ts.SyntaxKind.GreaterThanEqualsToken]: ">=",
|
|
1331
|
+
};
|
|
1332
|
+
const arith = NUM_BIN[op];
|
|
1333
|
+
const cmp = NUM_CMP[op];
|
|
1334
|
+
if (arith) {
|
|
1335
|
+
const l = lowerer.coerceToExpected(left, DYN);
|
|
1336
|
+
const r = lowerer.coerceToExpected(right, DYN);
|
|
1337
|
+
if (l.type.kind === "dyn" && r.type.kind === "dyn") {
|
|
1338
|
+
const value = {
|
|
1339
|
+
kind: "libCall",
|
|
1340
|
+
fn: "dyn.arithmetic",
|
|
1341
|
+
args: [l, r, { kind: "strLit", value: arith, type: STRING, loc }],
|
|
1342
|
+
type: DYN,
|
|
1343
|
+
loc,
|
|
1344
|
+
};
|
|
1345
|
+
const numeric = left.type.kind === "bigint" || right.type.kind === "bigint"
|
|
1346
|
+
? BIGINT_T
|
|
1347
|
+
: left.type.kind === "f64" || right.type.kind === "f64"
|
|
1348
|
+
? F64
|
|
1349
|
+
: null;
|
|
1350
|
+
return numeric ? { kind: "dynCheck", value, type: numeric, loc } : value;
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
if (cmp && lowerer.dynConvertible(left.type) && lowerer.dynConvertible(right.type)) {
|
|
1354
|
+
return {
|
|
1355
|
+
kind: "libCall",
|
|
1356
|
+
fn: "dyn.compare",
|
|
1357
|
+
args: [
|
|
1358
|
+
lowerer.coerceToExpected(left, DYN),
|
|
1359
|
+
lowerer.coerceToExpected(right, DYN),
|
|
1360
|
+
{ kind: "strLit", value: cmp, type: STRING, loc },
|
|
1361
|
+
],
|
|
1362
|
+
type: BOOL,
|
|
1363
|
+
loc,
|
|
1364
|
+
};
|
|
1365
|
+
}
|
|
1366
|
+
// Untyped addition chooses concatenation or numeric addition only
|
|
1367
|
+
// after both operands have undergone ToPrimitive at runtime.
|
|
1368
|
+
if (op === ts.SyntaxKind.PlusToken) {
|
|
1369
|
+
const l = lowerer.coerceToExpected(left, DYN);
|
|
1370
|
+
const r = lowerer.coerceToExpected(right, DYN);
|
|
1371
|
+
if (l.type.kind === "dyn" && r.type.kind === "dyn") {
|
|
1372
|
+
const value = { kind: "libCall", fn: "dyn.add", args: [l, r], type: DYN, loc };
|
|
1373
|
+
// A statically known string operand guarantees a string result.
|
|
1374
|
+
return other.type.kind === "string"
|
|
1375
|
+
? { kind: "dynCheck", value, type: STRING, loc }
|
|
1376
|
+
: value;
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
// Unsupported `any`-origin operations get their specific diagnostic;
|
|
1381
|
+
// unknown retains the narrowing diagnostic below.
|
|
1382
|
+
if ((left.type.kind === "dyn" && lowerer.anyOrigin(expr.left)) ||
|
|
1383
|
+
(right.type.kind === "dyn" && lowerer.anyOrigin(expr.right))) {
|
|
1384
|
+
// `JSON.parse` and other checked-dynamic producers deliberately
|
|
1385
|
+
// remain dyn when assigned to an `any` local: eagerly converting
|
|
1386
|
+
// the binding would deep-copy its data and sever aliases. At an
|
|
1387
|
+
// unsupported operator, require an explicit represented type.
|
|
1388
|
+
lowerer.anyOpFence(`the '${ts.tokenToString(op) ?? ts.syntaxKindName(op)}' operator`, expr);
|
|
1389
|
+
}
|
|
1390
|
+
// tsc allows ===/!== on unknown (arithmetic/comparisons it rejects
|
|
1391
|
+
// itself); a dynamic equality would need a dyn walk — validate first.
|
|
1392
|
+
lowerer.unsupported("SC1100", expr, "operators on 'unknown' values");
|
|
1393
|
+
}
|
|
1394
|
+
if (left.type.kind === "bigint" && right.type.kind === "bigint") {
|
|
1395
|
+
const binary = {
|
|
1396
|
+
[ts.SyntaxKind.PlusToken]: "bigint.add",
|
|
1397
|
+
[ts.SyntaxKind.MinusToken]: "bigint.sub",
|
|
1398
|
+
[ts.SyntaxKind.AsteriskToken]: "bigint.mul",
|
|
1399
|
+
[ts.SyntaxKind.SlashToken]: "bigint.div",
|
|
1400
|
+
[ts.SyntaxKind.PercentToken]: "bigint.mod",
|
|
1401
|
+
[ts.SyntaxKind.AsteriskAsteriskToken]: "bigint.pow",
|
|
1402
|
+
[ts.SyntaxKind.AmpersandToken]: "bigint.and",
|
|
1403
|
+
[ts.SyntaxKind.BarToken]: "bigint.or",
|
|
1404
|
+
[ts.SyntaxKind.CaretToken]: "bigint.xor",
|
|
1405
|
+
[ts.SyntaxKind.LessThanLessThanToken]: "bigint.shl",
|
|
1406
|
+
[ts.SyntaxKind.GreaterThanGreaterThanToken]: "bigint.shr",
|
|
1407
|
+
};
|
|
1408
|
+
const fn = binary[op];
|
|
1409
|
+
if (fn)
|
|
1410
|
+
return { kind: "libCall", fn, args: [left, right], type: BIGINT_T, loc };
|
|
1411
|
+
if (op === ts.SyntaxKind.EqualsEqualsEqualsToken ||
|
|
1412
|
+
op === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
1413
|
+
const equal = {
|
|
1414
|
+
kind: "libCall",
|
|
1415
|
+
fn: "bigint.eq",
|
|
1416
|
+
args: [left, right],
|
|
1417
|
+
type: BOOL,
|
|
1418
|
+
loc,
|
|
1419
|
+
};
|
|
1420
|
+
return op === ts.SyntaxKind.ExclamationEqualsEqualsToken
|
|
1421
|
+
? { kind: "unary", op: "!", operand: equal, type: BOOL, loc }
|
|
1422
|
+
: equal;
|
|
1423
|
+
}
|
|
1424
|
+
if (op === ts.SyntaxKind.LessThanToken ||
|
|
1425
|
+
op === ts.SyntaxKind.LessThanEqualsToken ||
|
|
1426
|
+
op === ts.SyntaxKind.GreaterThanToken ||
|
|
1427
|
+
op === ts.SyntaxKind.GreaterThanEqualsToken) {
|
|
1428
|
+
const cmp = {
|
|
1429
|
+
kind: "libCall",
|
|
1430
|
+
fn: "bigint.cmp",
|
|
1431
|
+
args: [left, right],
|
|
1432
|
+
type: F64,
|
|
1433
|
+
loc,
|
|
1434
|
+
};
|
|
1435
|
+
const zero = { kind: "numLit", value: 0, type: F64, loc };
|
|
1436
|
+
const cmpOp = op === ts.SyntaxKind.LessThanToken
|
|
1437
|
+
? "<"
|
|
1438
|
+
: op === ts.SyntaxKind.LessThanEqualsToken
|
|
1439
|
+
? "<="
|
|
1440
|
+
: op === ts.SyntaxKind.GreaterThanToken
|
|
1441
|
+
? ">"
|
|
1442
|
+
: ">=";
|
|
1443
|
+
return { kind: "bin", op: cmpOp, left: cmp, right: zero, type: BOOL, loc };
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
if ((left.type.kind === "bigint" && right.type.kind === "f64") ||
|
|
1447
|
+
(left.type.kind === "f64" && right.type.kind === "bigint")) {
|
|
1448
|
+
if (op === ts.SyntaxKind.LessThanToken ||
|
|
1449
|
+
op === ts.SyntaxKind.LessThanEqualsToken ||
|
|
1450
|
+
op === ts.SyntaxKind.GreaterThanToken ||
|
|
1451
|
+
op === ts.SyntaxKind.GreaterThanEqualsToken) {
|
|
1452
|
+
const big = left.type.kind === "bigint" ? left : right;
|
|
1453
|
+
const num = left.type.kind === "f64" ? left : right;
|
|
1454
|
+
const cmp = {
|
|
1455
|
+
kind: "libCall",
|
|
1456
|
+
fn: "bigint.cmpNumber",
|
|
1457
|
+
args: [big, num],
|
|
1458
|
+
type: F64,
|
|
1459
|
+
loc,
|
|
1460
|
+
};
|
|
1461
|
+
const cmpLocal = lowerer.declareHiddenLocal("%bigcmp", F64);
|
|
1462
|
+
const cmpRef = { kind: "varRef", localId: cmpLocal.id, type: F64, loc };
|
|
1463
|
+
const unordered = {
|
|
1464
|
+
kind: "bin",
|
|
1465
|
+
op: "===",
|
|
1466
|
+
left: cmpRef,
|
|
1467
|
+
right: { kind: "numLit", value: 2, type: F64, loc },
|
|
1468
|
+
type: BOOL,
|
|
1469
|
+
loc,
|
|
1470
|
+
};
|
|
1471
|
+
const zero = { kind: "numLit", value: 0, type: F64, loc };
|
|
1472
|
+
const leftBig = left.type.kind === "bigint";
|
|
1473
|
+
const cmpOp = leftBig
|
|
1474
|
+
? op === ts.SyntaxKind.LessThanToken
|
|
1475
|
+
? "<"
|
|
1476
|
+
: op === ts.SyntaxKind.LessThanEqualsToken
|
|
1477
|
+
? "<="
|
|
1478
|
+
: op === ts.SyntaxKind.GreaterThanToken
|
|
1479
|
+
? ">"
|
|
1480
|
+
: ">="
|
|
1481
|
+
: op === ts.SyntaxKind.LessThanToken
|
|
1482
|
+
? ">"
|
|
1483
|
+
: op === ts.SyntaxKind.LessThanEqualsToken
|
|
1484
|
+
? ">="
|
|
1485
|
+
: op === ts.SyntaxKind.GreaterThanToken
|
|
1486
|
+
? "<"
|
|
1487
|
+
: "<=";
|
|
1488
|
+
const result = {
|
|
1489
|
+
kind: "logical",
|
|
1490
|
+
op: "&&",
|
|
1491
|
+
left: { kind: "unary", op: "!", operand: unordered, type: BOOL, loc },
|
|
1492
|
+
right: { kind: "bin", op: cmpOp, left: cmpRef, right: zero, type: BOOL, loc },
|
|
1493
|
+
type: BOOL,
|
|
1494
|
+
loc,
|
|
1495
|
+
};
|
|
1496
|
+
return {
|
|
1497
|
+
kind: "seqExpr",
|
|
1498
|
+
stmts: [{ kind: "varDecl", localId: cmpLocal.id, init: cmp, loc }],
|
|
1499
|
+
result,
|
|
1500
|
+
type: BOOL,
|
|
1501
|
+
loc,
|
|
1502
|
+
};
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
// An unchecked array read keeps its undefined arm in the IR even when
|
|
1506
|
+
// the checker typed the binding as `string`. An optional string is not
|
|
1507
|
+
// itself a string operand for `+`: `undefined + 1` and
|
|
1508
|
+
// `undefined + undefined` are NaN, while a present string concatenates.
|
|
1509
|
+
// Keep this predicate exact so a nullable string does not take the
|
|
1510
|
+
// string path either.
|
|
1511
|
+
const optionalStringType = (type) => {
|
|
1512
|
+
if (type.kind !== "union")
|
|
1513
|
+
return false;
|
|
1514
|
+
const arms = lowerer.unions.get(type.unionId)?.arms;
|
|
1515
|
+
return (!!arms &&
|
|
1516
|
+
arms.length === 2 &&
|
|
1517
|
+
arms.some((arm) => arm.kind === "string") &&
|
|
1518
|
+
arms.some((arm) => arm.kind === "undefinedT"));
|
|
1519
|
+
};
|
|
1520
|
+
const arithmeticNumber = (operand, node) => lowerOptionalNumber(lowerer, operand, loc, node);
|
|
1521
|
+
const arithmeticLeft = strictEquality ? left : arithmeticNumber(left, expr.left);
|
|
1522
|
+
const arithmeticRight = strictEquality ? right : arithmeticNumber(right, expr.right);
|
|
1523
|
+
const bothNum = arithmeticLeft.type.kind === "f64" && arithmeticRight.type.kind === "f64";
|
|
1524
|
+
const bothStr = left.type.kind === "string" && right.type.kind === "string";
|
|
1525
|
+
const lowerOptionalStringPlus = () => {
|
|
1526
|
+
const leftOptional = optionalStringType(left.type);
|
|
1527
|
+
const rightOptional = optionalStringType(right.type);
|
|
1528
|
+
if (!leftOptional && !rightOptional)
|
|
1529
|
+
return null;
|
|
1530
|
+
const allowed = (type) => type.kind === "f64" || type.kind === "string" || optionalStringType(type);
|
|
1531
|
+
if (!allowed(left.type) || !allowed(right.type))
|
|
1532
|
+
return null;
|
|
1533
|
+
// The tag tests and the chosen concatenation branch must see the same
|
|
1534
|
+
// operand values. This matters for `take()[0] + 1` and for two reads
|
|
1535
|
+
// with observable getters/calls.
|
|
1536
|
+
const prefix = [];
|
|
1537
|
+
const stable = (operand) => {
|
|
1538
|
+
if (isSafeToRepeat(operand) || isSafeToDiscard(operand))
|
|
1539
|
+
return operand;
|
|
1540
|
+
const tmp = lowerer.declareHiddenLocal("%plus", operand.type);
|
|
1541
|
+
prefix.push({ kind: "varDecl", localId: tmp.id, init: operand, loc });
|
|
1542
|
+
return varRef(tmp.id, operand.type, loc);
|
|
1543
|
+
};
|
|
1544
|
+
const stableLeft = stable(left);
|
|
1545
|
+
const stableRight = stable(right);
|
|
1546
|
+
const leftString = lowerer.ensureString(stableLeft, expr.left);
|
|
1547
|
+
const rightString = lowerer.ensureString(stableRight, expr.right);
|
|
1548
|
+
const concat = {
|
|
1549
|
+
kind: "strConcat",
|
|
1550
|
+
left: leftString,
|
|
1551
|
+
right: rightString,
|
|
1552
|
+
type: STRING,
|
|
1553
|
+
loc,
|
|
1554
|
+
};
|
|
1555
|
+
const nan = {
|
|
1556
|
+
kind: "bin",
|
|
1557
|
+
op: "/",
|
|
1558
|
+
left: numLit(0, loc),
|
|
1559
|
+
right: numLit(0, loc),
|
|
1560
|
+
type: F64,
|
|
1561
|
+
loc,
|
|
1562
|
+
};
|
|
1563
|
+
const resultT = { kind: "union", unionId: lowerer.unions.intern([F64, STRING]) };
|
|
1564
|
+
lowerer.runtimeOptionalArithmeticTypes.set(expr, resultT);
|
|
1565
|
+
const numberTag = lowerer.armTag(resultT.unionId, F64);
|
|
1566
|
+
const stringTag = lowerer.armTag(resultT.unionId, STRING);
|
|
1567
|
+
if (numberTag < 0 || stringTag < 0)
|
|
1568
|
+
throw new InternalCompilerError("lowerer bug: optional string plus result union");
|
|
1569
|
+
const number = () => ({
|
|
1570
|
+
kind: "unionWrap",
|
|
1571
|
+
unionId: resultT.unionId,
|
|
1572
|
+
tag: numberTag,
|
|
1573
|
+
value: nan,
|
|
1574
|
+
type: resultT,
|
|
1575
|
+
loc,
|
|
1576
|
+
});
|
|
1577
|
+
const string = () => ({
|
|
1578
|
+
kind: "unionWrap",
|
|
1579
|
+
unionId: resultT.unionId,
|
|
1580
|
+
tag: stringTag,
|
|
1581
|
+
value: concat,
|
|
1582
|
+
type: resultT,
|
|
1583
|
+
loc,
|
|
1584
|
+
});
|
|
1585
|
+
const undefinedTest = (operand) => ({
|
|
1586
|
+
kind: "unionIsTag",
|
|
1587
|
+
unionId: operand.type.kind === "union" ? operand.type.unionId : "",
|
|
1588
|
+
tag: operand.type.kind === "union" ? lowerer.armTag(operand.type.unionId, UNDEFINED_T) : -1,
|
|
1589
|
+
negated: false,
|
|
1590
|
+
value: operand,
|
|
1591
|
+
type: BOOL,
|
|
1592
|
+
loc,
|
|
1593
|
+
});
|
|
1594
|
+
let result;
|
|
1595
|
+
if (leftOptional && rightOptional) {
|
|
1596
|
+
const rightMissing = undefinedTest(stableRight);
|
|
1597
|
+
const bothMissing = {
|
|
1598
|
+
kind: "ternary",
|
|
1599
|
+
cond: rightMissing,
|
|
1600
|
+
then: number(),
|
|
1601
|
+
else_: string(),
|
|
1602
|
+
type: resultT,
|
|
1603
|
+
loc,
|
|
1604
|
+
};
|
|
1605
|
+
result = {
|
|
1606
|
+
kind: "ternary",
|
|
1607
|
+
cond: undefinedTest(stableLeft),
|
|
1608
|
+
then: bothMissing,
|
|
1609
|
+
else_: string(),
|
|
1610
|
+
type: resultT,
|
|
1611
|
+
loc,
|
|
1612
|
+
};
|
|
1613
|
+
}
|
|
1614
|
+
else if (leftOptional) {
|
|
1615
|
+
result = {
|
|
1616
|
+
kind: "ternary",
|
|
1617
|
+
cond: undefinedTest(stableLeft),
|
|
1618
|
+
then: number(),
|
|
1619
|
+
else_: string(),
|
|
1620
|
+
type: resultT,
|
|
1621
|
+
loc,
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
else {
|
|
1625
|
+
result = {
|
|
1626
|
+
kind: "ternary",
|
|
1627
|
+
cond: undefinedTest(stableRight),
|
|
1628
|
+
then: number(),
|
|
1629
|
+
else_: string(),
|
|
1630
|
+
type: resultT,
|
|
1631
|
+
loc,
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
return prefix.length === 0
|
|
1635
|
+
? result
|
|
1636
|
+
: { kind: "seqExpr", stmts: prefix, result, type: resultT, loc };
|
|
1637
|
+
};
|
|
1638
|
+
switch (op) {
|
|
1639
|
+
case ts.SyntaxKind.PlusToken:
|
|
1640
|
+
if (bothNum)
|
|
1641
|
+
return {
|
|
1642
|
+
kind: "bin",
|
|
1643
|
+
op: "+",
|
|
1644
|
+
left: arithmeticLeft,
|
|
1645
|
+
right: arithmeticRight,
|
|
1646
|
+
type: F64,
|
|
1647
|
+
loc,
|
|
1648
|
+
};
|
|
1649
|
+
if (left.type.kind === "string" || right.type.kind === "string") {
|
|
1650
|
+
return {
|
|
1651
|
+
kind: "strConcat",
|
|
1652
|
+
left: concatOperand(lowerer, left, expr.left),
|
|
1653
|
+
right: concatOperand(lowerer, right, expr.right),
|
|
1654
|
+
type: STRING,
|
|
1655
|
+
loc,
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
const optionalStringPlus = lowerOptionalStringPlus();
|
|
1659
|
+
if (optionalStringPlus)
|
|
1660
|
+
return optionalStringPlus;
|
|
1661
|
+
{
|
|
1662
|
+
const primitive = (type) => type.kind === "f64" ||
|
|
1663
|
+
type.kind === "string" ||
|
|
1664
|
+
type.kind === "bool" ||
|
|
1665
|
+
isUnitType(type) ||
|
|
1666
|
+
(type.kind === "union" &&
|
|
1667
|
+
(lowerer.unions.get(type.unionId)?.arms.every(primitive) ?? false));
|
|
1668
|
+
if ((left.type.kind === "union" || right.type.kind === "union") &&
|
|
1669
|
+
primitive(left.type) &&
|
|
1670
|
+
primitive(right.type)) {
|
|
1671
|
+
lowerer.runtimeOptionalArithmeticTypes.set(expr, DYN);
|
|
1672
|
+
return {
|
|
1673
|
+
kind: "libCall",
|
|
1674
|
+
fn: "dyn.add",
|
|
1675
|
+
args: [lowerer.coerceToExpected(left, DYN), lowerer.coerceToExpected(right, DYN)],
|
|
1676
|
+
type: DYN,
|
|
1677
|
+
loc,
|
|
1678
|
+
};
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
operatorUnsupported(lowerer, expr, "+", [left.type, right.type]);
|
|
1682
|
+
break;
|
|
1683
|
+
case ts.SyntaxKind.MinusToken:
|
|
1684
|
+
case ts.SyntaxKind.AsteriskToken:
|
|
1685
|
+
case ts.SyntaxKind.SlashToken:
|
|
1686
|
+
case ts.SyntaxKind.PercentToken:
|
|
1687
|
+
case ts.SyntaxKind.AsteriskAsteriskToken: {
|
|
1688
|
+
if (!bothNum)
|
|
1689
|
+
operatorUnsupported(lowerer, expr, ts.tokenToString(op) ?? "?", [left.type, right.type]);
|
|
1690
|
+
const binOp = op === ts.SyntaxKind.MinusToken
|
|
1691
|
+
? "-"
|
|
1692
|
+
: op === ts.SyntaxKind.AsteriskToken
|
|
1693
|
+
? "*"
|
|
1694
|
+
: op === ts.SyntaxKind.SlashToken
|
|
1695
|
+
? "/"
|
|
1696
|
+
: op === ts.SyntaxKind.PercentToken
|
|
1697
|
+
? "%"
|
|
1698
|
+
: "**";
|
|
1699
|
+
return {
|
|
1700
|
+
kind: "bin",
|
|
1701
|
+
op: binOp,
|
|
1702
|
+
left: arithmeticLeft,
|
|
1703
|
+
right: arithmeticRight,
|
|
1704
|
+
type: F64,
|
|
1705
|
+
loc,
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
// The bitwise six, JS-exact: operands through ToInt32/ToUint32
|
|
1709
|
+
// (NaN/±Infinity → 0, truncate, wrap mod 2^32), the operation in
|
|
1710
|
+
// 32-bit space (shift counts masked to 5 bits), the result back to
|
|
1711
|
+
// f64 — `>>>` as Uint32, the rest as Int32 (runtime scr_bit_*).
|
|
1712
|
+
case ts.SyntaxKind.AmpersandToken:
|
|
1713
|
+
case ts.SyntaxKind.BarToken:
|
|
1714
|
+
case ts.SyntaxKind.CaretToken:
|
|
1715
|
+
case ts.SyntaxKind.LessThanLessThanToken:
|
|
1716
|
+
case ts.SyntaxKind.GreaterThanGreaterThanToken:
|
|
1717
|
+
case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: {
|
|
1718
|
+
if (!bothNum)
|
|
1719
|
+
operatorUnsupported(lowerer, expr, ts.tokenToString(op) ?? "?", [left.type, right.type]);
|
|
1720
|
+
const bitOp = op === ts.SyntaxKind.AmpersandToken
|
|
1721
|
+
? "&"
|
|
1722
|
+
: op === ts.SyntaxKind.BarToken
|
|
1723
|
+
? "|"
|
|
1724
|
+
: op === ts.SyntaxKind.CaretToken
|
|
1725
|
+
? "^"
|
|
1726
|
+
: op === ts.SyntaxKind.LessThanLessThanToken
|
|
1727
|
+
? "<<"
|
|
1728
|
+
: op === ts.SyntaxKind.GreaterThanGreaterThanToken
|
|
1729
|
+
? ">>"
|
|
1730
|
+
: ">>>";
|
|
1731
|
+
return {
|
|
1732
|
+
kind: "bin",
|
|
1733
|
+
op: bitOp,
|
|
1734
|
+
left: arithmeticLeft,
|
|
1735
|
+
right: arithmeticRight,
|
|
1736
|
+
type: F64,
|
|
1737
|
+
loc,
|
|
1738
|
+
};
|
|
1739
|
+
}
|
|
1740
|
+
case ts.SyntaxKind.EqualsEqualsEqualsToken:
|
|
1741
|
+
case ts.SyntaxKind.ExclamationEqualsEqualsToken:
|
|
1742
|
+
return lowerStrictEquality(lowerer, expr, expr.left, expr.right, left, right, op === ts.SyntaxKind.ExclamationEqualsEqualsToken, loc);
|
|
1743
|
+
case ts.SyntaxKind.LessThanToken:
|
|
1744
|
+
case ts.SyntaxKind.LessThanEqualsToken:
|
|
1745
|
+
case ts.SyntaxKind.GreaterThanToken:
|
|
1746
|
+
case ts.SyntaxKind.GreaterThanEqualsToken: {
|
|
1747
|
+
const cmpOp = op === ts.SyntaxKind.LessThanToken
|
|
1748
|
+
? "<"
|
|
1749
|
+
: op === ts.SyntaxKind.LessThanEqualsToken
|
|
1750
|
+
? "<="
|
|
1751
|
+
: op === ts.SyntaxKind.GreaterThanToken
|
|
1752
|
+
? ">"
|
|
1753
|
+
: ">=";
|
|
1754
|
+
if (bothNum)
|
|
1755
|
+
return {
|
|
1756
|
+
kind: "bin",
|
|
1757
|
+
op: cmpOp,
|
|
1758
|
+
left: arithmeticLeft,
|
|
1759
|
+
right: arithmeticRight,
|
|
1760
|
+
type: BOOL,
|
|
1761
|
+
loc,
|
|
1762
|
+
};
|
|
1763
|
+
if (bothStr)
|
|
1764
|
+
return { kind: "strCmp", op: cmpOp, left, right, type: BOOL, loc };
|
|
1765
|
+
// A Date converts to a new checked-dynamic Date on each crossing, so
|
|
1766
|
+
// comparisons keep their Date fence instead of comparing copies.
|
|
1767
|
+
if (left.type.kind !== "date" &&
|
|
1768
|
+
right.type.kind !== "date" &&
|
|
1769
|
+
lowerer.dynConvertible(left.type) &&
|
|
1770
|
+
lowerer.dynConvertible(right.type)) {
|
|
1771
|
+
return {
|
|
1772
|
+
kind: "libCall",
|
|
1773
|
+
fn: "dyn.compare",
|
|
1774
|
+
args: [
|
|
1775
|
+
lowerer.coerceToExpected(left, DYN),
|
|
1776
|
+
lowerer.coerceToExpected(right, DYN),
|
|
1777
|
+
{ kind: "strLit", value: cmpOp, type: STRING, loc },
|
|
1778
|
+
],
|
|
1779
|
+
type: BOOL,
|
|
1780
|
+
loc,
|
|
1781
|
+
};
|
|
1782
|
+
}
|
|
1783
|
+
lowerer.unsupported("SC1043", expr);
|
|
1784
|
+
break;
|
|
1785
|
+
}
|
|
1786
|
+
default:
|
|
1787
|
+
break;
|
|
1788
|
+
}
|
|
1789
|
+
lowerer.unsupported("SC1090", expr, `operator '${ts.tokenToString(op) ?? ts.syntaxKindName(op)}'`);
|
|
1790
|
+
}
|
|
1791
|
+
/** `left === right` (`!==` when negated) over lowered operands: JS strict
|
|
1792
|
+
* equality for every pair of static kinds the program can compare.
|
|
1793
|
+
* `node` anchors diagnostics, and `leftNode`/`rightNode` the coercions. */
|
|
1794
|
+
export function lowerStrictEquality(lowerer, node, leftNode, rightNode, left, right, negated, loc) {
|
|
1795
|
+
const plainBothNum = left.type.kind === "f64" && right.type.kind === "f64";
|
|
1796
|
+
const bothStr = left.type.kind === "string" && right.type.kind === "string";
|
|
1797
|
+
const indexed = tryLowerIndexedComparison(lowerer, left, right, negated, loc);
|
|
1798
|
+
if (indexed)
|
|
1799
|
+
return indexed;
|
|
1800
|
+
if (plainBothNum)
|
|
1801
|
+
return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc };
|
|
1802
|
+
if (bothStr) {
|
|
1803
|
+
if (left.kind === "strLit" && right.kind === "strLit")
|
|
1804
|
+
return {
|
|
1805
|
+
kind: "boolLit",
|
|
1806
|
+
value: (left.value === right.value) !== negated,
|
|
1807
|
+
type: BOOL,
|
|
1808
|
+
loc,
|
|
1809
|
+
};
|
|
1810
|
+
return { kind: "strEq", negated, left, right, type: BOOL, loc };
|
|
1811
|
+
}
|
|
1812
|
+
// bool === bool: a plain value compare (the config-drift checks'
|
|
1813
|
+
// `desired.lanMode !== actual.lanMode` shape).
|
|
1814
|
+
if (left.type.kind === "bool" && right.type.kind === "bool") {
|
|
1815
|
+
return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc };
|
|
1816
|
+
}
|
|
1817
|
+
const unitTest = lowerer.lowerUnitComparison(left, right, negated, loc);
|
|
1818
|
+
if (unitTest)
|
|
1819
|
+
return unitTest;
|
|
1820
|
+
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
1821
|
+
const compared = lowerUnionEquality(lowerer, left, right, negated, false, loc);
|
|
1822
|
+
if (compared)
|
|
1823
|
+
return compared;
|
|
1824
|
+
const aliasRefusal = (type) => {
|
|
1825
|
+
if (tagEqualityMayMissAlias(lowerer, type))
|
|
1826
|
+
lowerer.unsupported("SC1090", node, `comparisons of related class values beside structural union members (${NARROW_FIRST})`);
|
|
1827
|
+
};
|
|
1828
|
+
// JS strict equality of the ARM values, per union tag (a
|
|
1829
|
+
// per-union helper): equal tags compare payloads (f64 ==, string
|
|
1830
|
+
// bytes, bool ==, ref-arm POINTER identity), different tags are
|
|
1831
|
+
// never equal. Two shapes lower: same union on both sides, and
|
|
1832
|
+
// union vs plain arm value (`u === "text"` where the checker
|
|
1833
|
+
// didn't narrow) — the plain side wraps into the union, which
|
|
1834
|
+
// preserves payload identity. Different unions (tsc admits
|
|
1835
|
+
// partially-overlapping ones) still need narrowing first.
|
|
1836
|
+
const ut = left.type.kind === "union" ? left.type : right.type;
|
|
1837
|
+
const bothUnion = left.type.kind === "union" && right.type.kind === "union";
|
|
1838
|
+
const sameUnion = bothUnion && typeEquals(left.type, right.type);
|
|
1839
|
+
const plainFunc = left.type.kind === "func" ? left : right.type.kind === "func" ? right : null;
|
|
1840
|
+
const unionArms = lowerer.unions.get(ut.unionId)?.arms ?? [];
|
|
1841
|
+
const funcArm = unionArms.find((arm) => arm.kind === "func");
|
|
1842
|
+
// `listeners()` reports original prefix callbacks, but the
|
|
1843
|
+
// checker views an indexed result as function | undefined. For
|
|
1844
|
+
// identity comparison, retain the original closure pointer rather
|
|
1845
|
+
// than adapting it to the tuple signature.
|
|
1846
|
+
if (!bothUnion &&
|
|
1847
|
+
plainFunc !== null &&
|
|
1848
|
+
funcArm?.kind === "func" &&
|
|
1849
|
+
unionArms.filter((arm) => arm.kind === "func").length === 1 &&
|
|
1850
|
+
unionArms.some(isUnitType)) {
|
|
1851
|
+
return {
|
|
1852
|
+
kind: "unionFuncEq",
|
|
1853
|
+
unionId: ut.unionId,
|
|
1854
|
+
tag: lowerer.armTag(ut.unionId, funcArm),
|
|
1855
|
+
union: left.type.kind === "union" ? left : right,
|
|
1856
|
+
func: plainFunc,
|
|
1857
|
+
negated,
|
|
1858
|
+
type: BOOL,
|
|
1859
|
+
loc,
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
if ((sameUnion || !bothUnion) && lowerer.eqComparableUnion(ut.unionId)) {
|
|
1863
|
+
aliasRefusal(ut);
|
|
1864
|
+
return {
|
|
1865
|
+
kind: "unionEq",
|
|
1866
|
+
unionId: ut.unionId,
|
|
1867
|
+
negated,
|
|
1868
|
+
sameValue: false,
|
|
1869
|
+
left: lowerer.coerceInto(leftNode, left, ut),
|
|
1870
|
+
right: lowerer.coerceInto(rightNode, right, ut),
|
|
1871
|
+
type: BOOL,
|
|
1872
|
+
loc,
|
|
1873
|
+
};
|
|
1874
|
+
}
|
|
1875
|
+
if (left.type.kind === "union" && right.type.kind === "union") {
|
|
1876
|
+
const leftDef = lowerer.unions.get(left.type.unionId);
|
|
1877
|
+
const rightDef = lowerer.unions.get(right.type.unionId);
|
|
1878
|
+
if (leftDef && rightDef) {
|
|
1879
|
+
const leftValues = leftDef.arms.filter((arm) => !isUnitType(arm));
|
|
1880
|
+
const rightValues = rightDef.arms.filter((arm) => !isUnitType(arm));
|
|
1881
|
+
const sameValueArms = leftValues.length === rightValues.length &&
|
|
1882
|
+
leftValues.every((arm) => rightValues.some((candidate) => typeEquals(candidate, arm)));
|
|
1883
|
+
if (sameValueArms) {
|
|
1884
|
+
const arms = [...leftDef.arms];
|
|
1885
|
+
for (const arm of rightDef.arms) {
|
|
1886
|
+
if (!arms.some((candidate) => typeEquals(candidate, arm)))
|
|
1887
|
+
arms.push(arm);
|
|
1888
|
+
}
|
|
1889
|
+
arms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
|
|
1890
|
+
const common = {
|
|
1891
|
+
kind: "union",
|
|
1892
|
+
unionId: lowerer.unions.intern(arms),
|
|
1893
|
+
};
|
|
1894
|
+
aliasRefusal(common);
|
|
1895
|
+
return {
|
|
1896
|
+
kind: "unionEq",
|
|
1897
|
+
unionId: common.unionId,
|
|
1898
|
+
negated,
|
|
1899
|
+
sameValue: false,
|
|
1900
|
+
left: lowerer.coerceInto(leftNode, left, common),
|
|
1901
|
+
right: lowerer.coerceInto(rightNode, right, common),
|
|
1902
|
+
type: BOOL,
|
|
1903
|
+
loc,
|
|
1904
|
+
};
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
lowerer.unsupported("SC1090", node, `comparisons of union-typed values (${NARROW_FIRST})`);
|
|
1909
|
+
}
|
|
1910
|
+
// Arrays, maps, functions, class instances and records compare by
|
|
1911
|
+
// reference identity (pointer compare) — JS-exact object equality.
|
|
1912
|
+
// Hierarchy-related classes compare after widening the derived side
|
|
1913
|
+
// (same pointer either way — prefix layout).
|
|
1914
|
+
let idLeft = left;
|
|
1915
|
+
let idRight = right;
|
|
1916
|
+
if (left.type.kind === "object" && right.type.kind === "object") {
|
|
1917
|
+
if (lowerer.isSubclassOf(left.type.className, right.type.className)) {
|
|
1918
|
+
idLeft = lowerer.upcastTo(left, right.type.className);
|
|
1919
|
+
}
|
|
1920
|
+
else if (lowerer.isSubclassOf(right.type.className, left.type.className)) {
|
|
1921
|
+
idRight = lowerer.upcastTo(right, left.type.className);
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
// Two function values compare by identity whatever their STATIC
|
|
1925
|
+
// signatures (tsc admits the comparison when one side is
|
|
1926
|
+
// assignable to the other — a tuple-typed listeners() element
|
|
1927
|
+
// against a prefix-declared handler): the pointer answers it.
|
|
1928
|
+
if (idLeft.type.kind === "func" && idRight.type.kind === "func") {
|
|
1929
|
+
return {
|
|
1930
|
+
kind: "bin",
|
|
1931
|
+
op: negated ? "!==" : "===",
|
|
1932
|
+
left: idLeft,
|
|
1933
|
+
right: idRight,
|
|
1934
|
+
type: BOOL,
|
|
1935
|
+
loc,
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
// Two CLASS values compare by identity whatever their static
|
|
1939
|
+
// classes — one immortal object per class, one pointer compare
|
|
1940
|
+
// (the function-identity rule verbatim; `X === D` through a
|
|
1941
|
+
// base-typed slot answers exactly JS).
|
|
1942
|
+
if (idLeft.type.kind === "classval" && idRight.type.kind === "classval") {
|
|
1943
|
+
return {
|
|
1944
|
+
kind: "bin",
|
|
1945
|
+
op: negated ? "!==" : "===",
|
|
1946
|
+
left: idLeft,
|
|
1947
|
+
right: idRight,
|
|
1948
|
+
type: BOOL,
|
|
1949
|
+
loc,
|
|
1950
|
+
};
|
|
1951
|
+
}
|
|
1952
|
+
if (idLeft.type.kind === "moduleNs" && idRight.type.kind === "moduleNs") {
|
|
1953
|
+
return {
|
|
1954
|
+
kind: "bin",
|
|
1955
|
+
op: negated ? "!==" : "===",
|
|
1956
|
+
left: idLeft,
|
|
1957
|
+
right: idRight,
|
|
1958
|
+
type: BOOL,
|
|
1959
|
+
loc,
|
|
1960
|
+
};
|
|
1961
|
+
}
|
|
1962
|
+
if ((idLeft.type.kind === "array" ||
|
|
1963
|
+
idLeft.type.kind === "map" ||
|
|
1964
|
+
idLeft.type.kind === "set" ||
|
|
1965
|
+
idLeft.type.kind === "regex" ||
|
|
1966
|
+
idLeft.type.kind === "url" ||
|
|
1967
|
+
idLeft.type.kind === "object" ||
|
|
1968
|
+
idLeft.type.kind === "record" ||
|
|
1969
|
+
// Symbols ARE identity: `Symbol('a') === Symbol('a')` is false,
|
|
1970
|
+
// a symbol equals exactly itself, and Symbol.for's interned
|
|
1971
|
+
// values compare equal across call sites — all one pointer
|
|
1972
|
+
// compare, JS's spec without approximation.
|
|
1973
|
+
idLeft.type.kind === "symbol" ||
|
|
1974
|
+
// Typed arrays / Buffers ARE objects to ===: pointer identity
|
|
1975
|
+
// (buf === buf.swap16() — the in-place mutators return this).
|
|
1976
|
+
idLeft.type.kind === "bytes" ||
|
|
1977
|
+
idLeft.type.kind === "promise") &&
|
|
1978
|
+
typeEquals(idLeft.type, idRight.type)) {
|
|
1979
|
+
return {
|
|
1980
|
+
kind: "bin",
|
|
1981
|
+
op: negated ? "!==" : "===",
|
|
1982
|
+
left: idLeft,
|
|
1983
|
+
right: idRight,
|
|
1984
|
+
type: BOOL,
|
|
1985
|
+
loc,
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
// Runtime HANDLES are objects to === too: one handle per socket/
|
|
1989
|
+
// request/response, so pointer identity IS JS's object equality
|
|
1990
|
+
// (`c.pause() === c` — Node's chaining assertions). */
|
|
1991
|
+
if (DYN_HANDLE_KINDS.has(idLeft.type.kind) && typeEquals(idLeft.type, idRight.type)) {
|
|
1992
|
+
return {
|
|
1993
|
+
kind: "bin",
|
|
1994
|
+
op: negated ? "!==" : "===",
|
|
1995
|
+
left: idLeft,
|
|
1996
|
+
right: idRight,
|
|
1997
|
+
type: BOOL,
|
|
1998
|
+
loc,
|
|
1999
|
+
};
|
|
2000
|
+
}
|
|
2001
|
+
// A Date converts to a new checked-dynamic Date on each crossing; its
|
|
2002
|
+
// identity has no representation, so equality keeps the fence.
|
|
2003
|
+
if (idLeft.type.kind !== "date" &&
|
|
2004
|
+
idRight.type.kind !== "date" &&
|
|
2005
|
+
lowerer.dynConvertible(idLeft.type) &&
|
|
2006
|
+
lowerer.dynConvertible(idRight.type)) {
|
|
2007
|
+
return {
|
|
2008
|
+
kind: "dynScalarEq",
|
|
2009
|
+
left: lowerer.coerceToExpected(idLeft, DYN),
|
|
2010
|
+
right: lowerer.coerceToExpected(idRight, DYN),
|
|
2011
|
+
...(negated ? { negated: true } : {}),
|
|
2012
|
+
type: BOOL,
|
|
2013
|
+
loc,
|
|
2014
|
+
};
|
|
2015
|
+
}
|
|
2016
|
+
return lowerer.unsupported("SC1043", node);
|
|
2017
|
+
}
|
|
2018
|
+
function lowerLogicalChain(lowerer, expr) {
|
|
2019
|
+
// Logical chains have a left-nested AST. Keep the native stack bounded
|
|
2020
|
+
// while retaining each pair's checker type and lazy operand evaluation.
|
|
2021
|
+
const parents = [];
|
|
2022
|
+
let current = expr;
|
|
2023
|
+
let result;
|
|
2024
|
+
while (true) {
|
|
2025
|
+
if (current.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
2026
|
+
const fallback = lowerAbsenceAwareOrChain(lowerer, current);
|
|
2027
|
+
if (fallback !== null) {
|
|
2028
|
+
result = fallback;
|
|
2029
|
+
break;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
const left = current.left;
|
|
2033
|
+
if (ts.isBinaryExpression(left) &&
|
|
2034
|
+
(left.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
2035
|
+
left.operatorToken.kind === ts.SyntaxKind.BarBarToken) &&
|
|
2036
|
+
!lowerer.chainRecvByNode.has(left)) {
|
|
2037
|
+
parents.push(current);
|
|
2038
|
+
current = left;
|
|
2039
|
+
continue;
|
|
2040
|
+
}
|
|
2041
|
+
result = lowerLogicalPair(lowerer, current, current.operatorToken.kind === ts.SyntaxKind.BarBarToken
|
|
2042
|
+
? lowerPresenceOperand(lowerer, left)
|
|
2043
|
+
: (lowerAbsenceProbe(lowerer, left) ?? lowerer.lowerExpr(left)));
|
|
2044
|
+
break;
|
|
2045
|
+
}
|
|
2046
|
+
for (let i = parents.length - 1; i >= 0; i--) {
|
|
2047
|
+
result = lowerLogicalPair(lowerer, parents[i], result);
|
|
2048
|
+
}
|
|
2049
|
+
return result;
|
|
2050
|
+
}
|
|
2051
|
+
function lowerLogicalPair(lowerer, expr, left) {
|
|
2052
|
+
const op = expr.operatorToken.kind;
|
|
2053
|
+
const loc = locOf(expr);
|
|
2054
|
+
// Preserve short-circuiting during lowering too: an unreachable member
|
|
2055
|
+
// on a specialized value must not poison the surrounding JS statement.
|
|
2056
|
+
if (left.kind === "boolLit") {
|
|
2057
|
+
const takeRight = op === ts.SyntaxKind.AmpersandAmpersandToken ? left.value : !left.value;
|
|
2058
|
+
return takeRight ? lowerer.lowerExpr(expr.right) : left;
|
|
2059
|
+
}
|
|
2060
|
+
if (left.kind === "unitLit" && op === ts.SyntaxKind.AmpersandAmpersandToken)
|
|
2061
|
+
return left;
|
|
2062
|
+
if (op === ts.SyntaxKind.BarBarToken && REF_TRUTHY_KINDS.has(left.type.kind))
|
|
2063
|
+
return left;
|
|
2064
|
+
const right = lowerer.lowerExpr(expr.right);
|
|
2065
|
+
// A LITERAL-unit left operand (a compile-time undefined/null — the
|
|
2066
|
+
// capability-probe members: `process.features.inspector ||
|
|
2067
|
+
// !flag.startsWith('--inspect')` reads undefined in a compiled
|
|
2068
|
+
// binary): statically falsy, so the operator folds JS-exactly —
|
|
2069
|
+
// `unit || X` IS X, `unit && X` IS the unit (X's side effects never
|
|
2070
|
+
// run in JS either; the lowered right is simply dropped). Literal
|
|
2071
|
+
// units only — computed unit-typed values keep the fences below.
|
|
2072
|
+
if (left.kind === "unitLit") {
|
|
2073
|
+
return op === ts.SyntaxKind.BarBarToken ? right : left;
|
|
2074
|
+
}
|
|
2075
|
+
// JS objects and symbols are always truthy. In `ref || fallback`
|
|
2076
|
+
// the fallback is therefore unreachable and the result is the
|
|
2077
|
+
// already-evaluated left value — the browser-fallback idiom used by
|
|
2078
|
+
// packages for `process.argv || []` and `process.env || {}`. The
|
|
2079
|
+
// operand itself remains in the IR, preserving reads/calls that
|
|
2080
|
+
// produce the reference; only the unreachable right lowering drops.
|
|
2081
|
+
if (op === ts.SyntaxKind.BarBarToken && REF_TRUTHY_KINDS.has(left.type.kind)) {
|
|
2082
|
+
return left;
|
|
2083
|
+
}
|
|
2084
|
+
if (left.type.kind === "dyn" || right.type.kind === "dyn") {
|
|
2085
|
+
// A checked-dynamic operand (`fn.name || '<anonymous>'` —
|
|
2086
|
+
// test/common's _mustCallInner): both sides live in the checked-dynamic tree and
|
|
2087
|
+
// the deciding test is ToBoolean over the dyn kind
|
|
2088
|
+
// (scr_dyn_truthy) — JS value semantics exactly, result dyn. The
|
|
2089
|
+
// non-dyn side converts through the usual boundary; a value with
|
|
2090
|
+
// no dyn representation keeps the fence.
|
|
2091
|
+
const l = lowerer.coerceToExpected(left, DYN);
|
|
2092
|
+
const r = lowerer.coerceToExpected(right, DYN);
|
|
2093
|
+
if (l.type.kind !== "dyn" || r.type.kind !== "dyn") {
|
|
2094
|
+
lowerer.unsupported("SC1100", expr, "logical operators on 'unknown' values");
|
|
2095
|
+
}
|
|
2096
|
+
return {
|
|
2097
|
+
kind: "logical",
|
|
2098
|
+
op: op === ts.SyntaxKind.AmpersandAmpersandToken ? "&&" : "||",
|
|
2099
|
+
left: l,
|
|
2100
|
+
right: r,
|
|
2101
|
+
type: DYN,
|
|
2102
|
+
loc,
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
2105
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
2106
|
+
op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
2107
|
+
left.type.kind === "union" &&
|
|
2108
|
+
lowerer.unions.get(left.type.unionId)?.arms.some((arm) => arm.kind === "bool") &&
|
|
2109
|
+
!typeEquals(left.type, right.type) &&
|
|
2110
|
+
lowerer.dynConvertible(left.type) &&
|
|
2111
|
+
lowerer.dynConvertible(right.type)) {
|
|
2112
|
+
return {
|
|
2113
|
+
kind: "logical",
|
|
2114
|
+
op: "&&",
|
|
2115
|
+
left: lowerer.coerceToExpected(left, DYN),
|
|
2116
|
+
right: lowerer.coerceToExpected(right, DYN),
|
|
2117
|
+
type: DYN,
|
|
2118
|
+
loc,
|
|
2119
|
+
};
|
|
2120
|
+
}
|
|
2121
|
+
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
2122
|
+
// Test the deciding operand in its own representation. The result
|
|
2123
|
+
// contains only the values that can survive short-circuit evaluation.
|
|
2124
|
+
let target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
2125
|
+
// Index reads can be absent without noUncheckedIndexedAccess. Their
|
|
2126
|
+
// explicit nullish fallback still runs, even if the checker discarded it.
|
|
2127
|
+
if (target !== null) {
|
|
2128
|
+
const returned = [
|
|
2129
|
+
right.type,
|
|
2130
|
+
...(op === ts.SyntaxKind.AmpersandAmpersandToken ? [left.type] : []),
|
|
2131
|
+
];
|
|
2132
|
+
for (const type of returned) {
|
|
2133
|
+
const arms = type.kind === "union" ? (lowerer.unions.get(type.unionId)?.arms ?? []) : [type];
|
|
2134
|
+
for (const arm of arms) {
|
|
2135
|
+
if (arm.kind === "undefinedT" && !isUnitType(target))
|
|
2136
|
+
target = lowerer.runtimeOptionalType(target);
|
|
2137
|
+
if (arm.kind === "nullT")
|
|
2138
|
+
target = withUnitArm(target, arm.kind, lowerer.unions) ?? target;
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
// A broad-JSDoc npm-static body can leave the CHECKER result `any`
|
|
2143
|
+
// even after declaration-backed specialization has recovered both
|
|
2144
|
+
// operands (`helpOption && args.find(...)` in commander). When the
|
|
2145
|
+
// left consists only of always-truthy references and falsy units,
|
|
2146
|
+
// the static result is exactly the right operand plus those units.
|
|
2147
|
+
if (op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
2148
|
+
target === null &&
|
|
2149
|
+
lowerer.implicitParamTypes !== null &&
|
|
2150
|
+
npmStaticPackageOfPath(ts.getSourceFileOfNode(expr).fileName) !== null &&
|
|
2151
|
+
(lowerer.typeOf(expr).flags & ts.TypeFlags.Any) !== 0 &&
|
|
2152
|
+
left.type.kind === "union") {
|
|
2153
|
+
const leftArms = lowerer.unions.get(left.type.unionId)?.arms;
|
|
2154
|
+
const rightArms = right.type.kind === "union" ? lowerer.unions.get(right.type.unionId)?.arms : [right.type];
|
|
2155
|
+
const rightIsStatic = rightArms?.every((arm) => arm.kind !== "dyn" && arm.kind !== "caught" && arm.kind !== "void") ?? false;
|
|
2156
|
+
if (leftArms &&
|
|
2157
|
+
rightArms &&
|
|
2158
|
+
rightIsStatic &&
|
|
2159
|
+
leftArms.some(isUnitType) &&
|
|
2160
|
+
leftArms.every((arm) => isUnitType(arm) || REF_TRUTHY_KINDS.has(arm.kind))) {
|
|
2161
|
+
const byKey = new Map();
|
|
2162
|
+
for (const arm of [...rightArms, ...leftArms.filter(isUnitType)]) {
|
|
2163
|
+
byKey.set(typeKey(arm), arm);
|
|
2164
|
+
}
|
|
2165
|
+
const arms = [...byKey.values()].sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
|
|
2166
|
+
if (arms.length > 1) {
|
|
2167
|
+
const source = right.type.kind === "union" ? lowerer.unions.get(right.type.unionId) : undefined;
|
|
2168
|
+
target = {
|
|
2169
|
+
kind: "union",
|
|
2170
|
+
unionId: source ? lowerer.unions.transform(source, arms) : lowerer.unions.intern(arms),
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
// `&&` over an always-truthy plain left operand (an array, object or
|
|
2176
|
+
// function value) whose result union has no arm for it: every JS
|
|
2177
|
+
// object is truthy, so `list && list[0]` evaluates the left for its
|
|
2178
|
+
// effects and answers the right. Coercing the left into that union
|
|
2179
|
+
// would trap at run time where Node answers the right operand.
|
|
2180
|
+
if (op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
2181
|
+
target?.kind === "union" &&
|
|
2182
|
+
REF_TRUTHY_KINDS.has(left.type.kind) &&
|
|
2183
|
+
lowerer.armTag(target.unionId, left.type) < 0) {
|
|
2184
|
+
return {
|
|
2185
|
+
kind: "seqExpr",
|
|
2186
|
+
stmts: [{ kind: "exprStmt", expr: left, loc }],
|
|
2187
|
+
result: lowerer.coerceInto(expr.right, right, target),
|
|
2188
|
+
type: target,
|
|
2189
|
+
loc,
|
|
2190
|
+
};
|
|
2191
|
+
}
|
|
2192
|
+
if (target?.kind === "union") {
|
|
2193
|
+
// `&&` whose left does NOT fit the result union: the checker
|
|
2194
|
+
// built that result by DROPPING left arms which are always
|
|
2195
|
+
// truthy (`Option | undefined && string | undefined` answers
|
|
2196
|
+
// `string | undefined`, not `Option | string | undefined`).
|
|
2197
|
+
// Evaluate the left once, test it in its own union, and retag it
|
|
2198
|
+
// only on the falsy path. Any stranded reference arms are
|
|
2199
|
+
// unreachable there because every JS object is truthy.
|
|
2200
|
+
if (op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
2201
|
+
left.type.kind === "union" &&
|
|
2202
|
+
!typeEquals(left.type, target)) {
|
|
2203
|
+
const def = lowerer.unions.get(left.type.unionId);
|
|
2204
|
+
const trappable = new Set();
|
|
2205
|
+
def?.arms.forEach((arm, tag) => {
|
|
2206
|
+
if (lowerer.armTag(target.unionId, arm) < 0 && REF_TRUTHY_KINDS.has(arm.kind)) {
|
|
2207
|
+
trappable.add(tag);
|
|
2208
|
+
}
|
|
2209
|
+
});
|
|
2210
|
+
const retag = trappable.size === 0
|
|
2211
|
+
? null
|
|
2212
|
+
: lowerer.unionRetagHelper(left.type.unionId, target.unionId, loc, trappable);
|
|
2213
|
+
if (retag) {
|
|
2214
|
+
lowerer.requireTruthyUnion(left.type.unionId, expr);
|
|
2215
|
+
const stmts = [];
|
|
2216
|
+
let stable = left;
|
|
2217
|
+
if (!isSafeToRepeat(left)) {
|
|
2218
|
+
const local = lowerer.declareHiddenLocal("%and", left.type);
|
|
2219
|
+
stmts.push({ kind: "varDecl", localId: local.id, init: left, loc });
|
|
2220
|
+
stable = varRef(local.id, left.type, loc);
|
|
2221
|
+
}
|
|
2222
|
+
const result = {
|
|
2223
|
+
kind: "ternary",
|
|
2224
|
+
cond: lowerer.ensureBool(stable, expr.left),
|
|
2225
|
+
then: lowerer.coerceInto(expr.right, right, target),
|
|
2226
|
+
else_: { kind: "call", callee: retag, args: [stable], type: target, loc },
|
|
2227
|
+
type: target,
|
|
2228
|
+
loc,
|
|
2229
|
+
};
|
|
2230
|
+
return stmts.length === 0
|
|
2231
|
+
? result
|
|
2232
|
+
: { kind: "seqExpr", stmts, result, type: target, loc };
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
// `||` whose left does NOT fit the result union: the checker built
|
|
2236
|
+
// that result by DROPPING the left's falsy arms (`process.env.X ||
|
|
2237
|
+
// null` is `string | null`, `|| 3000` is `string | number` — the
|
|
2238
|
+
// `undefined` is gone from both), so coercing the left eagerly, as
|
|
2239
|
+
// the shared shape below does, retags an arm the test is about to
|
|
2240
|
+
// rule out and throws where Node yields the default. Single-eval
|
|
2241
|
+
// instead: test the left in its OWN union and retag only on the
|
|
2242
|
+
// truthy side, where the dropped arms are unreachable.
|
|
2243
|
+
if (op === ts.SyntaxKind.BarBarToken &&
|
|
2244
|
+
left.type.kind === "union" &&
|
|
2245
|
+
!typeEquals(left.type, target)) {
|
|
2246
|
+
const retag = lowerer.unionRetagHelper(left.type.unionId, target.unionId, loc);
|
|
2247
|
+
if (retag) {
|
|
2248
|
+
lowerer.requireTruthyUnion(left.type.unionId, expr);
|
|
2249
|
+
return {
|
|
2250
|
+
kind: "orDefault",
|
|
2251
|
+
left,
|
|
2252
|
+
right: lowerer.coerceInto(expr.right, right, target),
|
|
2253
|
+
retag,
|
|
2254
|
+
type: target,
|
|
2255
|
+
loc,
|
|
2256
|
+
};
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
lowerer.requireTruthyUnion(target.unionId, expr);
|
|
2260
|
+
return {
|
|
2261
|
+
kind: "logical",
|
|
2262
|
+
op: op === ts.SyntaxKind.AmpersandAmpersandToken ? "&&" : "||",
|
|
2263
|
+
left: lowerer.coerceInto(expr.left, left, target),
|
|
2264
|
+
right: lowerer.coerceInto(expr.right, right, target),
|
|
2265
|
+
type: target,
|
|
2266
|
+
loc,
|
|
2267
|
+
};
|
|
2268
|
+
}
|
|
2269
|
+
// `u || d` NARROWED by the default: the checker types the result
|
|
2270
|
+
// as u's single non-unit arm (`marker() || "default"`) — evaluate
|
|
2271
|
+
// u once, truthy extracts the arm, falsy takes d lazily (the
|
|
2272
|
+
// orDefault node, nullish's truthiness sibling). An UNMAPPABLE
|
|
2273
|
+
// checker result takes the same rule (`options.runner ||
|
|
2274
|
+
// defaultRunner` — tsc's union of two structurally-compatible
|
|
2275
|
+
// function types has no representation, while the left's one
|
|
2276
|
+
// non-unit arm is the only representable answer): the default
|
|
2277
|
+
// must coerce into the arm or fence on its own.
|
|
2278
|
+
if (op === ts.SyntaxKind.BarBarToken && left.type.kind === "union") {
|
|
2279
|
+
const def = lowerer.unions.get(left.type.unionId);
|
|
2280
|
+
const rest = def ? def.arms.filter((a) => !isUnitType(a)) : [];
|
|
2281
|
+
const funcArmDefault = rest[0]?.kind === "func" && (target === null || target.kind === "func");
|
|
2282
|
+
if (rest.length === 1 &&
|
|
2283
|
+
((target !== null && typeEquals(target, rest[0])) || funcArmDefault)) {
|
|
2284
|
+
lowerer.requireTruthyUnion(left.type.unionId, expr);
|
|
2285
|
+
const dflt = lowerer.lowerExprExpecting(expr.right, rest[0]);
|
|
2286
|
+
return { kind: "orDefault", left, right: dflt, type: rest[0], loc };
|
|
2287
|
+
}
|
|
2288
|
+
}
|
|
2289
|
+
// JavaScript defaults can join differently inferred object layouts.
|
|
2290
|
+
// When both operands have native checked representations, preserve
|
|
2291
|
+
// the deciding value and short-circuit evaluation in that domain.
|
|
2292
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
2293
|
+
lowerer.dynConvertible(left.type) &&
|
|
2294
|
+
lowerer.dynConvertible(right.type)) {
|
|
2295
|
+
return {
|
|
2296
|
+
kind: "logical",
|
|
2297
|
+
op: op === ts.SyntaxKind.AmpersandAmpersandToken ? "&&" : "||",
|
|
2298
|
+
left: lowerer.coerceInto(expr.left, left, DYN),
|
|
2299
|
+
right: lowerer.coerceInto(expr.right, right, DYN),
|
|
2300
|
+
type: DYN,
|
|
2301
|
+
loc,
|
|
2302
|
+
};
|
|
2303
|
+
}
|
|
2304
|
+
lowerer.unsupported("SC1090", expr, `logical operators on union-typed values outside conditions (${NARROW_FIRST})`);
|
|
2305
|
+
}
|
|
2306
|
+
const kind = left.type.kind;
|
|
2307
|
+
if (kind !== right.type.kind || (kind !== "f64" && kind !== "string" && kind !== "bool")) {
|
|
2308
|
+
// Mixed PLAIN operands (`value || null`, `flag || undefined`,
|
|
2309
|
+
// `s || 0`): JS value semantics still compile when the checker
|
|
2310
|
+
// types the RESULT as one union both operands coerce into — the
|
|
2311
|
+
// same lift the union-operand path above takes, arriving here
|
|
2312
|
+
// with two plain arm values instead.
|
|
2313
|
+
const target = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
2314
|
+
// An always-truthy left operand (a record, object, array or function
|
|
2315
|
+
// value: every JS object is truthy): `o && x` evaluates `o` for its
|
|
2316
|
+
// effects and answers `x`; `o || x` answers `o` and never evaluates
|
|
2317
|
+
// `x`. supports-color's `stream && stream.isTTY` is the shape. Ahead
|
|
2318
|
+
// of the union lift below exactly where that lift would store the
|
|
2319
|
+
// object in a result union with no arm for it; a union holding the
|
|
2320
|
+
// operand keeps the lift.
|
|
2321
|
+
if (REF_TRUTHY_KINDS.has(kind) &&
|
|
2322
|
+
(target?.kind !== "union" ||
|
|
2323
|
+
(op === ts.SyntaxKind.AmpersandAmpersandToken &&
|
|
2324
|
+
lowerer.armTag(target.unionId, left.type) < 0))) {
|
|
2325
|
+
const and = op === ts.SyntaxKind.AmpersandAmpersandToken;
|
|
2326
|
+
const answer = and ? right : left;
|
|
2327
|
+
const answerT = target ?? answer.type;
|
|
2328
|
+
if (answerT.kind !== "void") {
|
|
2329
|
+
const value = lowerer.coerceInto(and ? expr.right : expr.left, answer, answerT);
|
|
2330
|
+
if (!and)
|
|
2331
|
+
return value;
|
|
2332
|
+
return {
|
|
2333
|
+
kind: "seqExpr",
|
|
2334
|
+
stmts: [{ kind: "exprStmt", expr: left, loc }],
|
|
2335
|
+
result: value,
|
|
2336
|
+
type: answerT,
|
|
2337
|
+
loc,
|
|
2338
|
+
};
|
|
2339
|
+
}
|
|
2340
|
+
}
|
|
2341
|
+
if (target?.kind === "union") {
|
|
2342
|
+
lowerer.requireTruthyUnion(target.unionId, expr);
|
|
2343
|
+
return {
|
|
2344
|
+
kind: "logical",
|
|
2345
|
+
op: op === ts.SyntaxKind.AmpersandAmpersandToken ? "&&" : "||",
|
|
2346
|
+
left: lowerer.coerceInto(expr.left, left, target),
|
|
2347
|
+
right: lowerer.coerceInto(expr.right, right, target),
|
|
2348
|
+
type: target,
|
|
2349
|
+
loc,
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
2352
|
+
lowerer.unsupported("SC1042", expr);
|
|
2353
|
+
}
|
|
2354
|
+
return {
|
|
2355
|
+
kind: "logical",
|
|
2356
|
+
op: op === ts.SyntaxKind.AmpersandAmpersandToken ? "&&" : "||",
|
|
2357
|
+
left,
|
|
2358
|
+
right,
|
|
2359
|
+
type: left.type,
|
|
2360
|
+
loc,
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
function lowerAbsenceAwareOrChain(lowerer, expr) {
|
|
2364
|
+
const nodes = [];
|
|
2365
|
+
const pending = [expr];
|
|
2366
|
+
while (pending.length !== 0) {
|
|
2367
|
+
const node = pending.pop();
|
|
2368
|
+
if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
2369
|
+
pending.push(node.right, node.left);
|
|
2370
|
+
}
|
|
2371
|
+
else {
|
|
2372
|
+
nodes.push(node);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
if (nodes.length < 3)
|
|
2376
|
+
return null;
|
|
2377
|
+
const lowered = nodes.map((node) => lowerAbsenceProbe(lowerer, node) ?? lowerer.lowerExpr(node));
|
|
2378
|
+
if (!lowered.some((value) => value.type.kind === "union" && lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0)) {
|
|
2379
|
+
return null;
|
|
2380
|
+
}
|
|
2381
|
+
let result = lowered[lowered.length - 1];
|
|
2382
|
+
for (let i = lowered.length - 2; i >= 0; i--) {
|
|
2383
|
+
const left = lowered[i];
|
|
2384
|
+
const loc = locOf(nodes[i]);
|
|
2385
|
+
if (left.type.kind === "union") {
|
|
2386
|
+
const def = lowerer.unions.get(left.type.unionId);
|
|
2387
|
+
const nonUnit = def?.arms.filter((arm) => !isUnitType(arm)) ?? [];
|
|
2388
|
+
if (nonUnit.length !== 1 || !typeEquals(nonUnit[0], result.type))
|
|
2389
|
+
return null;
|
|
2390
|
+
lowerer.requireTruthyUnion(left.type.unionId, expr);
|
|
2391
|
+
result = { kind: "orDefault", left, right: result, type: result.type, loc };
|
|
2392
|
+
continue;
|
|
2393
|
+
}
|
|
2394
|
+
if (!typeEquals(left.type, result.type))
|
|
2395
|
+
return null;
|
|
2396
|
+
result = { kind: "logical", op: "||", left, right: result, type: result.type, loc };
|
|
2397
|
+
}
|
|
2398
|
+
return result;
|
|
2399
|
+
}
|
|
2400
|
+
/** `typeof WebAssembly === "object"` and `typeof WebAssembly.<member> ===
|
|
2401
|
+
* "function"`: the operand needs no value, so the test folds as bare typeof
|
|
2402
|
+
* does (builtins/webassembly.ts) before any dyn-typed operand lowers. */
|
|
2403
|
+
function lowerWebAssemblyTypeofTest(lowerer, expr, loc) {
|
|
2404
|
+
const negated = expr.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
2405
|
+
for (const [a, b] of operandPairs(expr)) {
|
|
2406
|
+
if (!ts.isTypeOfExpression(a) || !ts.isStringLiteral(b))
|
|
2407
|
+
continue;
|
|
2408
|
+
const folded = lowerWebAssemblyTypeof(lowerer, a.expression);
|
|
2409
|
+
if (folded?.kind !== "strLit")
|
|
2410
|
+
continue;
|
|
2411
|
+
return { kind: "boolLit", value: (folded.value === b.text) !== negated, type: BOOL, loc };
|
|
2412
|
+
}
|
|
2413
|
+
return null;
|
|
2414
|
+
}
|
|
2415
|
+
/** `typeof v === "lit"` / `typeof v !== "lit"` where v is UNION-typed: the
|
|
2416
|
+
* arms whose static typeof answer equals the literal form a tag set, and
|
|
2417
|
+
* the test is a runtime tag test — one `unionIsTag` for a single matching
|
|
2418
|
+
* arm (the operand embeds once, so even effectful operands compose), a
|
|
2419
|
+
* short-circuit chain for several (pure reads only — the operand rides
|
|
2420
|
+
* every test, exactly the `== null` composition rule). When every arm
|
|
2421
|
+
* answers the same way the comparison is statically decided and folds to
|
|
2422
|
+
* a bool literal — dropping only a side-effect-free read, the same
|
|
2423
|
+
* trust-the-checker bet as lowerUnitComparison. tsc's control-flow
|
|
2424
|
+
* narrowing then types the branches, and reads bridge through
|
|
2425
|
+
* maybeNarrow's unionNarrow as usual. Null when neither side is a typeof
|
|
2426
|
+
* over a union-typed operand or the literal side isn't a literal (the
|
|
2427
|
+
* bare-typeof value form then composes with strEq for pure operands). */
|
|
2428
|
+
function lowerUnionTypeofTest(lowerer, expr, loc) {
|
|
2429
|
+
const negated = expr.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken;
|
|
2430
|
+
for (const [a, b] of operandPairs(expr)) {
|
|
2431
|
+
if (!ts.isTypeOfExpression(a))
|
|
2432
|
+
continue;
|
|
2433
|
+
const stored = runtimeOptionalStorageOperand(lowerer, a.expression);
|
|
2434
|
+
if (stored === null && lowerer.mapTypeOf(lowerer.typeOf(a.expression))?.kind !== "union")
|
|
2435
|
+
continue;
|
|
2436
|
+
if (!ts.isStringLiteral(b))
|
|
2437
|
+
continue; // bare-typeof + strEq handles pure operands
|
|
2438
|
+
const value = stored ?? lowerer.lowerExpr(a.expression);
|
|
2439
|
+
if (value.type.kind !== "union")
|
|
2440
|
+
continue; // defensive: an already-narrowed use
|
|
2441
|
+
const unionId = value.type.unionId;
|
|
2442
|
+
const def = lowerer.unions.get(unionId);
|
|
2443
|
+
const answers = def?.arms.map(typeofAnswer);
|
|
2444
|
+
if (!def || !answers || !answers.every((s) => s !== null))
|
|
2445
|
+
continue;
|
|
2446
|
+
const tags = answers.flatMap((s, i) => (s === b.text ? [i] : []));
|
|
2447
|
+
if (tags.length === 0 || tags.length === def.arms.length) {
|
|
2448
|
+
if (!isSafeToRepeat(value)) {
|
|
2449
|
+
lowerer.unsupported("SC1090", expr, "statically-decided 'typeof' tests over effectful operands (bind the value to a const first)");
|
|
2450
|
+
}
|
|
2451
|
+
return { kind: "boolLit", value: (tags.length !== 0) !== negated, type: BOOL, loc };
|
|
2452
|
+
}
|
|
2453
|
+
const isTag = (tag) => ({
|
|
2454
|
+
kind: "unionIsTag",
|
|
2455
|
+
unionId,
|
|
2456
|
+
tag,
|
|
2457
|
+
negated,
|
|
2458
|
+
value,
|
|
2459
|
+
type: BOOL,
|
|
2460
|
+
loc,
|
|
2461
|
+
});
|
|
2462
|
+
if (tags.length === 1)
|
|
2463
|
+
return isTag(tags[0]);
|
|
2464
|
+
if (!isSafeToRepeat(value)) {
|
|
2465
|
+
lowerer.unsupported("SC1090", expr, "'typeof' tests matching several union arms over operands that aren't plain reads (bind the value to a const first)");
|
|
2466
|
+
}
|
|
2467
|
+
// Tag-in-set as a short-circuit chain (De Morgan for `!==`).
|
|
2468
|
+
let acc = isTag(tags[0]);
|
|
2469
|
+
for (const t of tags.slice(1)) {
|
|
2470
|
+
acc = {
|
|
2471
|
+
kind: "logical",
|
|
2472
|
+
op: negated ? "&&" : "||",
|
|
2473
|
+
left: acc,
|
|
2474
|
+
right: isTag(t),
|
|
2475
|
+
type: BOOL,
|
|
2476
|
+
loc,
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
return acc;
|
|
2480
|
+
}
|
|
2481
|
+
return null;
|
|
2482
|
+
}
|
|
2483
|
+
//# sourceMappingURL=binary.js.map
|