@scriptc/compiler 0.3.5 → 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 +960 -82
- 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 +324 -179
- 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 +576 -268
- package/dist/backend/llvm/emitter.js +801 -4447
- 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-dispatch.js +1 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.d.ts +3 -0
- package/dist/backend/llvm/expr-dynamic.js +92 -63
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +132 -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 +217 -24
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +102 -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 +77 -25
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +100 -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 +229 -5
- 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 +57 -8
- 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 +70 -9
- package/dist/backend/llvm/nullable-unions.js +105 -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 +13 -2
- package/dist/backend/llvm/record-results.js +66 -6
- 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 +143 -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 +69 -43
- package/dist/backend/llvm/shapes.js +285 -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/speculative-integers.d.ts +74 -0
- package/dist/backend/llvm/speculative-integers.js +571 -0
- package/dist/backend/llvm/speculative-integers.js.map +1 -0
- package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
- package/dist/backend/llvm/speculative-integers.test.js +148 -0
- package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
- 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 +6 -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 -134
- 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 +2 -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.d.ts +7 -3
- package/dist/backend/runtime-pack.js +12 -6
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +20 -6
- 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 +25 -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 +19 -6
- 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 +11 -7
- package/dist/diagnostics/diagnostic.js +35 -23
- 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 +72 -4
- 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 +45 -6
- 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 +18 -0
- package/dist/frontend/lowering/builtins/compression.js +230 -52
- 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 +223 -38
- 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 +174 -6
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +4 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +136 -113
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
- package/dist/frontend/lowering/builtins/filesystem.js +213 -76
- 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/hash-stream.d.ts +12 -0
- package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
- package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
- 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 +67 -46
- 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 +468 -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 +55 -13
- package/dist/frontend/lowering/builtins/readline.js +931 -69
- 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 +16 -0
- package/dist/frontend/lowering/builtins/workers.js +246 -3
- 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.d.ts +55 -0
- package/dist/frontend/lowering/class-protocols.js +738 -22
- 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 +19 -0
- package/dist/frontend/lowering/containers/array-from-async.js +427 -0
- package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
- 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 +219 -27
- package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +81 -48
- 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 +238 -128
- 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 +1298 -452
- 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 +1499 -456
- 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 +268 -71
- 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 +1493 -12407
- 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 +354 -99
- 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 +19 -2
- package/dist/frontend/lowering/lower-mock.js +557 -74
- package/dist/frontend/lowering/lower-mock.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +268 -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 +638 -105
- 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 +1589 -398
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +4 -3
- package/dist/frontend/lowering/lower-stream.js +714 -75
- 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 +574 -100
- 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 +409 -26
- package/dist/frontend/lowering/lowerer.js +1918 -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/null-prototype.d.ts +13 -0
- package/dist/frontend/lowering/null-prototype.js +33 -0
- package/dist/frontend/lowering/null-prototype.js.map +1 -0
- 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 +15 -6
- package/dist/frontend/lowering/surfaces.js +278 -45
- 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.d.ts +5 -0
- package/dist/frontend/mock-shapes.js +39 -7
- 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 -254
- 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 +2612 -695
- 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 +47 -10
- 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 +139 -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 +655 -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 +10 -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 +119 -14
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +29 -1
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loop-facts.d.ts +16 -6
- package/dist/ir/integer-loop-facts.js +143 -38
- 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 +4 -6
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +142 -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 +234 -58
- package/dist/ir/ir.js +123 -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 +150 -33
- package/dist/ir/runtime-features.js +672 -339
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +62 -0
- package/dist/ir/runtime-features.test.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 +107 -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 +220 -71
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +64 -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 +18 -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 +332 -36
|
@@ -0,0 +1,3544 @@
|
|
|
1
|
+
/* Property reads (`a.b`): lowerExprInner's property-access branch, intrinsic and union properties, field reads and targets, and match-group reads. */
|
|
2
|
+
import * as ts from "../../ts7/adapter.js";
|
|
3
|
+
import { lowerHistogramProperty } from "../builtins/performance.js";
|
|
4
|
+
import { staticFunctionNameRead } from "../static-function-names.js";
|
|
5
|
+
import { typedArgumentsArity } from "../typed-arguments.js";
|
|
6
|
+
import { isThisParameter } from "../call-signatures.js";
|
|
7
|
+
import { localPrivateBrandClass } from "../private-brands.js";
|
|
8
|
+
import { PoisonError, jsFuncNameOf, neverTaintedJsType, own } from "../lowerer.js";
|
|
9
|
+
import { ARRAY_METHODS, MAP_METHODS, NARROW_FIRST, OBJECT_CALLABLE_VALUES, SET_METHODS, STDLIB_SURFACE, STRING_INDEX_METHODS, STR_METHODS, isChildSurfaceMember, stdlibGlobalNameOf, } from "../surfaces.js";
|
|
10
|
+
import { isGenericCallableMemberType, isLegacyUrlSymbol, isOsConstantsType, isParseArgsDynTypeName, } from "../../type-mapper.js";
|
|
11
|
+
import { BOOL, BYTES_ELEMENT_NAME, DYN, F64, NULL_T, SEARCH_PARAMS_T, STRING, SYMBOL_T, UNDEFINED_T, arrayOf, canBoxFuncIntoDyn, funcOf, isDynTypedRefType, isUnitType, typeEquals, typeKey, unionContainerArmsOk, } from "../../../ir/ir.js";
|
|
12
|
+
import { lowerNavigatorMember } from "../builtins/navigator.js";
|
|
13
|
+
import { NODE_COMPAT_VERSION } from "../builtins/process.js";
|
|
14
|
+
import { inlineNamespaceRequireOf, lowerWithInlineRequireInit, wholeExportValue, } from "../cjs-inline-require.js";
|
|
15
|
+
import { cjsAccessorCall, constInitializerOf, exactUnionWidening, hasClassPayload, lowerExpr, matchAllCallbackRegexOf, matchAllRegexOf, namedCaptureGroupsOfPattern, primitiveCtorClosure, recordKeyResultOk, representedClassFieldTarget, staticRegexPatternOf, } from "../lower-exprs.js";
|
|
16
|
+
import { cjsInFileExportGlobalOf, isCjsExportsIdentifier, lowerCjsExportsObjectValue, } from "../cjs-exports-object.js";
|
|
17
|
+
import { tscInteropDefaultValueOf } from "../cjs-tsc-interop.js";
|
|
18
|
+
import { lifetimeRegionMemberOf } from "../../experimental-import.js";
|
|
19
|
+
import { lowerInternTableProperty } from "../intern-tables.js";
|
|
20
|
+
import { lowerThreadSlotsProperty } from "../thread-slots.js";
|
|
21
|
+
import { builtinClassRefOf, runtimeClassValueOfType } from "../builtins/class-values.js";
|
|
22
|
+
import { lowerRuntimeConstructor, lowerRuntimeConstructorName, runtimeConstructorReceiver, } from "../builtins/runtime-constructor.js";
|
|
23
|
+
import { findGenericMethodOn, lowerStaticFieldRead } from "../lower-classes.js";
|
|
24
|
+
import { lowerClassPrototypeData } from "../class-prototypes.js";
|
|
25
|
+
import { lowerEnumAccess } from "../lower-enums.js";
|
|
26
|
+
import { hasOptionalChainGuard, isOptionalChainTail, isRequireMainFilename, } from "./optional-chains.js";
|
|
27
|
+
import { isCjsModuleGlobal, lowerNodeModuleProperty, lowerRequireMainProperty, } from "../lower-node-module.js";
|
|
28
|
+
import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../../ir/build.js";
|
|
29
|
+
import { TEMPORAL_GLOBAL } from "../../builtin-modules.js";
|
|
30
|
+
import { tryLowerExpression } from "./try-lower-expression.js";
|
|
31
|
+
import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, cjsExportDiscardReason, isCjsExportTableLiteral, isCjsJsFile, isJsSourceFile, isModuleExportsAccess, isNodeEsmFile, locOf, } from "../../program.js";
|
|
32
|
+
import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, contextualUndefReadType, fenceEarlyNsMemberRef, nsMemberIdentOf, nsUndefRead, } from "../lower-namespaces.js";
|
|
33
|
+
import { expandoMemberRead } from "../lower-expando.js";
|
|
34
|
+
import { lowerProtocolPropertyRead } from "../class-protocol-dispatch.js";
|
|
35
|
+
import { lowerReadlineProperty } from "../builtins/readline.js";
|
|
36
|
+
import { lowerEventStaticProperty } from "../builtins/numbers.js";
|
|
37
|
+
import { lowerStreamProperty, lowerStreamStateProperty, streamSidesOf } from "../lower-stream.js";
|
|
38
|
+
import { lowerEventObjectProperty } from "../lower-event-target.js";
|
|
39
|
+
import { iteratorResultValueRead } from "../lower-generators.js";
|
|
40
|
+
import { lowerGlobalValue } from "../lower-global-value.js";
|
|
41
|
+
import { nullishGenericBindingUnitOf } from "../binding-analysis.js";
|
|
42
|
+
import { blockedBindingUseDiag } from "../../../diagnostics/diagnostic.js";
|
|
43
|
+
import { npmStaticPackageOfPath } from "../../npm-static.js";
|
|
44
|
+
import { importMetaField, isImportMeta } from "../import-meta.js";
|
|
45
|
+
import { builtinPrototypeMethod, lowerArrayIsArrayValue, lowerCheckedPredicateValue, lowerNumberParserValue, lowerObjectAssignValue, lowerStringCodesValue, } from "../lower-builtin-values.js";
|
|
46
|
+
import { lowerArrayFromValue } from "../containers/array-construction.js";
|
|
47
|
+
import { lowerNetAddressStaticRead } from "../builtins/net-address.js";
|
|
48
|
+
import { STATS_TYPE_TESTS } from "../builtins/filesystem.js";
|
|
49
|
+
import { arrayValueRead, arrayValueType } from "../array-values.js";
|
|
50
|
+
import { lowerClassMethodValue } from "../class-method-values.js";
|
|
51
|
+
import { objLitGenericFnInfoOf, objLitGenericFnNodeOf, requireObjLitGenericReceiver, } from "../generic-functions.js";
|
|
52
|
+
import { narrowStoredClassValue, structuralReadType } from "../class-unions.js";
|
|
53
|
+
import { InternalCompilerError } from "../../../errors.js";
|
|
54
|
+
import { lowerUnionFieldRead } from "./union-fields.js";
|
|
55
|
+
import { errorPropertyRead } from "../error-methods.js";
|
|
56
|
+
import { isSafeToRepeat } from "./evaluation-safety.js";
|
|
57
|
+
import { isZlibStreamMember, lowerZlibStreamBytesWritten } from "../builtins/compression.js";
|
|
58
|
+
import { isFsStreamMember, lowerFsStreamProperty } from "../builtins/fs-streams.js";
|
|
59
|
+
import { keyedFieldRead } from "./keyed-field-targets.js";
|
|
60
|
+
/** True when a property access names an ABSTRACT property declaration
|
|
61
|
+
* (`abstract p: number` — a PropertyDeclaration, not an accessor).
|
|
62
|
+
* These uses need concrete property dispatch because the base has no slot. */
|
|
63
|
+
export function abstractPropertyDeclOf(lowerer, expr) {
|
|
64
|
+
const sym = lowerer.checker.getSymbolAtLocation(expr.name);
|
|
65
|
+
if (!sym)
|
|
66
|
+
return false;
|
|
67
|
+
return sym.declarations.some((d) => ts.isPropertyDeclaration(d) &&
|
|
68
|
+
ts.getModifiers(d)?.some((m) => m.kind === ts.SyntaxKind.AbstractKeyword) === true);
|
|
69
|
+
}
|
|
70
|
+
/** A field declared by node:util's parseArgs checked-dynamic type family.
|
|
71
|
+
* Narrowing a ParseArgsToken exposes one anonymous union arm, so its alias
|
|
72
|
+
* identity no longer reaches mapType; declaration ancestry is the stable
|
|
73
|
+
* provenance check. */
|
|
74
|
+
/** The Uint8Array base64/hex prototype methods (ES2026) Node 24 lacks. */
|
|
75
|
+
const UINT8ARRAY_BASE64_METHODS = new Set([
|
|
76
|
+
"toBase64",
|
|
77
|
+
"toHex",
|
|
78
|
+
"setFromBase64",
|
|
79
|
+
"setFromHex",
|
|
80
|
+
]);
|
|
81
|
+
/** `Uint8Array.prototype.<base64/hex method>` read off the global. */
|
|
82
|
+
function isUint8ArrayBase64Probe(lowerer, expr) {
|
|
83
|
+
if (!UINT8ARRAY_BASE64_METHODS.has(expr.name.text))
|
|
84
|
+
return false;
|
|
85
|
+
const proto = expr.expression;
|
|
86
|
+
return (ts.isPropertyAccessExpression(proto) &&
|
|
87
|
+
!proto.questionDotToken &&
|
|
88
|
+
proto.name.text === "prototype" &&
|
|
89
|
+
stdlibGlobalNameOf(lowerer, proto.expression) === "Uint8Array");
|
|
90
|
+
}
|
|
91
|
+
function isParseArgsDynProperty(lowerer, expr) {
|
|
92
|
+
const sym = lowerer.checker.getSymbolAtLocation(expr.name);
|
|
93
|
+
if (!sym)
|
|
94
|
+
return false;
|
|
95
|
+
return sym.declarations.some((d) => {
|
|
96
|
+
if (!lowerer.isStdlibFile(ts.getSourceFileOfNode(d)))
|
|
97
|
+
return false;
|
|
98
|
+
let inParseArgsType = false;
|
|
99
|
+
for (let node = d.parent; node; node = node.parent) {
|
|
100
|
+
if ((ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) &&
|
|
101
|
+
isParseArgsDynTypeName(node.name.text)) {
|
|
102
|
+
inParseArgsType = true;
|
|
103
|
+
}
|
|
104
|
+
if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name)) {
|
|
105
|
+
return inParseArgsType && (node.name.text === "util" || node.name.text === "node:util");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function isStatFsDynProperty(lowerer, expr) {
|
|
112
|
+
if (!["type", "bsize", "blocks", "bfree", "bavail", "files", "ffree", "bigint"].includes(expr.name.text))
|
|
113
|
+
return false;
|
|
114
|
+
const symbol = lowerer.checker.getSymbolAtLocation(expr.name);
|
|
115
|
+
return (!!symbol &&
|
|
116
|
+
symbol.declarations.some((declaration) => {
|
|
117
|
+
if (!lowerer.isStdlibFile(ts.getSourceFileOfNode(declaration)))
|
|
118
|
+
return false;
|
|
119
|
+
const parent = declaration.parent;
|
|
120
|
+
if (!ts.isInterfaceDeclaration(parent))
|
|
121
|
+
return false;
|
|
122
|
+
if (expr.name.text === "bigint"
|
|
123
|
+
? parent.name.text !== "StatFsOptions"
|
|
124
|
+
: !["StatsFsBase", "StatsFs", "BigIntStatsFs"].includes(parent.name.text))
|
|
125
|
+
return false;
|
|
126
|
+
for (let node = parent.parent; node; node = node.parent) {
|
|
127
|
+
if (ts.isModuleDeclaration(node) && ts.isStringLiteral(node.name))
|
|
128
|
+
return node.name.text === "fs" || node.name.text === "node:fs";
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
export function lowerPropertyAccessExpr(lowerer, expr, loc) {
|
|
134
|
+
if (!expr.questionDotToken) {
|
|
135
|
+
const navigator = lowerNavigatorMember(lowerer, expr, NODE_COMPAT_VERSION);
|
|
136
|
+
if (navigator)
|
|
137
|
+
return navigator;
|
|
138
|
+
}
|
|
139
|
+
// `fn.name` on a function parameter of a generic instance keyed by
|
|
140
|
+
// its argument's static name (call-site specialization).
|
|
141
|
+
{
|
|
142
|
+
const staticName = staticFunctionNameRead(lowerer, expr);
|
|
143
|
+
if (staticName !== null)
|
|
144
|
+
return { kind: "strLit", value: staticName, type: STRING, loc };
|
|
145
|
+
}
|
|
146
|
+
// An IntervalHistogram's readings (min, max, mean, stddev, count, exceeds).
|
|
147
|
+
{
|
|
148
|
+
const reading = lowerHistogramProperty(lowerer, expr);
|
|
149
|
+
if (reading)
|
|
150
|
+
return reading;
|
|
151
|
+
}
|
|
152
|
+
// `.length` of a forwarded fixed tuple (a typed `arguments`, a tuple
|
|
153
|
+
// rest parameter, an alias of either): the signature's arity.
|
|
154
|
+
if (expr.name.text === "length" && !expr.questionDotToken) {
|
|
155
|
+
const arity = typedArgumentsArity(lowerer, expr.expression);
|
|
156
|
+
if (arity !== null)
|
|
157
|
+
return { kind: "numLit", value: arity, type: F64, loc };
|
|
158
|
+
}
|
|
159
|
+
// `require("./x").member` over a program module's export table: the
|
|
160
|
+
// module's %init at this position, then the member read exactly like
|
|
161
|
+
// a `const m = require("./x")` binding's (cjs-inline-require.ts).
|
|
162
|
+
if (!expr.questionDotToken) {
|
|
163
|
+
const req = inlineNamespaceRequireOf(lowerer, expr.expression);
|
|
164
|
+
if (req !== null && !lowerer.inlineRequireInitDone.has(req.call)) {
|
|
165
|
+
return lowerWithInlineRequireInit(lowerer, req, () => lowerExpr(lowerer, expr));
|
|
166
|
+
}
|
|
167
|
+
// `module.exports` compared by identity inside its own module, or
|
|
168
|
+
// refused by name as any other value (cjs-exports-object.ts).
|
|
169
|
+
if (expr.name.text === "exports") {
|
|
170
|
+
const exportsValue = lowerCjsExportsObjectValue(lowerer, expr);
|
|
171
|
+
if (exportsValue)
|
|
172
|
+
return exportsValue;
|
|
173
|
+
}
|
|
174
|
+
// tsc's `x_1.default` over a dependency whose whole export is one
|
|
175
|
+
// value: that value (cjs-tsc-interop.ts).
|
|
176
|
+
const interop = tscInteropDefaultValueOf(lowerer, expr);
|
|
177
|
+
if (interop !== null) {
|
|
178
|
+
const value = wholeExportValue(lowerer, interop.dep, expr);
|
|
179
|
+
if (value !== null)
|
|
180
|
+
return value;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
{
|
|
184
|
+
const member = lifetimeRegionMemberOf(lowerer.program, expr, lowerer.experimentalFiles);
|
|
185
|
+
if (member !== null)
|
|
186
|
+
lowerer.noLowering(`LifetimeRegion.${member} (@scriptc/experimental) as a value`, expr, `call region.${member}(${member === "run" ? "fn" : ""}) directly`);
|
|
187
|
+
}
|
|
188
|
+
{
|
|
189
|
+
const table = lowerInternTableProperty(lowerer, expr);
|
|
190
|
+
if (table)
|
|
191
|
+
return table;
|
|
192
|
+
}
|
|
193
|
+
lowerThreadSlotsProperty(lowerer, expr);
|
|
194
|
+
// `EventEmitter.name`, `zlib.Gzip.name`, `C.name` over a builtin
|
|
195
|
+
// class alias.
|
|
196
|
+
if (expr.name.text === "name" && !expr.questionDotToken) {
|
|
197
|
+
const ref = builtinClassRefOf(lowerer, expr.expression);
|
|
198
|
+
if (ref !== null)
|
|
199
|
+
return { kind: "strLit", value: ref.name, type: STRING, loc };
|
|
200
|
+
}
|
|
201
|
+
// `x.constructor.name` and `x.constructor` on an instance of
|
|
202
|
+
// EventEmitter or a stream class (builtins/runtime-constructor.ts).
|
|
203
|
+
if (expr.name.text === "name" && !expr.questionDotToken) {
|
|
204
|
+
const ctor = runtimeConstructorReceiver(lowerer, expr.expression);
|
|
205
|
+
if (ctor)
|
|
206
|
+
return lowerRuntimeConstructorName(lowerer, ctor.receiver, loc);
|
|
207
|
+
}
|
|
208
|
+
{
|
|
209
|
+
const ctor = runtimeConstructorReceiver(lowerer, expr);
|
|
210
|
+
if (ctor)
|
|
211
|
+
return lowerRuntimeConstructor(lowerer, expr, ctor.info);
|
|
212
|
+
}
|
|
213
|
+
// `C.name` through a runtime-provided class VALUE (a `typeof Readable`
|
|
214
|
+
// parameter): the class object's stored name.
|
|
215
|
+
if (expr.name.text === "name" &&
|
|
216
|
+
!expr.questionDotToken &&
|
|
217
|
+
runtimeClassValueOfType(lowerer, lowerer.typeOf(expr.expression)) !== null) {
|
|
218
|
+
const read = lowerer.lowerFieldRead(expr);
|
|
219
|
+
if (read)
|
|
220
|
+
return read;
|
|
221
|
+
}
|
|
222
|
+
// Expando statics may still be absent even when JS inference sees
|
|
223
|
+
// the eventual assignment's scalar type. Preserve the checked value.
|
|
224
|
+
const staticField = lowerStaticFieldRead(lowerer, expr);
|
|
225
|
+
if (staticField)
|
|
226
|
+
return staticField;
|
|
227
|
+
const prototypeData = lowerClassPrototypeData(lowerer, expr);
|
|
228
|
+
if (prototypeData)
|
|
229
|
+
return prototypeData;
|
|
230
|
+
if (ts.isPropertyAccessExpression(expr.expression) && expr.expression.name.text === "prototype") {
|
|
231
|
+
const prototype = lowerClassPrototypeData(lowerer, expr.expression);
|
|
232
|
+
if (prototype)
|
|
233
|
+
return {
|
|
234
|
+
kind: "dynKeyGet",
|
|
235
|
+
value: prototype,
|
|
236
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
237
|
+
type: DYN,
|
|
238
|
+
loc,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
// `super.x`: the base chain's GETTER, called directly (super
|
|
242
|
+
// dispatch is static in JS — never through the dynamic class).
|
|
243
|
+
// super.method() calls are routed at the call site; a bare super
|
|
244
|
+
// property read lands here.
|
|
245
|
+
if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
246
|
+
return lowerer.lowerSuperAccessorRead(expr);
|
|
247
|
+
}
|
|
248
|
+
// Enum member reads (`E.A`) fold to their compile-time constants —
|
|
249
|
+
// claimed FIRST so no receiver-shaped path (records, the
|
|
250
|
+
// identifier fence on the enum object) sees them. lower-enums.ts.
|
|
251
|
+
{
|
|
252
|
+
const en = lowerEnumAccess(lowerer, expr);
|
|
253
|
+
if (en)
|
|
254
|
+
return en;
|
|
255
|
+
}
|
|
256
|
+
// `import.meta.<field>` — the file-backed ESM metadata that survives
|
|
257
|
+
// compilation as a constant. Only direct, identifier-named reads are
|
|
258
|
+
// claimed here; the bare meta object, computed access, writes, and
|
|
259
|
+
// unsupported members continue through the generic module-loader fence
|
|
260
|
+
// below. The source file is the module identity, so imported modules
|
|
261
|
+
// receive their own filename/dirname and only the entry receives main.
|
|
262
|
+
const importMeta = importMetaProperty(lowerer, expr);
|
|
263
|
+
if (importMeta)
|
|
264
|
+
return importMeta;
|
|
265
|
+
// `require.main.filename` / `require.main?.filename` — CommonJS
|
|
266
|
+
// entry-module identity: in a compiled binary require.main IS the
|
|
267
|
+
// entry module (never undefined in a CJS graph, so the chain's guard
|
|
268
|
+
// folds away), and its filename is the ENTRY file's real path —
|
|
269
|
+
// Node's exact value when the same tree runs in place, exactly the
|
|
270
|
+
// __filename stance. Checked BEFORE the optional-chain gate: the
|
|
271
|
+
// checker types the chain `string | undefined`, but the value is a
|
|
272
|
+
// compile-time string.
|
|
273
|
+
if (isRequireMainFilename(lowerer, expr)) {
|
|
274
|
+
return { kind: "strLit", value: lowerer.entry.fileName, type: STRING, loc };
|
|
275
|
+
}
|
|
276
|
+
const requireMain = lowerRequireMainProperty(lowerer, expr);
|
|
277
|
+
if (requireMain)
|
|
278
|
+
return requireMain;
|
|
279
|
+
const moduleProperty = lowerNodeModuleProperty(lowerer, expr);
|
|
280
|
+
if (moduleProperty)
|
|
281
|
+
return moduleProperty;
|
|
282
|
+
if (stdlibGlobalNameOf(lowerer, expr.expression) === "Symbol" &&
|
|
283
|
+
[
|
|
284
|
+
"iterator",
|
|
285
|
+
"asyncIterator",
|
|
286
|
+
"toStringTag",
|
|
287
|
+
"toPrimitive",
|
|
288
|
+
"hasInstance",
|
|
289
|
+
"isConcatSpreadable",
|
|
290
|
+
"match",
|
|
291
|
+
"matchAll",
|
|
292
|
+
"replace",
|
|
293
|
+
"search",
|
|
294
|
+
"split",
|
|
295
|
+
"species",
|
|
296
|
+
"unscopables",
|
|
297
|
+
"dispose",
|
|
298
|
+
"asyncDispose",
|
|
299
|
+
].includes(expr.name.text)) {
|
|
300
|
+
return {
|
|
301
|
+
kind: "libCall",
|
|
302
|
+
fn: "sym.wellKnown",
|
|
303
|
+
args: [{ kind: "strLit", value: expr.name.text, type: STRING, loc }],
|
|
304
|
+
type: { kind: "symbol" },
|
|
305
|
+
loc,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
if (lowerer.stdlibGlobalMember(expr, "Object") === "freeze") {
|
|
309
|
+
const name = "%builtin.Object.freeze";
|
|
310
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name))
|
|
311
|
+
lowerer.liftedFns.push({
|
|
312
|
+
name,
|
|
313
|
+
params: [{ localId: "value", name: "value", type: DYN }],
|
|
314
|
+
locals: [{ id: "value", name: "value", type: DYN, mutable: false }],
|
|
315
|
+
returnType: DYN,
|
|
316
|
+
body: [
|
|
317
|
+
{
|
|
318
|
+
kind: "return",
|
|
319
|
+
value: {
|
|
320
|
+
kind: "libCall",
|
|
321
|
+
fn: "dyn.freeze",
|
|
322
|
+
args: [varRef("value", DYN, loc)],
|
|
323
|
+
type: DYN,
|
|
324
|
+
loc,
|
|
325
|
+
},
|
|
326
|
+
loc,
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
loc,
|
|
330
|
+
});
|
|
331
|
+
return { kind: "closure", fnName: name, captures: [], type: funcOf([DYN], DYN), loc };
|
|
332
|
+
}
|
|
333
|
+
// An Hmac has no copy() (Hash does): Node answers undefined, which
|
|
334
|
+
// `typeof mac.copy` feature checks read. TypeScript rejects the read.
|
|
335
|
+
if (expr.name.text === "copy" &&
|
|
336
|
+
lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind === "cryptoHmac") {
|
|
337
|
+
return {
|
|
338
|
+
kind: "seqExpr",
|
|
339
|
+
stmts: [{ kind: "exprStmt", expr: lowerer.lowerExpr(expr.expression), loc }],
|
|
340
|
+
result: dynUndefinedExpr(loc),
|
|
341
|
+
type: DYN,
|
|
342
|
+
loc,
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
if (lowerer.stdlibGlobalMember(expr, "globalThis") === "console") {
|
|
346
|
+
return { kind: "libCall", fn: "console.native", args: [], type: DYN, loc };
|
|
347
|
+
}
|
|
348
|
+
if (lowerer.stdlibGlobalMember(expr, "console") !== null) {
|
|
349
|
+
return {
|
|
350
|
+
kind: "dynKeyGet",
|
|
351
|
+
value: { kind: "libCall", fn: "console.native", args: [], type: DYN, loc },
|
|
352
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
353
|
+
type: DYN,
|
|
354
|
+
loc,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
// Missing host globals (Bun/Deno capability probes) have no binding
|
|
358
|
+
// in a native program. Declared globals retain their own lowering;
|
|
359
|
+
// arbitrary global-object mutation remains fenced. Preserve a dyn
|
|
360
|
+
// undefined value so stored probes compose with optional calls.
|
|
361
|
+
if (stdlibGlobalNameOf(lowerer, expr.expression) === "globalThis" &&
|
|
362
|
+
!lowerer.checker.getPropertyOfType(lowerer.typeOf(expr.expression), expr.name.text)) {
|
|
363
|
+
return dynUndefinedExpr(loc);
|
|
364
|
+
}
|
|
365
|
+
// `Uint8Array.prototype.toBase64` and its siblings, the base64/hex
|
|
366
|
+
// feature probes libraries such as jose make: the methods are newer
|
|
367
|
+
// than Node 24, whose Uint8Array prototype answers undefined for them.
|
|
368
|
+
if (isUint8ArrayBase64Probe(lowerer, expr))
|
|
369
|
+
return dynUndefinedExpr(loc);
|
|
370
|
+
if (expr.questionDotToken && expr.name.text === "electron") {
|
|
371
|
+
const processProperty = lowerer.lowerProcessProperty(expr);
|
|
372
|
+
if (processProperty)
|
|
373
|
+
return processProperty;
|
|
374
|
+
}
|
|
375
|
+
// Optional chaining `a?.b`: the guard lowers here (a tag test around
|
|
376
|
+
// the plain property lowering below); the handled marker keeps this
|
|
377
|
+
// re-entrant dispatch from looping.
|
|
378
|
+
if (expr.questionDotToken && !lowerer.chainHandled.has(expr)) {
|
|
379
|
+
return lowerer.lowerOptionalChain(expr);
|
|
380
|
+
}
|
|
381
|
+
// `a?.b.c` — the tail of a chain whose token sits deeper: the whole
|
|
382
|
+
// tail short-circuits with the guard.
|
|
383
|
+
if (!expr.questionDotToken && isOptionalChainTail(lowerer, expr)) {
|
|
384
|
+
return lowerer.lowerOptionalChain(expr);
|
|
385
|
+
}
|
|
386
|
+
// Known Web handles retain their declared surface even when their
|
|
387
|
+
// storage uses checked values. Apply this before generic reads.
|
|
388
|
+
lowerer.fenceStaticAbortControllerMemberRead(expr);
|
|
389
|
+
lowerer.fenceStaticResponseMember(expr, "read");
|
|
390
|
+
lowerer.fenceStaticHeadersMember(expr, "read");
|
|
391
|
+
lowerer.fenceStaticReadableStreamMember(expr, "read");
|
|
392
|
+
// — reading off null/undefined — bridged catchably like everything
|
|
393
|
+
// at the boundary). `o?.x` arrives here too, through the chain
|
|
394
|
+
// lowering's re-dispatch (a questionDotToken past the gate above is
|
|
395
|
+
// always chain-handled; the receiver reads back as the chain's
|
|
396
|
+
// bound handle).
|
|
397
|
+
// `m.index` on a for-of-over-matchAll binding reads the companion-
|
|
398
|
+
// index array at this iteration's cursor — always a number: every
|
|
399
|
+
// drained row matched, so the lib's `.index` is never undefined
|
|
400
|
+
// here (lowerForOfMatchAll).
|
|
401
|
+
if (expr.name.text === "index" && !expr.questionDotToken && ts.isIdentifier(expr.expression)) {
|
|
402
|
+
const sym = lowerer.checker.getSymbolAtLocation(expr.expression);
|
|
403
|
+
const companion = sym !== undefined ? lowerer.matchAllIndexBindings.get(sym) : undefined;
|
|
404
|
+
if (companion !== undefined) {
|
|
405
|
+
return {
|
|
406
|
+
kind: "arrayGet",
|
|
407
|
+
arr: { kind: "varRef", localId: companion.idxsLocalId, type: arrayOf(F64), loc },
|
|
408
|
+
index: { kind: "varRef", localId: companion.curLocalId, type: F64, loc },
|
|
409
|
+
type: F64,
|
|
410
|
+
loc,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if ((expr.name.text === "index" || expr.name.text === "input") && !expr.questionDotToken) {
|
|
415
|
+
const represented = tryLowerExpression(lowerer, expr.expression);
|
|
416
|
+
if (represented &&
|
|
417
|
+
isMatchSliceType(lowerer, represented.type) &&
|
|
418
|
+
(lowerer.isStdlibMember(expr) || isJsSourceFile(ts.getSourceFileOfNode(expr)))) {
|
|
419
|
+
const recv = represented;
|
|
420
|
+
const key = { kind: "strLit", value: expr.name.text, type: STRING, loc };
|
|
421
|
+
// A plain slice answers from its match source without a dynamic copy.
|
|
422
|
+
const read = typeEquals(recv.type, arrayOf(STRING))
|
|
423
|
+
? { kind: "libCall", fn: "regex.resultProp", args: [recv, key], type: DYN, loc }
|
|
424
|
+
: { kind: "dynKeyGet", value: lowerer.coerceToExpected(recv, DYN), key, type: DYN, loc };
|
|
425
|
+
return lowerer.maybeNarrow(read, expr);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
// `m.groups` on a match result whose regex is statically known:
|
|
429
|
+
// the compile-time record projection over the honest slice (or
|
|
430
|
+
// Node's undefined when the pattern has no named groups) — see
|
|
431
|
+
// lowerMatchGroupsRead.
|
|
432
|
+
{
|
|
433
|
+
const g = lowerMatchGroupsRead(lowerer, expr);
|
|
434
|
+
if (g !== null)
|
|
435
|
+
return g;
|
|
436
|
+
}
|
|
437
|
+
// `arguments.length` in a TYPED function whose signature is
|
|
438
|
+
// FIXED-ARITY (no optional/default/rest parameters): tsc enforces
|
|
439
|
+
// exact arity at every call site and call/apply/bind indirection is
|
|
440
|
+
// fenced, so the actual count IS the declared count — a compile-time
|
|
441
|
+
// constant. Arrows don't bind `arguments` (the walk skips them,
|
|
442
|
+
// exactly JS's scoping); variable-arity signatures keep the fence
|
|
443
|
+
// (the count would need a hidden argc). The JS-source variadic
|
|
444
|
+
// `arguments` object (dynRest) was claimed at identifier lowering.
|
|
445
|
+
if (expr.name.text === "length" &&
|
|
446
|
+
!expr.questionDotToken &&
|
|
447
|
+
ts.isIdentifier(expr.expression) &&
|
|
448
|
+
expr.expression.text === "arguments" &&
|
|
449
|
+
!lowerer.ctx.argumentsLocal &&
|
|
450
|
+
ts.symbolNameOf(lowerer.typeOf(expr.expression).getSymbol()) === "IArguments" &&
|
|
451
|
+
lowerer.isStdlibSymbol(lowerer.typeOf(expr.expression).getSymbol())) {
|
|
452
|
+
let fn = expr.parent;
|
|
453
|
+
while (fn !== undefined &&
|
|
454
|
+
!ts.isFunctionDeclaration(fn) &&
|
|
455
|
+
!ts.isFunctionExpression(fn) &&
|
|
456
|
+
!ts.isMethodDeclaration(fn) &&
|
|
457
|
+
!ts.isConstructorDeclaration(fn) &&
|
|
458
|
+
!ts.isGetAccessorDeclaration(fn) &&
|
|
459
|
+
!ts.isSetAccessorDeclaration(fn)) {
|
|
460
|
+
fn = ts.isSourceFile(fn) ? undefined : fn.parent;
|
|
461
|
+
}
|
|
462
|
+
if (fn !== undefined) {
|
|
463
|
+
const fixedArity = fn.parameters.nodes.every((p) => p.questionToken === undefined &&
|
|
464
|
+
p.initializer === undefined &&
|
|
465
|
+
p.dotDotDotToken === undefined);
|
|
466
|
+
if (fixedArity) {
|
|
467
|
+
// A `this` parameter is type-only: callers never pass it.
|
|
468
|
+
return {
|
|
469
|
+
kind: "numLit",
|
|
470
|
+
value: fn.parameters.nodes.filter((p) => !isThisParameter(p)).length,
|
|
471
|
+
type: F64,
|
|
472
|
+
loc,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
lowerer.unsupported("SC1090", expr, "'arguments.length' in functions with optional, default, or rest parameters (the count varies per call — a fixed-arity signature folds to a constant)");
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
// CommonJS namespace binding (`const lib = require("./lib.js")`):
|
|
479
|
+
// `lib.member` IS the member — the export table is alias plumbing,
|
|
480
|
+
// so the NAME resolves exactly like a bare identifier reference
|
|
481
|
+
// (resolveValueSymbol lands on the exporter's declaration and every
|
|
482
|
+
// existing path — globals, function values, classes — applies).
|
|
483
|
+
if (!expr.questionDotToken && lowerer.cjsLocalModuleBindingOf(expr.expression)) {
|
|
484
|
+
// A binding whose dep is a class-expression WHOLE export
|
|
485
|
+
// (`module.exports = class {…}`): the member surface is the
|
|
486
|
+
// CLASS's — `C.name` folds to NamedEvaluation's answer and own
|
|
487
|
+
// statics read their globals (lowerStaticFieldRead resolves the
|
|
488
|
+
// binding through the expression's own symbol). The plain
|
|
489
|
+
// member-name delegation below would resolve `name` against the
|
|
490
|
+
// stdlib var instead — a wrong VALUE, not a fence. Unknown
|
|
491
|
+
// members fall through to the delegation (expando statics ride
|
|
492
|
+
// their pre-registered export globals).
|
|
493
|
+
const viaClass = lowerStaticFieldRead(lowerer, expr);
|
|
494
|
+
if (viaClass)
|
|
495
|
+
return viaClass;
|
|
496
|
+
return lowerExpr(lowerer, expr.name);
|
|
497
|
+
}
|
|
498
|
+
// `module.exports` READ in a CommonJS file whose whole export IS a
|
|
499
|
+
// class expression (`module.exports = class …{}`): the read answers
|
|
500
|
+
// the class VALUE — `new module.exports()` inside the module is the
|
|
501
|
+
// requirer's `new C()` spelled locally. Top-level reads ABOVE the
|
|
502
|
+
// assignment fall through to their existing fences (Node still
|
|
503
|
+
// answers the original export object there); function bodies
|
|
504
|
+
// resolve unconditionally — they run after the module evaluated,
|
|
505
|
+
// the same approximation identifier exports already make. Every
|
|
506
|
+
// other module.exports read keeps its existing story.
|
|
507
|
+
if (!expr.questionDotToken &&
|
|
508
|
+
isModuleExportsAccess(expr) &&
|
|
509
|
+
isCjsJsFile(ts.getSourceFileOfNode(expr), lowerer.program)) {
|
|
510
|
+
const whole = cjsClassExprWholeExportOf(ts.getSourceFileOfNode(expr));
|
|
511
|
+
if (whole) {
|
|
512
|
+
let inBody = false;
|
|
513
|
+
for (let p = expr.parent; p !== undefined && !ts.isSourceFile(p); p = p.parent) {
|
|
514
|
+
if (ts.isFunctionLike(p) || ts.isClassDeclaration(p) || ts.isClassExpression(p)) {
|
|
515
|
+
inBody = true;
|
|
516
|
+
break;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
if (inBody || ts.tokenStartOfNode(expr) > whole.stmt.end) {
|
|
520
|
+
return lowerer.classValueRef(lowerer.lowerClassExpressionInfo(whole.classExpr), expr);
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
// `module.exports.Sub` / `exports.Sub` READ in the same module: an
|
|
525
|
+
// EXPRESSION-valued member rides its pre-registered export global —
|
|
526
|
+
// exactly what requirers see through `require('./x').Sub`, and the
|
|
527
|
+
// global IS the storage every `exports.Sub =` statement assigns, so
|
|
528
|
+
// the read is Node's live member. Identifier-valued members have no
|
|
529
|
+
// global (pure alias plumbing) and fall through unchanged; write
|
|
530
|
+
// positions belong to the export-assignment machinery.
|
|
531
|
+
{
|
|
532
|
+
const writePos = ts.isBinaryExpression(expr.parent) &&
|
|
533
|
+
expr.parent.left === expr &&
|
|
534
|
+
expr.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken;
|
|
535
|
+
const g = cjsInFileExportGlobalOf(lowerer, expr);
|
|
536
|
+
if (g && !writePos)
|
|
537
|
+
return { kind: "varRef", localId: g.id, type: g.type, loc };
|
|
538
|
+
}
|
|
539
|
+
// Namespace-qualified reads (`N.x`, `A.B.C.f`, import= alias
|
|
540
|
+
// chains): the member is a compile-time-known declaration of a
|
|
541
|
+
// lowered namespace block — it resolves exactly like a bare
|
|
542
|
+
// identifier reference (globals, function values, classes), guarded
|
|
543
|
+
// by the namespace source-order fences (lower-namespaces.ts).
|
|
544
|
+
if (!expr.questionDotToken) {
|
|
545
|
+
const nsMember = nsMemberIdentOf(lowerer, expr);
|
|
546
|
+
if (nsMember) {
|
|
547
|
+
const memberSym = lowerer.checker.getSymbolAtLocation(nsMember);
|
|
548
|
+
if (memberSym)
|
|
549
|
+
fenceEarlyNsMemberRef(lowerer, expr, memberSym);
|
|
550
|
+
return lowerExpr(lowerer, nsMember);
|
|
551
|
+
}
|
|
552
|
+
// Expando function members (`foo.bar` after `foo.bar = 12`): the
|
|
553
|
+
// member's module global (lower-expando.ts), before the ambient-
|
|
554
|
+
// namespace fence — a declare-namespace merge over a real function
|
|
555
|
+
// (`declare namespace Foo { var baz: number }` + `function Foo`)
|
|
556
|
+
// reads its assigned members, not the ambient ReferenceError.
|
|
557
|
+
{
|
|
558
|
+
const ex = expandoMemberRead(lowerer, expr);
|
|
559
|
+
if (ex)
|
|
560
|
+
return lowerer.maybeNarrow(ex, expr);
|
|
561
|
+
}
|
|
562
|
+
// An AMBIENT namespace receiver (`M.x` where only `declare
|
|
563
|
+
// namespace M` exists): the namespace object never exists at
|
|
564
|
+
// runtime — Node's exact catchable ReferenceError at the access,
|
|
565
|
+
// the ambient `declare const` stance.
|
|
566
|
+
const ambientRoot = ambientNsRootOf(lowerer, expr.expression);
|
|
567
|
+
if (ambientRoot !== null) {
|
|
568
|
+
const t = ambientUndefReadType(lowerer, expr);
|
|
569
|
+
if (t)
|
|
570
|
+
return nsUndefRead(lowerer, ambientRoot.text, expr, t);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
// `exports.<name>` READS in a module whose export object was
|
|
574
|
+
// REPLACED (`module.exports = ...`): `exports` still references the
|
|
575
|
+
// ORIGINAL object — Node's aliasing rule — so when nothing ever
|
|
576
|
+
// attached this name to it (`exports.<name> =` nowhere in the
|
|
577
|
+
// file), the honest answer is undefined. tsc types the read off the
|
|
578
|
+
// REPLACEMENT (its CJS model is identity-blind), which is exactly
|
|
579
|
+
// the undiagnosed divergence this lowering closes. Reads in modules with
|
|
580
|
+
// real `exports.<name> =` attachments keep their fences.
|
|
581
|
+
{
|
|
582
|
+
const ex = lowerReplacedExportsRead(lowerer, expr);
|
|
583
|
+
if (ex)
|
|
584
|
+
return ex;
|
|
585
|
+
}
|
|
586
|
+
// `this.<name>` inside a CJS export-table getter: Node binds the
|
|
587
|
+
// receiver to module.exports — the read is the sibling getter's
|
|
588
|
+
// lifted call.
|
|
589
|
+
{
|
|
590
|
+
const tm = lowerCjsExportTableThisMember(lowerer, expr);
|
|
591
|
+
if (tm)
|
|
592
|
+
return tm;
|
|
593
|
+
}
|
|
594
|
+
// Property signatures of class-backed protocols read implementing
|
|
595
|
+
// classes' fields directly.
|
|
596
|
+
if (!hasOptionalChainGuard(expr.expression)) {
|
|
597
|
+
const typed = lowerProtocolPropertyRead(lowerer, expr);
|
|
598
|
+
if (typed)
|
|
599
|
+
return typed;
|
|
600
|
+
}
|
|
601
|
+
const handled = lowerer.lowerProcessEnvGet(expr) ??
|
|
602
|
+
lowerer.lowerServerProperty(expr) ??
|
|
603
|
+
// diagnostics_channel Channel receivers — name/hasSubscribers
|
|
604
|
+
// over the f64 channel handle.
|
|
605
|
+
lowerer.lowerDiagnosticsChannelProperty(expr) ??
|
|
606
|
+
// readline Interface receivers — the history and option members
|
|
607
|
+
// over the f64 interface handle.
|
|
608
|
+
lowerReadlineProperty(lowerer, expr) ??
|
|
609
|
+
// TracingChannel receivers — the five event channels and
|
|
610
|
+
// hasSubscribers over the f64 tracing handle.
|
|
611
|
+
lowerer.lowerTracingChannelProperty(expr) ??
|
|
612
|
+
lowerer.lowerTestCtxProperty(expr) ??
|
|
613
|
+
lowerer.lowerProcessProperty(expr) ??
|
|
614
|
+
lowerer.lowerProcessStreamProperty(expr) ??
|
|
615
|
+
lowerer.lowerFsConstantsProperty(expr) ??
|
|
616
|
+
// http2.constants.NGHTTP2_CANCEL (any constants-object spelling):
|
|
617
|
+
// the baked-literal table.
|
|
618
|
+
lowerer.lowerBuiltinConstantsProperty(expr) ??
|
|
619
|
+
// Builtin namespace imports (`path.sep`, `os.EOL`,
|
|
620
|
+
// `fs.constants.R_OK` where the root is `import * as ...`): the
|
|
621
|
+
// same constants and per-member fences as named builtin imports.
|
|
622
|
+
lowerer.lowerNamespaceBuiltinProperty(expr) ??
|
|
623
|
+
lowerer.lowerJsonProperty(expr) ??
|
|
624
|
+
lowerer.lowerErrorCodeProperty(expr) ??
|
|
625
|
+
lowerer.lowerNumberStaticProperty(expr) ??
|
|
626
|
+
lowerEventStaticProperty(lowerer, expr) ??
|
|
627
|
+
lowerer.lowerMathProperty(expr) ??
|
|
628
|
+
lowerer.lowerIntrinsicProperty(expr) ??
|
|
629
|
+
// The _readableState/_writableState scalar READS (the suite's
|
|
630
|
+
// asserts) — checked before the generic stream property surface:
|
|
631
|
+
// the inner access maps no type of its own.
|
|
632
|
+
lowerStreamStateProperty(lowerer, expr) ??
|
|
633
|
+
lowerStreamObjectProperty(lowerer, expr) ??
|
|
634
|
+
lowerEventObjectProperty(lowerer, expr) ??
|
|
635
|
+
lowerer.lowerUnionProperty(expr) ??
|
|
636
|
+
// A builtin constructor reached through another binding (`const D =
|
|
637
|
+
// Date; D.prototype`) holds its interned function value, which
|
|
638
|
+
// models only name, length and constructor: a static member or the
|
|
639
|
+
// prototype that no lowering above claimed keeps the SC2020 fence
|
|
640
|
+
// rather than reading undefined through the field and dynamic reads.
|
|
641
|
+
fenceBuiltinConstructorStaticRead(lowerer, expr) ??
|
|
642
|
+
lowerer.lowerFieldRead(expr);
|
|
643
|
+
// A union-typed field read narrows like an identifier when the
|
|
644
|
+
// checker has narrowed this use to one arm.
|
|
645
|
+
if (handled) {
|
|
646
|
+
if (handled.type.kind === "union" &&
|
|
647
|
+
lowerer.armTag(handled.type.unionId, UNDEFINED_T) >= 0 &&
|
|
648
|
+
handled.kind === "recordGet" &&
|
|
649
|
+
lowerer.isRuntimeOptionalField(handled.shapeId, handled.field))
|
|
650
|
+
return handled;
|
|
651
|
+
// A class field assigned a missing read: the checker narrows this
|
|
652
|
+
// read to the assigned value's bare type, but the stored undefined
|
|
653
|
+
// arm is real (`obj.n = bytes[i]; obj.n` is undefined in Node).
|
|
654
|
+
if (runtimeOptionalClassField(lowerer, handled, expr))
|
|
655
|
+
return handled;
|
|
656
|
+
return iteratorResultValueRead(lowerer, handled, expr) ?? lowerer.maybeNarrow(handled, expr);
|
|
657
|
+
}
|
|
658
|
+
// `globalThis.<name>` that no lowering above claimed
|
|
659
|
+
// (globalThis.crypto, globalThis.SubtleCrypto, globalThis.localStorage
|
|
660
|
+
// — the harness's capability-conditional knownGlobals adds): the
|
|
661
|
+
// PROPERTY spelling of the identifier chokepoint's JS rule — a stdlib
|
|
662
|
+
// global taken as a VALUE in a JavaScript source is the same opaque
|
|
663
|
+
// IDENTITY TOKEN the bare spelling answers (`globalThis.crypto` IS
|
|
664
|
+
// `crypto` — one global, one token, or identity flows through Sets
|
|
665
|
+
// and === would disagree between the two spellings). TypeScript
|
|
666
|
+
// sources keep the SC2020 member fence below, like the bare form.
|
|
667
|
+
if (!expr.questionDotToken &&
|
|
668
|
+
stdlibGlobalNameOf(lowerer, expr.expression) === "globalThis" &&
|
|
669
|
+
isJsSourceFile(ts.getSourceFileOfNode(expr))) {
|
|
670
|
+
const canonical = stdlibGlobalNameOf(lowerer, expr);
|
|
671
|
+
if (canonical !== null) {
|
|
672
|
+
if (canonical === "globalThis")
|
|
673
|
+
return lowerGlobalValue(lowerer, expr);
|
|
674
|
+
// Typed for the programs that name it, absent in Node 24.
|
|
675
|
+
if (canonical === TEMPORAL_GLOBAL)
|
|
676
|
+
return dynUndefinedExpr(loc);
|
|
677
|
+
if (canonical === "ArrayBuffer")
|
|
678
|
+
return { kind: "libCall", fn: "arrayBuffer.constructor", args: [], type: DYN, loc };
|
|
679
|
+
if (canonical === "fetch")
|
|
680
|
+
return { kind: "libCall", fn: "fetch.function", args: [], type: DYN, loc };
|
|
681
|
+
if (Object.values(BYTES_ELEMENT_NAME).includes(canonical))
|
|
682
|
+
return {
|
|
683
|
+
kind: "libCall",
|
|
684
|
+
fn: "bytes.constructor",
|
|
685
|
+
args: [{ kind: "strLit", value: canonical, type: STRING, loc }],
|
|
686
|
+
type: DYN,
|
|
687
|
+
loc,
|
|
688
|
+
};
|
|
689
|
+
return (builtinGlobalValueAt(lowerer, expr, canonical, loc, true) ?? {
|
|
690
|
+
kind: "strLit",
|
|
691
|
+
value: `[builtin ${canonical}]`,
|
|
692
|
+
type: STRING,
|
|
693
|
+
loc,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
// A JS receiver whose CHECKER type has no mapping (`mustCallChecks
|
|
698
|
+
// .length` where the binding is an evolving any[] living as a
|
|
699
|
+
// checked-dynamic global): the stdlib member fence below would blame
|
|
700
|
+
// the unmappable checker type (`any[].length`), but the VALUE is a
|
|
701
|
+
// dyn node — lower the receiver first and read through the dyn keyed
|
|
702
|
+
// read (ARR answers length; everything else JS's own-property
|
|
703
|
+
// answer). Mapped receivers keep the fence-first order: their
|
|
704
|
+
// members' gaps are real surface gaps ([1,2].entries), not
|
|
705
|
+
// representation artifacts. `.length` on a receiver whose checker
|
|
706
|
+
// ARRAY type lowers to the checked-dynamic representation —
|
|
707
|
+
// `unknown[]`, the collapsed `(string | object)[]`, and the `any[]`
|
|
708
|
+
// an Array.isArray guard narrows a collapsed union to — is the checked-dynamic tree
|
|
709
|
+
// array's OWN length (a keyed read the ARR kind answers exactly),
|
|
710
|
+
// never an `Array.prototype` surface gap; both source languages.
|
|
711
|
+
// Prototype-method VALUE reads (`ps.map` unparenthesized) keep the
|
|
712
|
+
// fence-first order: a stored-member undefined would mis-answer
|
|
713
|
+
// them, and calls dispatch through the dyn method machinery
|
|
714
|
+
// instead.
|
|
715
|
+
if ((isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
716
|
+
(lowerer.mapTypeOf(lowerer.typeOf(expr.expression)) === null ||
|
|
717
|
+
(lowerer.typeOf(expr.expression).flags & ts.TypeFlags.Never) !== 0 ||
|
|
718
|
+
// A never-tainted receiver type maps (never rides as f64) but
|
|
719
|
+
// its VALUE lowered checked-dynamic — same dyn read.
|
|
720
|
+
neverTaintedJsType(lowerer, expr.expression, lowerer.typeOf(expr.expression)))) ||
|
|
721
|
+
(expr.name.text === "length" &&
|
|
722
|
+
(lowerer.checkerAnyArray(expr.expression) ||
|
|
723
|
+
(lowerer.checker.isArrayType(lowerer.typeOf(expr.expression)) &&
|
|
724
|
+
lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind === "dyn")))) {
|
|
725
|
+
const recv = lowerer.lowerExpr(expr.expression);
|
|
726
|
+
if (recv.type.kind === "dyn") {
|
|
727
|
+
const key = {
|
|
728
|
+
kind: "strLit",
|
|
729
|
+
value: expr.name.text,
|
|
730
|
+
type: STRING,
|
|
731
|
+
loc: locOf(expr.name),
|
|
732
|
+
};
|
|
733
|
+
const opt = hasOptionalChainGuard(expr.expression);
|
|
734
|
+
return lowerer.maybeNarrow({
|
|
735
|
+
kind: "dynKeyGet",
|
|
736
|
+
key,
|
|
737
|
+
...(opt ? { optional: true } : {}),
|
|
738
|
+
value: recv,
|
|
739
|
+
type: DYN,
|
|
740
|
+
loc,
|
|
741
|
+
}, expr);
|
|
742
|
+
}
|
|
743
|
+
if (expr.name.text === "length" &&
|
|
744
|
+
(recv.type.kind === "array" || recv.type.kind === "string")) {
|
|
745
|
+
return recv.type.kind === "array"
|
|
746
|
+
? { kind: "arrIntrinsic", method: "length", receiver: recv, args: [], type: F64, loc }
|
|
747
|
+
: { kind: "strIntrinsic", method: "length", receiver: recv, args: [], type: F64, loc };
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) && expr.name.text === "constructor") {
|
|
751
|
+
const receiver = tryLowerExpression(lowerer, expr.expression);
|
|
752
|
+
if (receiver?.type.kind === "dyn" ||
|
|
753
|
+
(receiver?.type.kind === "object" &&
|
|
754
|
+
!lowerer.classes.get(receiver.type.className)?.fields.has("constructor"))) {
|
|
755
|
+
return {
|
|
756
|
+
kind: "dynKeyGet",
|
|
757
|
+
value: lowerer.coerceToExpected(receiver, DYN),
|
|
758
|
+
key: { kind: "strLit", value: "constructor", type: STRING, loc },
|
|
759
|
+
type: DYN,
|
|
760
|
+
loc,
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
// A plain record's inherited Object.prototype members READ as values
|
|
765
|
+
// (`o.constructor`, `o.valueOf`, `({}).toString`, the isPlainObject and
|
|
766
|
+
// deep-equal idioms): the record boxes into its dynamic view, whose
|
|
767
|
+
// read answers the interned Object constructor and Object.prototype
|
|
768
|
+
// methods — the same values `Object` and `Object.prototype.valueOf`
|
|
769
|
+
// read, so identity comparisons are exact. Calls keep their own
|
|
770
|
+
// lowerings; a record declaring the name reads its field.
|
|
771
|
+
if (OBJECT_PROTOTYPE_VALUE_READS.has(expr.name.text) &&
|
|
772
|
+
!isCalleeOf(expr) &&
|
|
773
|
+
// `X.prototype.toString` keeps the builtin prototype-method lowering.
|
|
774
|
+
!(ts.isPropertyAccessExpression(expr.expression) && expr.expression.name.text === "prototype")) {
|
|
775
|
+
const receiver = tryLowerExpression(lowerer, expr.expression);
|
|
776
|
+
const name = expr.name.text;
|
|
777
|
+
const shape = receiver?.type.kind === "record" ? lowerer.shapes.get(receiver.type.shapeId) : undefined;
|
|
778
|
+
const info = receiver?.type.kind === "object" ? lowerer.classes.get(receiver.type.className) : undefined;
|
|
779
|
+
const inherits = receiver?.type.kind === "dyn" ||
|
|
780
|
+
(shape !== undefined && !shape.tuple && !shape.fields.some((field) => field.name === name)) ||
|
|
781
|
+
(info !== undefined &&
|
|
782
|
+
name !== "constructor" &&
|
|
783
|
+
!info.fields.has(name) &&
|
|
784
|
+
!lowerer.findMethodOn(info, name) &&
|
|
785
|
+
!lowerer.findMethodOn(info, `get:${name}`));
|
|
786
|
+
if (receiver !== null && receiver !== undefined && inherits) {
|
|
787
|
+
return {
|
|
788
|
+
kind: "dynKeyGet",
|
|
789
|
+
value: lowerer.coerceToExpected(receiver, DYN),
|
|
790
|
+
key: { kind: "strLit", value: name, type: STRING, loc },
|
|
791
|
+
type: DYN,
|
|
792
|
+
loc,
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
// `f.name` / `f.length` / own properties on a FUNCTION-typed JS
|
|
797
|
+
// value (the mustCall wrapper's function-instance members): read
|
|
798
|
+
// through the dyn box — the closure's own-property table answers
|
|
799
|
+
// first (defineProperties writes land there), then the box's
|
|
800
|
+
// best-effort static name and the declared arity; anything else is
|
|
801
|
+
// the own-property answer, undefined. Function.prototype METHOD
|
|
802
|
+
// names stay fenced (a stored-member undefined would mis-answer
|
|
803
|
+
// `f.call` as a value). Static callable values keep the existing TS fence; checked callable
|
|
804
|
+
// storage can expose its own name and length in both source languages.
|
|
805
|
+
if (!["apply", "bind", "call", "toString", "caller", "arguments"].includes(expr.name.text) &&
|
|
806
|
+
(isJsSourceFile(ts.getSourceFileOfNode(expr)) ||
|
|
807
|
+
expr.name.text === "name" ||
|
|
808
|
+
expr.name.text === "length" ||
|
|
809
|
+
expr.name.text === "constructor")) {
|
|
810
|
+
const probed = tryLowerExpression(lowerer, expr.expression);
|
|
811
|
+
// Inferred callable returns can use checked storage even when the
|
|
812
|
+
// checker still describes a function. Read its actual dyn value;
|
|
813
|
+
// the ambient Function member must not hide its own properties.
|
|
814
|
+
const receiverType = lowerer.typeOf(expr.expression);
|
|
815
|
+
const receiverSymbol = receiverType.getSymbol();
|
|
816
|
+
const checkedFunction = lowerer.checker.getCallSignatures(receiverType).length > 0 ||
|
|
817
|
+
(receiverSymbol !== undefined &&
|
|
818
|
+
ts.symbolName(receiverSymbol) === "Function" &&
|
|
819
|
+
lowerer.isStdlibSymbol(receiverSymbol));
|
|
820
|
+
if (probed?.type.kind === "dyn" && checkedFunction) {
|
|
821
|
+
const key = {
|
|
822
|
+
kind: "strLit",
|
|
823
|
+
value: expr.name.text,
|
|
824
|
+
type: STRING,
|
|
825
|
+
loc: locOf(expr.name),
|
|
826
|
+
};
|
|
827
|
+
const opt = hasOptionalChainGuard(expr.expression);
|
|
828
|
+
return lowerer.maybeNarrow({
|
|
829
|
+
kind: "dynKeyGet",
|
|
830
|
+
key,
|
|
831
|
+
value: probed,
|
|
832
|
+
...(opt ? { optional: true } : {}),
|
|
833
|
+
type: DYN,
|
|
834
|
+
loc,
|
|
835
|
+
}, expr);
|
|
836
|
+
}
|
|
837
|
+
if ((isJsSourceFile(ts.getSourceFileOfNode(expr)) || expr.name.text === "constructor") &&
|
|
838
|
+
probed?.type.kind === "func" &&
|
|
839
|
+
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
840
|
+
const fnName = jsFuncNameOf(expr.expression);
|
|
841
|
+
const boxed = {
|
|
842
|
+
kind: "dynFrom",
|
|
843
|
+
value: probed,
|
|
844
|
+
type: DYN,
|
|
845
|
+
...(fnName !== null ? { fnName } : {}),
|
|
846
|
+
loc,
|
|
847
|
+
};
|
|
848
|
+
const key = {
|
|
849
|
+
kind: "strLit",
|
|
850
|
+
value: expr.name.text,
|
|
851
|
+
type: STRING,
|
|
852
|
+
loc: locOf(expr.name),
|
|
853
|
+
};
|
|
854
|
+
return lowerer.maybeNarrow({ kind: "dynKeyGet", key, value: boxed, type: DYN, loc }, expr);
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
// A NARROWED IteratorResult receiver (`if (!r.done) r.value` — the
|
|
858
|
+
// checker narrows to IteratorYieldResult/IteratorReturnResult, whose
|
|
859
|
+
// own type cannot map: the shared record shape needs BOTH channels):
|
|
860
|
+
// the receiver's LOWERED record still carries the field, so the read
|
|
861
|
+
// is an ordinary recordGet — maybeNarrow then bridges the union slot
|
|
862
|
+
// to the checker's narrowed arm, exactly like a union field read.
|
|
863
|
+
if (expr.name.text === "done" || expr.name.text === "value") {
|
|
864
|
+
const receiverType = lowerer.typeOf(expr.expression);
|
|
865
|
+
const recvSym = ts.symbolNameOf(receiverType.getAliasSymbol()) === "IteratorResult"
|
|
866
|
+
? receiverType.getAliasSymbol()
|
|
867
|
+
: receiverType.getSymbol();
|
|
868
|
+
if (((recvSym !== undefined && ts.symbolName(recvSym) === "IteratorResult") ||
|
|
869
|
+
(recvSym !== undefined && ts.symbolName(recvSym) === "IteratorYieldResult") ||
|
|
870
|
+
(recvSym !== undefined && ts.symbolName(recvSym) === "IteratorReturnResult")) &&
|
|
871
|
+
recvSym.declarations.some((d) => (ts.isInterfaceDeclaration(d) || ts.isTypeAliasDeclaration(d)) &&
|
|
872
|
+
lowerer.isStdlibFile(ts.getSourceFileOfNode(d)))) {
|
|
873
|
+
const recv = lowerer.lowerExpr(expr.expression);
|
|
874
|
+
if (recv.type.kind === "dyn")
|
|
875
|
+
return lowerer.maybeNarrow({
|
|
876
|
+
kind: "dynKeyGet",
|
|
877
|
+
value: recv,
|
|
878
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
879
|
+
type: DYN,
|
|
880
|
+
loc,
|
|
881
|
+
}, expr);
|
|
882
|
+
if (recv.type.kind === "record") {
|
|
883
|
+
const shape = lowerer.shapes.get(recv.type.shapeId);
|
|
884
|
+
const field = shape?.fields.find((f) => f.name === expr.name.text);
|
|
885
|
+
if (field) {
|
|
886
|
+
const read = {
|
|
887
|
+
kind: "recordGet",
|
|
888
|
+
obj: recv,
|
|
889
|
+
shapeId: recv.type.shapeId,
|
|
890
|
+
field: field.name,
|
|
891
|
+
type: field.type,
|
|
892
|
+
loc,
|
|
893
|
+
};
|
|
894
|
+
return iteratorResultValueRead(lowerer, read, expr) ?? lowerer.maybeNarrow(read, expr);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
// A chain rooted at an initializer-less ambient `declare const/var`
|
|
900
|
+
// whose declared type has NO mapping (mappable roots compose through
|
|
901
|
+
// the bare-read undefRead and never reach here): Node throws the
|
|
902
|
+
// catchable ReferenceError at the ROOT read before any member
|
|
903
|
+
// matters, so the whole access lowers to that throw — typed by the
|
|
904
|
+
// use site, or by the context it flows into (the throw never
|
|
905
|
+
// returns, so the dummy is never observed).
|
|
906
|
+
{
|
|
907
|
+
const ambientRoot = ambientUndefVarRootOf(lowerer, expr);
|
|
908
|
+
if (ambientRoot !== null) {
|
|
909
|
+
const t = ambientUndefReadType(lowerer, expr) ?? contextualUndefReadType(lowerer, expr);
|
|
910
|
+
if (t)
|
|
911
|
+
return nsUndefRead(lowerer, ambientRoot.text, expr, t);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
// Checked-dynamic stdlib results retain ambient property symbols,
|
|
915
|
+
// including parseArgs tokens narrowed to anonymous union arms. Only
|
|
916
|
+
// members owned by these implemented families bypass the stdlib fence.
|
|
917
|
+
const segmentDataSymbol = lowerer.typeOf(expr.expression).getSymbol();
|
|
918
|
+
const segmentDataProperty = segmentDataSymbol !== undefined &&
|
|
919
|
+
ts.symbolName(segmentDataSymbol) === "SegmentData" &&
|
|
920
|
+
lowerer.isStdlibSymbol(segmentDataSymbol) &&
|
|
921
|
+
["segment", "index", "input", "isWordLike"].includes(expr.name.text);
|
|
922
|
+
// os.constants members vary by platform (the declared groups list
|
|
923
|
+
// every platform's names): a number member reads as `number |
|
|
924
|
+
// undefined`, like an array element, and a group stays checked.
|
|
925
|
+
const osConstants = isOsConstantsType(lowerer.typeOf(expr.expression), lowerer);
|
|
926
|
+
if (isParseArgsDynProperty(lowerer, expr) ||
|
|
927
|
+
isStatFsDynProperty(lowerer, expr) ||
|
|
928
|
+
segmentDataProperty ||
|
|
929
|
+
osConstants ||
|
|
930
|
+
isLegacyUrlSymbol(lowerer.checker.getSymbolAtLocation(expr.name), lowerer)) {
|
|
931
|
+
const recv = lowerer.lowerExpr(expr.expression);
|
|
932
|
+
if (recv.type.kind === "dyn") {
|
|
933
|
+
const key = {
|
|
934
|
+
kind: "strLit",
|
|
935
|
+
value: expr.name.text,
|
|
936
|
+
type: STRING,
|
|
937
|
+
loc: locOf(expr.name),
|
|
938
|
+
};
|
|
939
|
+
const opt = hasOptionalChainGuard(expr.expression);
|
|
940
|
+
const read = {
|
|
941
|
+
kind: "dynKeyGet",
|
|
942
|
+
key,
|
|
943
|
+
...(opt ? { optional: true } : {}),
|
|
944
|
+
value: recv,
|
|
945
|
+
type: DYN,
|
|
946
|
+
loc,
|
|
947
|
+
};
|
|
948
|
+
if (osConstants) {
|
|
949
|
+
return lowerer.mapTypeOf(lowerer.typeOf(expr))?.kind === "f64"
|
|
950
|
+
? lowerer.coerceToExpected(read, lowerer.withUndefinedArm(F64))
|
|
951
|
+
: read;
|
|
952
|
+
}
|
|
953
|
+
return lowerer.maybeNarrow(read, expr);
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
// A member read through a NULLISH generic binding (`const i: I<A &
|
|
957
|
+
// B> = null as any; const _i: I<A> = i.something` — the receiver
|
|
958
|
+
// provably holds null/undefined forever): the read throws Node's
|
|
959
|
+
// exact TypeError at the access.
|
|
960
|
+
if (ts.isIdentifier(expr.expression) && expr.questionDotToken === undefined) {
|
|
961
|
+
const unit = nullishGenericBindingUnitOf(lowerer, lowerer.resolveValueSymbol(expr.expression));
|
|
962
|
+
if (unit !== null) {
|
|
963
|
+
const t = ambientUndefReadType(lowerer, expr) ?? contextualUndefReadType(lowerer, expr) ?? F64;
|
|
964
|
+
return nodeThrowExpr(1, "", `Cannot read properties of ${unit} (reading '${expr.name.text}')`, t, loc);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
// A stdlib-declared member (`message` of an interface extending Error)
|
|
968
|
+
// on a catch binding narrowed to a structural type: the binding reads
|
|
969
|
+
// as its checked-dynamic value, so the member does too.
|
|
970
|
+
if (!expr.questionDotToken && lowerer.caughtLocalOf(expr.expression)) {
|
|
971
|
+
const recv = lowerer.lowerExpr(expr.expression);
|
|
972
|
+
if (recv.kind === "caughtToDyn") {
|
|
973
|
+
const read = {
|
|
974
|
+
kind: "dynKeyGet",
|
|
975
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
976
|
+
value: recv,
|
|
977
|
+
type: DYN,
|
|
978
|
+
loc,
|
|
979
|
+
};
|
|
980
|
+
const declared = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
981
|
+
return declared && declared.kind !== "void" ? lowerer.coerceToExpected(read, declared) : read;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
// The lib fence's PROPERTY chokepoint: a stdlib-declared member that
|
|
985
|
+
// no lowering above claimed ([1,2].entries, Math.SQRT2, Promise.all,
|
|
986
|
+
// re.exec as a value, ...) reports SC2020 here.
|
|
987
|
+
lowerer.stdlibMemberFence(expr);
|
|
988
|
+
// The npm chokepoint: a member on a package-typed receiver in a
|
|
989
|
+
// static build — attributed to the package, like every other site.
|
|
990
|
+
lowerer.npmMemberFence(expr);
|
|
991
|
+
// A property read rooted at a BLOCKED binding: the declaration
|
|
992
|
+
// carries the real diagnostic — the SC2004 cascade, not a generic
|
|
993
|
+
// "property access" rejection.
|
|
994
|
+
{
|
|
995
|
+
let root = expr.expression;
|
|
996
|
+
while (ts.isPropertyAccessExpression(root))
|
|
997
|
+
root = root.expression;
|
|
998
|
+
if (ts.isIdentifier(root) && lowerer.isBlockedBinding(lowerer.resolveValueSymbol(root))) {
|
|
999
|
+
lowerer.pushDiag(blockedBindingUseDiag(root.text, loc));
|
|
1000
|
+
throw new PoisonError();
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
// Nothing claimed the member. Lower the RECEIVER before rejecting:
|
|
1004
|
+
// when the receiver itself is the blocker (`(await import(x)).y` —
|
|
1005
|
+
// the dynamic import is the unsupported part), ITS diagnostic is the
|
|
1006
|
+
// honest one, not a generic recitation about the outer dot. A
|
|
1007
|
+
// receiver that lowers cleanly means the MEMBER is the gap — name
|
|
1008
|
+
// the property and the receiver's type instead of "property access".
|
|
1009
|
+
const recvLowered = lowerer.lowerExpr(expr.expression);
|
|
1010
|
+
// A dyn receiver — JSON.parse's `any`, or `unknown` the checker
|
|
1011
|
+
// narrowed to `object` — reads through the dyn keyed read: member
|
|
1012
|
+
// or undefined (JS's own-property answer), throwing JS's TypeError
|
|
1013
|
+
// on undefined/null receivers unless an earlier `?.` guards the
|
|
1014
|
+
// chain. Scalar-narrowed occurrences bridge via maybeNarrow's
|
|
1015
|
+
// validated dynCheck as usual.
|
|
1016
|
+
if (recvLowered.type.kind === "dyn" ||
|
|
1017
|
+
(isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
1018
|
+
(["f64", "bool", "bigint", "string", "symbol"].includes(recvLowered.type.kind) ||
|
|
1019
|
+
(recvLowered.type.kind === "union" && lowerer.dynConvertible(recvLowered.type))))) {
|
|
1020
|
+
const key = {
|
|
1021
|
+
kind: "strLit",
|
|
1022
|
+
value: expr.name.text,
|
|
1023
|
+
type: STRING,
|
|
1024
|
+
loc: locOf(expr.name),
|
|
1025
|
+
};
|
|
1026
|
+
const opt = hasOptionalChainGuard(expr.expression);
|
|
1027
|
+
return lowerer.maybeNarrow({
|
|
1028
|
+
kind: "dynKeyGet",
|
|
1029
|
+
key,
|
|
1030
|
+
...(opt ? { optional: true } : {}),
|
|
1031
|
+
value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
1032
|
+
type: DYN,
|
|
1033
|
+
loc,
|
|
1034
|
+
}, expr);
|
|
1035
|
+
}
|
|
1036
|
+
// The lowered receiver is a RECORD the checker spelled wider —
|
|
1037
|
+
// `s.match(re).groups.key` in a JS file: the checker says
|
|
1038
|
+
// `{ [key: string]: string } | undefined`, but the groups
|
|
1039
|
+
// projection already answered the record arm (its null trap
|
|
1040
|
+
// included). Declared fields read directly; an index-signature
|
|
1041
|
+
// shape serves undeclared keys through the overflow read, exactly
|
|
1042
|
+
// the dot-access rule on checker-spelled hybrids.
|
|
1043
|
+
if (recvLowered.type.kind === "record") {
|
|
1044
|
+
const recvShape = lowerer.shapes.get(recvLowered.type.shapeId);
|
|
1045
|
+
const field = recvShape?.fields.find((f) => f.name === expr.name.text);
|
|
1046
|
+
if (field) {
|
|
1047
|
+
return lowerer.maybeNarrow({
|
|
1048
|
+
kind: "recordGet",
|
|
1049
|
+
obj: recvLowered,
|
|
1050
|
+
shapeId: recvLowered.type.shapeId,
|
|
1051
|
+
field: field.name,
|
|
1052
|
+
type: field.type,
|
|
1053
|
+
loc,
|
|
1054
|
+
}, expr);
|
|
1055
|
+
}
|
|
1056
|
+
if (recvShape?.indexValue !== undefined && !recvShape.tuple) {
|
|
1057
|
+
return lowerer.maybeNarrow({
|
|
1058
|
+
kind: "recordKeyGet",
|
|
1059
|
+
obj: recvLowered,
|
|
1060
|
+
shapeId: recvLowered.type.shapeId,
|
|
1061
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
1062
|
+
overflowOnly: true,
|
|
1063
|
+
type: recvShape.indexValue,
|
|
1064
|
+
loc,
|
|
1065
|
+
}, expr);
|
|
1066
|
+
}
|
|
1067
|
+
// An inferred package-JS call specializes a parameter to the
|
|
1068
|
+
// caller's own record shape. Optional option names omitted by that
|
|
1069
|
+
// caller read undefined; the missing field is not a failed type
|
|
1070
|
+
// assertion. Known prototype members were handled/fenced above.
|
|
1071
|
+
if (recvShape &&
|
|
1072
|
+
!recvShape.tuple &&
|
|
1073
|
+
lowerer.implicitParamTypes !== null &&
|
|
1074
|
+
isJsSourceFile(ts.getSourceFileOfNode(expr)) &&
|
|
1075
|
+
npmStaticPackageOfPath(ts.getSourceFileOfNode(expr).fileName) !== null) {
|
|
1076
|
+
return {
|
|
1077
|
+
kind: "seqExpr",
|
|
1078
|
+
stmts: [{ kind: "exprStmt", expr: recvLowered, loc }],
|
|
1079
|
+
result: dynUndefinedExpr(loc),
|
|
1080
|
+
type: DYN,
|
|
1081
|
+
loc,
|
|
1082
|
+
};
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
// An ABSTRACT property through an abstract-typed receiver: the
|
|
1086
|
+
// declaration is erased at runtime — Node defines no field for it,
|
|
1087
|
+
// each concrete subclass declares its OWN (at its own layout
|
|
1088
|
+
// position), so no shared base slot exists to read. Abstract
|
|
1089
|
+
// ACCESSORS are the supported spelling: they declare a vtable slot.
|
|
1090
|
+
if (recvLowered.type.kind === "object" && abstractPropertyDeclOf(lowerer, expr)) {
|
|
1091
|
+
lowerer.unsupported("SC1090", expr, `reading the abstract property '${expr.name.text}' through a '${lowerer.checker.typeToString(lowerer.typeOf(expr.expression))}'-typed receiver (abstract property declarations are erased at runtime, so no shared slot exists — type the receiver as the concrete class, or declare an abstract getter instead)`);
|
|
1092
|
+
}
|
|
1093
|
+
// Array reads may add an undefined arm even when the checker still
|
|
1094
|
+
// reports a class. Its property bag must remain reachable, while
|
|
1095
|
+
// an absent element takes the normal checked-value TypeError.
|
|
1096
|
+
const nativeReceiver = lowerer.stripUndefinedArm(recvLowered.type);
|
|
1097
|
+
if (ts.isPrivateIdentifier(expr.name) && recvLowered.type.kind === "object") {
|
|
1098
|
+
const field = lowerer.classes.get(recvLowered.type.className)?.fields.get(expr.name.text);
|
|
1099
|
+
if (field)
|
|
1100
|
+
return {
|
|
1101
|
+
kind: "fieldGet",
|
|
1102
|
+
obj: recvLowered,
|
|
1103
|
+
className: recvLowered.type.className,
|
|
1104
|
+
field: expr.name.text,
|
|
1105
|
+
type: field,
|
|
1106
|
+
loc,
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
if (nativeReceiver.kind === "object" && nativeReceiver.className === "%Error") {
|
|
1110
|
+
return lowerer.maybeNarrow({
|
|
1111
|
+
kind: "dynKeyGet",
|
|
1112
|
+
value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
1113
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
1114
|
+
type: DYN,
|
|
1115
|
+
loc,
|
|
1116
|
+
}, expr);
|
|
1117
|
+
}
|
|
1118
|
+
if (isDynTypedRefType(nativeReceiver)) {
|
|
1119
|
+
const info = lowerer.classes.get(nativeReceiver.className);
|
|
1120
|
+
if (info &&
|
|
1121
|
+
!info.def.runtime &&
|
|
1122
|
+
!info.builtinError &&
|
|
1123
|
+
!info.builtinEmitter &&
|
|
1124
|
+
!info.builtinStream) {
|
|
1125
|
+
return lowerer.maybeNarrow({
|
|
1126
|
+
kind: "dynKeyGet",
|
|
1127
|
+
value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
1128
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
1129
|
+
type: DYN,
|
|
1130
|
+
loc,
|
|
1131
|
+
}, expr);
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
// A member a JavaScript module attached to one of its functions
|
|
1135
|
+
// (`status.message = codes; module.exports = status`), read from
|
|
1136
|
+
// TypeScript: JavaScript stores such members on the function's own
|
|
1137
|
+
// property table (`fn.member = v` writes through the function's
|
|
1138
|
+
// checked-dynamic face), so the read takes the same path and enters
|
|
1139
|
+
// the static code at the type inference gave the member.
|
|
1140
|
+
if (recvLowered.type.kind === "func" && jsFunctionExpandoMember(lowerer, expr)) {
|
|
1141
|
+
const read = {
|
|
1142
|
+
kind: "dynKeyGet",
|
|
1143
|
+
value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
1144
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
1145
|
+
type: DYN,
|
|
1146
|
+
loc,
|
|
1147
|
+
};
|
|
1148
|
+
const mapped = lowerer.mapTypeOf(lowerer.typeOf(expr));
|
|
1149
|
+
return mapped && mapped.kind !== "void" ? lowerer.coerceInto(expr, read, mapped) : read;
|
|
1150
|
+
}
|
|
1151
|
+
const asserted = assertedMemberRead(lowerer, expr, recvLowered, loc);
|
|
1152
|
+
if (asserted)
|
|
1153
|
+
return asserted;
|
|
1154
|
+
// A checker-`any` receiver whose value is a FRESH typed result of an
|
|
1155
|
+
// earlier step in the chain (`out.split(" ").length`, where split
|
|
1156
|
+
// extracted the string and answered a native string[]): the member read
|
|
1157
|
+
// goes through the boxed checked-dynamic value, as the method-call twin
|
|
1158
|
+
// does. The box copies; a call result has no other holder to observe it.
|
|
1159
|
+
if ((lowerer.typeOf(expr.expression).flags & ts.TypeFlags.Any) !== 0 &&
|
|
1160
|
+
isFreshCallResult(expr.expression) &&
|
|
1161
|
+
lowerer.dynConvertible(recvLowered.type)) {
|
|
1162
|
+
return lowerer.maybeNarrow({
|
|
1163
|
+
kind: "dynKeyGet",
|
|
1164
|
+
value: lowerer.coerceToExpected(recvLowered, DYN),
|
|
1165
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc },
|
|
1166
|
+
type: DYN,
|
|
1167
|
+
loc,
|
|
1168
|
+
}, expr);
|
|
1169
|
+
}
|
|
1170
|
+
lowerer.unsupported("SC1090", expr, `reading '${expr.name.text}' from a value of type '${lowerer.checker.typeToString(lowerer.typeOf(expr.expression))}'`);
|
|
1171
|
+
}
|
|
1172
|
+
/** A call expression, through parentheses: its value has no other holder. */
|
|
1173
|
+
function isFreshCallResult(node) {
|
|
1174
|
+
let e = node;
|
|
1175
|
+
while (ts.isParenthesizedExpression(e))
|
|
1176
|
+
e = e.expression;
|
|
1177
|
+
return ts.isCallExpression(e);
|
|
1178
|
+
}
|
|
1179
|
+
/** `(source as { repoName: string }).repoName` where the assertion names a
|
|
1180
|
+
* member some arms of the stored union of records do not declare: Node
|
|
1181
|
+
* reads the property off whichever object it is, so arms that declare it
|
|
1182
|
+
* answer their slot, and the others answer undefined (native records are
|
|
1183
|
+
* closed, so they cannot hold it). The result keeps that undefined arm
|
|
1184
|
+
* whatever the assertion claims; a consumer that needs the asserted type
|
|
1185
|
+
* checks it like any other narrowing. The arms that declare the member
|
|
1186
|
+
* must agree on its type. Null when the receiver is not such an
|
|
1187
|
+
* assertion over records, or no arm declares the member. */
|
|
1188
|
+
function assertedMemberRead(lowerer, expr, recv, loc) {
|
|
1189
|
+
let receiverNode = expr.expression;
|
|
1190
|
+
while (ts.isParenthesizedExpression(receiverNode))
|
|
1191
|
+
receiverNode = receiverNode.expression;
|
|
1192
|
+
if (!ts.isAsExpression(receiverNode) && !ts.isTypeAssertion(receiverNode))
|
|
1193
|
+
return null;
|
|
1194
|
+
if (recv.type.kind !== "union")
|
|
1195
|
+
return null;
|
|
1196
|
+
const unionId = recv.type.unionId;
|
|
1197
|
+
const arms = lowerer.unions.get(unionId)?.arms ?? [];
|
|
1198
|
+
const name = expr.name.text;
|
|
1199
|
+
let resultType = null;
|
|
1200
|
+
let records = 0;
|
|
1201
|
+
const declaring = [];
|
|
1202
|
+
const units = [];
|
|
1203
|
+
for (let tag = 0; tag < arms.length; tag++) {
|
|
1204
|
+
const arm = arms[tag];
|
|
1205
|
+
if (isUnitType(arm)) {
|
|
1206
|
+
units.push(tag);
|
|
1207
|
+
continue;
|
|
1208
|
+
}
|
|
1209
|
+
if (arm.kind !== "record")
|
|
1210
|
+
return null;
|
|
1211
|
+
records++;
|
|
1212
|
+
const shape = lowerer.shapes.get(arm.shapeId);
|
|
1213
|
+
if (!shape || shape.tuple || shape.indexValue)
|
|
1214
|
+
return null;
|
|
1215
|
+
const field = shape.fields.find((f) => f.name === name);
|
|
1216
|
+
if (!field)
|
|
1217
|
+
continue;
|
|
1218
|
+
// The declaring arms agree up to an undefined arm (`string` beside
|
|
1219
|
+
// `string | undefined`).
|
|
1220
|
+
const armResult = lowerer.withUndefinedArmOf(field.type);
|
|
1221
|
+
if (!armResult || (resultType && !typeEquals(resultType, armResult)))
|
|
1222
|
+
return null;
|
|
1223
|
+
resultType = armResult;
|
|
1224
|
+
declaring.push({ tag, shapeId: arm.shapeId, type: field.type });
|
|
1225
|
+
}
|
|
1226
|
+
if (!resultType || declaring.length === records)
|
|
1227
|
+
return null;
|
|
1228
|
+
const stable = lowerer.declareHiddenLocal("%assertedRecv", recv.type);
|
|
1229
|
+
const ref = () => ({ kind: "varRef", localId: stable.id, type: recv.type, loc });
|
|
1230
|
+
let result = lowerer.wrappedUndefined(resultType, loc);
|
|
1231
|
+
if (!result)
|
|
1232
|
+
return null;
|
|
1233
|
+
// A unit arm the checker narrowed away reads like Node would read it.
|
|
1234
|
+
for (const tag of units) {
|
|
1235
|
+
const unit = arms[tag].kind === "nullT" ? "null" : "undefined";
|
|
1236
|
+
result = {
|
|
1237
|
+
kind: "ternary",
|
|
1238
|
+
cond: { kind: "unionIsTag", unionId, tag, negated: false, value: ref(), type: BOOL, loc },
|
|
1239
|
+
then: nodeThrowExpr(1, "", `Cannot read properties of ${unit} (reading '${name}')`, resultType, loc),
|
|
1240
|
+
else_: result,
|
|
1241
|
+
type: resultType,
|
|
1242
|
+
loc,
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
for (const { tag, shapeId, type: fieldType } of declaring) {
|
|
1246
|
+
const read = {
|
|
1247
|
+
kind: "recordGet",
|
|
1248
|
+
obj: { kind: "unionNarrow", unionId, tag, value: ref(), type: arms[tag], loc },
|
|
1249
|
+
shapeId,
|
|
1250
|
+
field: name,
|
|
1251
|
+
type: fieldType,
|
|
1252
|
+
loc,
|
|
1253
|
+
};
|
|
1254
|
+
result = {
|
|
1255
|
+
kind: "ternary",
|
|
1256
|
+
cond: { kind: "unionIsTag", unionId, tag, negated: false, value: ref(), type: BOOL, loc },
|
|
1257
|
+
then: lowerer.coerceToExpected(read, resultType),
|
|
1258
|
+
else_: result,
|
|
1259
|
+
type: resultType,
|
|
1260
|
+
loc,
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
return {
|
|
1264
|
+
kind: "seqExpr",
|
|
1265
|
+
stmts: [{ kind: "varDecl", localId: stable.id, init: recv, loc }],
|
|
1266
|
+
result,
|
|
1267
|
+
type: resultType,
|
|
1268
|
+
loc,
|
|
1269
|
+
};
|
|
1270
|
+
}
|
|
1271
|
+
function importMetaProperty(lowerer, expr) {
|
|
1272
|
+
return isImportMeta(expr.expression) ? importMetaField(lowerer, expr, expr.name.text) : null;
|
|
1273
|
+
}
|
|
1274
|
+
/** The TypeError of a deferred-init field read that finds the field
|
|
1275
|
+
* unassigned where its declared type cannot hold undefined. */
|
|
1276
|
+
export const DEFERRED_READ_MESSAGE = "undefined is not representable in the target union (a value narrowed or asserted past it still held it)";
|
|
1277
|
+
/** Property access on a string or array receiver: `.length` lowers to the
|
|
1278
|
+
* matching intrinsic; a bare method reference (`const f = s.slice` — a
|
|
1279
|
+
* function value) is rejected with a specific message. Returns null for
|
|
1280
|
+
* other receivers (the generic property-access rejection applies). Both
|
|
1281
|
+
* the receiver type AND the ambient-file provenance of the member are
|
|
1282
|
+
* verified — the name alone proves nothing. */
|
|
1283
|
+
export function lowerIntrinsicProperty(lowerer, expr) {
|
|
1284
|
+
for (const name of ["String", "Number", "Boolean", "BigInt"]) {
|
|
1285
|
+
if (!lowerer.chainBlocked(expr) && lowerer.isStdlibGlobal(expr, name)) {
|
|
1286
|
+
return primitiveCtorClosure(lowerer, name, locOf(expr), isJsSourceFile(ts.getSourceFileOfNode(expr)));
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
if (lowerer.stdlibGlobalMember(expr, "Reflect") === "ownKeys") {
|
|
1290
|
+
const value = lowerer.lowerNativeCallableValue({
|
|
1291
|
+
fn: "dyn.ownKeys",
|
|
1292
|
+
params: [DYN],
|
|
1293
|
+
result: DYN,
|
|
1294
|
+
valueParams: [{ mode: "required", type: DYN }],
|
|
1295
|
+
}, "Reflect.ownKeys", locOf(expr));
|
|
1296
|
+
return { kind: "dynFrom", value, fnName: "ownKeys", type: DYN, loc: locOf(expr) };
|
|
1297
|
+
}
|
|
1298
|
+
if (lowerer.chainBlocked(expr))
|
|
1299
|
+
return null;
|
|
1300
|
+
// Object.prototype.constructor: the Object constructor value.
|
|
1301
|
+
if (expr.name.text === "constructor" &&
|
|
1302
|
+
ts.isPropertyAccessExpression(expr.expression) &&
|
|
1303
|
+
lowerer.stdlibGlobalMember(expr.expression, "Object") === "prototype")
|
|
1304
|
+
return builtinGlobalValue("Object", locOf(expr));
|
|
1305
|
+
const builtinPrototype = builtinPrototypeMethod(lowerer, expr);
|
|
1306
|
+
if (builtinPrototype)
|
|
1307
|
+
return {
|
|
1308
|
+
kind: "libCall",
|
|
1309
|
+
fn: "dyn.builtinMethod",
|
|
1310
|
+
args: [
|
|
1311
|
+
{ kind: "strLit", value: builtinPrototype, type: STRING, loc: locOf(expr) },
|
|
1312
|
+
{ kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
1313
|
+
],
|
|
1314
|
+
type: DYN,
|
|
1315
|
+
loc: locOf(expr),
|
|
1316
|
+
};
|
|
1317
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
1318
|
+
lowerer.stdlibGlobalMember(expr.expression, "Array") === "prototype") {
|
|
1319
|
+
return {
|
|
1320
|
+
kind: "dynKeyGet",
|
|
1321
|
+
value: {
|
|
1322
|
+
kind: "libCall",
|
|
1323
|
+
fn: "dyn.arrayPrototype",
|
|
1324
|
+
args: [],
|
|
1325
|
+
type: DYN,
|
|
1326
|
+
loc: locOf(expr.expression),
|
|
1327
|
+
},
|
|
1328
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
1329
|
+
type: DYN,
|
|
1330
|
+
loc: locOf(expr),
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
if (expr.name.text === "apply" &&
|
|
1334
|
+
ts.isPropertyAccessExpression(expr.expression) &&
|
|
1335
|
+
lowerer.stdlibGlobalMember(expr.expression, "Function") === "prototype")
|
|
1336
|
+
return { kind: "libCall", fn: "dyn.functionApply", args: [], type: DYN, loc: locOf(expr) };
|
|
1337
|
+
if (lowerer.stdlibGlobalMember(expr, "Array") === "prototype")
|
|
1338
|
+
return { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc: locOf(expr) };
|
|
1339
|
+
if (lowerer.stdlibGlobalMember(expr, "Object") === "prototype")
|
|
1340
|
+
return { kind: "libCall", fn: "dyn.objectPrototype", args: [], type: DYN, loc: locOf(expr) };
|
|
1341
|
+
// Function.prototype as a VALUE (a prototype-chain link:
|
|
1342
|
+
// `Object.setPrototypeOf(F.prototype, Function.prototype)`): one
|
|
1343
|
+
// anonymous function answering undefined, length 0 — a zero-capture
|
|
1344
|
+
// closure of a compiler helper, so every read is the same function
|
|
1345
|
+
// (closure identity) and shares its property table. Reads through it
|
|
1346
|
+
// find the function members the checked runtime models for every
|
|
1347
|
+
// function (apply, constructor, name, length). Member forms keep their
|
|
1348
|
+
// own lowerings.
|
|
1349
|
+
if (lowerer.stdlibGlobalMember(expr, "Function") === "prototype") {
|
|
1350
|
+
const loc = locOf(expr);
|
|
1351
|
+
const name = "%dyn.functionPrototype";
|
|
1352
|
+
if (!lowerer.liftedFns.some((fn) => fn.name === name))
|
|
1353
|
+
lowerer.liftedFns.push({
|
|
1354
|
+
name,
|
|
1355
|
+
params: [],
|
|
1356
|
+
locals: [],
|
|
1357
|
+
returnType: DYN,
|
|
1358
|
+
body: [{ kind: "return", value: dynUndefinedExpr(loc), loc }],
|
|
1359
|
+
loc,
|
|
1360
|
+
});
|
|
1361
|
+
return {
|
|
1362
|
+
kind: "dynFrom",
|
|
1363
|
+
value: { kind: "closure", fnName: name, captures: [], type: funcOf([], DYN), loc },
|
|
1364
|
+
fnName: "",
|
|
1365
|
+
type: DYN,
|
|
1366
|
+
loc,
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
if (lowerer.stdlibGlobalMember(expr, "Array") === "isArray")
|
|
1370
|
+
return lowerArrayIsArrayValue(lowerer, locOf(expr));
|
|
1371
|
+
if (lowerer.stdlibGlobalMember(expr, "Array") === "from")
|
|
1372
|
+
return lowerArrayFromValue(lowerer, locOf(expr));
|
|
1373
|
+
const stringMember = lowerer.stdlibGlobalMember(expr, "String");
|
|
1374
|
+
if (stringMember === "fromCharCode" || stringMember === "fromCodePoint")
|
|
1375
|
+
return lowerStringCodesValue(lowerer, stringMember, locOf(expr));
|
|
1376
|
+
const numberMember = lowerer.stdlibGlobalMember(expr, "Number");
|
|
1377
|
+
if (numberMember === "parseInt" || numberMember === "parseFloat")
|
|
1378
|
+
return lowerNumberParserValue(lowerer, numberMember, locOf(expr));
|
|
1379
|
+
if (lowerer.stdlibGlobalMember(expr, "Buffer") === "poolSize")
|
|
1380
|
+
return { kind: "libCall", fn: "buffer.poolSize", args: [], type: F64, loc: locOf(expr) };
|
|
1381
|
+
const netAddressStatic = lowerNetAddressStaticRead(lowerer, expr);
|
|
1382
|
+
if (netAddressStatic)
|
|
1383
|
+
return netAddressStatic;
|
|
1384
|
+
if (lowerer.stdlibGlobalMember(expr, "Buffer") === "isBuffer")
|
|
1385
|
+
return lowerCheckedPredicateValue(lowerer, "Buffer.isBuffer", "buffer", locOf(expr));
|
|
1386
|
+
if (lowerer.stdlibGlobalMember(expr, "Date") === "now")
|
|
1387
|
+
return lowerer.lowerNativeCallableValue({
|
|
1388
|
+
fn: "date.now",
|
|
1389
|
+
params: [],
|
|
1390
|
+
result: F64,
|
|
1391
|
+
valueParams: [],
|
|
1392
|
+
}, "Date.now", locOf(expr));
|
|
1393
|
+
if (stdlibGlobalNameOf(lowerer, expr.expression) === "Object") {
|
|
1394
|
+
if (expr.name.text === "assign")
|
|
1395
|
+
return lowerObjectAssignValue(lowerer, locOf(expr));
|
|
1396
|
+
const fn = own(OBJECT_CALLABLE_VALUES, expr.name.text);
|
|
1397
|
+
if (fn)
|
|
1398
|
+
return lowerer.lowerNativeCallableValue(fn, `Object.${expr.name.text}`, locOf(expr));
|
|
1399
|
+
}
|
|
1400
|
+
// A never-tainted JS receiver type lowered checked-dynamic
|
|
1401
|
+
// (neverTaintedJsType — `cmd.length` on `const cmd = ['pwd', []]`):
|
|
1402
|
+
// stand down so the dyn keyed read below the chain answers, instead
|
|
1403
|
+
// of an array libCall over a dyn receiver hitting the boundary fence.
|
|
1404
|
+
let kind = neverTaintedJsType(lowerer, expr.expression, lowerer.typeOf(expr.expression))
|
|
1405
|
+
? undefined
|
|
1406
|
+
: lowerer.mapTypeOf(lowerer.typeOf(expr.expression))?.kind;
|
|
1407
|
+
// A checker-`any[]` receiver (the readonly-array Array.isArray quirk)
|
|
1408
|
+
// whose VALUE lowers to a real static array (maybeNarrow's isArray
|
|
1409
|
+
// bridge): `.length` and friends ride the array path on the lowered
|
|
1410
|
+
// value (re-lowering is pure IR construction).
|
|
1411
|
+
if (kind === undefined && lowerer.checkerAnyArray(expr.expression)) {
|
|
1412
|
+
const probe = lowerer.lowerExpr(expr.expression);
|
|
1413
|
+
if (probe.type.kind === "array")
|
|
1414
|
+
kind = "array";
|
|
1415
|
+
}
|
|
1416
|
+
if (kind !== "string" &&
|
|
1417
|
+
kind !== "array" &&
|
|
1418
|
+
kind !== "map" &&
|
|
1419
|
+
kind !== "set" &&
|
|
1420
|
+
kind !== "f64" &&
|
|
1421
|
+
kind !== "date" &&
|
|
1422
|
+
kind !== "regex" &&
|
|
1423
|
+
kind !== "url" &&
|
|
1424
|
+
kind !== "searchParams" &&
|
|
1425
|
+
kind !== "stats" &&
|
|
1426
|
+
kind !== "spawnRes" &&
|
|
1427
|
+
kind !== "child" &&
|
|
1428
|
+
kind !== "bytes" &&
|
|
1429
|
+
kind !== "symbol") {
|
|
1430
|
+
return null;
|
|
1431
|
+
}
|
|
1432
|
+
// child receivers also admit the user's own child-shaped interface
|
|
1433
|
+
// members (the NgrokChildProcess duck rule — see isChildSurfaceMember).
|
|
1434
|
+
// The EMPTY tuple `[]` rides the array REPRESENTATION (type-mapper.ts), but
|
|
1435
|
+
// its `length` member is the tuple's own synthesized property, not
|
|
1436
|
+
// Array.prototype's — provenance alone would refuse it. It reads the
|
|
1437
|
+
// runtime length (always 0) through the array intrinsic like any other
|
|
1438
|
+
// array; non-empty tuples never reach here (they map to records and
|
|
1439
|
+
// fold their arity constant on the record path).
|
|
1440
|
+
const tupleLengthOnArray = kind === "array" &&
|
|
1441
|
+
expr.name.text === "length" &&
|
|
1442
|
+
lowerer.checker.isTupleType(lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(expr.expression)));
|
|
1443
|
+
if (kind === "child"
|
|
1444
|
+
? !isChildSurfaceMember(lowerer, expr)
|
|
1445
|
+
: !tupleLengthOnArray && !lowerer.isStdlibMember(expr))
|
|
1446
|
+
return null;
|
|
1447
|
+
const name = expr.name.text;
|
|
1448
|
+
if (kind === "array" && name === "constructor" && isJsSourceFile(ts.getSourceFileOfNode(expr))) {
|
|
1449
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1450
|
+
if (receiver.type.kind === "dyn")
|
|
1451
|
+
return {
|
|
1452
|
+
kind: "dynKeyGet",
|
|
1453
|
+
value: receiver,
|
|
1454
|
+
key: { kind: "strLit", value: name, type: STRING, loc: locOf(expr) },
|
|
1455
|
+
type: DYN,
|
|
1456
|
+
loc: locOf(expr),
|
|
1457
|
+
};
|
|
1458
|
+
const result = {
|
|
1459
|
+
kind: "libCall",
|
|
1460
|
+
fn: "dyn.arrayConstructor",
|
|
1461
|
+
args: [],
|
|
1462
|
+
type: DYN,
|
|
1463
|
+
loc: locOf(expr),
|
|
1464
|
+
};
|
|
1465
|
+
return {
|
|
1466
|
+
kind: "seqExpr",
|
|
1467
|
+
stmts: [{ kind: "exprStmt", expr: receiver, loc: locOf(expr) }],
|
|
1468
|
+
result,
|
|
1469
|
+
type: DYN,
|
|
1470
|
+
loc: locOf(expr),
|
|
1471
|
+
};
|
|
1472
|
+
}
|
|
1473
|
+
const strictReceiver = (expected) => {
|
|
1474
|
+
const value = lowerer.lowerExpr(expr.expression);
|
|
1475
|
+
if (value.type.kind === "dyn") {
|
|
1476
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) && name === "length")
|
|
1477
|
+
return value;
|
|
1478
|
+
return lowerer.coerceInto(expr.expression, value, expected);
|
|
1479
|
+
}
|
|
1480
|
+
return lowerer.runtimeOptionalPropertyReceiver(expr.expression, value, expected, name) ?? value;
|
|
1481
|
+
};
|
|
1482
|
+
if (kind === "child") {
|
|
1483
|
+
const loc = locOf(expr);
|
|
1484
|
+
// The lifecycle reads, Node's exact shapes (SEMANTICS.md pins the
|
|
1485
|
+
// matrix): pid is `number | undefined` (undefined = spawn failure),
|
|
1486
|
+
// exitCode `number | null` (null while running and after a signal
|
|
1487
|
+
// death; -errno once a spawn failure settled), killed the
|
|
1488
|
+
// sent-a-signal flag. The unions build type-directedly in the
|
|
1489
|
+
// backend (the spawnRes.status pattern); a checker-narrowed read
|
|
1490
|
+
// extracts through maybeNarrow like any union member.
|
|
1491
|
+
if (name === "pid") {
|
|
1492
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1493
|
+
const type = { kind: "union", unionId: lowerer.unions.intern([F64, UNDEFINED_T]) };
|
|
1494
|
+
return { kind: "libCall", fn: "child.pid", args: [receiver], type, loc };
|
|
1495
|
+
}
|
|
1496
|
+
if (name === "exitCode") {
|
|
1497
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1498
|
+
const type = { kind: "union", unionId: lowerer.unions.intern([F64, NULL_T]) };
|
|
1499
|
+
return { kind: "libCall", fn: "child.exitCode", args: [receiver], type, loc };
|
|
1500
|
+
}
|
|
1501
|
+
if (name === "killed") {
|
|
1502
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1503
|
+
return { kind: "libCall", fn: "child.killed", args: [receiver], type: BOOL, loc };
|
|
1504
|
+
}
|
|
1505
|
+
if (name === "on" || name === "once" || name === "kill" || name === "unref") {
|
|
1506
|
+
lowerer.unsupported("SC1090", expr, `child methods as values (call '${name}' directly)`);
|
|
1507
|
+
}
|
|
1508
|
+
lowerer.noLowering(`ChildProcess.${name}`, expr, 'on/once("exit" | "close" | "error", cb), pid, exitCode, killed, kill(signal?), and unref() are the supported ChildProcess members', lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1509
|
+
}
|
|
1510
|
+
if (kind === "spawnRes") {
|
|
1511
|
+
// The spawnSync-result reads. status is the interned `number | null`
|
|
1512
|
+
// union (null = signal death or spawn failure); stdout/stderr are
|
|
1513
|
+
// the captured utf8 strings — under @types/node WITHOUT the
|
|
1514
|
+
// {encoding: "utf8"} options argument the checker types them Buffer,
|
|
1515
|
+
// which is re-fenced here (the call site already said so).
|
|
1516
|
+
const loc = locOf(expr);
|
|
1517
|
+
if (name === "status") {
|
|
1518
|
+
// Always the interned `number | null` union; a checker-NARROWED
|
|
1519
|
+
// read (`missing.status === null ? ... : ${missing.status}`)
|
|
1520
|
+
// bridges through maybeNarrow like any union read.
|
|
1521
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1522
|
+
const type = { kind: "union", unionId: lowerer.unions.intern([F64, NULL_T]) };
|
|
1523
|
+
const read = { kind: "libCall", fn: "spawnRes.status", args: [receiver], type, loc };
|
|
1524
|
+
return lowerer.maybeNarrow(read, expr);
|
|
1525
|
+
}
|
|
1526
|
+
if (name === "stdout" || name === "stderr") {
|
|
1527
|
+
if (lowerer.mapTypeOf(lowerer.typeOf(expr))?.kind !== "string") {
|
|
1528
|
+
lowerer.noLowering(`spawnSync's ${name} without the "utf8" encoding`, expr, 'Buffer captures are not representable — call spawnSync(cmd, args, { encoding: "utf8" }) so the outputs are strings');
|
|
1529
|
+
}
|
|
1530
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1531
|
+
const fn = name === "stdout" ? "spawnRes.stdout" : "spawnRes.stderr";
|
|
1532
|
+
return { kind: "libCall", fn, args: [receiver], type: STRING, loc };
|
|
1533
|
+
}
|
|
1534
|
+
if (name === "error") {
|
|
1535
|
+
// Node's spawn-failure carrier: `Error | undefined` — a fresh
|
|
1536
|
+
// %Error ("spawnSync <file> ENOENT", `code` stamped) when the
|
|
1537
|
+
// spawn itself failed, the undefined arm otherwise. The libCall
|
|
1538
|
+
// always carries the interned union (the declared `error?: Error`),
|
|
1539
|
+
// and a checker-NARROWED read (`if (r.error) r.error.message`)
|
|
1540
|
+
// bridges through maybeNarrow like any union read.
|
|
1541
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1542
|
+
const type = lowerer.withUndefinedArmOf({ kind: "object", className: "%Error" });
|
|
1543
|
+
if (!type)
|
|
1544
|
+
lowerer.badType(expr, lowerer.typeOf(expr));
|
|
1545
|
+
const read = { kind: "libCall", fn: "spawnRes.error", args: [receiver], type, loc };
|
|
1546
|
+
return lowerer.maybeNarrow(read, expr);
|
|
1547
|
+
}
|
|
1548
|
+
lowerer.noLowering(`SpawnSyncReturns.${name}`, expr, "status, stdout, stderr, and error are the supported spawnSync-result members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1549
|
+
}
|
|
1550
|
+
if (kind === "stats") {
|
|
1551
|
+
if (name === "size") {
|
|
1552
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1553
|
+
return { kind: "libCall", fn: "stats.size", args: [receiver], type: F64, loc: locOf(expr) };
|
|
1554
|
+
}
|
|
1555
|
+
if (Object.hasOwn(STATS_TYPE_TESTS, name)) {
|
|
1556
|
+
lowerer.unsupported("SC1090", expr, `Stats methods as values (call '${name}' directly)`);
|
|
1557
|
+
}
|
|
1558
|
+
lowerer.noLowering(`Stats.${name}`, expr, "isFile(), isDirectory(), isSymbolicLink(), isBlockDevice(), isCharacterDevice(), isFIFO(), isSocket(), dev, mode, nlink, uid, gid, rdev, blksize, ino, size, blocks, atimeMs, mtimeMs, ctimeMs, birthtimeMs, atime, mtime, ctime, and birthtime are the supported Stats members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1559
|
+
}
|
|
1560
|
+
if (kind === "date") {
|
|
1561
|
+
const methods = new Set([
|
|
1562
|
+
"getTime",
|
|
1563
|
+
"valueOf",
|
|
1564
|
+
"toISOString",
|
|
1565
|
+
"getFullYear",
|
|
1566
|
+
"getUTCFullYear",
|
|
1567
|
+
"getMonth",
|
|
1568
|
+
"getUTCMonth",
|
|
1569
|
+
"getDate",
|
|
1570
|
+
"getUTCDate",
|
|
1571
|
+
"getDay",
|
|
1572
|
+
"getUTCDay",
|
|
1573
|
+
"getHours",
|
|
1574
|
+
"getUTCHours",
|
|
1575
|
+
"getMinutes",
|
|
1576
|
+
"getUTCMinutes",
|
|
1577
|
+
"getSeconds",
|
|
1578
|
+
"getUTCSeconds",
|
|
1579
|
+
"getMilliseconds",
|
|
1580
|
+
"getUTCMilliseconds",
|
|
1581
|
+
"getTimezoneOffset",
|
|
1582
|
+
]);
|
|
1583
|
+
if (methods.has(name)) {
|
|
1584
|
+
lowerer.unsupported("SC1090", expr, `Date methods as values (call '${name}' directly)`);
|
|
1585
|
+
}
|
|
1586
|
+
lowerer.noLowering(`Date.prototype.${name}`, expr, "getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1587
|
+
}
|
|
1588
|
+
if (kind === "symbol") {
|
|
1589
|
+
const loc = locOf(expr);
|
|
1590
|
+
// `.description`: the checker's `string | undefined` — undefined
|
|
1591
|
+
// exactly for the description-less Symbol()/Symbol(undefined) forms
|
|
1592
|
+
// (Symbol("") answers the EMPTY STRING arm, like Node). The interned
|
|
1593
|
+
// union builds in the backend from the runtime's +1-or-NULL answer
|
|
1594
|
+
// (the child.stdout pattern); a checker-narrowed read extracts
|
|
1595
|
+
// through maybeNarrow like any union member.
|
|
1596
|
+
if (name === "description") {
|
|
1597
|
+
const receiver = lowerer.coerceToExpected(lowerer.lowerExpr(expr.expression), SYMBOL_T);
|
|
1598
|
+
const type = { kind: "union", unionId: lowerer.unions.intern([STRING, UNDEFINED_T]) };
|
|
1599
|
+
return { kind: "libCall", fn: "sym.desc", args: [receiver], type, loc };
|
|
1600
|
+
}
|
|
1601
|
+
if (name === "toString" || name === "valueOf") {
|
|
1602
|
+
lowerer.unsupported("SC1090", expr, `symbol methods as values (call '${name}' directly)`);
|
|
1603
|
+
}
|
|
1604
|
+
lowerer.noLowering(`Symbol.prototype.${name}`, expr, "description and toString() are the supported symbol members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1605
|
+
}
|
|
1606
|
+
if (kind === "url") {
|
|
1607
|
+
// The supported URL getters. Everything else the lib declares
|
|
1608
|
+
// (searchParams, setters-as-reads, ...) fences with the
|
|
1609
|
+
// member-qualified name and the supported list. `host` is the WHATWG
|
|
1610
|
+
// serialization: lowercased hostname, `:port` appended exactly when
|
|
1611
|
+
// a non-default port is present (scr_url_host — Node-exact,
|
|
1612
|
+
// opaque-path URLs answer ""); `hostname` is the stored port-less
|
|
1613
|
+
// host field verbatim, including IPv6 brackets.
|
|
1614
|
+
if (name === "protocol" ||
|
|
1615
|
+
name === "origin" ||
|
|
1616
|
+
name === "username" ||
|
|
1617
|
+
name === "password" ||
|
|
1618
|
+
name === "pathname" ||
|
|
1619
|
+
name === "href" ||
|
|
1620
|
+
name === "host" ||
|
|
1621
|
+
name === "hostname" ||
|
|
1622
|
+
name === "port" ||
|
|
1623
|
+
name === "search" ||
|
|
1624
|
+
name === "hash") {
|
|
1625
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1626
|
+
const fn = name === "protocol"
|
|
1627
|
+
? "url.protocol"
|
|
1628
|
+
: name === "origin"
|
|
1629
|
+
? "url.origin"
|
|
1630
|
+
: name === "username"
|
|
1631
|
+
? "url.username"
|
|
1632
|
+
: name === "password"
|
|
1633
|
+
? "url.password"
|
|
1634
|
+
: name === "pathname"
|
|
1635
|
+
? "url.pathname"
|
|
1636
|
+
: name === "host"
|
|
1637
|
+
? "url.host"
|
|
1638
|
+
: name === "hostname"
|
|
1639
|
+
? "url.hostname"
|
|
1640
|
+
: name === "port"
|
|
1641
|
+
? "url.port"
|
|
1642
|
+
: name === "search"
|
|
1643
|
+
? "url.search"
|
|
1644
|
+
: name === "hash"
|
|
1645
|
+
? "url.hash"
|
|
1646
|
+
: "url.href";
|
|
1647
|
+
return { kind: "libCall", fn, args: [receiver], type: STRING, loc: locOf(expr) };
|
|
1648
|
+
}
|
|
1649
|
+
// `u.searchParams`: the LIVE cached view (one identity per URL —
|
|
1650
|
+
// mutations through it re-serialize into the URL's query, so href
|
|
1651
|
+
// reflects immediately; Node's binding exactly).
|
|
1652
|
+
if (name === "searchParams") {
|
|
1653
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1654
|
+
return {
|
|
1655
|
+
kind: "libCall",
|
|
1656
|
+
fn: "url.searchParams",
|
|
1657
|
+
args: [receiver],
|
|
1658
|
+
type: SEARCH_PARAMS_T,
|
|
1659
|
+
loc: locOf(expr),
|
|
1660
|
+
};
|
|
1661
|
+
}
|
|
1662
|
+
if (name === "toString" || name === "toJSON") {
|
|
1663
|
+
lowerer.unsupported("SC1090", expr, `URL methods as values (call '${name}' directly)`);
|
|
1664
|
+
}
|
|
1665
|
+
lowerer.noLowering(`URL.${name}`, expr, "protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, and toString() are the supported URL members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1666
|
+
}
|
|
1667
|
+
if (kind === "searchParams") {
|
|
1668
|
+
const SEARCH_PARAMS_METHODS = new Set([
|
|
1669
|
+
"get",
|
|
1670
|
+
"getAll",
|
|
1671
|
+
"set",
|
|
1672
|
+
"append",
|
|
1673
|
+
"delete",
|
|
1674
|
+
"has",
|
|
1675
|
+
"sort",
|
|
1676
|
+
"toString",
|
|
1677
|
+
"forEach",
|
|
1678
|
+
"keys",
|
|
1679
|
+
"values",
|
|
1680
|
+
"entries",
|
|
1681
|
+
]);
|
|
1682
|
+
// The one data property; every method lowers at its CALL
|
|
1683
|
+
// (lowerSearchParamsMethodCall) — bare method references fence.
|
|
1684
|
+
if (name === "size") {
|
|
1685
|
+
const receiver = lowerer.lowerExpr(expr.expression);
|
|
1686
|
+
return { kind: "libCall", fn: "sp.size", args: [receiver], type: F64, loc: locOf(expr) };
|
|
1687
|
+
}
|
|
1688
|
+
if (SEARCH_PARAMS_METHODS.has(name)) {
|
|
1689
|
+
lowerer.unsupported("SC1090", expr, `URLSearchParams methods as values (call '${name}' directly)`);
|
|
1690
|
+
}
|
|
1691
|
+
lowerer.noLowering(`URLSearchParams.${name}`, expr, "get, getAll, set, append, delete, has, sort, size, toString(), forEach, and for-of iteration are the supported URLSearchParams members", lowerer.checker.getSymbolAtLocation(expr.name));
|
|
1692
|
+
}
|
|
1693
|
+
if (kind === "regex") {
|
|
1694
|
+
if (name === "lastIndex") {
|
|
1695
|
+
return {
|
|
1696
|
+
kind: "regexIntrinsic",
|
|
1697
|
+
method: "lastIndex",
|
|
1698
|
+
receiver: strictReceiver({ kind: "regex" }),
|
|
1699
|
+
args: [],
|
|
1700
|
+
type: F64,
|
|
1701
|
+
loc: locOf(expr),
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
if (name === "source" || name === "flags") {
|
|
1705
|
+
const receiver = strictReceiver({ kind: "regex" });
|
|
1706
|
+
return {
|
|
1707
|
+
kind: "regexIntrinsic",
|
|
1708
|
+
method: name,
|
|
1709
|
+
receiver,
|
|
1710
|
+
args: [],
|
|
1711
|
+
type: STRING,
|
|
1712
|
+
loc: locOf(expr),
|
|
1713
|
+
};
|
|
1714
|
+
}
|
|
1715
|
+
// The flag getters answer whether `flags` holds the flag's letter.
|
|
1716
|
+
const flag = REGEX_FLAG_GETTERS.get(name);
|
|
1717
|
+
if (flag !== undefined) {
|
|
1718
|
+
const loc = locOf(expr);
|
|
1719
|
+
const flags = {
|
|
1720
|
+
kind: "regexIntrinsic",
|
|
1721
|
+
method: "flags",
|
|
1722
|
+
receiver: strictReceiver({ kind: "regex" }),
|
|
1723
|
+
args: [],
|
|
1724
|
+
type: STRING,
|
|
1725
|
+
loc,
|
|
1726
|
+
};
|
|
1727
|
+
return {
|
|
1728
|
+
kind: "strIntrinsic",
|
|
1729
|
+
method: "includes",
|
|
1730
|
+
receiver: flags,
|
|
1731
|
+
args: [{ kind: "strLit", value: flag, type: STRING, loc }],
|
|
1732
|
+
type: BOOL,
|
|
1733
|
+
loc,
|
|
1734
|
+
};
|
|
1735
|
+
}
|
|
1736
|
+
if (name === "test") {
|
|
1737
|
+
lowerer.unsupported("SC1090", expr, "regex methods as values (call 'test' directly)");
|
|
1738
|
+
}
|
|
1739
|
+
return null;
|
|
1740
|
+
}
|
|
1741
|
+
if (kind === "f64") {
|
|
1742
|
+
if (own(STDLIB_SURFACE.number, name) !== undefined) {
|
|
1743
|
+
lowerer.unsupported("SC1090", expr, `number methods as values (call '${name}' directly)`);
|
|
1744
|
+
}
|
|
1745
|
+
return null;
|
|
1746
|
+
}
|
|
1747
|
+
if (kind === "bytes") {
|
|
1748
|
+
const loc = locOf(expr);
|
|
1749
|
+
if (name === "constructor") {
|
|
1750
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1751
|
+
const receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1752
|
+
return {
|
|
1753
|
+
kind: "dynKeyGet",
|
|
1754
|
+
value: lowerer.coerceInto(expr.expression, receiver, DYN),
|
|
1755
|
+
key: { kind: "strLit", value: name, type: STRING, loc },
|
|
1756
|
+
type: DYN,
|
|
1757
|
+
loc,
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
if (name === "length" || name === "byteLength") {
|
|
1761
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1762
|
+
let receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1763
|
+
if (receiver.type.kind === "dyn")
|
|
1764
|
+
return {
|
|
1765
|
+
kind: "dynCheck",
|
|
1766
|
+
value: {
|
|
1767
|
+
kind: "dynKeyGet",
|
|
1768
|
+
value: receiver,
|
|
1769
|
+
key: { kind: "strLit", value: name, type: STRING, loc: locOf(expr) },
|
|
1770
|
+
type: DYN,
|
|
1771
|
+
loc: locOf(expr),
|
|
1772
|
+
},
|
|
1773
|
+
type: F64,
|
|
1774
|
+
loc: locOf(expr),
|
|
1775
|
+
};
|
|
1776
|
+
if (receiver.type.kind === "union" &&
|
|
1777
|
+
lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0) {
|
|
1778
|
+
const present = lowerer.stripUndefinedArm(receiver.type);
|
|
1779
|
+
const helper = present.kind === "bytes"
|
|
1780
|
+
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
1781
|
+
: null;
|
|
1782
|
+
receiver = helper
|
|
1783
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
1784
|
+
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
1785
|
+
}
|
|
1786
|
+
// property read, exiting at the declared number type (the array
|
|
1787
|
+
return { kind: "bytesIntrinsic", method: name, receiver, args: [], type: F64, loc };
|
|
1788
|
+
}
|
|
1789
|
+
if (name === "byteOffset") {
|
|
1790
|
+
// 0 for owners (scriptc typed arrays own their whole storage —
|
|
1791
|
+
// SEMANTICS.md notes the divergence from Node's Buffer pooling),
|
|
1792
|
+
// the view's real offset for a DataView. A runtime read, so the
|
|
1793
|
+
// receiver's evaluation is never discarded.
|
|
1794
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1795
|
+
const receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1796
|
+
return { kind: "bytesIntrinsic", method: "byteOffset", receiver, args: [], type: F64, loc };
|
|
1797
|
+
}
|
|
1798
|
+
if (name === "buffer") {
|
|
1799
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1800
|
+
const receiver = expected?.kind === "bytes" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1801
|
+
return { kind: "bytesIntrinsic", method: "buffer", receiver, args: [], type: DYN, loc };
|
|
1802
|
+
}
|
|
1803
|
+
if (name === "slice" || name === "subarray" || name === "set" || name === "toString") {
|
|
1804
|
+
lowerer.unsupported("SC1090", expr, `typed-array methods as values (call '${name}' directly)`);
|
|
1805
|
+
}
|
|
1806
|
+
return null; // fill, reverse, ... → the SC2020 member fence
|
|
1807
|
+
}
|
|
1808
|
+
if (kind === "map") {
|
|
1809
|
+
if (name === "size") {
|
|
1810
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1811
|
+
const receiver = expected?.kind === "map" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1812
|
+
return {
|
|
1813
|
+
kind: "mapIntrinsic",
|
|
1814
|
+
method: "size",
|
|
1815
|
+
receiver,
|
|
1816
|
+
args: [],
|
|
1817
|
+
type: F64,
|
|
1818
|
+
loc: locOf(expr),
|
|
1819
|
+
};
|
|
1820
|
+
}
|
|
1821
|
+
if (MAP_METHODS.has(name) || name === "forEach") {
|
|
1822
|
+
lowerer.unsupported("SC1090", expr, `Map methods as values (call '${name}' directly)`);
|
|
1823
|
+
}
|
|
1824
|
+
return null;
|
|
1825
|
+
}
|
|
1826
|
+
if (kind === "set") {
|
|
1827
|
+
if (name === "size") {
|
|
1828
|
+
const expected = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1829
|
+
const receiver = expected?.kind === "set" ? strictReceiver(expected) : lowerer.lowerExpr(expr.expression);
|
|
1830
|
+
return {
|
|
1831
|
+
kind: "setIntrinsic",
|
|
1832
|
+
method: "size",
|
|
1833
|
+
receiver,
|
|
1834
|
+
args: [],
|
|
1835
|
+
type: F64,
|
|
1836
|
+
loc: locOf(expr),
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
if (SET_METHODS.has(name)) {
|
|
1840
|
+
lowerer.unsupported("SC1090", expr, `Set methods as values (call '${name}' directly)`);
|
|
1841
|
+
}
|
|
1842
|
+
return null;
|
|
1843
|
+
}
|
|
1844
|
+
if (name === "length") {
|
|
1845
|
+
const expected = kind === "string" ? STRING : lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
1846
|
+
let receiver = lowerer.lowerExpr(expr.expression);
|
|
1847
|
+
if (receiver.type.kind !== "dyn" &&
|
|
1848
|
+
expected &&
|
|
1849
|
+
(expected.kind === "string" || expected.kind === "array")) {
|
|
1850
|
+
receiver =
|
|
1851
|
+
lowerer.runtimeOptionalPropertyReceiver(expr.expression, receiver, expected, name) ??
|
|
1852
|
+
receiver;
|
|
1853
|
+
}
|
|
1854
|
+
if (receiver.type.kind === "union" &&
|
|
1855
|
+
lowerer.armTag(receiver.type.unionId, UNDEFINED_T) >= 0 &&
|
|
1856
|
+
kind === "array") {
|
|
1857
|
+
const present = lowerer.stripUndefinedArm(receiver.type);
|
|
1858
|
+
const helper = present.kind === "array"
|
|
1859
|
+
? lowerer.narrowedArmHelper(receiver.type.unionId, present, locOf(expr.expression))
|
|
1860
|
+
: null;
|
|
1861
|
+
receiver = helper
|
|
1862
|
+
? lowerer.checkedNarrowCall(helper, receiver, present, locOf(expr.expression))
|
|
1863
|
+
: lowerer.maybeNarrow(receiver, expr.expression);
|
|
1864
|
+
}
|
|
1865
|
+
// A CHECKED-DYNAMIC value behind an array-typed checker spelling
|
|
1866
|
+
// (`Object.keys(u).length` — the dyn walk answers a dyn array while
|
|
1867
|
+
// tsc spells string[]): the runtime-world dispatch — a dyn keyed
|
|
1868
|
+
// read validated into the declared number (a lying length throws
|
|
1869
|
+
// the catchable TypeError, the dynCheck stance).
|
|
1870
|
+
if (receiver.type.kind === "dyn") {
|
|
1871
|
+
const read = {
|
|
1872
|
+
kind: "dynKeyGet",
|
|
1873
|
+
key: { kind: "strLit", value: "length", type: STRING, loc: locOf(expr) },
|
|
1874
|
+
...(expr.questionDotToken ? { optional: true } : {}),
|
|
1875
|
+
value: receiver,
|
|
1876
|
+
type: DYN,
|
|
1877
|
+
loc: locOf(expr),
|
|
1878
|
+
};
|
|
1879
|
+
if (expr.questionDotToken)
|
|
1880
|
+
return read;
|
|
1881
|
+
return { kind: "dynCheck", value: read, type: F64, loc: locOf(expr) };
|
|
1882
|
+
}
|
|
1883
|
+
return kind === "string"
|
|
1884
|
+
? { kind: "strIntrinsic", method: "length", receiver, args: [], type: F64, loc: locOf(expr) }
|
|
1885
|
+
: { kind: "arrIntrinsic", method: "length", receiver, args: [], type: F64, loc: locOf(expr) };
|
|
1886
|
+
}
|
|
1887
|
+
if (kind === "string"
|
|
1888
|
+
? own(STR_METHODS, name) !== undefined ||
|
|
1889
|
+
STRING_INDEX_METHODS.has(name) ||
|
|
1890
|
+
own(STDLIB_SURFACE.string, name) !== undefined
|
|
1891
|
+
: ARRAY_METHODS.has(name)) {
|
|
1892
|
+
lowerer.unsupported("SC1090", expr, `${kind} methods as values (call '${name}' directly)`);
|
|
1893
|
+
}
|
|
1894
|
+
return null;
|
|
1895
|
+
}
|
|
1896
|
+
/** A `T | undefined` class field read that the checker narrowed to `T`
|
|
1897
|
+
* where the field was assigned a value that may be missing (an unchecked
|
|
1898
|
+
* indexed read). TypeScript's assignment narrowing is not a runtime fact
|
|
1899
|
+
* there, so the read keeps the stored union instead of extracting `T`. */
|
|
1900
|
+
function runtimeOptionalClassField(lowerer, value, node) {
|
|
1901
|
+
if (value.kind !== "fieldGet" || value.type.kind !== "union")
|
|
1902
|
+
return false;
|
|
1903
|
+
if (lowerer.armTag(value.type.unionId, UNDEFINED_T) < 0)
|
|
1904
|
+
return false;
|
|
1905
|
+
if ((lowerer.unions.get(value.type.unionId)?.arms.length ?? 0) !== 2)
|
|
1906
|
+
return false;
|
|
1907
|
+
const symbol = lowerer.checker.getSymbolAtLocation(node.name);
|
|
1908
|
+
if (!symbol || !lowerer.runtimeOptionalAssignedSymbols.has(symbol))
|
|
1909
|
+
return false;
|
|
1910
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
1911
|
+
return narrowed !== null && typeEquals(narrowed, lowerer.stripUndefinedArm(value.type));
|
|
1912
|
+
}
|
|
1913
|
+
/** `exports.<name>` in a JS module whose `module.exports =` REPLACED the
|
|
1914
|
+
* export object, with no `exports.<name> =` attachment anywhere in the
|
|
1915
|
+
* file: the read observes the ORIGINAL (empty-here) exports object, so
|
|
1916
|
+
* the honest value is undefined (Node's object identity exactly; tsc's
|
|
1917
|
+
* CJS model types the read off the replacement — identity-blind). Null
|
|
1918
|
+
* everywhere else: no replacement, a real attachment of this name, a
|
|
1919
|
+
* shadowing binding named `exports`, or write position. */
|
|
1920
|
+
function lowerReplacedExportsRead(lowerer, expr) {
|
|
1921
|
+
if (expr.questionDotToken)
|
|
1922
|
+
return null;
|
|
1923
|
+
const recv = expr.expression;
|
|
1924
|
+
if (!ts.isIdentifier(recv) || recv.text !== "exports")
|
|
1925
|
+
return null;
|
|
1926
|
+
const sf = ts.getSourceFileOfNode(expr);
|
|
1927
|
+
if (!isJsSourceFile(sf) || isNodeEsmFile(sf, lowerer.program))
|
|
1928
|
+
return null;
|
|
1929
|
+
if (lowerer.peekLocal(recv) || lowerer.globalOf(recv))
|
|
1930
|
+
return null; // a user binding shadows
|
|
1931
|
+
// Write position is the export-assignment machinery's territory.
|
|
1932
|
+
if (ts.isBinaryExpression(expr.parent) &&
|
|
1933
|
+
expr.parent.left === expr &&
|
|
1934
|
+
expr.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken) {
|
|
1935
|
+
return null;
|
|
1936
|
+
}
|
|
1937
|
+
let replaced = false;
|
|
1938
|
+
for (const stmt of sf.statements.nodes) {
|
|
1939
|
+
const cjs = cjsExportAssignmentOf(stmt);
|
|
1940
|
+
if (!cjs)
|
|
1941
|
+
continue;
|
|
1942
|
+
if (cjs.kind === "table" && cjsExportDiscardReason(stmt) === null)
|
|
1943
|
+
replaced = true;
|
|
1944
|
+
if (cjs.kind === "member" && ts.isIdentifier(cjs.name) && cjs.name.text === expr.name.text) {
|
|
1945
|
+
return null; // a real attachment of this name exists somewhere
|
|
1946
|
+
}
|
|
1947
|
+
}
|
|
1948
|
+
if (!replaced)
|
|
1949
|
+
return null;
|
|
1950
|
+
return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc: locOf(expr) };
|
|
1951
|
+
}
|
|
1952
|
+
/** `this.<name>` INSIDE a CJS export-table accessor (test/common's
|
|
1953
|
+
* `get localhostIPv4() { if (this.inFreeBSDJail) ... }`): Node binds the
|
|
1954
|
+
* getter's receiver to module.exports, so the read is the SIBLING table
|
|
1955
|
+
* property — a sibling GETTER's lifted call (per-read evaluation, like
|
|
1956
|
+
* any accessor read). Only arrows inherit the binding (a nested function
|
|
1957
|
+
* expression's `this` is its own). Null everywhere else — non-getter
|
|
1958
|
+
* siblings and absent names keep their per-site fences (none of the
|
|
1959
|
+
* probed suite shapes read them). */
|
|
1960
|
+
function lowerCjsExportTableThisMember(lowerer, expr) {
|
|
1961
|
+
if (expr.expression.kind !== ts.SyntaxKind.ThisKeyword || expr.questionDotToken)
|
|
1962
|
+
return null;
|
|
1963
|
+
if (!isJsSourceFile(ts.getSourceFileOfNode(expr)))
|
|
1964
|
+
return null;
|
|
1965
|
+
// The enclosing accessor, crossing only arrow boundaries (arrows
|
|
1966
|
+
// inherit `this`; any other function form rebinds it).
|
|
1967
|
+
let n = expr.parent;
|
|
1968
|
+
while (n !== undefined && !ts.isGetAccessorDeclaration(n) && !ts.isSetAccessorDeclaration(n)) {
|
|
1969
|
+
if (ts.isFunctionLike(n) && !ts.isArrowFunction(n))
|
|
1970
|
+
return null;
|
|
1971
|
+
if (ts.isSourceFile(n))
|
|
1972
|
+
return null;
|
|
1973
|
+
n = n.parent;
|
|
1974
|
+
}
|
|
1975
|
+
if (n === undefined ||
|
|
1976
|
+
!ts.isObjectLiteralExpression(n.parent) ||
|
|
1977
|
+
!isCjsExportTableLiteral(n.parent)) {
|
|
1978
|
+
return null;
|
|
1979
|
+
}
|
|
1980
|
+
const sibling = n.parent.properties.nodes.find((p) => ts.isGetAccessorDeclaration(p) && ts.isIdentifier(p.name) && p.name.text === expr.name.text);
|
|
1981
|
+
if (!sibling)
|
|
1982
|
+
return null;
|
|
1983
|
+
return cjsAccessorCall(lowerer, sibling, locOf(expr));
|
|
1984
|
+
}
|
|
1985
|
+
/** RegExp.prototype's flag getters and the flag each one reads. */
|
|
1986
|
+
const REGEX_FLAG_GETTERS = new Map([
|
|
1987
|
+
["hasIndices", "d"],
|
|
1988
|
+
["global", "g"],
|
|
1989
|
+
["ignoreCase", "i"],
|
|
1990
|
+
["multiline", "m"],
|
|
1991
|
+
["dotAll", "s"],
|
|
1992
|
+
["unicode", "u"],
|
|
1993
|
+
["unicodeSets", "v"],
|
|
1994
|
+
["sticky", "y"],
|
|
1995
|
+
]);
|
|
1996
|
+
/** The named-group table of the regex that PRODUCED a match-result
|
|
1997
|
+
* expression — the `.groups` desugar's provenance question. Traces
|
|
1998
|
+
* (through parens, `!`, and const bindings):
|
|
1999
|
+
* - `re.exec(s)` / `s.match(re)` → re's static pattern
|
|
2000
|
+
* - a matchAll ROW: `rows[i]`, the for-of binding over a direct
|
|
2001
|
+
* `s.matchAll(re)` or a stored const drain → re's static pattern
|
|
2002
|
+
* Answers null when the producing regex isn't statically known (the
|
|
2003
|
+
* caller keeps its fence), or the groups list (possibly empty — a
|
|
2004
|
+
* traced regex WITHOUT named groups is the Node-undefined case). */
|
|
2005
|
+
export function matchResultNamedGroupsOf(lowerer, e) {
|
|
2006
|
+
let producer = e;
|
|
2007
|
+
while (ts.isParenthesizedExpression(producer) || ts.isNonNullExpression(producer))
|
|
2008
|
+
producer = producer.expression;
|
|
2009
|
+
if (ts.isIdentifier(producer)) {
|
|
2010
|
+
const init = constInitializerOf(lowerer, producer);
|
|
2011
|
+
if (init !== null)
|
|
2012
|
+
return matchResultNamedGroupsOf(lowerer, init);
|
|
2013
|
+
}
|
|
2014
|
+
const reExpr = matchProducerRegexOf(lowerer, e);
|
|
2015
|
+
if (reExpr === null)
|
|
2016
|
+
return null;
|
|
2017
|
+
if (ts.isCallExpression(producer) &&
|
|
2018
|
+
ts.isPropertyAccessExpression(producer.expression) &&
|
|
2019
|
+
producer.expression.name.text === "match") {
|
|
2020
|
+
const flags = staticRegexFlagsOf(lowerer, reExpr);
|
|
2021
|
+
if (flags === null)
|
|
2022
|
+
return null;
|
|
2023
|
+
// Global String.match returns whole matches without a groups
|
|
2024
|
+
// property, even when the pattern contains named captures.
|
|
2025
|
+
if (flags.includes("g"))
|
|
2026
|
+
return [];
|
|
2027
|
+
}
|
|
2028
|
+
const pattern = staticRegexPatternOf(lowerer, reExpr);
|
|
2029
|
+
if (pattern === null)
|
|
2030
|
+
return null;
|
|
2031
|
+
return namedCaptureGroupsOfPattern(pattern);
|
|
2032
|
+
}
|
|
2033
|
+
function staticRegexFlagsOf(lowerer, node) {
|
|
2034
|
+
let expr = node;
|
|
2035
|
+
while (ts.isParenthesizedExpression(expr) || ts.isNonNullExpression(expr))
|
|
2036
|
+
expr = expr.expression;
|
|
2037
|
+
if (ts.isRegularExpressionLiteral(expr))
|
|
2038
|
+
return expr.text.slice(expr.text.lastIndexOf("/") + 1);
|
|
2039
|
+
if (ts.isIdentifier(expr)) {
|
|
2040
|
+
const init = constInitializerOf(lowerer, expr);
|
|
2041
|
+
return init !== null ? staticRegexFlagsOf(lowerer, init) : null;
|
|
2042
|
+
}
|
|
2043
|
+
if (ts.isNewExpression(expr) &&
|
|
2044
|
+
ts.isIdentifier(expr.expression) &&
|
|
2045
|
+
lowerer.isStdlibGlobal(expr.expression, "RegExp")) {
|
|
2046
|
+
const flags = expr.arguments?.nodes[1];
|
|
2047
|
+
if (!flags)
|
|
2048
|
+
return "";
|
|
2049
|
+
if (ts.isStringLiteral(flags) || ts.isNoSubstitutionTemplateLiteral(flags))
|
|
2050
|
+
return flags.text;
|
|
2051
|
+
}
|
|
2052
|
+
return null;
|
|
2053
|
+
}
|
|
2054
|
+
/** The regex EXPRESSION whose match produced `e` (see
|
|
2055
|
+
* matchResultNamedGroupsOf for the traced shapes). */
|
|
2056
|
+
function matchProducerRegexOf(lowerer, e) {
|
|
2057
|
+
let expr = e;
|
|
2058
|
+
for (;;) {
|
|
2059
|
+
if (ts.isParenthesizedExpression(expr) || ts.isNonNullExpression(expr)) {
|
|
2060
|
+
expr = expr.expression;
|
|
2061
|
+
continue;
|
|
2062
|
+
}
|
|
2063
|
+
break;
|
|
2064
|
+
}
|
|
2065
|
+
// The direct producers: re.exec(s) / s.match(re) — the receiver's
|
|
2066
|
+
// mapped type pins the STDLIB operation (a regex for exec, a string
|
|
2067
|
+
// or its nullable spelling for match — the claim string-and-regexp
|
|
2068
|
+
// makes), so a user method that happens to be named `match` with a
|
|
2069
|
+
// regex argument never traces.
|
|
2070
|
+
if (ts.isCallExpression(expr) && ts.isPropertyAccessExpression(expr.expression)) {
|
|
2071
|
+
const name = expr.expression.name.text;
|
|
2072
|
+
const recvT = lowerer.mapTypeOf(lowerer.typeOf(expr.expression.expression));
|
|
2073
|
+
if (name === "exec" && expr.arguments.nodes.length === 1 && recvT?.kind === "regex") {
|
|
2074
|
+
return expr.expression.expression;
|
|
2075
|
+
}
|
|
2076
|
+
if (name === "match" &&
|
|
2077
|
+
expr.arguments.nodes.length === 1 &&
|
|
2078
|
+
(recvT?.kind === "string" ||
|
|
2079
|
+
(recvT !== null && recvT !== undefined && nullableStringType(lowerer, recvT))) &&
|
|
2080
|
+
lowerer.mapTypeOf(lowerer.typeOf(expr.arguments.nodes[0]))?.kind === "regex") {
|
|
2081
|
+
return expr.arguments.nodes[0];
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
// A matchAll ROW by element access: rows[i] with rows tracing to the
|
|
2085
|
+
// drain call — or the direct s.matchAll(re)[i] spelling.
|
|
2086
|
+
if (ts.isElementAccessExpression(expr)) {
|
|
2087
|
+
return matchAllRegexOf(lowerer, expr.expression);
|
|
2088
|
+
}
|
|
2089
|
+
// A row picked by `rows.find(cb)`, `rows.findLast(cb)` or `rows.at(i)`.
|
|
2090
|
+
if (ts.isCallExpression(expr) &&
|
|
2091
|
+
ts.isPropertyAccessExpression(expr.expression) &&
|
|
2092
|
+
MATCH_ROW_PICK_METHODS.has(expr.expression.name.text) &&
|
|
2093
|
+
lowerer.isStdlibMember(expr.expression)) {
|
|
2094
|
+
return matchAllRegexOf(lowerer, expr.expression.expression);
|
|
2095
|
+
}
|
|
2096
|
+
if (ts.isIdentifier(expr)) {
|
|
2097
|
+
// The for-of binding over a matchAll drain: `for (const m of
|
|
2098
|
+
// s.matchAll(re))` (or over a stored const rows).
|
|
2099
|
+
const sym = lowerer.resolveValueSymbol(expr);
|
|
2100
|
+
const decl = sym ? sym.valueDeclaration : undefined;
|
|
2101
|
+
if (decl !== undefined &&
|
|
2102
|
+
ts.isVariableDeclaration(decl) &&
|
|
2103
|
+
ts.isVariableDeclarationList(decl.parent) &&
|
|
2104
|
+
ts.isForOfStatement(decl.parent.parent)) {
|
|
2105
|
+
return matchAllRegexOf(lowerer, decl.parent.parent.expression);
|
|
2106
|
+
}
|
|
2107
|
+
// A stored const match result: `const m = re.exec(s)`.
|
|
2108
|
+
const init = constInitializerOf(lowerer, expr);
|
|
2109
|
+
if (init !== null)
|
|
2110
|
+
return matchProducerRegexOf(lowerer, init);
|
|
2111
|
+
// The element parameter of an array callback over matchAll rows:
|
|
2112
|
+
// `[...s.matchAll(re)].map((m) => m.groups)`, and Array.from's
|
|
2113
|
+
// mapping function over `s.matchAll(re)`.
|
|
2114
|
+
if (decl !== undefined && ts.isParameter(decl))
|
|
2115
|
+
return matchAllCallbackRegexOf(lowerer, decl);
|
|
2116
|
+
}
|
|
2117
|
+
return null;
|
|
2118
|
+
}
|
|
2119
|
+
/** Array methods that return one row of the receiver. */
|
|
2120
|
+
const MATCH_ROW_PICK_METHODS = new Set(["find", "findLast", "at"]);
|
|
2121
|
+
/** `m.groups` on a match result whose producing regex is statically
|
|
2122
|
+
* known: the honest slice already HOLDS every named group's value at
|
|
2123
|
+
* its capture index, so the groups object is a compile-time record
|
|
2124
|
+
* projection — `{ year: m[1], month: m[2] }` — built by one interned
|
|
2125
|
+
* helper per (shape, index list, receiver type). Node's exact shape
|
|
2126
|
+
* decisions:
|
|
2127
|
+
* - no named groups → `undefined` (the identifier-receiver shapes —
|
|
2128
|
+
* a call receiver would lose its own null trap, so those keep the
|
|
2129
|
+
* member fence);
|
|
2130
|
+
* - a nullable receiver (the JS `s.match(re).groups` idiom) throws
|
|
2131
|
+
* Node's exact TypeError on the unit arms;
|
|
2132
|
+
* - every declared name is a key (nonparticipating groups hold undefined,
|
|
2133
|
+
* exactly the slice elements they project);
|
|
2134
|
+
* - ES2025 duplicate names (distinct alternatives) project the first
|
|
2135
|
+
* participating occurrence, including a participating empty string;
|
|
2136
|
+
* - key order is group declaration order (declaredOrder), Node's own.
|
|
2137
|
+
* The record has a null prototype, like Node's groups object. A
|
|
2138
|
+
* JavaScript callback parameter holds the row as a dynamic array; the
|
|
2139
|
+
* projection reads its elements through dynamic reads. Null when the
|
|
2140
|
+
* receiver isn't a match slice or the regex isn't traceable — the
|
|
2141
|
+
* caller's member fence (with the groups hint) names the gap. */
|
|
2142
|
+
function lowerMatchGroupsRead(lowerer, expr) {
|
|
2143
|
+
if (expr.name.text !== "groups")
|
|
2144
|
+
return null;
|
|
2145
|
+
// `m?.groups` re-dispatches through the optional-chain machinery, which
|
|
2146
|
+
// narrows the receiver to its match arm first.
|
|
2147
|
+
if (expr.questionDotToken !== undefined && !lowerer.chainHandled.has(expr))
|
|
2148
|
+
return null;
|
|
2149
|
+
const loc = locOf(expr);
|
|
2150
|
+
const strArr = arrayOf(STRING);
|
|
2151
|
+
const recvT = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
2152
|
+
if (!recvT || !isMatchSliceType(lowerer, recvT) || !lowerer.isStdlibMember(expr))
|
|
2153
|
+
return null;
|
|
2154
|
+
const groups = matchResultNamedGroupsOf(lowerer, expr.expression);
|
|
2155
|
+
// An untraced regex: TypeScript reaches the member fence; JavaScript
|
|
2156
|
+
// would otherwise read the slice's absent expando as undefined.
|
|
2157
|
+
if (groups === null && isJsSourceFile(ts.getSourceFileOfNode(expr)))
|
|
2158
|
+
lowerer.stdlibMemberFence(expr);
|
|
2159
|
+
if (groups === null)
|
|
2160
|
+
return null;
|
|
2161
|
+
if (groups.length === 0) {
|
|
2162
|
+
// Node: a match result of a group-less regex answers undefined —
|
|
2163
|
+
// the unit literal, exactly the `undefined` identifier's lowering.
|
|
2164
|
+
// Identifier receivers only (evaluation-free): a CALL receiver's
|
|
2165
|
+
// exec/match must still run and null-trap, which a folded unit
|
|
2166
|
+
// cannot carry — those keep the fence.
|
|
2167
|
+
let r = expr.expression;
|
|
2168
|
+
while (ts.isParenthesizedExpression(r) || ts.isNonNullExpression(r))
|
|
2169
|
+
r = r.expression;
|
|
2170
|
+
if (ts.isIdentifier(r) && typeEquals(recvT, strArr)) {
|
|
2171
|
+
return { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc };
|
|
2172
|
+
}
|
|
2173
|
+
return null;
|
|
2174
|
+
}
|
|
2175
|
+
const recv = lowerer.lowerExpr(expr.expression);
|
|
2176
|
+
// A JavaScript callback parameter holds the row as a dynamic array.
|
|
2177
|
+
const dynRow = recv.type.kind === "dyn" && isJsSourceFile(ts.getSourceFileOfNode(expr));
|
|
2178
|
+
if (!dynRow && !isMatchSliceType(lowerer, recv.type))
|
|
2179
|
+
return null;
|
|
2180
|
+
return lowerGroupsProjection(lowerer, recv, groups, loc);
|
|
2181
|
+
}
|
|
2182
|
+
/** True when the IR type is a string-or-units union — the Dict<string>
|
|
2183
|
+
* member spelling (`process.versions.openssl`), match's nullable
|
|
2184
|
+
* receiver claim. */
|
|
2185
|
+
function nullableStringType(lowerer, t) {
|
|
2186
|
+
if (t.kind !== "union")
|
|
2187
|
+
return false;
|
|
2188
|
+
const arms = lowerer.unions.get(t.unionId)?.arms ?? [];
|
|
2189
|
+
return (arms.some((a) => a.kind === "string") && arms.every((a) => a.kind === "string" || isUnitType(a)));
|
|
2190
|
+
}
|
|
2191
|
+
/** True when the IR type is the honest match slice — `string[]`, or a
|
|
2192
|
+
* union of it with unit arms only (`string[] | null`). The groups
|
|
2193
|
+
* projection's receiver gate, shared with the destructure interception. */
|
|
2194
|
+
export function isMatchSliceType(lowerer, t) {
|
|
2195
|
+
if (typeEquals(t, arrayOf(STRING)))
|
|
2196
|
+
return true;
|
|
2197
|
+
return t.kind === "union" && matchSliceUnionArms(lowerer, t.unionId) !== null;
|
|
2198
|
+
}
|
|
2199
|
+
/** The union-arm layout of a nullable match slice (`string[] | null`,
|
|
2200
|
+
* matchAll's checker spellings with undefined arms included): the
|
|
2201
|
+
* string[] arm's tag plus each unit arm's tag and spelling. Null when
|
|
2202
|
+
* the union holds anything else. */
|
|
2203
|
+
function matchSliceUnionArms(lowerer, unionId) {
|
|
2204
|
+
const def = lowerer.unions.get(unionId);
|
|
2205
|
+
if (!def)
|
|
2206
|
+
return null;
|
|
2207
|
+
const strArr = arrayOf(STRING);
|
|
2208
|
+
const arrTag = def.arms.findIndex((a) => typeEquals(a, strArr));
|
|
2209
|
+
if (arrTag < 0)
|
|
2210
|
+
return null;
|
|
2211
|
+
const units = [];
|
|
2212
|
+
for (let i = 0; i < def.arms.length; i++) {
|
|
2213
|
+
if (i === arrTag)
|
|
2214
|
+
continue;
|
|
2215
|
+
const a = def.arms[i];
|
|
2216
|
+
if (!isUnitType(a))
|
|
2217
|
+
return null;
|
|
2218
|
+
units.push({ tag: i, unit: a.kind === "nullT" ? "null" : "undefined" });
|
|
2219
|
+
}
|
|
2220
|
+
return { arrTag, units };
|
|
2221
|
+
}
|
|
2222
|
+
/** Node's TypeError for `.groups` read off null or undefined. */
|
|
2223
|
+
function groupsReadTypeError(unit, loc) {
|
|
2224
|
+
return {
|
|
2225
|
+
kind: "throw",
|
|
2226
|
+
value: {
|
|
2227
|
+
kind: "libCall",
|
|
2228
|
+
fn: "error.new",
|
|
2229
|
+
args: [strLit(`Cannot read properties of ${unit} (reading 'groups')`, loc)],
|
|
2230
|
+
type: { kind: "object", className: "%TypeError" },
|
|
2231
|
+
loc,
|
|
2232
|
+
},
|
|
2233
|
+
loc,
|
|
2234
|
+
};
|
|
2235
|
+
}
|
|
2236
|
+
/** The groups-record projection holds string | undefined values, including
|
|
2237
|
+
* an own overflow entry for every nonparticipating capture. One lifted helper per
|
|
2238
|
+
* (index list, receiver representation) builds it; see
|
|
2239
|
+
* lowerMatchGroupsRead for the semantics the body encodes. */
|
|
2240
|
+
export function lowerGroupsProjection(lowerer, recv, groups, loc) {
|
|
2241
|
+
// Name → its capture indices, in declaration order (duplicates keep
|
|
2242
|
+
// every occurrence — the projection picks the participating one).
|
|
2243
|
+
const order = [];
|
|
2244
|
+
const indicesByName = new Map();
|
|
2245
|
+
for (const g of groups) {
|
|
2246
|
+
const got = indicesByName.get(g.name);
|
|
2247
|
+
if (got) {
|
|
2248
|
+
got.push(g.index);
|
|
2249
|
+
}
|
|
2250
|
+
else {
|
|
2251
|
+
indicesByName.set(g.name, [g.index]);
|
|
2252
|
+
order.push(g.name);
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
const valueType = arrayValueType(lowerer, STRING);
|
|
2256
|
+
const shapeId = lowerer.shapes.intern([], false, valueType);
|
|
2257
|
+
const recordT = { kind: "record", shapeId };
|
|
2258
|
+
const recvKey = recv.type.kind === "union" ? recv.type.unionId : recv.type.kind === "dyn" ? "dyn" : "arr";
|
|
2259
|
+
const key = `regexgroups:${shapeId}:${groups.map((g) => `${g.name}=${g.index}`).join(",")}:${recvKey}`;
|
|
2260
|
+
let helper = lowerer.valueHelpers.get(key);
|
|
2261
|
+
if (!helper) {
|
|
2262
|
+
helper = `%regex.groups.${lowerer.valueHelpers.size}`;
|
|
2263
|
+
lowerer.valueHelpers.set(key, helper);
|
|
2264
|
+
const body = [];
|
|
2265
|
+
const locals = [{ id: "m.0", name: "m", type: recv.type, mutable: true }];
|
|
2266
|
+
let mRef = { kind: "varRef", localId: "m.0", type: recv.type, loc };
|
|
2267
|
+
if (recv.type.kind === "union") {
|
|
2268
|
+
// Node's exact TypeError per unit arm, then the checked narrow.
|
|
2269
|
+
const arms = matchSliceUnionArms(lowerer, recv.type.unionId);
|
|
2270
|
+
for (const u of arms.units) {
|
|
2271
|
+
body.push({
|
|
2272
|
+
kind: "if",
|
|
2273
|
+
cond: {
|
|
2274
|
+
kind: "unionIsTag",
|
|
2275
|
+
unionId: recv.type.unionId,
|
|
2276
|
+
tag: u.tag,
|
|
2277
|
+
negated: false,
|
|
2278
|
+
value: mRef,
|
|
2279
|
+
type: BOOL,
|
|
2280
|
+
loc,
|
|
2281
|
+
},
|
|
2282
|
+
then: [groupsReadTypeError(u.unit, loc)],
|
|
2283
|
+
else_: null,
|
|
2284
|
+
loc,
|
|
2285
|
+
});
|
|
2286
|
+
}
|
|
2287
|
+
const narrowed = {
|
|
2288
|
+
kind: "unionNarrow",
|
|
2289
|
+
unionId: recv.type.unionId,
|
|
2290
|
+
tag: arms.arrTag,
|
|
2291
|
+
value: mRef,
|
|
2292
|
+
type: arrayOf(STRING),
|
|
2293
|
+
loc,
|
|
2294
|
+
};
|
|
2295
|
+
locals.push({ id: "arr.0", name: "arr", type: arrayOf(STRING), mutable: false });
|
|
2296
|
+
body.push({ kind: "varDecl", localId: "arr.0", init: narrowed, loc });
|
|
2297
|
+
mRef = { kind: "varRef", localId: "arr.0", type: arrayOf(STRING), loc };
|
|
2298
|
+
}
|
|
2299
|
+
else if (recv.type.kind === "dyn") {
|
|
2300
|
+
// A JavaScript callback parameter holds the row as a dynamic array:
|
|
2301
|
+
// Node's TypeError for null and undefined, then dynamic element reads.
|
|
2302
|
+
for (const unit of ["null", "undefined"]) {
|
|
2303
|
+
body.push({
|
|
2304
|
+
kind: "if",
|
|
2305
|
+
cond: { kind: "dynTest", test: unit, value: mRef, type: BOOL, loc },
|
|
2306
|
+
then: [groupsReadTypeError(unit, loc)],
|
|
2307
|
+
else_: null,
|
|
2308
|
+
loc,
|
|
2309
|
+
});
|
|
2310
|
+
}
|
|
2311
|
+
}
|
|
2312
|
+
const elem = (index) => mRef.type.kind === "dyn"
|
|
2313
|
+
? lowerer.coerceToExpected({
|
|
2314
|
+
kind: "dynKeyGet",
|
|
2315
|
+
value: mRef,
|
|
2316
|
+
key: strLit(String(index), loc),
|
|
2317
|
+
type: DYN,
|
|
2318
|
+
loc,
|
|
2319
|
+
}, valueType)
|
|
2320
|
+
: arrayValueRead(lowerer, mRef, numLit(index, loc), STRING, loc);
|
|
2321
|
+
const values = new Map();
|
|
2322
|
+
order.forEach((name, i) => {
|
|
2323
|
+
const idxs = indicesByName.get(name);
|
|
2324
|
+
if (idxs.length === 1) {
|
|
2325
|
+
values.set(name, elem(idxs[0]));
|
|
2326
|
+
return;
|
|
2327
|
+
}
|
|
2328
|
+
// Duplicates: the first participating occurrence. Empty strings
|
|
2329
|
+
// participate; undefined means this alternative did not match.
|
|
2330
|
+
const id = `g${i}.0`;
|
|
2331
|
+
locals.push({ id, name: `g${i}`, type: valueType, mutable: true });
|
|
2332
|
+
body.push({ kind: "varDecl", localId: id, init: elem(idxs[0]), loc });
|
|
2333
|
+
const gRef = { kind: "varRef", localId: id, type: valueType, loc };
|
|
2334
|
+
for (const idx of idxs.slice(1)) {
|
|
2335
|
+
body.push({
|
|
2336
|
+
kind: "if",
|
|
2337
|
+
cond: {
|
|
2338
|
+
kind: "unionIsTag",
|
|
2339
|
+
unionId: valueType.kind === "union" ? valueType.unionId : "",
|
|
2340
|
+
tag: valueType.kind === "union" ? lowerer.armTag(valueType.unionId, UNDEFINED_T) : -1,
|
|
2341
|
+
negated: false,
|
|
2342
|
+
value: gRef,
|
|
2343
|
+
type: BOOL,
|
|
2344
|
+
loc,
|
|
2345
|
+
},
|
|
2346
|
+
then: [{ kind: "assign", localId: id, value: elem(idx), loc }],
|
|
2347
|
+
else_: null,
|
|
2348
|
+
loc,
|
|
2349
|
+
});
|
|
2350
|
+
}
|
|
2351
|
+
values.set(name, gRef);
|
|
2352
|
+
});
|
|
2353
|
+
body.push({
|
|
2354
|
+
kind: "return",
|
|
2355
|
+
value: {
|
|
2356
|
+
kind: "recordLit",
|
|
2357
|
+
fields: order.map((name) => ({ name, value: values.get(name), overflow: true })),
|
|
2358
|
+
nullProto: true,
|
|
2359
|
+
type: recordT,
|
|
2360
|
+
loc,
|
|
2361
|
+
},
|
|
2362
|
+
loc,
|
|
2363
|
+
});
|
|
2364
|
+
lowerer.liftedFns.push({
|
|
2365
|
+
name: helper,
|
|
2366
|
+
params: [{ localId: "m.0", name: "m", type: recv.type }],
|
|
2367
|
+
returnType: recordT,
|
|
2368
|
+
locals,
|
|
2369
|
+
body,
|
|
2370
|
+
loc,
|
|
2371
|
+
});
|
|
2372
|
+
}
|
|
2373
|
+
return { kind: "call", callee: helper, args: [recv], type: recordT, loc };
|
|
2374
|
+
}
|
|
2375
|
+
/** Field reads use the shared FieldTarget union. Native method reads select
|
|
2376
|
+
* an interned unbound callable; invocation supplies its receiver separately. */
|
|
2377
|
+
export function lowerFieldRead(lowerer, expr) {
|
|
2378
|
+
// A checked receiver already owns its property table. An ambient
|
|
2379
|
+
// generic method signature must not divert its value into native
|
|
2380
|
+
// object-literal specialization (Array.prototype.map is one example).
|
|
2381
|
+
if (ts.isIdentifier(expr.expression)) {
|
|
2382
|
+
const stored = lowerer.peekLocal(expr.expression) ?? lowerer.globalOf(expr.expression);
|
|
2383
|
+
if (stored?.type.kind === "dyn") {
|
|
2384
|
+
const value = lowerer.lowerExpr(expr.expression);
|
|
2385
|
+
if (value.type.kind === "dyn")
|
|
2386
|
+
return {
|
|
2387
|
+
kind: "dynKeyGet",
|
|
2388
|
+
value,
|
|
2389
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
2390
|
+
...(expr.questionDotToken || hasOptionalChainGuard(expr.expression)
|
|
2391
|
+
? { optional: true }
|
|
2392
|
+
: {}),
|
|
2393
|
+
type: DYN,
|
|
2394
|
+
loc: locOf(expr),
|
|
2395
|
+
};
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
const target = lowerer.fieldTarget(expr);
|
|
2399
|
+
if (target)
|
|
2400
|
+
return lowerer.fieldGetExpr(target, locOf(expr), expr);
|
|
2401
|
+
if (expr.questionDotToken)
|
|
2402
|
+
return null;
|
|
2403
|
+
let receiverIr = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
2404
|
+
// The readonly-tuple Array.isArray narrow has no directly mappable
|
|
2405
|
+
// checker type (`Result & any[]`), but maybeNarrow extracted the tuple
|
|
2406
|
+
// record behind it. Route tuple properties such as `.length` from that
|
|
2407
|
+
// lowered value, the element-access bridge's twin.
|
|
2408
|
+
const checkerArray = lowerer.checkerArrayValue(expr.expression);
|
|
2409
|
+
if (checkerArray?.type.kind === "record")
|
|
2410
|
+
receiverIr = checkerArray.type;
|
|
2411
|
+
if (receiverIr?.kind === "object" &&
|
|
2412
|
+
(lowerer.findMethodOn(lowerer.classes.get(receiverIr.className) ?? null, expr.name.text) ||
|
|
2413
|
+
findGenericMethodOn(lowerer, lowerer.classes.get(receiverIr.className) ?? null, expr.name.text))) {
|
|
2414
|
+
const info = lowerer.classes.get(receiverIr.className);
|
|
2415
|
+
if (info)
|
|
2416
|
+
return lowerClassMethodValue(lowerer, expr, info);
|
|
2417
|
+
}
|
|
2418
|
+
// An object-literal GENERIC method as a VALUE (`o.m` — the member is
|
|
2419
|
+
// excluded from the record shape): the pinned-value rule verbatim when
|
|
2420
|
+
// the receiver is the defining literal's own const binding (the value
|
|
2421
|
+
// is the pinned instance's closure — no `this` exists); anything else
|
|
2422
|
+
// fences by name inside the helpers.
|
|
2423
|
+
{
|
|
2424
|
+
const propSym = lowerer.checker.getPropertyOfType(lowerer.typeOf(expr.expression), expr.name.text);
|
|
2425
|
+
if (receiverIr?.kind !== "object" &&
|
|
2426
|
+
propSym &&
|
|
2427
|
+
isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker) &&
|
|
2428
|
+
// CLASS members keep the class-path fences (a poisoned class's own
|
|
2429
|
+
// diagnostics, the bound-method fence above).
|
|
2430
|
+
!propSym.declarations.some((d) => d.parent !== undefined &&
|
|
2431
|
+
(ts.isClassDeclaration(d.parent) || ts.isClassExpression(d.parent)))) {
|
|
2432
|
+
const found = objLitGenericFnNodeOf(lowerer, propSym);
|
|
2433
|
+
if (!found) {
|
|
2434
|
+
lowerer.unsupported("SC1090", expr, `the generic method '${expr.name.text}' as a value with no defining object literal (only methods declared with a body in an object literal compile)`);
|
|
2435
|
+
}
|
|
2436
|
+
requireObjLitGenericReceiver(lowerer, expr, expr.expression, found.literal, expr.name.text);
|
|
2437
|
+
return lowerer.lowerGenericFnValue(expr, objLitGenericFnInfoOf(lowerer, expr, expr.name.text, found));
|
|
2438
|
+
}
|
|
2439
|
+
}
|
|
2440
|
+
// Dot access to an UNDECLARED key of an index-signature shape
|
|
2441
|
+
// (`bag.count` on `Record<string, number>`): tsc allows it without
|
|
2442
|
+
// noPropertyAccessFromIndexSignature, but the bracket spelling is the
|
|
2443
|
+
// canonical index-signature form here — point at it.
|
|
2444
|
+
if (receiverIr?.kind === "record") {
|
|
2445
|
+
const shape = lowerer.shapes.get(receiverIr.shapeId);
|
|
2446
|
+
if (shape?.indexValue && !shape.fields.some((f) => f.name === expr.name.text)) {
|
|
2447
|
+
const actual = tryLowerExpression(lowerer, expr.expression);
|
|
2448
|
+
if (actual?.type.kind === "dyn")
|
|
2449
|
+
return {
|
|
2450
|
+
kind: "dynKeyGet",
|
|
2451
|
+
value: actual,
|
|
2452
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
2453
|
+
type: DYN,
|
|
2454
|
+
loc: locOf(expr),
|
|
2455
|
+
};
|
|
2456
|
+
if (actual?.type.kind === "record") {
|
|
2457
|
+
const field = lowerer.shapes
|
|
2458
|
+
.get(actual.type.shapeId)
|
|
2459
|
+
?.fields.find((field) => field.name === expr.name.text);
|
|
2460
|
+
if (field)
|
|
2461
|
+
return {
|
|
2462
|
+
kind: "recordGet",
|
|
2463
|
+
obj: actual,
|
|
2464
|
+
shapeId: actual.type.shapeId,
|
|
2465
|
+
field: field.name,
|
|
2466
|
+
type: field.type,
|
|
2467
|
+
loc: locOf(expr),
|
|
2468
|
+
};
|
|
2469
|
+
}
|
|
2470
|
+
// A member the checker declares on the receiver, stored in a pure
|
|
2471
|
+
// index-signature record (an object literal that spread one, see
|
|
2472
|
+
// dictSpreadLiteralShape): the key is always present, so the keyed
|
|
2473
|
+
// read answers the member through the slot type.
|
|
2474
|
+
if (actual?.type.kind === "record" &&
|
|
2475
|
+
shape.fields.length === 0 &&
|
|
2476
|
+
declaredMemberOf(lowerer, expr.expression, expr.name.text)) {
|
|
2477
|
+
return lowerer.maybeNarrow({
|
|
2478
|
+
kind: "recordKeyGet",
|
|
2479
|
+
obj: actual,
|
|
2480
|
+
shapeId: actual.type.shapeId,
|
|
2481
|
+
key: { kind: "strLit", value: expr.name.text, type: STRING, loc: locOf(expr.name) },
|
|
2482
|
+
type: shape.indexValue,
|
|
2483
|
+
loc: locOf(expr),
|
|
2484
|
+
}, expr);
|
|
2485
|
+
}
|
|
2486
|
+
lowerer.unsupported("SC1090", expr, `dot access to index-signature keys (spell it r["${expr.name.text}"] — brackets are the index-signature form)`);
|
|
2487
|
+
}
|
|
2488
|
+
}
|
|
2489
|
+
// `t.length` on a tuple: the arity CONSTANT (tuples are fixed-shape —
|
|
2490
|
+
// the checker types it as the literal arity too). Folding discards the
|
|
2491
|
+
// receiver's evaluation, so only side-effect-free receivers fold;
|
|
2492
|
+
// anything else (a call result) binds to a const first.
|
|
2493
|
+
if (receiverIr?.kind === "record" && expr.name.text === "length") {
|
|
2494
|
+
const shape = lowerer.shapes.get(receiverIr.shapeId);
|
|
2495
|
+
if (shape?.tuple) {
|
|
2496
|
+
let root = expr.expression;
|
|
2497
|
+
while (ts.isPropertyAccessExpression(root))
|
|
2498
|
+
root = root.expression;
|
|
2499
|
+
if (!ts.isIdentifier(root) && root.kind !== ts.SyntaxKind.ThisKeyword) {
|
|
2500
|
+
lowerer.unsupported("SC1090", expr, "'.length' of a computed tuple expression (the arity is a constant — bind the tuple to a const first)");
|
|
2501
|
+
}
|
|
2502
|
+
return { kind: "numLit", value: shape.fields.length, type: F64, loc: locOf(expr) };
|
|
2503
|
+
}
|
|
2504
|
+
}
|
|
2505
|
+
return null;
|
|
2506
|
+
}
|
|
2507
|
+
/** Shared-field read `r.f` on a UNION receiver: supported exactly when
|
|
2508
|
+
* every arm is a record/class possessing the field with ONE shared IR
|
|
2509
|
+
* type — the discriminant pattern (`r.kind`, primitive) and the
|
|
2510
|
+
* shared-payload pattern (`spec.config` where every ServiceSpec arm
|
|
2511
|
+
* carries the same record). Lowers to `unionDisc` (the backend switches
|
|
2512
|
+
* on the runtime tag and reads the field from the concrete arm), which
|
|
2513
|
+
* composes with existing strEq/bin/switch nodes, so `r.kind === "ok"`
|
|
2514
|
+
* and `switch (r.kind)` work without dedicated test nodes. Anything else
|
|
2515
|
+
* on a union receiver is rejected specifically (narrow first). */
|
|
2516
|
+
export function lowerUnionProperty(lowerer, expr) {
|
|
2517
|
+
if (lowerer.chainBlocked(expr))
|
|
2518
|
+
return null;
|
|
2519
|
+
const receiverIr = structuralReadType(lowerer, expr.expression) ??
|
|
2520
|
+
lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
2521
|
+
if (receiverIr?.kind !== "union")
|
|
2522
|
+
return null;
|
|
2523
|
+
// Lower the receiver first: its runtime value can still carry the full
|
|
2524
|
+
// binding union even when the checker has removed several variants.
|
|
2525
|
+
let value = lowerer.lowerExpr(expr.expression);
|
|
2526
|
+
// A guard can remove several variants without selecting one record.
|
|
2527
|
+
// Materialize that sub-union before looking for common fields; arms
|
|
2528
|
+
// ruled out by the guard must not veto a field shared by the survivors.
|
|
2529
|
+
if (value.type.kind === "union" && !typeEquals(value.type, receiverIr)) {
|
|
2530
|
+
const helper = lowerer.narrowedRetagHelper(expr.expression, value.type.unionId, receiverIr.unionId, locOf(expr));
|
|
2531
|
+
if (helper)
|
|
2532
|
+
value = { kind: "call", callee: helper, args: [value], type: receiverIr, loc: locOf(expr) };
|
|
2533
|
+
// Optional storage of a base class (a runtime-optional binding holding
|
|
2534
|
+
// `Base | undefined`) that `instanceof` narrowed to several subclasses:
|
|
2535
|
+
// extract the instance and test its class, as typed slots do.
|
|
2536
|
+
else
|
|
2537
|
+
value = narrowStoredClassValue(lowerer, value, receiverIr) ?? value;
|
|
2538
|
+
}
|
|
2539
|
+
// A checker-union receiver whose VALUE lowered to a plain RECORD (the
|
|
2540
|
+
// merged-signature fiction — `runner(cmd, args)` where runner joined
|
|
2541
|
+
// a structural runner type with spawnSync's, and the local adopted
|
|
2542
|
+
// the record arm): read the record field directly, the dyn-receiver
|
|
2543
|
+
// fallback's discipline.
|
|
2544
|
+
// A checker-union receiver whose VALUE lowered checked-dynamic (a
|
|
2545
|
+
// never-tainted JS chain — `cmd[1].length` on `const cmd = ['pwd',
|
|
2546
|
+
// []]`, where the element read stayed a dyn node): read through the
|
|
2547
|
+
// dyn keyed read like the unmappable-receiver path below the chain.
|
|
2548
|
+
if (value.type.kind === "dyn") {
|
|
2549
|
+
const key = {
|
|
2550
|
+
kind: "strLit",
|
|
2551
|
+
value: expr.name.text,
|
|
2552
|
+
type: STRING,
|
|
2553
|
+
loc: locOf(expr.name),
|
|
2554
|
+
};
|
|
2555
|
+
return { kind: "dynKeyGet", key, value, type: DYN, loc: locOf(expr) };
|
|
2556
|
+
}
|
|
2557
|
+
if (value.type.kind === "record") {
|
|
2558
|
+
const shape = lowerer.shapes.get(value.type.shapeId);
|
|
2559
|
+
const f = shape?.fields.find((x) => x.name === expr.name.text);
|
|
2560
|
+
if (f) {
|
|
2561
|
+
return {
|
|
2562
|
+
kind: "recordGet",
|
|
2563
|
+
obj: value,
|
|
2564
|
+
shapeId: value.type.shapeId,
|
|
2565
|
+
field: f.name,
|
|
2566
|
+
type: f.type,
|
|
2567
|
+
loc: locOf(expr),
|
|
2568
|
+
};
|
|
2569
|
+
}
|
|
2570
|
+
return null;
|
|
2571
|
+
}
|
|
2572
|
+
// A class instance the checker sees through a wider union (`(concrete
|
|
2573
|
+
// as A | B).value`): the value is that class's instance, so read its
|
|
2574
|
+
// field directly.
|
|
2575
|
+
if (value.type.kind === "object") {
|
|
2576
|
+
const className = value.type.className;
|
|
2577
|
+
const info = lowerer.classes.get(className) ?? null;
|
|
2578
|
+
const field = expr.name.text;
|
|
2579
|
+
const fieldType = info?.fields.get(field);
|
|
2580
|
+
if (fieldType !== undefined)
|
|
2581
|
+
return lowerer.fieldGetExpr({ container: "class", obj: value, className, field, fieldType }, locOf(expr), expr);
|
|
2582
|
+
const getter = lowerer.findMethodOn(info, `get:${field}`);
|
|
2583
|
+
if (getter)
|
|
2584
|
+
return lowerer.fieldGetExpr({ container: "accessor", obj: value, className, field, fieldType: getter.sig.ret }, locOf(expr), expr);
|
|
2585
|
+
}
|
|
2586
|
+
if (value.type.kind !== "union") {
|
|
2587
|
+
lowerer.unsupported("SC1090", expr, "shared property access without a represented union receiver");
|
|
2588
|
+
}
|
|
2589
|
+
const def = lowerer.unions.get(value.type.unionId);
|
|
2590
|
+
if (!def)
|
|
2591
|
+
throw new InternalCompilerError(`lowerer bug: unknown union ${value.type.unionId}`);
|
|
2592
|
+
const field = expr.name.text;
|
|
2593
|
+
if (field === "length") {
|
|
2594
|
+
const presentArms = def.arms.filter((arm) => !isUnitType(arm));
|
|
2595
|
+
const present = presentArms.length === 1 ? presentArms[0] : null;
|
|
2596
|
+
if (present?.kind === "string" || present?.kind === "array") {
|
|
2597
|
+
const receiver = lowerer.runtimeOptionalPropertyReceiver(expr.expression, value, present, field);
|
|
2598
|
+
if (receiver !== null) {
|
|
2599
|
+
return present.kind === "string"
|
|
2600
|
+
? {
|
|
2601
|
+
kind: "strIntrinsic",
|
|
2602
|
+
method: "length",
|
|
2603
|
+
receiver,
|
|
2604
|
+
args: [],
|
|
2605
|
+
type: F64,
|
|
2606
|
+
loc: locOf(expr),
|
|
2607
|
+
}
|
|
2608
|
+
: {
|
|
2609
|
+
kind: "arrIntrinsic",
|
|
2610
|
+
method: "length",
|
|
2611
|
+
receiver,
|
|
2612
|
+
args: [],
|
|
2613
|
+
type: F64,
|
|
2614
|
+
loc: locOf(expr),
|
|
2615
|
+
};
|
|
2616
|
+
}
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
const nonUnitArms = def.arms.filter((arm) => !isUnitType(arm));
|
|
2620
|
+
if (nonUnitArms.length === 1 && nonUnitArms[0]?.kind === "object") {
|
|
2621
|
+
const objectType = nonUnitArms[0];
|
|
2622
|
+
const fieldType = lowerer.classes.get(objectType.className)?.fields.get(field);
|
|
2623
|
+
if (fieldType !== undefined) {
|
|
2624
|
+
let receiver = lowerer.runtimeOptionalPropertyReceiver(expr.expression, value, objectType, field);
|
|
2625
|
+
if (receiver === null) {
|
|
2626
|
+
const helper = lowerer.narrowedArmHelper(value.type.unionId, objectType, locOf(expr.expression));
|
|
2627
|
+
if (helper !== null)
|
|
2628
|
+
receiver = lowerer.checkedNarrowCall(helper, value, objectType, locOf(expr.expression));
|
|
2629
|
+
}
|
|
2630
|
+
if (receiver !== null) {
|
|
2631
|
+
return {
|
|
2632
|
+
kind: "fieldGet",
|
|
2633
|
+
obj: receiver,
|
|
2634
|
+
className: objectType.className,
|
|
2635
|
+
field,
|
|
2636
|
+
type: fieldType,
|
|
2637
|
+
loc: locOf(expr),
|
|
2638
|
+
};
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
}
|
|
2642
|
+
let common = null;
|
|
2643
|
+
for (const arm of def.arms) {
|
|
2644
|
+
let ft;
|
|
2645
|
+
if (arm.kind === "record") {
|
|
2646
|
+
ft = lowerer.shapes.get(arm.shapeId)?.fields.find((f) => f.name === field)?.type;
|
|
2647
|
+
}
|
|
2648
|
+
else if (arm.kind === "object") {
|
|
2649
|
+
ft = lowerer.classes.get(arm.className)?.fields.get(field);
|
|
2650
|
+
}
|
|
2651
|
+
if (!ft || ft.kind === "void" || isUnitType(ft) || (common && !typeEquals(common, ft))) {
|
|
2652
|
+
common = null;
|
|
2653
|
+
break;
|
|
2654
|
+
}
|
|
2655
|
+
common = ft;
|
|
2656
|
+
}
|
|
2657
|
+
if (common) {
|
|
2658
|
+
return {
|
|
2659
|
+
kind: "unionDisc",
|
|
2660
|
+
unionId: value.type.unionId,
|
|
2661
|
+
field,
|
|
2662
|
+
value,
|
|
2663
|
+
type: common,
|
|
2664
|
+
loc: locOf(expr),
|
|
2665
|
+
};
|
|
2666
|
+
}
|
|
2667
|
+
// The arms answer DIFFERENT types (or through index signatures / unit
|
|
2668
|
+
// arms): the JOIN path — `env.PORTLESS_PORT` on `ProcessEnv |
|
|
2669
|
+
// Record<string, string>`, the tail read of `loaded?.config.script`.
|
|
2670
|
+
const key = { kind: "strLit", value: field, type: STRING, loc: locOf(expr.name) };
|
|
2671
|
+
const keyed = lowerUnionKeyedRead(lowerer, expr, value.type.unionId, value, key, field);
|
|
2672
|
+
if (keyed)
|
|
2673
|
+
return keyed;
|
|
2674
|
+
// Class arms declaring the field with compatible but different types
|
|
2675
|
+
// (`T | undefined` beside `T`): per-arm slot reads widened to one type.
|
|
2676
|
+
const widened = lowerUnionFieldRead(lowerer, expr, value);
|
|
2677
|
+
if (widened)
|
|
2678
|
+
return widened;
|
|
2679
|
+
// JavaScript overloads commonly inspect a class brand on a scalar-or-
|
|
2680
|
+
// instance argument (e.g. Matrix4.makeTranslation). Preserve primitive
|
|
2681
|
+
// missing-property semantics and dispatch class data through its native
|
|
2682
|
+
// capsule instead of demanding a field shared by every union arm.
|
|
2683
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(expr)) && lowerer.dynConvertible(value.type)) {
|
|
2684
|
+
return {
|
|
2685
|
+
kind: "dynKeyGet",
|
|
2686
|
+
value: lowerer.coerceToExpected(value, DYN),
|
|
2687
|
+
key,
|
|
2688
|
+
...(hasOptionalChainGuard(expr.expression) ? { optional: true } : {}),
|
|
2689
|
+
type: DYN,
|
|
2690
|
+
loc: locOf(expr),
|
|
2691
|
+
};
|
|
2692
|
+
}
|
|
2693
|
+
lowerer.unsupported("SC1090", expr, `reading '${field}' on a union-typed value (every arm must be an object/record ` +
|
|
2694
|
+
`with a same-typed field '${field}'; ` +
|
|
2695
|
+
`${NARROW_FIRST})`);
|
|
2696
|
+
}
|
|
2697
|
+
/** The unionDisc generalization: a keyed read on a union receiver whose
|
|
2698
|
+
* arms answer DIFFERENT (but joinable) types. Each arm contributes its
|
|
2699
|
+
* declared answer — an array element's type (number keys), a declared field's type (literal keys), an
|
|
2700
|
+
* index-signature arm's value type (plus its declared fields' types for
|
|
2701
|
+
* runtime keys, which reach them through the keyed-read helper), and
|
|
2702
|
+
* UNDEFINED for unit arms (reachable only through optional-chain tails,
|
|
2703
|
+
* where JS short-circuits to undefined; a unit arm the checker narrowed
|
|
2704
|
+
* away is simply unreachable). The result type is the JOIN of those
|
|
2705
|
+
* answers; every arm's answer must be the join itself, one of its
|
|
2706
|
+
* arms, or a sub-union whose payload representations are unchanged.
|
|
2707
|
+
* Array reads retain the ordinary invalid-index trap policy.
|
|
2708
|
+
* Returns null when any arm cannot answer — the caller owns the fence
|
|
2709
|
+
* message. The caller (the property/element dispatch) maybeNarrows. */
|
|
2710
|
+
export function lowerUnionKeyedRead(lowerer, expr, unionId, value, key, literalField) {
|
|
2711
|
+
const def = lowerer.unions.get(unionId);
|
|
2712
|
+
if (!def)
|
|
2713
|
+
return null;
|
|
2714
|
+
// Pass 1: per-arm declared answers, joined into the result type.
|
|
2715
|
+
const joinArms = [];
|
|
2716
|
+
const seen = new Set();
|
|
2717
|
+
const push = (t) => {
|
|
2718
|
+
const k = typeKey(t);
|
|
2719
|
+
if (!seen.has(k)) {
|
|
2720
|
+
seen.add(k);
|
|
2721
|
+
joinArms.push(t);
|
|
2722
|
+
}
|
|
2723
|
+
};
|
|
2724
|
+
const pushAnswer = (t) => {
|
|
2725
|
+
if (t.kind === "void")
|
|
2726
|
+
return false;
|
|
2727
|
+
if (t.kind === "union") {
|
|
2728
|
+
const inner = lowerer.unions.get(t.unionId);
|
|
2729
|
+
if (!inner)
|
|
2730
|
+
return false;
|
|
2731
|
+
for (const a of inner.arms)
|
|
2732
|
+
push(a);
|
|
2733
|
+
return true;
|
|
2734
|
+
}
|
|
2735
|
+
push(t);
|
|
2736
|
+
return true;
|
|
2737
|
+
};
|
|
2738
|
+
for (const arm of def.arms) {
|
|
2739
|
+
if (isUnitType(arm)) {
|
|
2740
|
+
push(UNDEFINED_T);
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
if (key.type.kind === "f64") {
|
|
2744
|
+
if (arm.kind !== "array" || !pushAnswer(arm.elem))
|
|
2745
|
+
return null;
|
|
2746
|
+
continue;
|
|
2747
|
+
}
|
|
2748
|
+
if (arm.kind !== "record")
|
|
2749
|
+
return null;
|
|
2750
|
+
const shape = lowerer.shapes.get(arm.shapeId);
|
|
2751
|
+
if (!shape || shape.tuple)
|
|
2752
|
+
return null;
|
|
2753
|
+
const declared = literalField !== null ? shape.fields.find((f) => f.name === literalField)?.type : undefined;
|
|
2754
|
+
if (declared) {
|
|
2755
|
+
if (!pushAnswer(declared))
|
|
2756
|
+
return null;
|
|
2757
|
+
continue;
|
|
2758
|
+
}
|
|
2759
|
+
// Runtime keys can reach the declared fields through the keyed-read
|
|
2760
|
+
// helper's string switch — every one joins.
|
|
2761
|
+
if (literalField === null) {
|
|
2762
|
+
for (const f of shape.fields)
|
|
2763
|
+
if (!pushAnswer(f.type))
|
|
2764
|
+
return null;
|
|
2765
|
+
}
|
|
2766
|
+
if (!shape.indexValue) {
|
|
2767
|
+
if (literalField === null && shape.fields.length > 0)
|
|
2768
|
+
continue;
|
|
2769
|
+
return null;
|
|
2770
|
+
}
|
|
2771
|
+
if (!pushAnswer(shape.indexValue))
|
|
2772
|
+
return null;
|
|
2773
|
+
}
|
|
2774
|
+
if (joinArms.length === 0)
|
|
2775
|
+
return null;
|
|
2776
|
+
// The join must satisfy native union invariants. The caller owns the
|
|
2777
|
+
// diagnostic when a container or opaque arm prevents that join.
|
|
2778
|
+
if (joinArms.length > 1 &&
|
|
2779
|
+
(!unionContainerArmsOk(joinArms) ||
|
|
2780
|
+
joinArms.some((a) => a.kind === "dyn" || a.kind === "generator" || a.kind === "caught"))) {
|
|
2781
|
+
return null;
|
|
2782
|
+
}
|
|
2783
|
+
joinArms.sort((a, b) => (typeKey(a) < typeKey(b) ? -1 : 1));
|
|
2784
|
+
const type = joinArms.length === 1
|
|
2785
|
+
? joinArms[0]
|
|
2786
|
+
: { kind: "union", unionId: lowerer.unions.intern(joinArms) };
|
|
2787
|
+
// Pass 2: every arm's answer must SURFACE as the join, and index arms
|
|
2788
|
+
// must pass the single-record keyed-read constraints (the helper is
|
|
2789
|
+
// shared with recordKeyGet, its missing-key policy included).
|
|
2790
|
+
const surfaces = (t) => typeEquals(t, type) ||
|
|
2791
|
+
(type.kind === "union" && lowerer.armTag(type.unionId, t) >= 0) ||
|
|
2792
|
+
exactUnionWidening(lowerer, t, type);
|
|
2793
|
+
for (const arm of def.arms) {
|
|
2794
|
+
if (isUnitType(arm)) {
|
|
2795
|
+
if (!(type.kind === "union" && lowerer.armTag(type.unionId, UNDEFINED_T) >= 0))
|
|
2796
|
+
return null;
|
|
2797
|
+
continue;
|
|
2798
|
+
}
|
|
2799
|
+
if (key.type.kind === "f64") {
|
|
2800
|
+
if (arm.kind !== "array" || !surfaces(arm.elem))
|
|
2801
|
+
return null;
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
if (arm.kind !== "record")
|
|
2805
|
+
return null;
|
|
2806
|
+
const shape = lowerer.shapes.get(arm.shapeId);
|
|
2807
|
+
if (!shape)
|
|
2808
|
+
return null;
|
|
2809
|
+
const declared = literalField !== null ? shape.fields.find((f) => f.name === literalField)?.type : undefined;
|
|
2810
|
+
if (declared) {
|
|
2811
|
+
if (!surfaces(declared))
|
|
2812
|
+
return null;
|
|
2813
|
+
continue;
|
|
2814
|
+
}
|
|
2815
|
+
const ovfShape = literalField !== null && shape.indexValue ? { ...shape, fields: [] } : shape;
|
|
2816
|
+
if (!recordKeyResultOk(lowerer, ovfShape, type))
|
|
2817
|
+
return null;
|
|
2818
|
+
}
|
|
2819
|
+
return { kind: "unionKeyGet", unionId, key, value, type, loc: locOf(expr) };
|
|
2820
|
+
}
|
|
2821
|
+
/** A structural TypeScript view does not change a nominal object's layout
|
|
2822
|
+
* or accessor dispatch. Resolve the property from the represented class;
|
|
2823
|
+
* the optional checker view must not turn its getter into a record read. */
|
|
2824
|
+
export function classFieldTarget(lowerer, receiverNode, receiverType, fieldName, saved) {
|
|
2825
|
+
const represented = saved ?? lowerer.lowerExpr(receiverNode);
|
|
2826
|
+
if (represented.type.kind === "dyn" &&
|
|
2827
|
+
isJsSourceFile(ts.getSourceFileOfNode(receiverNode)) &&
|
|
2828
|
+
!fieldName.startsWith("#")) {
|
|
2829
|
+
return { container: "dynamic", obj: represented, field: fieldName, fieldType: DYN };
|
|
2830
|
+
}
|
|
2831
|
+
const info = lowerer.classes.get(receiverType.className);
|
|
2832
|
+
if (!info) {
|
|
2833
|
+
// A receiver typed as a class whose collection deferred: the
|
|
2834
|
+
// deferred diagnostics are what explains the miss.
|
|
2835
|
+
lowerer.flushDeferredClass(receiverType.className);
|
|
2836
|
+
return null;
|
|
2837
|
+
}
|
|
2838
|
+
const fieldType = info.fields.get(fieldName);
|
|
2839
|
+
const lowerObjectReceiver = () => {
|
|
2840
|
+
let obj = represented;
|
|
2841
|
+
if (obj.type.kind === "union") {
|
|
2842
|
+
// A receiver that may hold a missing value (a field assigned an
|
|
2843
|
+
// unchecked read): Node's member-read TypeError for the unit arm.
|
|
2844
|
+
const present = lowerer.runtimeOptionalPropertyReceiver(receiverNode, obj, receiverType, fieldName);
|
|
2845
|
+
if (present)
|
|
2846
|
+
return present;
|
|
2847
|
+
const helper = lowerer.narrowedArmHelper(obj.type.unionId, receiverType, locOf(receiverNode));
|
|
2848
|
+
obj = helper
|
|
2849
|
+
? lowerer.checkedNarrowCall(helper, obj, receiverType, locOf(receiverNode))
|
|
2850
|
+
: lowerer.maybeNarrow(obj, receiverNode);
|
|
2851
|
+
}
|
|
2852
|
+
return lowerer.coerceInto(receiverNode, obj, receiverType);
|
|
2853
|
+
};
|
|
2854
|
+
if (fieldName === "cause" && receiverType.className !== "%DOMException") {
|
|
2855
|
+
let root = info;
|
|
2856
|
+
while (root.base)
|
|
2857
|
+
root = root.base;
|
|
2858
|
+
if (root.def.name === "%Error") {
|
|
2859
|
+
return {
|
|
2860
|
+
container: "errorCause",
|
|
2861
|
+
obj: lowerObjectReceiver(),
|
|
2862
|
+
field: "cause",
|
|
2863
|
+
fieldType: DYN,
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (fieldType) {
|
|
2868
|
+
const obj = lowerObjectReceiver();
|
|
2869
|
+
if (isJsSourceFile(ts.getSourceFileOfNode(receiverNode)) &&
|
|
2870
|
+
!fieldName.startsWith("#") &&
|
|
2871
|
+
[...lowerer.classes.values()].some((candidate) => lowerer.isSubclassOf(candidate.def.name, receiverType.className) &&
|
|
2872
|
+
(candidate.methods.has(`get:${fieldName}`) || candidate.methods.has(`set:${fieldName}`)))) {
|
|
2873
|
+
return {
|
|
2874
|
+
container: "dynamic",
|
|
2875
|
+
obj: lowerer.coerceToExpected(obj, DYN),
|
|
2876
|
+
field: fieldName,
|
|
2877
|
+
fieldType: DYN,
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
return {
|
|
2881
|
+
container: "class",
|
|
2882
|
+
obj,
|
|
2883
|
+
className: receiverType.className,
|
|
2884
|
+
field: fieldName,
|
|
2885
|
+
fieldType,
|
|
2886
|
+
};
|
|
2887
|
+
}
|
|
2888
|
+
// Accessor property: either half declared anywhere on the chain
|
|
2889
|
+
// makes the name an accessor target (fields and accessors share a
|
|
2890
|
+
// namespace — tsc rejects mixing them, so the halves agree on kind).
|
|
2891
|
+
const getF = lowerer.findMethodOn(info, `get:${fieldName}`);
|
|
2892
|
+
const setF = lowerer.findMethodOn(info, `set:${fieldName}`);
|
|
2893
|
+
if (getF || setF) {
|
|
2894
|
+
const obj = lowerObjectReceiver();
|
|
2895
|
+
return {
|
|
2896
|
+
container: "accessor",
|
|
2897
|
+
obj,
|
|
2898
|
+
className: receiverType.className,
|
|
2899
|
+
field: fieldName,
|
|
2900
|
+
fieldType: getF ? getF.sig.ret : setF.sig.params[0].type,
|
|
2901
|
+
};
|
|
2902
|
+
}
|
|
2903
|
+
if (info.decl && isJsSourceFile(ts.getSourceFileOfNode(info.decl))) {
|
|
2904
|
+
const property = lowerer.checker.getPropertyOfType(lowerer.checker.getTypeAtLocation(receiverNode), fieldName);
|
|
2905
|
+
if (property &&
|
|
2906
|
+
property.declarations.some((declaration) => ts.isPropertyAccessExpression(declaration) ||
|
|
2907
|
+
ts.isBinaryExpression(declaration) ||
|
|
2908
|
+
ts.isElementAccessExpression(declaration))) {
|
|
2909
|
+
return {
|
|
2910
|
+
container: "dynamic",
|
|
2911
|
+
obj: lowerer.coerceToExpected(lowerObjectReceiver(), DYN),
|
|
2912
|
+
field: fieldName,
|
|
2913
|
+
fieldType: DYN,
|
|
2914
|
+
};
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
return null;
|
|
2918
|
+
}
|
|
2919
|
+
/** Recognizes `obj.field` as an assignable field target: receiver is a
|
|
2920
|
+
* known class instance OR a record, and the member is a field or (class
|
|
2921
|
+
* receivers) a declared accessor property. Returns the pieces of a
|
|
2922
|
+
* fieldSet/recordSet/accessor-call (minus value/kind) or null. */
|
|
2923
|
+
export function fieldTarget(lowerer, access) {
|
|
2924
|
+
if (lowerer.cjsLocalModuleBindingOf(access.expression))
|
|
2925
|
+
return null;
|
|
2926
|
+
// `module.exports` / `module.id`: CommonJS module surface, never a field.
|
|
2927
|
+
if (isCjsModuleGlobal(lowerer, access.expression))
|
|
2928
|
+
return null;
|
|
2929
|
+
if (isCjsExportsIdentifier(lowerer, access.expression))
|
|
2930
|
+
return null;
|
|
2931
|
+
if (lowerer.chainBlocked(access))
|
|
2932
|
+
return null;
|
|
2933
|
+
if (access.name.text === "stackTraceLimit" &&
|
|
2934
|
+
lowerer.isStdlibGlobal(access.expression, "Error")) {
|
|
2935
|
+
return {
|
|
2936
|
+
container: "errorStackLimit",
|
|
2937
|
+
obj: { kind: "numLit", value: 0, type: F64, loc: locOf(access) },
|
|
2938
|
+
field: "stackTraceLimit",
|
|
2939
|
+
fieldType: F64,
|
|
2940
|
+
};
|
|
2941
|
+
}
|
|
2942
|
+
// `this.#x` in a function-local class's prototype method: the field of
|
|
2943
|
+
// the brand-checked receiver (checkedPrivateReceiver).
|
|
2944
|
+
if (ts.isPrivateIdentifier(access.name) &&
|
|
2945
|
+
access.expression.kind === ts.SyntaxKind.ThisKeyword &&
|
|
2946
|
+
lowerer.resolveThis()?.type.kind === "dyn") {
|
|
2947
|
+
const owner = localPrivateBrandClass(lowerer, access.name);
|
|
2948
|
+
if (owner) {
|
|
2949
|
+
const ownerType = {
|
|
2950
|
+
kind: "object",
|
|
2951
|
+
className: owner.info.def.name,
|
|
2952
|
+
};
|
|
2953
|
+
return classFieldTarget(lowerer, access.expression, ownerType, access.name.text);
|
|
2954
|
+
}
|
|
2955
|
+
}
|
|
2956
|
+
const stored = ts.isIdentifier(access.expression)
|
|
2957
|
+
? (lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type)
|
|
2958
|
+
: undefined;
|
|
2959
|
+
const narrowed = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
2960
|
+
// Structural record views retain their storage layout, while a nominal
|
|
2961
|
+
// subclass guard proves a more specific layout of the same object.
|
|
2962
|
+
const receiverIr = stored?.kind === "record"
|
|
2963
|
+
? stored
|
|
2964
|
+
: stored?.kind === "object" &&
|
|
2965
|
+
!(narrowed?.kind === "object" &&
|
|
2966
|
+
lowerer.isSubclassOf(narrowed.className, stored.className))
|
|
2967
|
+
? stored
|
|
2968
|
+
: narrowed;
|
|
2969
|
+
if (receiverIr?.kind === "object") {
|
|
2970
|
+
const target = classFieldTarget(lowerer, access.expression, receiverIr, access.name.text);
|
|
2971
|
+
if (target)
|
|
2972
|
+
return target;
|
|
2973
|
+
// Abstract properties declare no base storage. Resolve the concrete
|
|
2974
|
+
// instance's live field or accessor through the existing class bridge;
|
|
2975
|
+
// inventing a shared field offset would misread subclass layouts.
|
|
2976
|
+
if (abstractPropertyDeclOf(lowerer, access)) {
|
|
2977
|
+
return {
|
|
2978
|
+
container: "dynamic",
|
|
2979
|
+
obj: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN),
|
|
2980
|
+
field: access.name.text,
|
|
2981
|
+
fieldType: lowerer.irTypeOf(access),
|
|
2982
|
+
};
|
|
2983
|
+
}
|
|
2984
|
+
return null;
|
|
2985
|
+
}
|
|
2986
|
+
if (receiverIr?.kind === "union" && hasClassPayload(lowerer, receiverIr)) {
|
|
2987
|
+
return representedClassFieldTarget(lowerer, access.expression, access.name.text, lowerer.lowerExpr(access.expression));
|
|
2988
|
+
}
|
|
2989
|
+
if (receiverIr?.kind === "record") {
|
|
2990
|
+
const shape = lowerer.shapes.get(receiverIr.shapeId);
|
|
2991
|
+
const fieldType = shape?.fields.find((f) => f.name === access.name.text)?.type;
|
|
2992
|
+
if (fieldType) {
|
|
2993
|
+
let obj = lowerer.lowerExpr(access.expression);
|
|
2994
|
+
const nominal = representedClassFieldTarget(lowerer, access.expression, access.name.text, obj);
|
|
2995
|
+
if (nominal)
|
|
2996
|
+
return nominal;
|
|
2997
|
+
// A checker-record receiver whose VALUE stayed dyn (the erased
|
|
2998
|
+
// all-unknown-fields cast — `(err as { code?: unknown }).code`):
|
|
2999
|
+
// decline, and the dyn keyed-read fallback answers.
|
|
3000
|
+
if (obj.type.kind === "union" && lowerer.armTag(obj.type.unionId, UNDEFINED_T) >= 0) {
|
|
3001
|
+
// A nested property read such as `rows[i].value` or
|
|
3002
|
+
// `table[k].value`: the outer read can miss. Validate the record
|
|
3003
|
+
// arm before fieldGet/recordGet so a missing outer value raises
|
|
3004
|
+
// Node's TypeError rather than reaching the backend with a union
|
|
3005
|
+
// receiver.
|
|
3006
|
+
const present = lowerer.stripUndefinedArm(obj.type);
|
|
3007
|
+
const parent = access.parent;
|
|
3008
|
+
const written = parent !== undefined &&
|
|
3009
|
+
ts.isBinaryExpression(parent) &&
|
|
3010
|
+
parent.left === access &&
|
|
3011
|
+
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken;
|
|
3012
|
+
const helper = present.kind === "record"
|
|
3013
|
+
? lowerer.narrowedArmHelper(obj.type.unionId, present, locOf(access.expression))
|
|
3014
|
+
: null;
|
|
3015
|
+
obj =
|
|
3016
|
+
(present.kind === "record"
|
|
3017
|
+
? lowerer.runtimeOptionalPropertyReceiver(access.expression, obj, present, access.name.text, written ? "set" : "read")
|
|
3018
|
+
: null) ??
|
|
3019
|
+
(helper
|
|
3020
|
+
? lowerer.checkedNarrowCall(helper, obj, present, locOf(access.expression))
|
|
3021
|
+
: lowerer.maybeNarrow(obj, access.expression));
|
|
3022
|
+
}
|
|
3023
|
+
if (obj.type.kind !== "record")
|
|
3024
|
+
return null;
|
|
3025
|
+
const actualShape = lowerer.shapes.get(obj.type.shapeId);
|
|
3026
|
+
const actualField = actualShape?.fields.find((f) => f.name === access.name.text);
|
|
3027
|
+
return {
|
|
3028
|
+
container: "record",
|
|
3029
|
+
obj,
|
|
3030
|
+
shapeId: obj.type.shapeId,
|
|
3031
|
+
field: access.name.text,
|
|
3032
|
+
fieldType: actualField?.type ?? fieldType,
|
|
3033
|
+
};
|
|
3034
|
+
}
|
|
3035
|
+
// A RECORD accessor property: either slot present makes the name an
|
|
3036
|
+
// accessor target (get/set share the property namespace — tsc
|
|
3037
|
+
// rejects mixing an accessor with a data property, so the halves
|
|
3038
|
+
// agree). Reads dispatch the %get: closure, writes the %set: one.
|
|
3039
|
+
{
|
|
3040
|
+
const getSlot = shape?.fields.find((f) => f.name === `%get:${access.name.text}`)?.type;
|
|
3041
|
+
const setSlot = shape?.fields.find((f) => f.name === `%set:${access.name.text}`)?.type;
|
|
3042
|
+
if (getSlot?.kind === "func" || setSlot?.kind === "func") {
|
|
3043
|
+
const obj = lowerer.lowerExpr(access.expression);
|
|
3044
|
+
if (obj.type.kind !== "record")
|
|
3045
|
+
return null; // dyn-valued receiver: the keyed fallback answers
|
|
3046
|
+
const getType = getSlot?.kind === "func" ? getSlot : undefined;
|
|
3047
|
+
const setType = setSlot?.kind === "func" ? setSlot : undefined;
|
|
3048
|
+
return {
|
|
3049
|
+
container: "recordAccessor",
|
|
3050
|
+
obj,
|
|
3051
|
+
shapeId: receiverIr.shapeId,
|
|
3052
|
+
field: access.name.text,
|
|
3053
|
+
fieldType: getType ? getType.ret : setType.params[0],
|
|
3054
|
+
...(getType ? { getType } : {}),
|
|
3055
|
+
...(setType ? { setType } : {}),
|
|
3056
|
+
};
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
// Dot access to an UNDECLARED key of an index-signature shape: tsc
|
|
3060
|
+
// types it through the signature — the access resolves to NO property
|
|
3061
|
+
// symbol (mapped types like Record<string, T>) or to the signature's
|
|
3062
|
+
// own `__index` symbol (interface-declared signatures). A real member
|
|
3063
|
+
// symbol means a lib member like `toString` — not an index access;
|
|
3064
|
+
// those keep their fences below. It IS the bracket access in dot
|
|
3065
|
+
// spelling — the same overflow path.
|
|
3066
|
+
const nameSym = lowerer.checker.getSymbolAtLocation(access.name);
|
|
3067
|
+
if (shape?.indexValue && !shape.tuple) {
|
|
3068
|
+
// A member the shape CANONICALIZATION dropped into the overflow
|
|
3069
|
+
// (the header family: @types declares `host?: string` on
|
|
3070
|
+
// IncomingHttpHeaders while the canonical shape is a pure index
|
|
3071
|
+
// record) is the bracket access in dot spelling too: a PROPERTY
|
|
3072
|
+
// declaration whose own type fits within the index value. METHOD
|
|
3073
|
+
// members (`toString` — the lib's inherited surface) keep their
|
|
3074
|
+
// fences: JS finds the prototype function, never an overflow miss.
|
|
3075
|
+
const canonicalized = () => {
|
|
3076
|
+
if (!nameSym)
|
|
3077
|
+
return false;
|
|
3078
|
+
const nameDecls = nameSym.declarations;
|
|
3079
|
+
if (!nameDecls.length)
|
|
3080
|
+
return false;
|
|
3081
|
+
if (!nameDecls.every((d) => ts.isPropertySignature(d)))
|
|
3082
|
+
return false;
|
|
3083
|
+
const declared = lowerer.mapTypeOf(lowerer.typeOf(access));
|
|
3084
|
+
if (!declared)
|
|
3085
|
+
return false;
|
|
3086
|
+
const iv = shape.indexValue;
|
|
3087
|
+
if (typeEquals(declared, iv))
|
|
3088
|
+
return true;
|
|
3089
|
+
if (iv.kind !== "union")
|
|
3090
|
+
return false;
|
|
3091
|
+
const ivArms = lowerer.unions.get(iv.unionId)?.arms;
|
|
3092
|
+
if (!ivArms)
|
|
3093
|
+
return false;
|
|
3094
|
+
const declaredArms = declared.kind === "union"
|
|
3095
|
+
? (lowerer.unions.get(declared.unionId)?.arms ?? [declared])
|
|
3096
|
+
: [declared];
|
|
3097
|
+
return declaredArms.every((a) => ivArms.some((b) => typeEquals(a, b)));
|
|
3098
|
+
};
|
|
3099
|
+
if (!nameSym || ts.symbolName(nameSym) === ts.InternalSymbolName.Index || canonicalized()) {
|
|
3100
|
+
let obj = lowerer.lowerExpr(access.expression);
|
|
3101
|
+
if (obj.type.kind === "union" && lowerer.armTag(obj.type.unionId, UNDEFINED_T) >= 0) {
|
|
3102
|
+
const present = lowerer.stripUndefinedArm(obj.type);
|
|
3103
|
+
obj =
|
|
3104
|
+
present.kind === "record"
|
|
3105
|
+
? (lowerer.runtimeOptionalPropertyReceiver(access.expression, obj, present, access.name.text) ?? obj)
|
|
3106
|
+
: lowerer.maybeNarrow(obj, access.expression);
|
|
3107
|
+
}
|
|
3108
|
+
if (obj.type.kind !== "record")
|
|
3109
|
+
return null;
|
|
3110
|
+
const actualShape = lowerer.shapes.get(obj.type.shapeId);
|
|
3111
|
+
if (!actualShape?.indexValue)
|
|
3112
|
+
return null;
|
|
3113
|
+
return {
|
|
3114
|
+
container: "recordOvf",
|
|
3115
|
+
obj,
|
|
3116
|
+
shapeId: obj.type.shapeId,
|
|
3117
|
+
field: access.name.text,
|
|
3118
|
+
fieldType: actualShape.indexValue,
|
|
3119
|
+
};
|
|
3120
|
+
}
|
|
3121
|
+
}
|
|
3122
|
+
return null;
|
|
3123
|
+
}
|
|
3124
|
+
return null;
|
|
3125
|
+
}
|
|
3126
|
+
/** The read expression for a field target (fieldGet / recordGet /
|
|
3127
|
+
* getter call). `blame` locates the rejection of a setter-only read —
|
|
3128
|
+
* tsc-clean (the property types as the setter's param), but Node yields
|
|
3129
|
+
* undefined, which these property types cannot represent. */
|
|
3130
|
+
export function fieldGetExpr(lowerer, target, loc, blame) {
|
|
3131
|
+
// A member read through an unassigned deferred-init field throws Node's
|
|
3132
|
+
// member-read TypeError instead of the generic checked extraction.
|
|
3133
|
+
if (target.container === "class" &&
|
|
3134
|
+
ts.isPropertyAccessExpression(blame) &&
|
|
3135
|
+
target.obj.type.kind === "object" &&
|
|
3136
|
+
lowerer.deferredFieldSlot(target.obj) !== null) {
|
|
3137
|
+
const checked = lowerer.runtimeOptionalPropertyReceiver(blame.expression, target.obj, target.obj.type, target.field);
|
|
3138
|
+
if (checked)
|
|
3139
|
+
target = { ...target, obj: checked };
|
|
3140
|
+
}
|
|
3141
|
+
if (target.container === "recordKeyed")
|
|
3142
|
+
return keyedFieldRead(lowerer, target, loc);
|
|
3143
|
+
if (target.container === "dynamic")
|
|
3144
|
+
return lowerer.coerceInto(blame, {
|
|
3145
|
+
kind: "dynKeyGet",
|
|
3146
|
+
value: target.obj,
|
|
3147
|
+
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
3148
|
+
type: DYN,
|
|
3149
|
+
loc,
|
|
3150
|
+
}, target.fieldType);
|
|
3151
|
+
if (target.container === "class" &&
|
|
3152
|
+
(target.field === "message" || target.field === "name") &&
|
|
3153
|
+
(target.className === "%Error" || lowerer.isSubclassOf(target.className, "%Error")))
|
|
3154
|
+
return errorPropertyRead(lowerer, target.obj, target.field);
|
|
3155
|
+
if (target.container === "errorStackLimit") {
|
|
3156
|
+
return { kind: "libCall", fn: "error.stackLimitGet", args: [], type: F64, loc };
|
|
3157
|
+
}
|
|
3158
|
+
if (target.container === "errorCause") {
|
|
3159
|
+
return { kind: "libCall", fn: "error.cause", args: [target.obj], type: DYN, loc };
|
|
3160
|
+
}
|
|
3161
|
+
// A record-shaped CHECKER target whose receiver VALUE lives in the checked-dynamic tree
|
|
3162
|
+
// (a JS file-scope object-literal global): the checked-dynamic keyed
|
|
3163
|
+
// read — dynKeyGet (a missing key answers the dyn undefined, exactly
|
|
3164
|
+
// JS); consumers validate (dynCheck) where a static type is required.
|
|
3165
|
+
if ((target.container === "record" || target.container === "recordOvf") &&
|
|
3166
|
+
target.obj.type.kind === "dyn") {
|
|
3167
|
+
return {
|
|
3168
|
+
kind: "dynKeyGet",
|
|
3169
|
+
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
3170
|
+
value: target.obj,
|
|
3171
|
+
type: DYN,
|
|
3172
|
+
loc,
|
|
3173
|
+
};
|
|
3174
|
+
}
|
|
3175
|
+
if (target.container === "accessor") {
|
|
3176
|
+
const getF = lowerer.findMethodOn(lowerer.classes.get(target.className) ?? null, `get:${target.field}`);
|
|
3177
|
+
if (!getF) {
|
|
3178
|
+
lowerer.unsupported("SC1090", blame, `reading a property that has only a setter ('${target.field}' — Node would yield undefined)`);
|
|
3179
|
+
}
|
|
3180
|
+
if (!target.field.startsWith("#") &&
|
|
3181
|
+
isJsSourceFile(ts.getSourceFileOfNode(blame)) &&
|
|
3182
|
+
lowerer.dynConvertible(getF.sig.ret)) {
|
|
3183
|
+
const value = {
|
|
3184
|
+
kind: "dynKeyGet",
|
|
3185
|
+
value: lowerer.coerceToExpected(target.obj, DYN),
|
|
3186
|
+
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
3187
|
+
type: DYN,
|
|
3188
|
+
loc,
|
|
3189
|
+
};
|
|
3190
|
+
return lowerer.coerceToExpected(value, getF.sig.ret);
|
|
3191
|
+
}
|
|
3192
|
+
return lowerer.accessorCall(target.className, `get:${target.field}`, target.obj, [], getF.sig.ret, loc);
|
|
3193
|
+
}
|
|
3194
|
+
// Record accessor properties: the read IS a call of the %get: closure
|
|
3195
|
+
// — once per read, side effects and all (JS's evaluation). The
|
|
3196
|
+
// setter-only read keeps the class-path fence: the property types as
|
|
3197
|
+
// the setter's param where Node yields undefined.
|
|
3198
|
+
if (target.container === "recordAccessor") {
|
|
3199
|
+
if (!target.getType) {
|
|
3200
|
+
lowerer.unsupported("SC1090", blame, `reading a property that has only a setter ('${target.field}' — Node would yield undefined)`);
|
|
3201
|
+
}
|
|
3202
|
+
const closure = {
|
|
3203
|
+
kind: "recordGet",
|
|
3204
|
+
obj: target.obj,
|
|
3205
|
+
shapeId: target.shapeId,
|
|
3206
|
+
field: `%get:${target.field}`,
|
|
3207
|
+
type: target.getType,
|
|
3208
|
+
loc,
|
|
3209
|
+
};
|
|
3210
|
+
return { kind: "callValue", callee: closure, args: [], type: target.getType.ret, loc };
|
|
3211
|
+
}
|
|
3212
|
+
// Overflow dot reads: exactly the bracket read with a literal key —
|
|
3213
|
+
// recordKeyGet, overflowOnly (the name declares no field by
|
|
3214
|
+
// construction), typed as the index value armed with undefined
|
|
3215
|
+
// (mirroring lowerRecordKeyRead).
|
|
3216
|
+
if (target.container === "recordOvf") {
|
|
3217
|
+
let obj = target.obj;
|
|
3218
|
+
if (obj.type.kind === "union" && ts.isPropertyAccessExpression(blame)) {
|
|
3219
|
+
const present = lowerer.stripUndefinedArm(obj.type);
|
|
3220
|
+
if (present.kind === "record") {
|
|
3221
|
+
obj =
|
|
3222
|
+
lowerer.runtimeOptionalPropertyReceiver(blame.expression, obj, present, target.field) ??
|
|
3223
|
+
obj;
|
|
3224
|
+
}
|
|
3225
|
+
}
|
|
3226
|
+
if (obj.type.kind !== "record") {
|
|
3227
|
+
lowerer.unsupported("SC1090", blame, `reading '${target.field}' on a non-record receiver (narrow first)`);
|
|
3228
|
+
}
|
|
3229
|
+
const shape = lowerer.shapes.get(obj.type.shapeId);
|
|
3230
|
+
if (!shape?.indexValue)
|
|
3231
|
+
lowerer.unsupported("SC1090", blame, `reading '${target.field}' on a record without an index signature`);
|
|
3232
|
+
let t = shape.indexValue;
|
|
3233
|
+
if (t.kind !== "dyn") {
|
|
3234
|
+
const armed = lowerer.withUndefinedArmOf(t);
|
|
3235
|
+
if (!armed)
|
|
3236
|
+
lowerer.badType(blame, lowerer.typeOf(blame));
|
|
3237
|
+
t = armed;
|
|
3238
|
+
}
|
|
3239
|
+
return {
|
|
3240
|
+
kind: "recordKeyGet",
|
|
3241
|
+
obj,
|
|
3242
|
+
shapeId: obj.type.shapeId,
|
|
3243
|
+
key: { kind: "strLit", value: target.field, type: STRING, loc },
|
|
3244
|
+
overflowOnly: true,
|
|
3245
|
+
type: t,
|
|
3246
|
+
loc,
|
|
3247
|
+
};
|
|
3248
|
+
}
|
|
3249
|
+
if (target.container === "class") {
|
|
3250
|
+
const read = {
|
|
3251
|
+
kind: "fieldGet",
|
|
3252
|
+
obj: target.obj,
|
|
3253
|
+
className: target.className,
|
|
3254
|
+
field: target.field,
|
|
3255
|
+
type: target.fieldType,
|
|
3256
|
+
loc,
|
|
3257
|
+
};
|
|
3258
|
+
// DEFERRED-INIT fields (`stream!: T` assigned past the constructor's
|
|
3259
|
+
// top level — ClassInfo.deferredInitFields): the SLOT is the
|
|
3260
|
+
// undefined-armed union; the read CHECKED-extracts the declared type
|
|
3261
|
+
// — a genuinely unassigned read throws the catchable TypeError
|
|
3262
|
+
// where Node reads an undefined the declared type cannot hold.
|
|
3263
|
+
if (lowerer.classes.get(target.className)?.deferredInitFields?.has(target.field) === true &&
|
|
3264
|
+
target.fieldType.kind === "union") {
|
|
3265
|
+
const inner = lowerer.stripUndefinedArm(target.fieldType);
|
|
3266
|
+
// Reference arms over a stable receiver check inline: the present
|
|
3267
|
+
// arm is a plain projection of the slot, so ordinary reads keep their
|
|
3268
|
+
// borrowed form and only an unassigned slot reaches the throw.
|
|
3269
|
+
const unionId = target.fieldType.unionId;
|
|
3270
|
+
const presentTag = lowerer.armTag(unionId, inner);
|
|
3271
|
+
const undefTag = lowerer.armTag(unionId, UNDEFINED_T);
|
|
3272
|
+
if (inner.kind === "object" &&
|
|
3273
|
+
presentTag >= 0 &&
|
|
3274
|
+
undefTag >= 0 &&
|
|
3275
|
+
lowerer.unions.get(unionId)?.arms.length === 2 &&
|
|
3276
|
+
isSafeToRepeat(read)) {
|
|
3277
|
+
return {
|
|
3278
|
+
kind: "ternary",
|
|
3279
|
+
cond: {
|
|
3280
|
+
kind: "unionIsTag",
|
|
3281
|
+
unionId,
|
|
3282
|
+
tag: undefTag,
|
|
3283
|
+
negated: false,
|
|
3284
|
+
value: read,
|
|
3285
|
+
type: BOOL,
|
|
3286
|
+
loc,
|
|
3287
|
+
},
|
|
3288
|
+
then: nodeThrowExpr(1, "", DEFERRED_READ_MESSAGE, inner, loc),
|
|
3289
|
+
else_: { kind: "unionNarrow", unionId, tag: presentTag, value: read, type: inner, loc },
|
|
3290
|
+
type: inner,
|
|
3291
|
+
loc,
|
|
3292
|
+
};
|
|
3293
|
+
}
|
|
3294
|
+
const helper = lowerer.deferredReadHelper(target.fieldType.unionId, inner, loc);
|
|
3295
|
+
if (helper)
|
|
3296
|
+
return { kind: "call", callee: helper, args: [read], type: inner, loc };
|
|
3297
|
+
}
|
|
3298
|
+
return read;
|
|
3299
|
+
}
|
|
3300
|
+
return {
|
|
3301
|
+
kind: "recordGet",
|
|
3302
|
+
obj: target.obj,
|
|
3303
|
+
shapeId: target.shapeId,
|
|
3304
|
+
field: target.field,
|
|
3305
|
+
type: target.fieldType,
|
|
3306
|
+
loc,
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3309
|
+
/** Stream-rooted receivers' property surface (readableEnded, destroyed,
|
|
3310
|
+
* ...): the receiver's mapped class dispatches into lower-stream.ts.
|
|
3311
|
+
* Null off the stream hierarchy or for names the spoke does not own. */
|
|
3312
|
+
function lowerStreamObjectProperty(lowerer, expr) {
|
|
3313
|
+
if (expr.questionDotToken && !lowerer.chainHandled.has(expr))
|
|
3314
|
+
return null;
|
|
3315
|
+
const recvT = lowerer.mapTypeOf(lowerer.typeOf(expr.expression));
|
|
3316
|
+
if (recvT?.kind !== "object")
|
|
3317
|
+
return null;
|
|
3318
|
+
const info = lowerer.classes.get(recvT.className);
|
|
3319
|
+
if (!info || streamSidesOf(lowerer, info) === null)
|
|
3320
|
+
return null;
|
|
3321
|
+
if (expr.name.text === "bytesWritten" && isZlibStreamMember(lowerer, expr)) {
|
|
3322
|
+
return lowerZlibStreamBytesWritten(lowerer, expr);
|
|
3323
|
+
}
|
|
3324
|
+
if (isFsStreamMember(lowerer, expr)) {
|
|
3325
|
+
const member = lowerFsStreamProperty(lowerer, expr);
|
|
3326
|
+
if (member)
|
|
3327
|
+
return member;
|
|
3328
|
+
}
|
|
3329
|
+
return lowerStreamProperty(lowerer, expr, info);
|
|
3330
|
+
}
|
|
3331
|
+
/** The builtin constructors JavaScript sources read as real function
|
|
3332
|
+
* values rather than identity tokens: the runtime interns one function per
|
|
3333
|
+
* constructor, and dynamic values answer `.constructor` with the same one,
|
|
3334
|
+
* so `o.constructor === Object` is an exact identity test. */
|
|
3335
|
+
const GLOBAL_CONSTRUCTOR_VALUES = new Set([
|
|
3336
|
+
"Object",
|
|
3337
|
+
"Function",
|
|
3338
|
+
"Date",
|
|
3339
|
+
"RegExp",
|
|
3340
|
+
"Map",
|
|
3341
|
+
"Set",
|
|
3342
|
+
"Promise",
|
|
3343
|
+
"WeakMap",
|
|
3344
|
+
"WeakSet",
|
|
3345
|
+
]);
|
|
3346
|
+
/** The builtin global functions JavaScript sources read as interned
|
|
3347
|
+
* function values (the `cond ? setImmediate : process.nextTick` feature
|
|
3348
|
+
* probe of bcryptjs and async libraries): typeof answers "function",
|
|
3349
|
+
* identity holds across spellings, and calls run the timer APIs. */
|
|
3350
|
+
const GLOBAL_FUNCTION_VALUES = new Set([
|
|
3351
|
+
"setTimeout",
|
|
3352
|
+
"setInterval",
|
|
3353
|
+
"setImmediate",
|
|
3354
|
+
"clearTimeout",
|
|
3355
|
+
"clearInterval",
|
|
3356
|
+
"clearImmediate",
|
|
3357
|
+
"queueMicrotask",
|
|
3358
|
+
]);
|
|
3359
|
+
/** A builtin function value: one interned runtime function per name. */
|
|
3360
|
+
export function builtinFunctionValue(name, loc) {
|
|
3361
|
+
return {
|
|
3362
|
+
kind: "libCall",
|
|
3363
|
+
fn: "dyn.builtinFunction",
|
|
3364
|
+
args: [{ kind: "strLit", value: name, type: STRING, loc }],
|
|
3365
|
+
type: DYN,
|
|
3366
|
+
loc,
|
|
3367
|
+
};
|
|
3368
|
+
}
|
|
3369
|
+
/** The value a source reads for the stdlib global `canonical` (builtin
|
|
3370
|
+
* constructors in both languages, builtin functions in JavaScript), or
|
|
3371
|
+
* null when it stays an identity token (JavaScript) or fenced. */
|
|
3372
|
+
export function builtinGlobalValue(canonical, loc, js = false) {
|
|
3373
|
+
if (js && GLOBAL_FUNCTION_VALUES.has(canonical))
|
|
3374
|
+
return builtinFunctionValue(canonical, loc);
|
|
3375
|
+
if (GLOBAL_CONSTRUCTOR_VALUES.has(canonical)) {
|
|
3376
|
+
return {
|
|
3377
|
+
kind: "libCall",
|
|
3378
|
+
fn: "dyn.globalConstructor",
|
|
3379
|
+
args: [{ kind: "strLit", value: canonical, type: STRING, loc }],
|
|
3380
|
+
type: DYN,
|
|
3381
|
+
loc,
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
return null;
|
|
3385
|
+
}
|
|
3386
|
+
/** The members the interned builtin function values model (the runtime
|
|
3387
|
+
* answers each one as Node does); any other member read through them would
|
|
3388
|
+
* answer undefined, so it keeps its static lowering or its fence. */
|
|
3389
|
+
const BUILTIN_VALUE_MEMBERS = new Set(["name", "length", "constructor"]);
|
|
3390
|
+
/** The Object statics whose answers for an interned builtin function value
|
|
3391
|
+
* match Node's (identity, and the empty enumerable own-key lists). */
|
|
3392
|
+
const BUILTIN_VALUE_REFLECTION = new Set(["is", "keys", "values", "entries"]);
|
|
3393
|
+
/** The value `builtinGlobalValue` gives the stdlib global `expr` read at its
|
|
3394
|
+
* use site: null when the use reads the global's members (they keep their
|
|
3395
|
+
* lowerings and fences), and SC2020 when it is the target of reflection or
|
|
3396
|
+
* redefinition (`Object.hasOwn(Object, "hasOwn")`,
|
|
3397
|
+
* `Object.defineProperty(Promise, ...)`, `hasOwnProperty.call(Map, ...)`),
|
|
3398
|
+
* which would observe or change members the interned value does not
|
|
3399
|
+
* model. */
|
|
3400
|
+
export function builtinGlobalValueAt(lowerer, expr, canonical, loc, js) {
|
|
3401
|
+
if (readsBuiltinGlobalMembers(expr))
|
|
3402
|
+
return null;
|
|
3403
|
+
const value = builtinGlobalValue(canonical, loc, js);
|
|
3404
|
+
if (value === null)
|
|
3405
|
+
return null;
|
|
3406
|
+
let node = expr;
|
|
3407
|
+
while (node.parent !== undefined && ts.isParenthesizedExpression(node.parent))
|
|
3408
|
+
node = node.parent;
|
|
3409
|
+
const call = node.parent;
|
|
3410
|
+
if (call !== undefined &&
|
|
3411
|
+
ts.isCallExpression(call) &&
|
|
3412
|
+
call.expression !== node &&
|
|
3413
|
+
ts.isPropertyAccessExpression(call.expression)) {
|
|
3414
|
+
const callee = call.expression;
|
|
3415
|
+
const owner = stdlibGlobalNameOf(lowerer, callee.expression);
|
|
3416
|
+
const reflects = owner === "Reflect" ||
|
|
3417
|
+
(owner === "Object" && !BUILTIN_VALUE_REFLECTION.has(callee.name.text)) ||
|
|
3418
|
+
((callee.name.text === "call" || callee.name.text === "apply") &&
|
|
3419
|
+
call.arguments.nodes[0] === node &&
|
|
3420
|
+
lowerer.isStdlibSymbol(lowerer.checker.getSymbolAtLocation(ts.isPropertyAccessExpression(callee.expression)
|
|
3421
|
+
? callee.expression.name
|
|
3422
|
+
: callee.expression)));
|
|
3423
|
+
if (reflects) {
|
|
3424
|
+
const name = owner !== null
|
|
3425
|
+
? `${owner}.${callee.name.text}`
|
|
3426
|
+
: ts.getTextOfNode(callee).replace(/\s+/g, "");
|
|
3427
|
+
lowerer.noLowering(`${name}(${canonical}, ...)`, expr, "builtin constructor and function values model only name, length and constructor, so reflecting on or redefining their members has no lowering");
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
return value;
|
|
3431
|
+
}
|
|
3432
|
+
/** Whether the stdlib global `expr` is read for its members (`Map.prototype`,
|
|
3433
|
+
* `Date["UTC"]`, `"prototype" in Map`) rather than as a value. Those reads
|
|
3434
|
+
* keep the global's member lowerings and fences: its interned function value
|
|
3435
|
+
* models only BUILTIN_VALUE_MEMBERS. */
|
|
3436
|
+
function readsBuiltinGlobalMembers(expr) {
|
|
3437
|
+
let node = expr;
|
|
3438
|
+
while (node.parent !== undefined && ts.isParenthesizedExpression(node.parent))
|
|
3439
|
+
node = node.parent;
|
|
3440
|
+
const parent = node.parent;
|
|
3441
|
+
if (parent === undefined)
|
|
3442
|
+
return false;
|
|
3443
|
+
if (ts.isPropertyAccessExpression(parent) && parent.expression === node)
|
|
3444
|
+
return !BUILTIN_VALUE_MEMBERS.has(parent.name.text);
|
|
3445
|
+
if (ts.isElementAccessExpression(parent) && parent.expression === node)
|
|
3446
|
+
return true;
|
|
3447
|
+
return (ts.isBinaryExpression(parent) &&
|
|
3448
|
+
parent.operatorToken.kind === ts.SyntaxKind.InKeyword &&
|
|
3449
|
+
parent.right === node);
|
|
3450
|
+
}
|
|
3451
|
+
/** Reports SC2020 when `access` reads a stdlib static member or the
|
|
3452
|
+
* prototype of a builtin constructor with an interned function value through
|
|
3453
|
+
* a receiver the checker types as the constructor's static side
|
|
3454
|
+
* (`MapConstructor`); null otherwise. Calls that lower statically never
|
|
3455
|
+
* reach the member read. */
|
|
3456
|
+
function fenceBuiltinConstructorStaticRead(lowerer, access) {
|
|
3457
|
+
if (BUILTIN_VALUE_MEMBERS.has(access.name.text))
|
|
3458
|
+
return null;
|
|
3459
|
+
const symbol = lowerer.typeOf(access.expression).getSymbol();
|
|
3460
|
+
if (symbol !== undefined &&
|
|
3461
|
+
ts.symbolName(symbol).endsWith("Constructor") &&
|
|
3462
|
+
GLOBAL_CONSTRUCTOR_VALUES.has(ts.symbolName(symbol).slice(0, -"Constructor".length)) &&
|
|
3463
|
+
lowerer.isStdlibSymbol(symbol))
|
|
3464
|
+
lowerer.stdlibMemberFence(access);
|
|
3465
|
+
return null;
|
|
3466
|
+
}
|
|
3467
|
+
/** Object.prototype members a plain record inherits, read as values. */
|
|
3468
|
+
const OBJECT_PROTOTYPE_VALUE_READS = new Set([
|
|
3469
|
+
"constructor",
|
|
3470
|
+
"valueOf",
|
|
3471
|
+
"toString",
|
|
3472
|
+
"hasOwnProperty",
|
|
3473
|
+
"propertyIsEnumerable",
|
|
3474
|
+
]);
|
|
3475
|
+
/** Whether `expr` is the callee of a call (`o.toString()`), which keeps its
|
|
3476
|
+
* call lowering rather than reading the member as a value. */
|
|
3477
|
+
function isCalleeOf(expr) {
|
|
3478
|
+
let node = expr;
|
|
3479
|
+
while (node.parent !== undefined && ts.isParenthesizedExpression(node.parent))
|
|
3480
|
+
node = node.parent;
|
|
3481
|
+
const parent = node.parent;
|
|
3482
|
+
return (parent !== undefined &&
|
|
3483
|
+
(ts.isCallExpression(parent) || ts.isNewExpression(parent)) &&
|
|
3484
|
+
parent.expression === node);
|
|
3485
|
+
}
|
|
3486
|
+
/** The constructor a primitive dynamic value answers for `.constructor`:
|
|
3487
|
+
* the same interned closure the `Number`/`String`/`Boolean`/`BigInt`
|
|
3488
|
+
* identifiers read (dequal's `(ctor = foo.constructor) === bar.constructor`
|
|
3489
|
+
* over numbers), or `otherwise` for non-primitives. `value` must be safe to
|
|
3490
|
+
* read repeatedly. */
|
|
3491
|
+
export function primitiveConstructorOr(lowerer, value, otherwise, loc) {
|
|
3492
|
+
let result = otherwise;
|
|
3493
|
+
for (const [test, name] of [
|
|
3494
|
+
["bigint", "BigInt"],
|
|
3495
|
+
["boolean", "Boolean"],
|
|
3496
|
+
["string", "String"],
|
|
3497
|
+
["number", "Number"],
|
|
3498
|
+
]) {
|
|
3499
|
+
result = {
|
|
3500
|
+
kind: "ternary",
|
|
3501
|
+
cond: { kind: "dynTest", test, value, type: BOOL, loc },
|
|
3502
|
+
then: {
|
|
3503
|
+
kind: "dynFrom",
|
|
3504
|
+
value: primitiveCtorClosure(lowerer, name, loc, true),
|
|
3505
|
+
type: DYN,
|
|
3506
|
+
loc,
|
|
3507
|
+
},
|
|
3508
|
+
else_: result,
|
|
3509
|
+
type: DYN,
|
|
3510
|
+
loc,
|
|
3511
|
+
};
|
|
3512
|
+
}
|
|
3513
|
+
return result;
|
|
3514
|
+
}
|
|
3515
|
+
/** True when `access` reads a member that JavaScript sources attach to a
|
|
3516
|
+
* function by assignment (`fn.member = value`): the receiver's type is
|
|
3517
|
+
* callable and every declaration of the member is such an assignment in a
|
|
3518
|
+
* JS file. */
|
|
3519
|
+
function jsFunctionExpandoMember(lowerer, access) {
|
|
3520
|
+
if (access.questionDotToken || !ts.isIdentifier(access.name))
|
|
3521
|
+
return false;
|
|
3522
|
+
const recvType = lowerer.typeOf(access.expression);
|
|
3523
|
+
if (lowerer.checker.getCallSignatures(recvType).length === 0)
|
|
3524
|
+
return false;
|
|
3525
|
+
const member = lowerer.checker.getPropertyOfType(recvType, access.name.text);
|
|
3526
|
+
const decls = member ? member.declarations : [];
|
|
3527
|
+
return (decls.length > 0 &&
|
|
3528
|
+
decls.every((d) => {
|
|
3529
|
+
if (!isJsSourceFile(ts.getSourceFileOfNode(d)))
|
|
3530
|
+
return false;
|
|
3531
|
+
const assign = ts.isBinaryExpression(d) ? d : d.parent;
|
|
3532
|
+
return (assign !== undefined &&
|
|
3533
|
+
ts.isBinaryExpression(assign) &&
|
|
3534
|
+
assign.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
3535
|
+
ts.isPropertyAccessExpression(assign.left));
|
|
3536
|
+
}));
|
|
3537
|
+
}
|
|
3538
|
+
/** Whether the checker declares `name` as a property of `receiver`'s type
|
|
3539
|
+
* (as opposed to reading it through an index signature). */
|
|
3540
|
+
export function declaredMemberOf(lowerer, receiver, name) {
|
|
3541
|
+
const symbol = lowerer.checker.getPropertyOfType(lowerer.typeOf(receiver), name);
|
|
3542
|
+
return !!symbol && symbol.declarations.length > 0;
|
|
3543
|
+
}
|
|
3544
|
+
//# sourceMappingURL=property-access.js.map
|