@scriptc/compiler 0.1.7 → 0.2.1
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 +98 -39
- package/ambient/scriptc-overrides.d.ts +10 -6
- package/ambient/scriptc.d.ts +15 -0
- package/dist/backend/build-cache.d.ts +1 -3
- package/dist/backend/build-cache.js +3 -22
- package/dist/backend/build-cache.js.map +1 -1
- package/dist/backend/cache-root.d.ts +3 -0
- package/dist/backend/cache-root.js +23 -0
- package/dist/backend/cache-root.js.map +1 -0
- package/dist/backend/cycle-analysis.d.ts +15 -0
- package/dist/backend/cycle-analysis.js +108 -0
- package/dist/backend/cycle-analysis.js.map +1 -0
- package/dist/backend/cycle-analysis.test.js +124 -0
- package/dist/backend/cycle-analysis.test.js.map +1 -0
- package/dist/backend/executable-features.d.ts +4 -0
- package/dist/backend/executable-features.js +42 -0
- package/dist/backend/executable-features.js.map +1 -0
- package/dist/backend/external-c.d.ts +5 -27
- package/dist/backend/external-c.js +5 -40
- package/dist/backend/external-c.js.map +1 -1
- package/dist/backend/ffi-callbacks.d.ts +2 -3
- package/dist/backend/ffi-callbacks.js +2 -3
- package/dist/backend/ffi-callbacks.js.map +1 -1
- package/dist/backend/library-identity-markers.d.ts +4 -9
- package/dist/backend/library-identity-markers.js +11 -49
- package/dist/backend/library-identity-markers.js.map +1 -1
- package/dist/backend/library-pack.d.ts +5 -0
- package/dist/backend/library-pack.js +123 -0
- package/dist/backend/library-pack.js.map +1 -0
- package/dist/backend/link-plan-core.d.ts +20 -0
- package/dist/backend/link-plan-core.js +18 -0
- package/dist/backend/link-plan-core.js.map +1 -0
- package/dist/backend/link-plan.d.ts +1 -1
- package/dist/backend/link-plan.js +16 -17
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/link-trace.d.ts +2 -0
- package/dist/backend/link-trace.js +24 -0
- package/dist/backend/link-trace.js.map +1 -0
- package/dist/backend/linker.js +1 -1
- package/dist/backend/linker.js.map +1 -1
- package/dist/backend/literals.d.ts +9 -0
- package/dist/backend/literals.js +35 -0
- package/dist/backend/literals.js.map +1 -0
- package/dist/backend/literals.test.d.ts +1 -0
- package/dist/backend/literals.test.js +53 -0
- package/dist/backend/literals.test.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +2 -0
- package/dist/backend/llvm/blocks.js +9 -4
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/blocks.test.d.ts +1 -0
- package/dist/backend/llvm/blocks.test.js +91 -0
- package/dist/backend/llvm/blocks.test.js.map +1 -0
- package/dist/backend/llvm/classes.d.ts +14 -8
- package/dist/backend/llvm/classes.js +88 -30
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +5 -1
- package/dist/backend/llvm/common.js +45 -4
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/debug-info.js +2 -7
- package/dist/backend/llvm/debug-info.js.map +1 -1
- package/dist/backend/llvm/debug-info.test.d.ts +1 -0
- package/dist/backend/llvm/debug-info.test.js +110 -0
- package/dist/backend/llvm/debug-info.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +21 -2
- package/dist/backend/llvm/dyn.js +647 -251
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +596 -1
- package/dist/backend/llvm/emitter.js +769 -425
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.d.ts +1 -0
- package/dist/backend/llvm/emitter.test.js +179 -0
- package/dist/backend/llvm/emitter.test.js.map +1 -0
- package/dist/backend/llvm/expr-async.js +23 -14
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.d.ts +2 -2
- package/dist/backend/llvm/expr-bytes.js +60 -31
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +1 -1
- package/dist/backend/llvm/expr-callbacks.js +25 -22
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +136 -35
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.d.ts +1 -1
- package/dist/backend/llvm/expr-containers.js +43 -14
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-context.d.ts +5 -260
- package/dist/backend/llvm/expr-control.js +10 -6
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.d.ts +1 -1
- package/dist/backend/llvm/expr-dispatch.js +2 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +78 -81
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-island.d.ts +1 -1
- package/dist/backend/llvm/expr-island.js +11 -7
- package/dist/backend/llvm/expr-island.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +62 -31
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.test.js +1 -1
- package/dist/backend/llvm/expr-records.d.ts +5 -1
- package/dist/backend/llvm/expr-records.js +54 -7
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.d.ts +4 -4
- package/dist/backend/llvm/expr-stream-bridges.js +220 -131
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.d.ts +1 -0
- package/dist/backend/llvm/expr-stream-bridges.test.js +55 -0
- package/dist/backend/llvm/expr-stream-bridges.test.js.map +1 -0
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +1 -1
- package/dist/backend/llvm/expr-stream-callbacks.js +12 -12
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -1
- package/dist/backend/llvm/layouts.d.ts +19 -0
- package/dist/backend/llvm/layouts.js +12 -0
- package/dist/backend/llvm/layouts.js.map +1 -0
- package/dist/backend/llvm/lib-abi.d.ts +19 -0
- package/dist/backend/llvm/lib-abi.js +82 -0
- package/dist/backend/llvm/lib-abi.js.map +1 -0
- package/dist/backend/llvm/lib-connect.d.ts +2 -0
- package/dist/backend/llvm/lib-connect.js +51 -0
- package/dist/backend/llvm/lib-connect.js.map +1 -0
- package/dist/backend/llvm/lib-datagram.d.ts +2 -0
- package/dist/backend/llvm/lib-datagram.js +135 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -0
- package/dist/backend/llvm/lib-dispatch.js +50 -6
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +30 -18
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-http2.d.ts +2 -0
- package/dist/backend/llvm/lib-http2.js +215 -0
- package/dist/backend/llvm/lib-http2.js.map +1 -0
- package/dist/backend/llvm/lib-lookup.d.ts +2 -0
- package/dist/backend/llvm/lib-lookup.js +39 -0
- package/dist/backend/llvm/lib-lookup.js.map +1 -0
- package/dist/backend/llvm/lib-network.js +25 -2
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +44 -19
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +162 -3
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-stream.js +3 -2
- package/dist/backend/llvm/lib-stream.js.map +1 -1
- package/dist/backend/llvm/lib-test.d.ts +2 -0
- package/dist/backend/llvm/lib-test.js +34 -0
- package/dist/backend/llvm/lib-test.js.map +1 -0
- package/dist/backend/llvm/lib-tls.d.ts +2 -0
- package/dist/backend/llvm/lib-tls.js +82 -0
- package/dist/backend/llvm/lib-tls.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +10 -9
- package/dist/backend/llvm/shapes.js +42 -131
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/unsupported.d.ts +1 -0
- package/dist/backend/llvm/unsupported.js +1 -2
- package/dist/backend/llvm/unsupported.js.map +1 -1
- package/dist/backend/llvm/walkers.js +1 -7
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/mangle.d.ts +2 -2
- package/dist/backend/mangle.js +16 -5
- package/dist/backend/mangle.js.map +1 -1
- package/dist/backend/{c/may-throw.d.ts → may-throw.d.ts} +1 -1
- package/dist/backend/{c/may-throw.js → may-throw.js} +51 -46
- package/dist/backend/may-throw.js.map +1 -0
- package/dist/backend/may-throw.test.d.ts +1 -0
- package/dist/backend/may-throw.test.js +58 -0
- package/dist/backend/may-throw.test.js.map +1 -0
- package/dist/backend/native-codegen-core.d.ts +22 -0
- package/dist/backend/native-codegen-core.js +44 -0
- package/dist/backend/native-codegen-core.js.map +1 -0
- package/dist/backend/native-codegen.d.ts +3 -19
- package/dist/backend/native-codegen.js +5 -44
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +2 -2
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +94 -0
- package/dist/backend/native-link-info-core.js +62 -0
- package/dist/backend/native-link-info-core.js.map +1 -0
- package/dist/backend/native-link-info.d.ts +3 -88
- package/dist/backend/native-link-info.js +12 -243
- package/dist/backend/native-link-info.js.map +1 -1
- package/dist/backend/native-link-info.test.js +41 -146
- package/dist/backend/native-link-info.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +12 -30
- package/dist/backend/native-toolchain.js +83 -233
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +77 -5
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/native-tools.d.ts +24 -0
- package/dist/backend/native-tools.js +33 -0
- package/dist/backend/native-tools.js.map +1 -0
- package/dist/backend/object-localize.js +19 -8
- package/dist/backend/object-localize.js.map +1 -1
- package/dist/backend/object-localize.test.js +22 -0
- package/dist/backend/object-localize.test.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +101 -0
- package/dist/backend/runtime-pack-core.js +172 -0
- package/dist/backend/runtime-pack-core.js.map +1 -0
- package/dist/backend/runtime-pack-native.d.ts +21 -0
- package/dist/backend/runtime-pack-native.js +73 -0
- package/dist/backend/runtime-pack-native.js.map +1 -0
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.d.ts +3 -83
- package/dist/backend/runtime-pack.js +8 -151
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +24 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.d.ts +22 -0
- package/dist/backend/target-diagnostics.js +108 -0
- package/dist/backend/target-diagnostics.js.map +1 -0
- package/dist/backend/target-platform.d.ts +15 -0
- package/dist/backend/target-platform.js +72 -0
- package/dist/backend/target-platform.js.map +1 -0
- package/dist/backend/targets.d.ts +13 -4
- package/dist/backend/targets.js +103 -34
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +72 -4
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/backend/toolchain-environment.d.ts +6 -0
- package/dist/backend/toolchain-environment.js +99 -0
- package/dist/backend/toolchain-environment.js.map +1 -0
- package/dist/backend/vendor-archives.d.ts +1 -9
- package/dist/backend/vendor-archives.js +2 -9
- package/dist/backend/vendor-archives.js.map +1 -1
- package/dist/backend/vendor-inputs.d.ts +9 -0
- package/dist/backend/vendor-inputs.js +10 -0
- package/dist/backend/vendor-inputs.js.map +1 -0
- package/dist/backend/warm-cache.d.ts +3 -0
- package/dist/backend/warm-cache.js +41 -0
- package/dist/backend/warm-cache.js.map +1 -0
- package/dist/cli/command.d.ts +3 -0
- package/dist/cli/command.js +328 -0
- package/dist/cli/command.js.map +1 -0
- package/dist/cli/host.d.ts +24 -0
- package/dist/cli/host.js +2 -0
- package/dist/cli/host.js.map +1 -0
- package/dist/cli/output-options.d.ts +26 -0
- package/dist/cli/output-options.js +60 -0
- package/dist/cli/output-options.js.map +1 -0
- package/dist/cli/paths.d.ts +12 -0
- package/dist/cli/paths.js +42 -0
- package/dist/cli/paths.js.map +1 -0
- package/dist/cli/usage.d.ts +74 -0
- package/dist/cli/usage.js +86 -0
- package/dist/cli/usage.js.map +1 -0
- package/dist/cli/wasi-paths.d.ts +8 -0
- package/dist/cli/wasi-paths.js +41 -0
- package/dist/cli/wasi-paths.js.map +1 -0
- package/dist/cli/wasi-runner.d.ts +2 -0
- package/dist/cli/wasi-runner.js +28 -0
- package/dist/cli/wasi-runner.js.map +1 -0
- package/dist/compat/fetch-profile.js +37 -7
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/compile-types.d.ts +162 -0
- package/dist/compile-types.js +2 -0
- package/dist/compile-types.js.map +1 -0
- package/dist/coverage/report.js +11 -5
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.js +5 -2
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.js +5 -10
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +3 -4
- package/dist/executable/executable-cache.js +5 -6
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +16 -17
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/executable/prepare.d.ts +14 -0
- package/dist/executable/prepare.js +66 -0
- package/dist/executable/prepare.js.map +1 -0
- package/dist/ffi/ffi-manifest.d.ts +11 -4
- package/dist/ffi/ffi-manifest.js +170 -58
- package/dist/ffi/ffi-manifest.js.map +1 -1
- package/dist/ffi/ffi-manifest.test.d.ts +1 -0
- package/dist/ffi/ffi-manifest.test.js +111 -0
- package/dist/ffi/ffi-manifest.test.js.map +1 -0
- package/dist/format-integer.d.ts +3 -0
- package/dist/format-integer.js +14 -0
- package/dist/format-integer.js.map +1 -0
- package/dist/frontend/analysis.d.ts +5 -0
- package/dist/frontend/analysis.js +88 -0
- package/dist/frontend/analysis.js.map +1 -0
- package/dist/frontend/arguments-usage.d.ts +1 -3
- package/dist/frontend/arguments-usage.js.map +1 -1
- package/dist/frontend/builtin-modules.d.ts +1 -1
- package/dist/frontend/builtin-modules.js +1 -1
- package/dist/frontend/builtin-modules.js.map +1 -1
- package/dist/frontend/cjs-lexer.d.ts +4 -25
- package/dist/frontend/cjs-lexer.js +6 -806
- package/dist/frontend/cjs-lexer.js.map +1 -1
- package/dist/frontend/cjs-resolve.d.ts +5 -0
- package/dist/frontend/cjs-resolve.js +429 -0
- package/dist/frontend/cjs-resolve.js.map +1 -0
- package/dist/frontend/cjs-syntax.d.ts +26 -0
- package/dist/frontend/cjs-syntax.js +806 -0
- package/dist/frontend/cjs-syntax.js.map +1 -0
- package/dist/frontend/comptime-node.d.ts +4 -0
- package/dist/frontend/comptime-node.js +16 -0
- package/dist/frontend/comptime-node.js.map +1 -0
- package/dist/frontend/comptime-node.test.d.ts +1 -0
- package/dist/frontend/comptime-node.test.js +37 -0
- package/dist/frontend/comptime-node.test.js.map +1 -0
- package/dist/frontend/dts-paths.d.ts +3 -4
- package/dist/frontend/dts-paths.js +15 -8
- package/dist/frontend/dts-paths.js.map +1 -1
- package/dist/frontend/fork-target.js +2 -2
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/helper-tokens.d.ts +1 -0
- package/dist/frontend/helper-tokens.js +147 -0
- package/dist/frontend/helper-tokens.js.map +1 -0
- package/dist/frontend/helper-tokens.test.d.ts +1 -0
- package/dist/frontend/helper-tokens.test.js +35 -0
- package/dist/frontend/helper-tokens.test.js.map +1 -0
- package/dist/frontend/inferred-js-diagnostics.d.ts +5 -0
- package/dist/frontend/inferred-js-diagnostics.js +69 -0
- package/dist/frontend/inferred-js-diagnostics.js.map +1 -0
- package/dist/frontend/inferred-js-diagnostics.test.d.ts +1 -0
- package/dist/frontend/inferred-js-diagnostics.test.js +58 -0
- package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -0
- package/dist/frontend/input-tracker.d.ts +5 -2
- package/dist/frontend/input-tracker.js +24 -3
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/input-tracker.test.js +23 -0
- package/dist/frontend/input-tracker.test.js.map +1 -1
- package/dist/frontend/lib-contract.js +32 -24
- package/dist/frontend/lib-contract.js.map +1 -1
- package/dist/frontend/literal-values.d.ts +4 -0
- package/dist/frontend/literal-values.js +21 -0
- package/dist/frontend/literal-values.js.map +1 -0
- package/dist/frontend/literal-values.test.d.ts +1 -0
- package/dist/frontend/literal-values.test.js +91 -0
- package/dist/frontend/literal-values.test.js.map +1 -0
- package/dist/frontend/lowering/abstract-equality.d.ts +1 -1
- package/dist/frontend/lowering/abstract-equality.js +3 -0
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/array-indexed-mutation.js +11 -6
- package/dist/frontend/lowering/array-indexed-mutation.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +4 -1
- package/dist/frontend/lowering/array-values.js +43 -1
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/callback-arg.js +1 -0
- package/dist/frontend/lowering/callback-arg.js.map +1 -1
- package/dist/frontend/lowering/class-callbacks.d.ts +12 -0
- package/dist/frontend/lowering/class-callbacks.js +74 -0
- package/dist/frontend/lowering/class-callbacks.js.map +1 -0
- package/dist/frontend/lowering/class-construction.d.ts +12 -0
- package/dist/frontend/lowering/class-construction.js +156 -0
- package/dist/frontend/lowering/class-construction.js.map +1 -0
- package/dist/frontend/lowering/class-descriptors.d.ts +10 -0
- package/dist/frontend/lowering/class-descriptors.js +114 -0
- package/dist/frontend/lowering/class-descriptors.js.map +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +51 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +1158 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.d.ts +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js +93 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.test.js.map +1 -0
- package/dist/frontend/lowering/class-instance-constructor.d.ts +7 -0
- package/dist/frontend/lowering/class-instance-constructor.js +67 -0
- package/dist/frontend/lowering/class-instance-constructor.js.map +1 -0
- package/dist/frontend/lowering/class-method-values.d.ts +13 -0
- package/dist/frontend/lowering/class-method-values.js +235 -0
- package/dist/frontend/lowering/class-method-values.js.map +1 -0
- package/dist/frontend/lowering/class-prototypes.d.ts +19 -0
- package/dist/frontend/lowering/class-prototypes.js +242 -0
- package/dist/frontend/lowering/class-prototypes.js.map +1 -0
- package/dist/frontend/lowering/class-runtime-statics.d.ts +8 -0
- package/dist/frontend/lowering/class-runtime-statics.js +66 -0
- package/dist/frontend/lowering/class-runtime-statics.js.map +1 -0
- package/dist/frontend/lowering/class-static-data.d.ts +6 -0
- package/dist/frontend/lowering/class-static-data.js +56 -0
- package/dist/frontend/lowering/class-static-data.js.map +1 -0
- package/dist/frontend/lowering/containers/buffer-numeric-methods.d.ts +4 -0
- package/dist/frontend/lowering/containers/buffer-numeric-methods.js +26 -0
- package/dist/frontend/lowering/containers/buffer-numeric-methods.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.d.ts +11 -7
- package/dist/frontend/lowering/containers/bytes.js +208 -163
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.d.ts +2 -2
- package/dist/frontend/lowering/containers/string-and-regexp.js +58 -63
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/containers/string-replacement.d.ts +7 -0
- package/dist/frontend/lowering/containers/string-replacement.js +217 -0
- package/dist/frontend/lowering/containers/string-replacement.js.map +1 -0
- package/dist/frontend/lowering/error-methods.d.ts +14 -0
- package/dist/frontend/lowering/error-methods.js +177 -0
- package/dist/frontend/lowering/error-methods.js.map +1 -0
- package/dist/frontend/lowering/expressions/global-symbols.d.ts +6 -0
- package/dist/frontend/lowering/expressions/global-symbols.js +11 -0
- package/dist/frontend/lowering/expressions/global-symbols.js.map +1 -0
- package/dist/frontend/lowering/expressions/native-proxy.d.ts +7 -0
- package/dist/frontend/lowering/expressions/native-proxy.js +51 -0
- package/dist/frontend/lowering/expressions/native-proxy.js.map +1 -0
- package/dist/frontend/lowering/expressions/nullish-assignment.d.ts +6 -0
- package/dist/frontend/lowering/expressions/nullish-assignment.js +132 -0
- package/dist/frontend/lowering/expressions/nullish-assignment.js.map +1 -0
- package/dist/frontend/lowering/expressions/object-literals.d.ts +8 -8
- package/dist/frontend/lowering/expressions/object-literals.js +509 -183
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.d.ts +3 -4
- package/dist/frontend/lowering/expressions/optional-chains.js +88 -24
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/expressions/try-lower-expression.js +1 -0
- package/dist/frontend/lowering/expressions/try-lower-expression.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +8 -0
- package/dist/frontend/lowering/expressions/union-field-write.js +71 -0
- package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -0
- package/dist/frontend/lowering/function-context.d.ts +101 -0
- package/dist/frontend/lowering/function-context.js +109 -0
- package/dist/frontend/lowering/function-context.js.map +1 -0
- package/dist/frontend/lowering/generator-delegation.d.ts +7 -0
- package/dist/frontend/lowering/generator-delegation.js +85 -0
- package/dist/frontend/lowering/generator-delegation.js.map +1 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.d.ts +11 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js +143 -0
- package/dist/frontend/lowering/generator-dynamic-dispatch.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.d.ts +4 -1
- package/dist/frontend/lowering/lib-boundary.js +112 -20
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lib-boundary.test.d.ts +1 -0
- package/dist/frontend/lowering/lib-boundary.test.js +45 -0
- package/dist/frontend/lowering/lib-boundary.test.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
- package/dist/frontend/lowering/lower-assert.d.ts +1 -1
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-async-iteration.d.ts +1 -1
- package/dist/frontend/lowering/lower-async-iteration.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +18 -0
- package/dist/frontend/lowering/lower-builtin-values.js +249 -0
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -0
- package/dist/frontend/lowering/lower-builtins.d.ts +33 -46
- package/dist/frontend/lowering/lower-builtins.js +676 -365
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +28 -22
- package/dist/frontend/lowering/lower-calls.js +1660 -412
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +95 -57
- package/dist/frontend/lowering/lower-classes.js +1491 -404
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.d.ts +1 -1
- package/dist/frontend/lowering/lower-comptime.js +23 -32
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +36 -32
- package/dist/frontend/lowering/lower-containers.js +925 -181
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.d.ts +1 -1
- package/dist/frontend/lowering/lower-dgram.js +3 -2
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-enums.d.ts +1 -1
- package/dist/frontend/lowering/lower-enums.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +30 -1
- package/dist/frontend/lowering/lower-event-emitter.js +58 -26
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-expando.d.ts +7 -1
- package/dist/frontend/lowering/lower-expando.js +14 -6
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +37 -13
- package/dist/frontend/lowering/lower-exprs.js +2163 -863
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +2 -5
- package/dist/frontend/lowering/lower-generators.js +88 -46
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-global-value.d.ts +7 -0
- package/dist/frontend/lowering/lower-global-value.js +17 -0
- package/dist/frontend/lowering/lower-global-value.js.map +1 -0
- package/dist/frontend/lowering/lower-inspect.d.ts +1 -1
- package/dist/frontend/lowering/lower-inspect.js +17 -8
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +7 -8
- package/dist/frontend/lowering/lower-island.js +66 -33
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.d.ts +2 -2
- package/dist/frontend/lowering/lower-mixins.js +5 -3
- package/dist/frontend/lowering/lower-mixins.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +1 -1
- package/dist/frontend/lowering/lower-modules.js +445 -39
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-modules.test.js +39 -0
- package/dist/frontend/lowering/lower-modules.test.js.map +1 -0
- package/dist/frontend/lowering/lower-namespaces.d.ts +1 -1
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-node-module.d.ts +1 -1
- package/dist/frontend/lowering/lower-node-module.js +13 -10
- package/dist/frontend/lowering/lower-node-module.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +1 -1
- package/dist/frontend/lowering/lower-server.js +6 -10
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +17 -17
- package/dist/frontend/lowering/lower-stmts.js +855 -514
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +1 -1
- package/dist/frontend/lowering/lower-stream.js +20 -11
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.d.ts +1 -1
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lower-url.d.ts +6 -0
- package/dist/frontend/lowering/lower-url.js +77 -0
- package/dist/frontend/lowering/lower-url.js.map +1 -0
- package/dist/frontend/lowering/lowerer.d.ts +140 -190
- package/dist/frontend/lowering/lowerer.js +1193 -712
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/lowerer.test.d.ts +1 -0
- package/dist/frontend/lowering/lowerer.test.js +172 -0
- package/dist/frontend/lowering/lowerer.test.js.map +1 -0
- package/dist/frontend/lowering/native-ffi.d.ts +5 -0
- package/dist/frontend/lowering/native-ffi.js +40 -0
- package/dist/frontend/lowering/native-ffi.js.map +1 -0
- package/dist/frontend/lowering/object-enumeration-receiver.d.ts +7 -0
- package/dist/frontend/lowering/object-enumeration-receiver.js +33 -0
- package/dist/frontend/lowering/object-enumeration-receiver.js.map +1 -0
- package/dist/frontend/lowering/object-factory-new.d.ts +8 -0
- package/dist/frontend/lowering/object-factory-new.js +68 -0
- package/dist/frontend/lowering/object-factory-new.js.map +1 -0
- package/dist/frontend/lowering/optional-arguments.js +6 -1
- package/dist/frontend/lowering/optional-arguments.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.js +2 -1
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-locals.d.ts +14 -0
- package/dist/frontend/lowering/runtime-optional-locals.js +41 -0
- package/dist/frontend/lowering/runtime-optional-locals.js.map +1 -0
- package/dist/frontend/lowering/runtime-optional-locals.test.d.ts +1 -0
- package/dist/frontend/lowering/runtime-optional-locals.test.js +85 -0
- package/dist/frontend/lowering/runtime-optional-locals.test.js.map +1 -0
- package/dist/frontend/lowering/sanitize-class-types.d.ts +8 -0
- package/dist/frontend/lowering/sanitize-class-types.js +79 -0
- package/dist/frontend/lowering/sanitize-class-types.js.map +1 -0
- package/dist/frontend/lowering/sanitize-class-types.test.d.ts +1 -0
- package/dist/frontend/lowering/sanitize-class-types.test.js +60 -0
- package/dist/frontend/lowering/sanitize-class-types.test.js.map +1 -0
- package/dist/frontend/lowering/static-this.d.ts +5 -1
- package/dist/frontend/lowering/static-this.js +28 -2
- package/dist/frontend/lowering/static-this.js.map +1 -1
- package/dist/frontend/lowering/string-index.d.ts +7 -0
- package/dist/frontend/lowering/string-index.js +39 -0
- package/dist/frontend/lowering/string-index.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +10 -3
- package/dist/frontend/lowering/surfaces.js +86 -37
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/symbol-fields.d.ts +22 -0
- package/dist/frontend/lowering/symbol-fields.js +183 -0
- package/dist/frontend/lowering/symbol-fields.js.map +1 -0
- package/dist/frontend/lowering/symbol-methods.d.ts +7 -0
- package/dist/frontend/lowering/symbol-methods.js +30 -0
- package/dist/frontend/lowering/symbol-methods.js.map +1 -0
- package/dist/frontend/lowering/text-decoder-encoding.d.ts +12 -0
- package/dist/frontend/lowering/text-decoder-encoding.js +82 -0
- package/dist/frontend/lowering/text-decoder-encoding.js.map +1 -0
- package/dist/frontend/lowering/text-decoder-encoding.test.d.ts +1 -0
- package/dist/frontend/lowering/text-decoder-encoding.test.js +38 -0
- package/dist/frontend/lowering/text-decoder-encoding.test.js.map +1 -0
- package/dist/frontend/lowering/union-narrow.d.ts +9 -0
- package/dist/frontend/lowering/union-narrow.js +59 -0
- package/dist/frontend/lowering/union-narrow.js.map +1 -0
- package/dist/frontend/lowering/union-narrow.test.d.ts +1 -0
- package/dist/frontend/lowering/union-narrow.test.js +72 -0
- package/dist/frontend/lowering/union-narrow.test.js.map +1 -0
- package/dist/frontend/lowering/union-retag.d.ts +43 -0
- package/dist/frontend/lowering/union-retag.js +259 -0
- package/dist/frontend/lowering/union-retag.js.map +1 -0
- package/dist/frontend/lowering/union-retag.test.d.ts +1 -0
- package/dist/frontend/lowering/union-retag.test.js +405 -0
- package/dist/frontend/lowering/union-retag.test.js.map +1 -0
- package/dist/frontend/lowering/unregistered-class-types.d.ts +14 -0
- package/dist/frontend/lowering/unregistered-class-types.js +94 -0
- package/dist/frontend/lowering/unregistered-class-types.js.map +1 -0
- package/dist/frontend/lowering/unregistered-class-types.test.d.ts +1 -0
- package/dist/frontend/lowering/unregistered-class-types.test.js +65 -0
- package/dist/frontend/lowering/unregistered-class-types.test.js.map +1 -0
- package/dist/frontend/lowering/width-lift.d.ts +40 -0
- package/dist/frontend/lowering/width-lift.js +2 -0
- package/dist/frontend/lowering/width-lift.js.map +1 -0
- package/dist/frontend/module-syntax.d.ts +58 -0
- package/dist/frontend/module-syntax.js +123 -0
- package/dist/frontend/module-syntax.js.map +1 -0
- package/dist/frontend/module-syntax.test.d.ts +1 -0
- package/dist/frontend/module-syntax.test.js +78 -0
- package/dist/frontend/module-syntax.test.js.map +1 -0
- package/dist/frontend/npm-fetch-analysis.d.ts +17 -0
- package/dist/frontend/npm-fetch-analysis.js +100 -0
- package/dist/frontend/npm-fetch-analysis.js.map +1 -0
- package/dist/frontend/npm-fetch-analysis.test.d.ts +1 -0
- package/dist/frontend/npm-fetch-analysis.test.js +107 -0
- package/dist/frontend/npm-fetch-analysis.test.js.map +1 -0
- package/dist/frontend/npm-fetch-node.d.ts +2 -0
- package/dist/frontend/npm-fetch-node.js +12 -0
- package/dist/frontend/npm-fetch-node.js.map +1 -0
- package/dist/frontend/npm-fetch-syntax.d.ts +6 -0
- package/dist/frontend/npm-fetch-syntax.js +207 -0
- package/dist/frontend/npm-fetch-syntax.js.map +1 -0
- package/dist/frontend/npm-node.d.ts +10 -0
- package/dist/frontend/npm-node.js +14 -0
- package/dist/frontend/npm-node.js.map +1 -0
- package/dist/frontend/npm-static-bundled-cjs.d.ts +8 -0
- package/dist/frontend/npm-static-bundled-cjs.js +236 -0
- package/dist/frontend/npm-static-bundled-cjs.js.map +1 -0
- package/dist/frontend/npm-static-bundled-cjs.test.d.ts +1 -0
- package/dist/frontend/npm-static-bundled-cjs.test.js +69 -0
- package/dist/frontend/npm-static-bundled-cjs.test.js.map +1 -0
- package/dist/frontend/npm-static-declaration-syntax.d.ts +57 -0
- package/dist/frontend/npm-static-declaration-syntax.js +944 -0
- package/dist/frontend/npm-static-declaration-syntax.js.map +1 -0
- package/dist/frontend/npm-static-declarations.d.ts +11 -39
- package/dist/frontend/npm-static-declarations.js +22 -561
- package/dist/frontend/npm-static-declarations.js.map +1 -1
- package/dist/frontend/npm-static-declarations.test.js +245 -6
- package/dist/frontend/npm-static-declarations.test.js.map +1 -1
- package/dist/frontend/npm-static-prune.d.ts +1 -1
- package/dist/frontend/npm-static-prune.js +121 -38
- package/dist/frontend/npm-static-prune.js.map +1 -1
- package/dist/frontend/npm-static-prune.test.js +9 -1
- package/dist/frontend/npm-static-prune.test.js.map +1 -1
- package/dist/frontend/npm-static-rewrite-host.d.ts +4 -0
- package/dist/frontend/npm-static-rewrite-host.js +179 -0
- package/dist/frontend/npm-static-rewrite-host.js.map +1 -0
- package/dist/frontend/npm-static-rewrite-syntax.d.ts +16 -0
- package/dist/frontend/npm-static-rewrite-syntax.js +905 -0
- package/dist/frontend/npm-static-rewrite-syntax.js.map +1 -0
- package/dist/frontend/npm-static-rewrite.d.ts +0 -5
- package/dist/frontend/npm-static-rewrite.js +2 -1079
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static-subtyping.d.ts +5 -0
- package/dist/frontend/npm-static-subtyping.js +55 -0
- package/dist/frontend/npm-static-subtyping.js.map +1 -0
- package/dist/frontend/npm-static-subtyping.test.d.ts +1 -0
- package/dist/frontend/npm-static-subtyping.test.js +58 -0
- package/dist/frontend/npm-static-subtyping.test.js.map +1 -0
- package/dist/frontend/npm-static.d.ts +7 -15
- package/dist/frontend/npm-static.js +19 -28
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +8 -69
- package/dist/frontend/npm.js +21 -361
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/npm.test.js +2 -2
- package/dist/frontend/npm.test.js.map +1 -1
- package/dist/frontend/pipeline-native.d.ts +6 -0
- package/dist/frontend/pipeline-native.js +32 -0
- package/dist/frontend/pipeline-native.js.map +1 -0
- package/dist/frontend/pipeline.d.ts +54 -0
- package/dist/frontend/pipeline.js +382 -0
- package/dist/frontend/pipeline.js.map +1 -0
- package/dist/frontend/pipeline.test.d.ts +1 -0
- package/dist/frontend/pipeline.test.js +77 -0
- package/dist/frontend/pipeline.test.js.map +1 -0
- package/dist/frontend/program-analysis.d.ts +10 -0
- package/dist/frontend/program-analysis.js +14 -0
- package/dist/frontend/program-analysis.js.map +1 -0
- package/dist/frontend/program-node.d.ts +9 -0
- package/dist/frontend/program-node.js +48 -0
- package/dist/frontend/program-node.js.map +1 -0
- package/dist/frontend/program.d.ts +39 -20
- package/dist/frontend/program.js +393 -189
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +105 -2
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/provenance-core.d.ts +9 -0
- package/dist/frontend/provenance-core.js +435 -0
- package/dist/frontend/provenance-core.js.map +1 -0
- package/dist/frontend/provenance.d.ts +0 -4
- package/dist/frontend/provenance.js +4 -459
- package/dist/frontend/provenance.js.map +1 -1
- package/dist/frontend/resolve.d.ts +3 -1
- package/dist/frontend/resolve.js +6 -3
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/runtime-resolve.d.ts +4 -3
- package/dist/frontend/runtime-resolve.js +22 -18
- package/dist/frontend/runtime-resolve.js.map +1 -1
- package/dist/frontend/runtime-resolve.test.js +53 -0
- package/dist/frontend/runtime-resolve.test.js.map +1 -1
- package/dist/frontend/services-node.d.ts +5 -0
- package/dist/frontend/services-node.js +19 -0
- package/dist/frontend/services-node.js.map +1 -0
- package/dist/frontend/services-node.test.d.ts +1 -0
- package/dist/frontend/services-node.test.js +70 -0
- package/dist/frontend/services-node.test.js.map +1 -0
- package/dist/frontend/services.d.ts +44 -0
- package/dist/frontend/services.js +90 -0
- package/dist/frontend/services.js.map +1 -0
- package/dist/frontend/services.test.d.ts +1 -0
- package/dist/frontend/services.test.js +174 -0
- package/dist/frontend/services.test.js.map +1 -0
- package/dist/frontend/ts7/adapter.d.ts +3 -3
- package/dist/frontend/ts7/adapter.js +14 -31
- package/dist/frontend/ts7/adapter.js.map +1 -1
- package/dist/frontend/ts7/api.d.ts +16 -0
- package/dist/frontend/ts7/api.js +24 -0
- package/dist/frontend/ts7/api.js.map +1 -0
- package/dist/frontend/ts7/ast-bytes.d.ts +31 -0
- package/dist/frontend/ts7/ast-bytes.js +137 -0
- package/dist/frontend/ts7/ast-bytes.js.map +1 -0
- package/dist/frontend/ts7/ast-bytes.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-bytes.test.js +73 -0
- package/dist/frontend/ts7/ast-bytes.test.js.map +1 -0
- package/dist/frontend/ts7/ast-guards.generated.d.ts +353 -0
- package/dist/frontend/ts7/ast-guards.generated.js +1951 -0
- package/dist/frontend/ts7/ast-guards.generated.js.map +1 -0
- package/dist/frontend/ts7/ast-guards.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-guards.test.js +43 -0
- package/dist/frontend/ts7/ast-guards.test.js.map +1 -0
- package/dist/frontend/ts7/ast-node.d.ts +194 -0
- package/dist/frontend/ts7/ast-node.js +448 -0
- package/dist/frontend/ts7/ast-node.js.map +1 -0
- package/dist/frontend/ts7/ast-node.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-node.test.js +266 -0
- package/dist/frontend/ts7/ast-node.test.js.map +1 -0
- package/dist/frontend/ts7/ast-schema.generated.d.ts +503 -0
- package/dist/frontend/ts7/ast-schema.generated.js +1446 -0
- package/dist/frontend/ts7/ast-schema.generated.js.map +1 -0
- package/dist/frontend/ts7/ast-text.d.ts +6 -0
- package/dist/frontend/ts7/ast-text.js +124 -0
- package/dist/frontend/ts7/ast-text.js.map +1 -0
- package/dist/frontend/ts7/ast-text.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-text.test.js +38 -0
- package/dist/frontend/ts7/ast-text.test.js.map +1 -0
- package/dist/frontend/ts7/ast-tokens.generated.d.ts +2 -0
- package/dist/frontend/ts7/ast-tokens.generated.js +155 -0
- package/dist/frontend/ts7/ast-tokens.generated.js.map +1 -0
- package/dist/frontend/ts7/ast-types.d.ts +42 -0
- package/dist/frontend/ts7/ast-types.generated.d.ts +1615 -0
- package/dist/frontend/ts7/ast-types.generated.js +5 -0
- package/dist/frontend/ts7/ast-types.generated.js.map +1 -0
- package/dist/frontend/ts7/ast-types.js +3 -0
- package/dist/frontend/ts7/ast-types.js.map +1 -0
- package/dist/frontend/ts7/ast-wire.d.ts +58 -0
- package/dist/frontend/ts7/ast-wire.js +267 -0
- package/dist/frontend/ts7/ast-wire.js.map +1 -0
- package/dist/frontend/ts7/ast-wire.test.d.ts +1 -0
- package/dist/frontend/ts7/ast-wire.test.js +151 -0
- package/dist/frontend/ts7/ast-wire.test.js.map +1 -0
- package/dist/frontend/ts7/ast.d.ts +14 -14
- package/dist/frontend/ts7/ast.js +25 -18
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/census-check.js +1 -0
- package/dist/frontend/ts7/census-check.js.map +1 -1
- package/dist/frontend/ts7/checker-cache.d.ts +48 -0
- package/dist/frontend/ts7/checker-cache.js +92 -0
- package/dist/frontend/ts7/checker-cache.js.map +1 -0
- package/dist/frontend/ts7/checker.d.ts +19 -46
- package/dist/frontend/ts7/checker.js +231 -161
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.d.ts +1 -0
- package/dist/frontend/ts7/checker.test.js +335 -0
- package/dist/frontend/ts7/checker.test.js.map +1 -0
- package/dist/frontend/ts7/enums.d.ts +4 -27
- package/dist/frontend/ts7/enums.generated.d.ts +878 -0
- package/dist/frontend/ts7/enums.generated.js +1313 -0
- package/dist/frontend/ts7/enums.generated.js.map +1 -0
- package/dist/frontend/ts7/enums.js +4 -45
- package/dist/frontend/ts7/enums.js.map +1 -1
- package/dist/frontend/ts7/enums.test.d.ts +1 -0
- package/dist/frontend/ts7/enums.test.js +48 -0
- package/dist/frontend/ts7/enums.test.js.map +1 -0
- package/dist/frontend/ts7/native-api.d.ts +10 -0
- package/dist/frontend/ts7/native-api.js +10 -0
- package/dist/frontend/ts7/native-api.js.map +1 -0
- package/dist/frontend/ts7/native-host.d.ts +2 -0
- package/dist/frontend/ts7/native-host.js +11 -0
- package/dist/frontend/ts7/native-host.js.map +1 -0
- package/dist/frontend/ts7/native-process.d.ts +14 -0
- package/dist/frontend/ts7/native-process.js +62 -0
- package/dist/frontend/ts7/native-process.js.map +1 -0
- package/dist/frontend/ts7/program-adapter.d.ts +10 -98
- package/dist/frontend/ts7/program-adapter.js +16 -310
- package/dist/frontend/ts7/program-adapter.js.map +1 -1
- package/dist/frontend/ts7/program-host.d.ts +115 -0
- package/dist/frontend/ts7/program-host.js +347 -0
- package/dist/frontend/ts7/program-host.js.map +1 -0
- package/dist/frontend/ts7/program-host.test.d.ts +1 -0
- package/dist/frontend/ts7/program-host.test.js +207 -0
- package/dist/frontend/ts7/program-host.test.js.map +1 -0
- package/dist/frontend/ts7/rpc-api.d.ts +12 -0
- package/dist/frontend/ts7/rpc-api.js +23 -0
- package/dist/frontend/ts7/rpc-api.js.map +1 -0
- package/dist/frontend/ts7/rpc-client.d.ts +27 -0
- package/dist/frontend/ts7/rpc-client.js +102 -0
- package/dist/frontend/ts7/rpc-client.js.map +1 -0
- package/dist/frontend/ts7/rpc-client.test.d.ts +1 -0
- package/dist/frontend/ts7/rpc-client.test.js +133 -0
- package/dist/frontend/ts7/rpc-client.test.js.map +1 -0
- package/dist/frontend/ts7/rpc-filesystem.d.ts +16 -0
- package/dist/frontend/ts7/rpc-filesystem.js +42 -0
- package/dist/frontend/ts7/rpc-filesystem.js.map +1 -0
- package/dist/frontend/ts7/rpc-filesystem.test.d.ts +1 -0
- package/dist/frontend/ts7/rpc-filesystem.test.js +89 -0
- package/dist/frontend/ts7/rpc-filesystem.test.js.map +1 -0
- package/dist/frontend/ts7/rpc-process.d.ts +2 -0
- package/dist/frontend/ts7/rpc-process.js +148 -0
- package/dist/frontend/ts7/rpc-process.js.map +1 -0
- package/dist/frontend/ts7/rpc-process.test.d.ts +1 -0
- package/dist/frontend/ts7/rpc-process.test.js +29 -0
- package/dist/frontend/ts7/rpc-process.test.js.map +1 -0
- package/dist/frontend/ts7/rpc-wire.d.ts +46 -0
- package/dist/frontend/ts7/rpc-wire.js +195 -0
- package/dist/frontend/ts7/rpc-wire.js.map +1 -0
- package/dist/frontend/ts7/rpc-wire.test.d.ts +1 -0
- package/dist/frontend/ts7/rpc-wire.test.js +168 -0
- package/dist/frontend/ts7/rpc-wire.test.js.map +1 -0
- package/dist/frontend/ts7/semantic-checker.d.ts +137 -0
- package/dist/frontend/ts7/semantic-checker.js +221 -0
- package/dist/frontend/ts7/semantic-checker.js.map +1 -0
- package/dist/frontend/ts7/semantic-checker.test.d.ts +1 -0
- package/dist/frontend/ts7/semantic-checker.test.js +119 -0
- package/dist/frontend/ts7/semantic-checker.test.js.map +1 -0
- package/dist/frontend/ts7/semantic-json.d.ts +5 -0
- package/dist/frontend/ts7/semantic-json.js +47 -0
- package/dist/frontend/ts7/semantic-json.js.map +1 -0
- package/dist/frontend/ts7/semantic-json.test.d.ts +1 -0
- package/dist/frontend/ts7/semantic-json.test.js +42 -0
- package/dist/frontend/ts7/semantic-json.test.js.map +1 -0
- package/dist/frontend/ts7/semantic-model.d.ts +222 -0
- package/dist/frontend/ts7/semantic-model.js +423 -0
- package/dist/frontend/ts7/semantic-model.js.map +1 -0
- package/dist/frontend/ts7/semantic-model.test.d.ts +1 -0
- package/dist/frontend/ts7/semantic-model.test.js +322 -0
- package/dist/frontend/ts7/semantic-model.test.js.map +1 -0
- package/dist/frontend/ts7/semantic-schema.generated.d.ts +283 -0
- package/dist/frontend/ts7/semantic-schema.generated.js +222 -0
- package/dist/frontend/ts7/semantic-schema.generated.js.map +1 -0
- package/dist/frontend/ts7/semantic-types.d.ts +5 -0
- package/dist/frontend/ts7/semantic-types.js +2 -0
- package/dist/frontend/ts7/semantic-types.js.map +1 -0
- package/dist/frontend/ts7/session-cache.d.ts +17 -0
- package/dist/frontend/ts7/session-cache.js +97 -0
- package/dist/frontend/ts7/session-cache.js.map +1 -0
- package/dist/frontend/ts7/session-cache.test.d.ts +1 -0
- package/dist/frontend/ts7/session-cache.test.js +87 -0
- package/dist/frontend/ts7/session-cache.test.js.map +1 -0
- package/dist/frontend/ts7/session-path.d.ts +18 -0
- package/dist/frontend/ts7/session-path.js +203 -0
- package/dist/frontend/ts7/session-path.js.map +1 -0
- package/dist/frontend/ts7/session-path.test.d.ts +1 -0
- package/dist/frontend/ts7/session-path.test.js +34 -0
- package/dist/frontend/ts7/session-path.test.js.map +1 -0
- package/dist/frontend/ts7/session-schema.generated.d.ts +167 -0
- package/dist/frontend/ts7/session-schema.generated.js +5 -0
- package/dist/frontend/ts7/session-schema.generated.js.map +1 -0
- package/dist/frontend/ts7/session-timing.d.ts +50 -0
- package/dist/frontend/ts7/session-timing.js +61 -0
- package/dist/frontend/ts7/session-timing.js.map +1 -0
- package/dist/frontend/ts7/session-timing.test.d.ts +1 -0
- package/dist/frontend/ts7/session-timing.test.js +52 -0
- package/dist/frontend/ts7/session-timing.test.js.map +1 -0
- package/dist/frontend/ts7/session.d.ts +105 -0
- package/dist/frontend/ts7/session.js +233 -0
- package/dist/frontend/ts7/session.js.map +1 -0
- package/dist/frontend/ts7/session.test.d.ts +1 -0
- package/dist/frontend/ts7/session.test.js +215 -0
- package/dist/frontend/ts7/session.test.js.map +1 -0
- package/dist/frontend/ts7/source-parser-node.d.ts +6 -0
- package/dist/frontend/ts7/source-parser-node.js +15 -0
- package/dist/frontend/ts7/source-parser-node.js.map +1 -0
- package/dist/frontend/ts7/source-parser.d.ts +25 -0
- package/dist/frontend/ts7/source-parser.js +96 -0
- package/dist/frontend/ts7/source-parser.js.map +1 -0
- package/dist/frontend/ts7/source-parser.test.d.ts +1 -0
- package/dist/frontend/ts7/source-parser.test.js +151 -0
- package/dist/frontend/ts7/source-parser.test.js.map +1 -0
- package/dist/frontend/ts7/syntax.d.ts +3 -0
- package/dist/frontend/ts7/syntax.js +4 -0
- package/dist/frontend/ts7/syntax.js.map +1 -0
- package/dist/frontend/tsc-codes.js +3 -0
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +34 -18
- package/dist/frontend/type-mapper.js +552 -131
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.js +146 -2
- package/dist/frontend/type-mapper.test.js.map +1 -1
- package/dist/frontend/union-discriminants.d.ts +16 -0
- package/dist/frontend/union-discriminants.js +98 -0
- package/dist/frontend/union-discriminants.js.map +1 -0
- package/dist/frontend/union-discriminants.test.d.ts +1 -0
- package/dist/frontend/union-discriminants.test.js +182 -0
- package/dist/frontend/union-discriminants.test.js.map +1 -0
- package/dist/index.d.ts +7 -198
- package/dist/index.js +369 -1572
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +16 -4
- package/dist/ir/analysis.js +23 -4
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +15 -2
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/constant-tables.js +67 -49
- package/dist/ir/constant-tables.js.map +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/control-flow.d.ts +6 -0
- package/dist/ir/control-flow.js +142 -0
- package/dist/ir/control-flow.js.map +1 -0
- package/dist/ir/control-flow.test.d.ts +1 -0
- package/dist/ir/control-flow.test.js +113 -0
- package/dist/ir/control-flow.test.js.map +1 -0
- package/dist/ir/integer-loops.js +7 -18
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-ranges.js +53 -27
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/ir.d.ts +334 -176
- package/dist/ir/ir.js +710 -903
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +162 -1
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/scalar-records.js +165 -134
- package/dist/ir/scalar-records.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/serialize.d.ts +4 -2
- package/dist/ir/serialize.js +33 -14
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/serialize.test.d.ts +1 -0
- package/dist/ir/serialize.test.js +57 -0
- package/dist/ir/serialize.test.js.map +1 -0
- package/dist/ir/traverse.d.ts +41 -0
- package/dist/ir/traverse.js +660 -0
- package/dist/ir/traverse.js.map +1 -0
- package/dist/ir/traverse.test.d.ts +1 -0
- package/dist/ir/traverse.test.js +242 -0
- package/dist/ir/traverse.test.js.map +1 -0
- package/dist/ir/validate.js +2018 -1498
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +536 -2
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/cache-primitives.d.ts +2 -3
- package/dist/library/cache-primitives.js +4 -6
- package/dist/library/cache-primitives.js.map +1 -1
- package/dist/library/fence-eval.js +2 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.js +7 -6
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/library-cache.d.ts +3 -2
- package/dist/library/library-cache.js +5 -17
- package/dist/library/library-cache.js.map +1 -1
- package/dist/library/library-cache.test.js +54 -41
- package/dist/library/library-cache.test.js.map +1 -1
- package/dist/library/library-profile.d.ts +3 -1
- package/dist/library/library-profile.js +15 -6
- package/dist/library/library-profile.js.map +1 -1
- package/dist/library/prepare.d.ts +15 -0
- package/dist/library/prepare.js +584 -0
- package/dist/library/prepare.js.map +1 -0
- package/dist/library/semantic-source.d.ts +1 -1
- package/dist/library/semantic-source.js +8 -6
- package/dist/library/semantic-source.js.map +1 -1
- package/dist/library/sidecar-validate.js +4 -4
- package/dist/library/sidecar-validate.js.map +1 -1
- package/dist/library/sidecar.d.ts +2 -0
- package/dist/library/sidecar.js +10 -3
- package/dist/library/sidecar.js.map +1 -1
- package/dist/native/cache.d.ts +11 -0
- package/dist/native/cache.js +113 -0
- package/dist/native/cache.js.map +1 -0
- package/dist/native/cache.test.d.ts +1 -0
- package/dist/native/cache.test.js +66 -0
- package/dist/native/cache.test.js.map +1 -0
- package/dist/native/cli.d.ts +1 -0
- package/dist/native/cli.js +112 -0
- package/dist/native/cli.js.map +1 -0
- package/dist/native/compiler.d.ts +15 -0
- package/dist/native/compiler.js +336 -0
- package/dist/native/compiler.js.map +1 -0
- package/dist/native/compiler.test.d.ts +1 -0
- package/dist/native/compiler.test.js +174 -0
- package/dist/native/compiler.test.js.map +1 -0
- package/dist/native/comptime.d.ts +5 -0
- package/dist/native/comptime.js +73 -0
- package/dist/native/comptime.js.map +1 -0
- package/dist/native/comptime.test.d.ts +1 -0
- package/dist/native/comptime.test.js +65 -0
- package/dist/native/comptime.test.js.map +1 -0
- package/dist/native/executable-cache.d.ts +26 -0
- package/dist/native/executable-cache.js +228 -0
- package/dist/native/executable-cache.js.map +1 -0
- package/dist/native/executable-cache.test.d.ts +1 -0
- package/dist/native/executable-cache.test.js +151 -0
- package/dist/native/executable-cache.test.js.map +1 -0
- package/dist/native/file-identity.d.ts +4 -0
- package/dist/native/file-identity.js +14 -0
- package/dist/native/file-identity.js.map +1 -0
- package/dist/native/file-identity.test.d.ts +1 -0
- package/dist/native/file-identity.test.js +43 -0
- package/dist/native/file-identity.test.js.map +1 -0
- package/dist/native/library.d.ts +22 -0
- package/dist/native/library.js +83 -0
- package/dist/native/library.js.map +1 -0
- package/dist/native/prepare.d.ts +21 -0
- package/dist/native/prepare.js +174 -0
- package/dist/native/prepare.js.map +1 -0
- package/dist/native/prepare.test.d.ts +1 -0
- package/dist/native/prepare.test.js +70 -0
- package/dist/native/prepare.test.js.map +1 -0
- package/dist/native/sanitizer.d.ts +11 -0
- package/dist/native/sanitizer.js +137 -0
- package/dist/native/sanitizer.js.map +1 -0
- package/dist/native/sanitizer.test.d.ts +1 -0
- package/dist/native/sanitizer.test.js +58 -0
- package/dist/native/sanitizer.test.js.map +1 -0
- package/dist/native/task.d.ts +4 -0
- package/dist/native/task.js +16 -0
- package/dist/native/task.js.map +1 -0
- package/dist/native/task.test.d.ts +1 -0
- package/dist/native/task.test.js +17 -0
- package/dist/native/task.test.js.map +1 -0
- package/dist/native/toolchain.d.ts +45 -0
- package/dist/native/toolchain.js +94 -0
- package/dist/native/toolchain.js.map +1 -0
- package/dist/native/toolchain.test.d.ts +1 -0
- package/dist/native/toolchain.test.js +85 -0
- package/dist/native/toolchain.test.js.map +1 -0
- package/dist/startup-cache.d.ts +1 -1
- package/dist/startup-cache.js +2 -5
- package/dist/startup-cache.js.map +1 -1
- package/dist/timing.d.ts +4 -0
- package/dist/timing.js +19 -0
- package/dist/timing.js.map +1 -0
- package/dist/wasi-paths.js +10 -7
- package/dist/wasi-paths.js.map +1 -1
- package/package.json +28 -19
- package/surface-manifest.json +107 -98
- package/dist/backend/c/async.d.ts +0 -171
- package/dist/backend/c/async.js +0 -1317
- package/dist/backend/c/async.js.map +0 -1
- package/dist/backend/c/c-emitter.d.ts +0 -536
- package/dist/backend/c/c-emitter.js +0 -1932
- package/dist/backend/c/c-emitter.js.map +0 -1
- package/dist/backend/c/exprs.d.ts +0 -15
- package/dist/backend/c/exprs.js +0 -8847
- package/dist/backend/c/exprs.js.map +0 -1
- package/dist/backend/c/island.d.ts +0 -45
- package/dist/backend/c/island.js +0 -281
- package/dist/backend/c/island.js.map +0 -1
- package/dist/backend/c/may-throw.js.map +0 -1
- package/dist/backend/c/shapes.d.ts +0 -142
- package/dist/backend/c/shapes.js +0 -603
- package/dist/backend/c/shapes.js.map +0 -1
- package/dist/backend/c/stmts.d.ts +0 -76
- package/dist/backend/c/stmts.js +0 -1108
- package/dist/backend/c/stmts.js.map +0 -1
- package/dist/backend/c/types.d.ts +0 -71
- package/dist/backend/c/types.js +0 -459
- package/dist/backend/c/types.js.map +0 -1
- package/dist/backend/c/types.test.js +0 -32
- package/dist/backend/c/types.test.js.map +0 -1
- package/dist/backend/c/walkers.d.ts +0 -134
- package/dist/backend/c/walkers.js +0 -1772
- package/dist/backend/c/walkers.js.map +0 -1
- /package/dist/backend/{c/types.test.d.ts → cycle-analysis.test.d.ts} +0 -0
|
@@ -1,28 +1,35 @@
|
|
|
1
|
+
import { objectEnumerationReceiver } from "./object-enumeration-receiver.js";
|
|
1
2
|
import { InternalCompilerError } from "../../errors.js";
|
|
2
3
|
/* Call lowering: the lowerCall dispatch chain, parameter-shape analysis and
|
|
3
4
|
* argument completion (optional/default/rest, explicit-undefined ≡ omission),
|
|
4
5
|
* function/lambda lowering and signature collection, and monomorphizing
|
|
5
6
|
* generic instantiation (bounded by MAX_GENERIC_INSTANCES). */
|
|
6
7
|
import * as ts from "../ts7/adapter.js";
|
|
8
|
+
import { AstNode } from "../ts7/ast-node.js";
|
|
7
9
|
import { bodyReadsArguments } from "../arguments-usage.js";
|
|
8
10
|
import { lowerGenMethodCall } from "./lower-generators.js";
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
11
|
+
import { lowerClassSymbolMethodCall } from "./symbol-methods.js";
|
|
12
|
+
import { errorToStringCall } from "./error-methods.js";
|
|
13
|
+
import { lowerClassPrototypeAssign } from "./class-prototypes.js";
|
|
14
|
+
import { BYTES_ELEMENT_NAME, BIGINT_T, BOOL, CAUGHT, DYN, F64, JSVAL, NULL_T, STRING, SYMBOL_T, UNDEFINED_T, VOID, arrayOf, canBoxFuncIntoDyn, canConvertToDyn, canDynCheckTo, canMarshalTypedFuncIntoIsland, ffiClassType, ffiSourceParamTypes, funcOf, isDynTypedRefType, isFfiCallbackParam, isFfiContextParam, isFfiReleaseParam, isUnitType, shapeHasAccessorSlots, typeEquals } from "../../ir/ir.js";
|
|
15
|
+
import { isJsSourceFile, isNodeEsmFile, locOf, requireSpecOf } from "../program.js";
|
|
16
|
+
import { genResultRecord, isGenericCallableMemberType, jsOpenObjectType, typeKey } from "../type-mapper.js";
|
|
17
|
+
import { PoisonError, dynFallbackType, dynUndefinedExpr, importCallHandleType, jsFuncNameOf, neverTaintedJsType, newFnCtx, nodeThrowExpr, staticImportNamespaceType } from "./lowerer.js";
|
|
18
|
+
import { enforceLibBoundary, lowerSurplusCalls } from "./lib-boundary.js";
|
|
19
|
+
import { NARROW_FIRST, STRING_INDEX_METHODS, STR_METHODS, builtinFenceHintOf, builtinModuleFnOf, stdlibGlobalNameOf } from "./surfaces.js";
|
|
15
20
|
import { ffiBindingDiag, ffiSignatureDiag, libCallbackDiag, requiresDynamicDiag } from "../../diagnostics/diagnostic.js";
|
|
16
21
|
import { mixinFnShapeOf } from "./lower-mixins.js";
|
|
17
|
-
import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
18
|
-
import {
|
|
22
|
+
import { dynStringReceiver, lowerArrayConstructor, lowerArrayFromCall, lowerArrayOfCall, lowerDynArrayFilterCall, lowerDynArrayFlatMapCall, lowerGroupByStaticCall, lowerIteratorHelperCall, lowerObjectAssignIndexShape, lowerObjectConstructor, lowerObjectFromEntriesCall, lowerObjectIterOverIndexShape, lowerTupleReadMethodCall } from "./lower-containers.js";
|
|
23
|
+
import { lowerBytesStaticCall } from "./containers/bytes.js";
|
|
19
24
|
import { lowerRegexMethodCall, lowerStringIndexCall, lowerStringMethodCall, lowerStringPaddingCall, lowerStringSplitCall } from "./containers/string-and-regexp.js";
|
|
20
|
-
import { lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall,
|
|
21
|
-
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, templateRawTextOf } from "./lower-exprs.js";
|
|
25
|
+
import { createRequireSpecOf, lowerChildStreamMethodCall, lowerChildWriterMethodCall, lowerCreateRequireCall, lowerCryptoHashMethodCall, lowerDirentMethodCall, lowerFileHandleMethodCall, lowerImportMetaResolveCall, lowerNodeModuleCall, lowerPerfHooksCall, lowerProcStreamMethodCall, lowerReflectCall, lowerRequireResolveCall, lowerWatcherMethodCall } from "./lower-builtins.js";
|
|
26
|
+
import { lowerAbsenceProbe, lowerPromiseAllTupleCall, lowerPromiseRejectCall, stringWrapperToString, symbolFieldInfo, templateRawTextOf } from "./lower-exprs.js";
|
|
22
27
|
import { isSafeToDiscard } from "./expressions/evaluation-safety.js";
|
|
23
28
|
import { tryLowerExpression } from "./expressions/try-lower-expression.js";
|
|
29
|
+
import { hasRuntimeStatics } from "./class-runtime-statics.js";
|
|
24
30
|
import { httpClientFnBindingOf, isStreamUndefCallExpr, lowerCompatReqStreamOptionalCall, lowerHttpClientFnCall } from "./lower-server.js";
|
|
25
|
-
import { EMITTER_API_MEMBERS, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall } from "./lower-classes.js";
|
|
31
|
+
import { EMITTER_API_MEMBERS, exactClassOfReceiver, exactInstanceClassOf, findGenericMethodOn, lowerClassGenericMethodCall, lowerStaticMethodCall, lowerStaticFieldRead, returnsOnlyThis, storedClassValueType } from "./lower-classes.js";
|
|
32
|
+
import { classCallbackCall, isClassCallback } from "./class-callbacks.js";
|
|
26
33
|
import { emitterRooted, lowerEmitterMethodCall } from "./lower-event-emitter.js";
|
|
27
34
|
import { lowerConsoleInspectArg, lowerFormatCall } from "./lower-inspect.js";
|
|
28
35
|
import { STREAM_API_MEMBERS, lowerStreamMethodCall, lowerStreamModuleCall, lowerStreamStaticCall, streamSidesOf } from "./lower-stream.js";
|
|
@@ -30,10 +37,14 @@ import { ambientNsRootOf, ambientUndefReadType, ambientUndefVarRootOf, ambientUn
|
|
|
30
37
|
import { declSymbolOf } from "./lower-modules.js";
|
|
31
38
|
import { expandoMemberRead } from "./lower-expando.js";
|
|
32
39
|
import { npmStaticPackageOfPath } from "../npm-static.js";
|
|
33
|
-
import { countedFor, varRef } from "../../ir/build.js";
|
|
40
|
+
import { countedFor, numLit, varRef } from "../../ir/build.js";
|
|
34
41
|
import { rejectStaticThis } from "./static-this.js";
|
|
35
42
|
import { fenceNodeModuleMutationCall, lowerRequireCacheKeys } from "./lower-node-module.js";
|
|
36
43
|
import { defaultAfterUndefined, lowerOptionalArgument, lowerStaticallyUndefinedArgument, positionNumber } from "./optional-arguments.js";
|
|
44
|
+
import { fenceSymbolFieldCopy } from "./symbol-fields.js";
|
|
45
|
+
import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js";
|
|
46
|
+
import { classStaticDataFor } from "./class-static-data.js";
|
|
47
|
+
import { jsBindingHasOpenWrites } from "./lower-stmts.js";
|
|
37
48
|
export { bodyReadsArguments };
|
|
38
49
|
/** The one func-type projection of completed parameter shapes. Typed rest
|
|
39
50
|
* parameters keep their packed array as the trailing native ABI slot and
|
|
@@ -51,11 +62,7 @@ export function funcTypeFromParamShapes(shapes, ret) {
|
|
|
51
62
|
ret,
|
|
52
63
|
...(typedRest || dynRest || islandRest || argumentsAll ? { rest: true } : {}),
|
|
53
64
|
...(argumentsAll ? { argumentsAll: true } : {}),
|
|
54
|
-
...(typedRest
|
|
55
|
-
? { restAbi: "typed" }
|
|
56
|
-
: islandRest
|
|
57
|
-
? { restAbi: "jsval" }
|
|
58
|
-
: {}),
|
|
65
|
+
...(typedRest || islandRest ? { restAbi: typedRest ? "typed" : "jsval" } : {}),
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
68
|
/** Registers `const alias = overloadedDeclaration` as a compile-time
|
|
@@ -118,6 +125,25 @@ export const MAX_GENERIC_INSTANCES = 100;
|
|
|
118
125
|
* - `...xs: T[]`: the ABI type is the array; call sites pack the surplus.
|
|
119
126
|
*/
|
|
120
127
|
export function paramShape(lowerer, param) {
|
|
128
|
+
if (param.initializer && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
129
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
130
|
+
return { type: DYN, mode: "omittable", bodyType: DYN };
|
|
131
|
+
}
|
|
132
|
+
// Inferred JS array patterns describe the bindings, not an exact tuple
|
|
133
|
+
// contract. Consume the actual iterable, including surplus elements.
|
|
134
|
+
if (ts.isArrayBindingPattern(param.name) && isJsSourceFile(param.getSourceFile()) && !param.type &&
|
|
135
|
+
!/@(?:param|type)\b/.test(param.getSourceFile().text.slice(param.parent?.pos ?? param.pos, param.getStart()))) {
|
|
136
|
+
if (param.dotDotDotToken)
|
|
137
|
+
return { type: DYN, mode: "dynRest" };
|
|
138
|
+
return param.initializer ? { type: DYN, mode: "omittable", bodyType: DYN } : { type: DYN, mode: "required" };
|
|
139
|
+
}
|
|
140
|
+
if (lowerer.checkedCallbackParams.has(param)) {
|
|
141
|
+
if (param.dotDotDotToken)
|
|
142
|
+
return { type: DYN, mode: "dynRest" };
|
|
143
|
+
return param.initializer
|
|
144
|
+
? { type: DYN, mode: "omittable", bodyType: DYN }
|
|
145
|
+
: { type: DYN, mode: "required" };
|
|
146
|
+
}
|
|
121
147
|
const moduleNs = lowerer.moduleNsParamOverrides.get(param);
|
|
122
148
|
if (moduleNs !== undefined) {
|
|
123
149
|
return { type: moduleNs, mode: param.questionToken ? "omittable" : "required" };
|
|
@@ -159,21 +185,7 @@ export function paramShape(lowerer, param) {
|
|
|
159
185
|
// default when the argument was omitted or undefined, then the
|
|
160
186
|
// pattern destructures the picked value (declareParams).
|
|
161
187
|
const raw = lowerer.irTypeOf(param.name);
|
|
162
|
-
|
|
163
|
-
// `a: any` — jsval for island values, dyn for the checked-dynamic
|
|
164
|
-
// dyn): the slot holds its tier's undefined DIRECTLY, so the ABI
|
|
165
|
-
// is the slot itself — no synthesized union; the prologue tests
|
|
166
|
-
// undefined at runtime (declareParams).
|
|
167
|
-
if (raw.kind === "dyn" || raw.kind === "jsval") {
|
|
168
|
-
return { type: raw, mode: "omittable", bodyType: raw };
|
|
169
|
-
}
|
|
170
|
-
const bodyType = lowerer.stripUndefinedArm(raw);
|
|
171
|
-
lowerer.checkDefaultParamBodyType(param, bodyType);
|
|
172
|
-
const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
|
|
173
|
-
if (!abi) {
|
|
174
|
-
lowerer.badType(param.name, lowerer.typeOf(param.name)); // defensive: unknown union id
|
|
175
|
-
}
|
|
176
|
-
return { type: abi, mode: "omittable", bodyType };
|
|
188
|
+
return defaultParameterShape(lowerer, param, raw);
|
|
177
189
|
}
|
|
178
190
|
return { type: lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name)), mode: "required" };
|
|
179
191
|
}
|
|
@@ -207,41 +219,12 @@ export function paramShape(lowerer, param) {
|
|
|
207
219
|
}
|
|
208
220
|
if (param.initializer) {
|
|
209
221
|
const raw = lowerer.irTypeOf(param.name);
|
|
210
|
-
|
|
211
|
-
// — tsc types x any; jsval for island values, dyn for the checked-
|
|
212
|
-
// dynamic dyn): the slot holds its tier's undefined directly, so
|
|
213
|
-
// the ABI is the slot itself and the prologue's default test is the
|
|
214
|
-
// runtime undefined test (declareParams).
|
|
215
|
-
if (raw.kind === "dyn" || raw.kind === "jsval") {
|
|
216
|
-
return { type: raw, mode: "omittable", bodyType: raw };
|
|
217
|
-
}
|
|
218
|
-
// A default that may ITSELF be undefined (`x = process.env.FOO`):
|
|
219
|
-
// tsc keeps undefined in the body's type, so there is nothing to
|
|
220
|
-
// narrow — the ABI union IS the body type and the prologue passes a
|
|
221
|
-
// present argument through unchanged (declareParams's pass-through
|
|
222
|
-
// branch). The generic strip-and-narrow below would demand a
|
|
223
|
-
// `string`-typed default and fence on the union re-tag.
|
|
224
|
-
if (lowerer.bareUndefinedArmedUnion(raw)) {
|
|
225
|
-
const initT = lowerer.mapTypeOf(lowerer.typeOf(param.initializer));
|
|
226
|
-
if (initT && (initT.kind === "undefinedT" || lowerer.bareUndefinedArmedUnion(initT))) {
|
|
227
|
-
return { type: raw, mode: "omittable", bodyType: raw };
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
const bodyType = lowerer.stripUndefinedArm(raw);
|
|
231
|
-
lowerer.checkDefaultParamBodyType(param, bodyType);
|
|
232
|
-
// A UNION body type (`tlds: string | string[] = "localhost"`) arms
|
|
233
|
-
// the ABI with undefined ON TOP of the body's arms; the prologue
|
|
234
|
-
// re-tags a present argument back into the body union (undefined
|
|
235
|
-
// sorts last among arm typeKeys in practice, so the mapping is
|
|
236
|
-
// usually the identity prefix — the interned retag helper handles
|
|
237
|
-
// any order).
|
|
238
|
-
const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
|
|
239
|
-
if (!abi) {
|
|
240
|
-
lowerer.badType(param.name, lowerer.typeOf(param.name)); // defensive: unknown union id
|
|
241
|
-
}
|
|
242
|
-
return { type: abi, mode: "omittable", bodyType };
|
|
222
|
+
return defaultParameterShape(lowerer, param, raw);
|
|
243
223
|
}
|
|
244
224
|
const type = lowerer.runtimeOptionalBindingType(param.name, lowerer.irTypeOf(param.name));
|
|
225
|
+
if (type.kind === "void") {
|
|
226
|
+
return { type: DYN, mode: param.questionToken ? "omittable" : "required" };
|
|
227
|
+
}
|
|
245
228
|
if (param.questionToken && !lowerer.bareUndefinedArmedUnion(type) && type.kind !== "dyn" && type.kind !== "jsval") {
|
|
246
229
|
// `x?: unknown` where unknown came from an annotation: undefined is
|
|
247
230
|
// absorbed into the hole type, so no undefined ARM exists — but a
|
|
@@ -269,7 +252,7 @@ export function paramShapes(lowerer, params, signature, blameOf) {
|
|
|
269
252
|
return params.map((declParam, i) => {
|
|
270
253
|
const symbol = signature.getParameters()[i];
|
|
271
254
|
const tsType = symbol ? lowerer.checker.getTypeOfSymbol(symbol) : lowerer.typeOf(declParam.name);
|
|
272
|
-
const mapped = lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name));
|
|
255
|
+
const mapped = jsOpenObjectType(declParam, lowerer.runtimeOptionalBindingType(declParam.name, lowerer.mapTypeOf(tsType) ?? lowerer.irTypeOf(declParam.name)), lowerer.shapes, lowerer.unions);
|
|
273
256
|
if (!mapped || mapped.kind === "void")
|
|
274
257
|
lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
|
|
275
258
|
if (declParam.dotDotDotToken) {
|
|
@@ -277,30 +260,46 @@ export function paramShapes(lowerer, params, signature, blameOf) {
|
|
|
277
260
|
lowerer.badType(blameOf?.(declParam, i) ?? declParam.name, tsType);
|
|
278
261
|
return { type: mapped, mode: "rest" };
|
|
279
262
|
}
|
|
280
|
-
if (declParam.initializer)
|
|
281
|
-
|
|
282
|
-
return { type: mapped, mode: "omittable", bodyType: mapped };
|
|
283
|
-
}
|
|
284
|
-
const bodyType = lowerer.stripUndefinedArm(mapped);
|
|
285
|
-
lowerer.checkDefaultParamBodyType(declParam, bodyType);
|
|
286
|
-
return { type: lowerer.withUndefinedArm(bodyType), mode: "omittable", bodyType };
|
|
287
|
-
}
|
|
263
|
+
if (declParam.initializer)
|
|
264
|
+
return defaultParameterShape(lowerer, declParam, mapped);
|
|
288
265
|
if (declParam.questionToken && !lowerer.bareUndefinedArmedUnion(mapped)) {
|
|
289
266
|
lowerer.unsupported("SC1090", declParam, `optional parameters of type '${lowerer.fmt(mapped)}'`);
|
|
290
267
|
}
|
|
291
268
|
return { type: mapped, mode: declParam.questionToken ? "omittable" : "required" };
|
|
292
269
|
});
|
|
293
270
|
}
|
|
271
|
+
/** A default expression may itself yield undefined. Keep that arm in the
|
|
272
|
+
* body and parameter-property storage, including for literal `undefined`
|
|
273
|
+
* and void expressions: the general type mapper represents those as VOID,
|
|
274
|
+
* so checking only a mapped undefinedT silently erased a valid value.
|
|
275
|
+
* Shared by declared and instantiated signatures, including destructuring. */
|
|
276
|
+
function defaultParameterShape(lowerer, param, raw) {
|
|
277
|
+
if (raw.kind === "dyn" || raw.kind === "jsval") {
|
|
278
|
+
return { type: raw, mode: "omittable", bodyType: raw };
|
|
279
|
+
}
|
|
280
|
+
if (lowerer.bareUndefinedArmedUnion(raw) && param.initializer) {
|
|
281
|
+
const initializer = lowerer.typeOf(param.initializer);
|
|
282
|
+
const parts = initializer.isUnionType() ? ts.constituentTypes(initializer) : [initializer];
|
|
283
|
+
if (parts.some((part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0)) {
|
|
284
|
+
return { type: raw, mode: "omittable", bodyType: raw };
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const bodyType = lowerer.stripUndefinedArm(raw);
|
|
288
|
+
lowerer.checkDefaultParamBodyType(param, bodyType);
|
|
289
|
+
const abi = bodyType.kind === "union" ? lowerer.withUndefinedArmOf(bodyType) : lowerer.withUndefinedArm(bodyType);
|
|
290
|
+
if (!abi)
|
|
291
|
+
lowerer.badType(param.name, lowerer.typeOf(param.name));
|
|
292
|
+
return { type: abi, mode: "omittable", bodyType };
|
|
293
|
+
}
|
|
294
294
|
/** The fences on a defaulted parameter's body type: it becomes the value
|
|
295
295
|
* arm of the synthesized `T | undefined` ABI union, so it must be a valid
|
|
296
|
-
* single arm.
|
|
296
|
+
* single arm. Functions, Maps and Sets are valid: the ABI union's test is
|
|
297
297
|
* the prologue's own undefined-tag check (never a user narrowing, which
|
|
298
|
-
* is what keeps
|
|
298
|
+
* is what keeps containers out of unions with data siblings), so `runner: Runner =
|
|
299
299
|
* defaultRunner` and `skip: Set<string> = new Set()` arm like any ref
|
|
300
300
|
* kind — the nullable-callback union shape, built by the compiler. */
|
|
301
301
|
export function checkDefaultParamBodyType(lowerer, param, bodyType) {
|
|
302
302
|
if (bodyType.kind === "void" ||
|
|
303
|
-
bodyType.kind === "map" ||
|
|
304
303
|
bodyType.kind === "regex" ||
|
|
305
304
|
bodyType.kind === "date" ||
|
|
306
305
|
bodyType.kind === "dyn" ||
|
|
@@ -336,7 +335,62 @@ export function completeArgs(lowerer, argNodes, shapes, loc, blame,
|
|
|
336
335
|
* coercion an ordinary argument gets (coerceInto against its shape,
|
|
337
336
|
* DYN conversion in a dyn rest, element coercion in a typed rest). */
|
|
338
337
|
leading) {
|
|
339
|
-
|
|
338
|
+
// Conversion eligibility can traverse the whole recursive parameter
|
|
339
|
+
// graph. Ordinary calls and fixed tuples never need that analysis.
|
|
340
|
+
if (argNodes.some((arg) => ts.isSpreadElement(arg) && !fixedTupleSpreadInfo(lowerer, arg.expression)) &&
|
|
341
|
+
canCompleteRuntimeSpread(lowerer, shapes)) {
|
|
342
|
+
// Runtime-length spreads determine the complete argument list before
|
|
343
|
+
// any parameter default runs. Build it once in source order, then
|
|
344
|
+
// extract the fixed native ABI slots; missing elements are undefined.
|
|
345
|
+
const pack = lowerer.declareHiddenLocal("%spreadArgs", DYN);
|
|
346
|
+
const ref = () => ({ kind: "varRef", localId: pack.id, type: DYN, loc });
|
|
347
|
+
const stmts = [{ kind: "varDecl", localId: pack.id, init: { kind: "dynArrLit", elems: [], type: DYN, loc }, loc }];
|
|
348
|
+
const push = (value, fn) => {
|
|
349
|
+
stmts.push({ kind: "exprStmt", expr: { kind: "libCall", fn, args: [ref(), value], type: VOID, loc: value.loc }, loc: value.loc });
|
|
350
|
+
};
|
|
351
|
+
for (const value of leading ?? [])
|
|
352
|
+
push(lowerer.coerceInto(blame, value, DYN), "dyn.packPush");
|
|
353
|
+
const spreads = argNodes.filter(ts.isSpreadElement).length;
|
|
354
|
+
argNodes.forEach((arg, index) => {
|
|
355
|
+
if (!ts.isSpreadElement(arg)) {
|
|
356
|
+
push(lowerer.lowerExprExpecting(arg, DYN), "dyn.packPush");
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
let value = lowerer.lowerExpr(arg.expression);
|
|
360
|
+
if (value.type.kind === "set") {
|
|
361
|
+
value = { kind: "setIntrinsic", method: "toArray", receiver: value, args: [], type: arrayOf(value.type.elem), loc: value.loc };
|
|
362
|
+
}
|
|
363
|
+
else if (value.type.kind === "object") {
|
|
364
|
+
value = lowerer.classIteratorDrainCall(value, locOf(arg)) ?? value;
|
|
365
|
+
}
|
|
366
|
+
if (value.type.kind === "array") {
|
|
367
|
+
// Argument iteration materializes holes as present undefined
|
|
368
|
+
// before conversion to the dense checked-dynamic argument pack.
|
|
369
|
+
value = { kind: "arrayLit", elems: [value], spreads: [0], type: value.type, loc: value.loc };
|
|
370
|
+
}
|
|
371
|
+
value = lowerer.coerceInto(arg.expression, value, DYN);
|
|
372
|
+
if (spreads === 1 && index === argNodes.length - 1) {
|
|
373
|
+
stmts.push({ kind: "exprStmt", expr: {
|
|
374
|
+
kind: "libCall", fn: "dyn.packPushSpread", args: [ref(), value, { kind: "strLit", value: arg.expression.getText(), type: STRING, loc }], type: VOID, loc,
|
|
375
|
+
}, loc });
|
|
376
|
+
}
|
|
377
|
+
else
|
|
378
|
+
push(value, "dyn.packPushSpreadIter");
|
|
379
|
+
});
|
|
380
|
+
const args = shapes.map((shape, index) => {
|
|
381
|
+
if (shape.mode === "arguments")
|
|
382
|
+
return ref();
|
|
383
|
+
const value = shape.mode === "rest" || shape.mode === "dynRest"
|
|
384
|
+
? { kind: "dynInvoke", recv: ref(), method: "slice", calleeName: "arguments.slice", args: [{ kind: "dynFrom", value: { kind: "numLit", value: index, type: F64, loc }, type: DYN, loc }], type: DYN, loc }
|
|
385
|
+
: { kind: "dynKeyGet", value: ref(), key: { kind: "strLit", value: String(index), type: STRING, loc }, type: DYN, loc };
|
|
386
|
+
return lowerer.coerceInto(blame, value, shape.type);
|
|
387
|
+
});
|
|
388
|
+
// Every supported form has at least one native slot to carry the
|
|
389
|
+
// evaluation prefix, including calls whose only slot is their rest.
|
|
390
|
+
args[0] = { kind: "seqExpr", stmts, result: args[0], type: args[0].type, loc };
|
|
391
|
+
return args;
|
|
392
|
+
}
|
|
393
|
+
const isIr = (s) => s !== undefined && !(s instanceof AstNode);
|
|
340
394
|
const sources = leading?.map((ir) => ({ ir })) ?? [];
|
|
341
395
|
for (const arg of argNodes) {
|
|
342
396
|
if (!ts.isSpreadElement(arg)) {
|
|
@@ -399,9 +453,20 @@ leading) {
|
|
|
399
453
|
lowerer.unsupported("SC1090", source, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
400
454
|
}
|
|
401
455
|
const slotType = i < restAt ? positional[i].type : DYN;
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
456
|
+
let value;
|
|
457
|
+
if (isIr(source)) {
|
|
458
|
+
let ir = source.ir;
|
|
459
|
+
// Tuple-spread storage also feeds later arguments. Declare it in
|
|
460
|
+
// this shared sequence, not inside one argument's initializer,
|
|
461
|
+
// whose statement frame ends before the next field is read.
|
|
462
|
+
if (ir.kind === "seqExpr") {
|
|
463
|
+
stmts.push(...ir.stmts);
|
|
464
|
+
ir = ir.result;
|
|
465
|
+
}
|
|
466
|
+
value = lowerer.coerceInto(blame, ir, slotType);
|
|
467
|
+
}
|
|
468
|
+
else
|
|
469
|
+
value = lowerer.lowerExprExpecting(source, slotType);
|
|
405
470
|
const saved = lowerer.declareHiddenLocal("%callArg", slotType);
|
|
406
471
|
stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc });
|
|
407
472
|
return { kind: "varRef", localId: saved.id, type: slotType, loc: value.loc };
|
|
@@ -409,7 +474,7 @@ leading) {
|
|
|
409
474
|
const fixed = positional.map((shape, i) => {
|
|
410
475
|
if (i < passed.length)
|
|
411
476
|
return passed[i];
|
|
412
|
-
if (shape.mode === "omittable")
|
|
477
|
+
if (shape.mode === "omittable" || lowerer.bareUndefinedArmedUnion(shape.type))
|
|
413
478
|
return shape.callDefault ?? lowerer.undefinedArgFor(shape.type, loc, blame);
|
|
414
479
|
if (shape.type.kind === "dyn")
|
|
415
480
|
return { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
|
|
@@ -434,9 +499,19 @@ leading) {
|
|
|
434
499
|
// completion has no home for that. Spreads fill REST slots only.
|
|
435
500
|
lowerer.unsupported("SC1090", arg, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
436
501
|
}
|
|
437
|
-
if (arg)
|
|
502
|
+
if (arg) {
|
|
503
|
+
let operand = arg;
|
|
504
|
+
while (ts.isParenthesizedExpression(operand))
|
|
505
|
+
operand = operand.expression;
|
|
506
|
+
if (ts.isVoidExpression(operand)) {
|
|
507
|
+
const absent = omittedArgFor(lowerer, shape.type, loc);
|
|
508
|
+
const effect = lowerStaticallyUndefinedArgument(lowerer, operand);
|
|
509
|
+
if (absent && effect)
|
|
510
|
+
return defaultAfterUndefined(effect, absent);
|
|
511
|
+
}
|
|
438
512
|
return lowerer.lowerExprExpecting(arg, shape.type);
|
|
439
|
-
|
|
513
|
+
}
|
|
514
|
+
if (shape.mode !== "omittable" && !lowerer.bareUndefinedArmedUnion(shape.type)) {
|
|
440
515
|
// A missing argument for a CHECKED-DYNAMIC param (an implicit-any
|
|
441
516
|
// JS signature called short — `mustCall(fn)` with `expected`
|
|
442
517
|
// omitted): JS fills undefined, and the dyn slot holds exactly
|
|
@@ -565,8 +640,7 @@ leading) {
|
|
|
565
640
|
lowerer.unsupported("SC1090", a, "spread arguments into fixed parameter positions (a spread can only fill a rest parameter)");
|
|
566
641
|
}
|
|
567
642
|
const v = lowerer.lowerExpr(a);
|
|
568
|
-
if (v
|
|
569
|
-
v.kind !== "boolLit" && v.kind !== "varRef" && v.kind !== "closure") {
|
|
643
|
+
if (!isSafeToDiscard(v)) {
|
|
570
644
|
lowerer.unsupported("SC1090", a, "surplus arguments with side effects (JS evaluates surplus arguments to a function without a rest parameter, then drops them; only effect-free surplus arguments compile)");
|
|
571
645
|
}
|
|
572
646
|
}
|
|
@@ -690,7 +764,9 @@ export function requireExactArityValue(lowerer, blame, contextual, shapes, funcT
|
|
|
690
764
|
// slot): judge by the expression's OWN completed type; the slot's
|
|
691
765
|
// coercion still enforces (or adapts) the flow it lands in.
|
|
692
766
|
if (mappedFn?.kind !== "func" && contextual) {
|
|
693
|
-
|
|
767
|
+
const ownType = lowerer.typeOf(contextual);
|
|
768
|
+
mappedFn = lowerer.mapTypeOf(ownType) ??
|
|
769
|
+
(isJsSourceFile(contextual.getSourceFile()) ? dynFallbackType(lowerer, contextual, ownType) : null);
|
|
694
770
|
}
|
|
695
771
|
if (mappedFn && typeEquals(mappedFn, funcType))
|
|
696
772
|
return;
|
|
@@ -795,7 +871,7 @@ export function appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc) {
|
|
|
795
871
|
/** A declaration's checker-derived IR return type. The unmappable-type
|
|
796
872
|
* diagnostic points at `blame` (the name for top-level declarations, the
|
|
797
873
|
* whole node for lambda-likes — preserving each caller's historical loc). */
|
|
798
|
-
function hasExplicitJsDocReturn(decl) {
|
|
874
|
+
export function hasExplicitJsDocReturn(decl) {
|
|
799
875
|
const sourceFile = decl.getSourceFile();
|
|
800
876
|
return /@returns?\b/.test(sourceFile.text.slice(decl.pos, decl.getStart(sourceFile)));
|
|
801
877
|
}
|
|
@@ -805,11 +881,25 @@ function promiseCarriesDyn(lowerer, type) {
|
|
|
805
881
|
return type.kind === "union" &&
|
|
806
882
|
(lowerer.unions.get(type.unionId)?.arms.some((arm) => promiseCarriesDyn(lowerer, arm)) ?? false);
|
|
807
883
|
}
|
|
884
|
+
function producesConstructor(lowerer, type) {
|
|
885
|
+
let result = type;
|
|
886
|
+
for (let depth = 0; result && depth < 8; depth++) {
|
|
887
|
+
if (lowerer.checker.getConstructSignatures(result).length > 0)
|
|
888
|
+
return true;
|
|
889
|
+
const signatures = lowerer.checker.getCallSignatures(result);
|
|
890
|
+
result = signatures.length === 1 ? lowerer.checker.getReturnTypeOfSignature(signatures[0]) : undefined;
|
|
891
|
+
}
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
808
894
|
export function declaredReturnType(lowerer, decl, blame) {
|
|
809
895
|
const sig = lowerer.checker.getSignatureFromDeclaration(decl);
|
|
810
896
|
if (!sig)
|
|
811
897
|
lowerer.unsupported("SC1090", decl, "this function form");
|
|
812
898
|
const retTsType = lowerer.checker.getReturnTypeOfSignature(sig);
|
|
899
|
+
// An inferred null/undefined return in JS can read a mutable checked-value
|
|
900
|
+
// field. Keep the actual value instead of restricting it to the initializer.
|
|
901
|
+
if (isJsSourceFile(decl.getSourceFile()) && (retTsType.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined)) !== 0)
|
|
902
|
+
return DYN;
|
|
813
903
|
// A body that always throws infers `never` — as a RETURN type that is
|
|
814
904
|
// void with a stronger guarantee (`() => never` is assignable to
|
|
815
905
|
// `() => void`), and throw-only callbacks are ordinary code
|
|
@@ -817,10 +907,36 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
817
907
|
if (retTsType.flags & ts.TypeFlags.Never)
|
|
818
908
|
return VOID;
|
|
819
909
|
const mappedReturn = lowerer.mapTypeOf(retTsType);
|
|
910
|
+
if (isJsSourceFile(decl.getSourceFile()) && mappedReturn?.kind === "array" && mappedReturn.elem.kind === "f64")
|
|
911
|
+
return DYN;
|
|
912
|
+
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) && mappedReturn?.kind === "date")
|
|
913
|
+
return DYN;
|
|
914
|
+
// JS inference assigns Number to arithmetic over any, although the
|
|
915
|
+
// runtime operands can both be BigInts. Preserve that native result.
|
|
916
|
+
if (isJsSourceFile(decl.getSourceFile()) && !decl.type && !hasExplicitJsDocReturn(decl) &&
|
|
917
|
+
mappedReturn?.kind === "f64") {
|
|
918
|
+
let numericAnyReturn = false;
|
|
919
|
+
const numeric = new Set([ts.SyntaxKind.MinusToken, ts.SyntaxKind.AsteriskToken,
|
|
920
|
+
ts.SyntaxKind.SlashToken, ts.SyntaxKind.PercentToken, ts.SyntaxKind.AsteriskAsteriskToken]);
|
|
921
|
+
const check = (node) => {
|
|
922
|
+
if (node !== decl && ts.isFunctionLike(node))
|
|
923
|
+
return;
|
|
924
|
+
const value = ts.isReturnStatement(node) ? node.expression
|
|
925
|
+
: node === decl && ts.isArrowFunction(decl) && !ts.isBlock(decl.body) ? decl.body : undefined;
|
|
926
|
+
if (value && ts.isBinaryExpression(value) && numeric.has(value.operatorToken.kind) &&
|
|
927
|
+
[value.left, value.right].some((operand) => (lowerer.typeOf(operand).flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0))
|
|
928
|
+
numericAnyReturn = true;
|
|
929
|
+
node.forEachChild(check);
|
|
930
|
+
};
|
|
931
|
+
check(decl);
|
|
932
|
+
if (numericAnyReturn)
|
|
933
|
+
return DYN;
|
|
934
|
+
}
|
|
820
935
|
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
821
936
|
!hasExplicitJsDocReturn(decl) &&
|
|
822
937
|
mappedReturn !== null &&
|
|
823
938
|
promiseCarriesDyn(lowerer, mappedReturn) &&
|
|
939
|
+
!decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) &&
|
|
824
940
|
decl.parameters.some((param) => {
|
|
825
941
|
const mapped = lowerer.mapTypeOf(lowerer.typeOf(param.name));
|
|
826
942
|
return mapped === null || mapped.kind === "dyn";
|
|
@@ -852,14 +968,22 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
852
968
|
// checked-dynamic (or none): a lambda with RECORD-typed parameters
|
|
853
969
|
// (a reduce reducer over a typed array) legitimately returns its
|
|
854
970
|
// parameters' records and keeps the static type.
|
|
971
|
+
// Native-only members (such as Int32Array layout offsets) cannot cross
|
|
972
|
+
// that boundary; their factories keep the native record ABI.
|
|
973
|
+
const asyncReturn = decl.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) && mappedReturn?.kind === "promise";
|
|
974
|
+
const recordReturn = asyncReturn ? mappedReturn.inner : mappedReturn;
|
|
975
|
+
const recordArms = recordReturn?.kind === "union" ? lowerer.unions.get(recordReturn.unionId)?.arms : recordReturn ? [recordReturn] : undefined;
|
|
976
|
+
const inferredRecordReturn = recordArms?.some((arm) => arm.kind === "record" || arm.kind === "object") &&
|
|
977
|
+
recordArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" && !hasExplicitJsDocReturn(decl));
|
|
855
978
|
if (isJsSourceFile(decl.getSourceFile()) &&
|
|
856
979
|
decl.type === undefined &&
|
|
857
|
-
|
|
980
|
+
recordReturn !== null && recordReturn !== undefined && inferredRecordReturn &&
|
|
981
|
+
lowerer.dynConvertible(recordReturn) &&
|
|
858
982
|
decl.parameters.every((p) => {
|
|
859
983
|
const mt = lowerer.mapTypeOf(lowerer.typeOf(p));
|
|
860
984
|
return mt === null || mt.kind === "dyn";
|
|
861
985
|
})) {
|
|
862
|
-
return DYN;
|
|
986
|
+
return asyncReturn ? { kind: "promise", inner: DYN } : DYN;
|
|
863
987
|
}
|
|
864
988
|
const returnType = lowerer.mapTypeOf(retTsType);
|
|
865
989
|
if (!returnType) {
|
|
@@ -884,7 +1008,7 @@ export function declaredReturnType(lowerer, decl, blame) {
|
|
|
884
1008
|
* other unmappable type (the caller's badType reports those). */
|
|
885
1009
|
function fenceGenericSignatureResult(lowerer, blame, t) {
|
|
886
1010
|
const parts = t.isUnionType() ? ts.constituentTypes(t) : [t];
|
|
887
|
-
if (!parts.some((p) => lowerer.checker.getCallSignatures(p).some((s) =>
|
|
1011
|
+
if (!parts.some((p) => lowerer.checker.getCallSignatures(p).some((s) => s.getTypeParameters().length > 0))) {
|
|
888
1012
|
return;
|
|
889
1013
|
}
|
|
890
1014
|
lowerer.unsupported("SC1090", blame, `results that are themselves generic functions ('${lowerer.checker.typeToString(t)}' keeps its type parameters — no call-site instantiation pins them, and the returned value would need the producing call's frame; restructure to one generic function taking all arguments)`);
|
|
@@ -961,7 +1085,7 @@ export function collectSignatureInner(lowerer, decl) {
|
|
|
961
1085
|
if (!params.some((sh) => sh.mode === "rest" || sh.mode === "dynRest" || sh.mode === "islandRest") &&
|
|
962
1086
|
isJsSourceFile(decl.getSourceFile()) &&
|
|
963
1087
|
bodyReadsArguments(decl)) {
|
|
964
|
-
if (decl.parameters.length > 0 && !isNodeEsmFile(decl.getSourceFile())) {
|
|
1088
|
+
if (decl.parameters.length > 0 && !isNodeEsmFile(decl.getSourceFile(), lowerer.program)) {
|
|
965
1089
|
lowerer.unsupported("SC1090", decl, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
|
|
966
1090
|
}
|
|
967
1091
|
params.push({ type: DYN, mode: decl.parameters.length > 0 ? "arguments" : "dynRest" });
|
|
@@ -1193,7 +1317,7 @@ export function inferTypeParamBindings(lowerer, expr, info, rsig, tsBindings) {
|
|
|
1193
1317
|
return;
|
|
1194
1318
|
const taT = lowerer.checker.getTypeFromTypeNode(ta);
|
|
1195
1319
|
const mapped = lowerer.mapTypeOf(taT);
|
|
1196
|
-
if (mapped
|
|
1320
|
+
if (mapped) {
|
|
1197
1321
|
bindings.set(tp, mapped);
|
|
1198
1322
|
tsBindings?.set(tp, taT);
|
|
1199
1323
|
}
|
|
@@ -1213,7 +1337,7 @@ function bindDefaultTypeParams(lowerer, typeParams, typeParamDecls, bindings, ts
|
|
|
1213
1337
|
return;
|
|
1214
1338
|
const defT = lowerer.checker.getTypeFromTypeNode(tpDecl.defaultType);
|
|
1215
1339
|
const mapped = lowerer.mapTypeOf(defT);
|
|
1216
|
-
if (mapped
|
|
1340
|
+
if (mapped) {
|
|
1217
1341
|
bindings.set(tp, mapped);
|
|
1218
1342
|
tsBindings?.set(tp, defT);
|
|
1219
1343
|
}
|
|
@@ -1255,7 +1379,10 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
|
|
|
1255
1379
|
}
|
|
1256
1380
|
if (!bindings.has(sym)) {
|
|
1257
1381
|
const mapped = lowerer.mapTypeOf(inst);
|
|
1258
|
-
|
|
1382
|
+
// A visitor's inferred T can be void. It still binds the
|
|
1383
|
+
// return convention of `(node) => T`; discarding it leaves
|
|
1384
|
+
// the callback's return type spuriously uninstantiated.
|
|
1385
|
+
if (mapped)
|
|
1259
1386
|
bindings.set(sym, mapped);
|
|
1260
1387
|
}
|
|
1261
1388
|
}
|
|
@@ -1270,10 +1397,20 @@ function unifySignatureBindings(lowerer, info, rsig, bindings, tsBindings) {
|
|
|
1270
1397
|
// unbound type parameter surfaces as a mapping diagnostic later).
|
|
1271
1398
|
if (declared.isUnionType()) {
|
|
1272
1399
|
const unitFlags = ts.TypeFlags.Undefined | ts.TypeFlags.Null;
|
|
1273
|
-
const
|
|
1274
|
-
const
|
|
1400
|
+
const declaredParts = ts.constituentTypes(declared);
|
|
1401
|
+
const declaredUnits = declaredParts.reduce((flags, t) => flags | (t.flags & unitFlags), 0);
|
|
1402
|
+
const dParts = declaredParts.filter((t) => !(t.flags & unitFlags));
|
|
1403
|
+
const iParts = inst.isUnionType() ? ts.constituentTypes(inst).filter((t) => !(t.flags & declaredUnits)) : [inst];
|
|
1275
1404
|
if (dParts.length === 1 && iParts.length === 1)
|
|
1276
1405
|
unify(dParts[0], iParts[0], depth + 1);
|
|
1406
|
+
else if (dParts.length === 1 && iParts.length > 1 &&
|
|
1407
|
+
iParts.every((t) => (t.flags & unitFlags) === 0)) {
|
|
1408
|
+
// T | undefined can receive boolean | undefined: boolean itself
|
|
1409
|
+
// has two literal arms. There is still one declared data slot,
|
|
1410
|
+
// so match it against the whole remaining union. Removing null
|
|
1411
|
+
// too is safe only when no undeclared null arm remains.
|
|
1412
|
+
unify(dParts[0], lowerer.checker.getNonNullableType(inst), depth + 1);
|
|
1413
|
+
}
|
|
1277
1414
|
return;
|
|
1278
1415
|
}
|
|
1279
1416
|
// Instantiations of the SAME generic ALIAS (Partial<T> vs
|
|
@@ -1426,16 +1563,21 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1426
1563
|
fnCtx.generator = generatorMeta(lowerer, inst.returnType);
|
|
1427
1564
|
}
|
|
1428
1565
|
lowerer.fnStack.push(fnCtx);
|
|
1566
|
+
lowerer.localClassInstantiations.push({ owner: decl, name: inst.name });
|
|
1429
1567
|
try {
|
|
1430
|
-
//
|
|
1431
|
-
//
|
|
1432
|
-
//
|
|
1433
|
-
// are transparent (they inherit the method's `this`); this-binding
|
|
1434
|
-
// function forms are opaque.
|
|
1568
|
+
// Static specializations bind lexical this only when the caller
|
|
1569
|
+
// proved its exact receiver. Other instances retain the fence;
|
|
1570
|
+
// super remains unsupported. Arrows inherit the lexical receiver.
|
|
1435
1571
|
if (info.member?.kind === "static" && decl.body) {
|
|
1436
|
-
rejectStaticThis(lowerer, decl.body, (keyword) => `'${keyword}' in static methods (it names the RECEIVER class — a dynamic value; reference the class by name instead)
|
|
1572
|
+
rejectStaticThis(lowerer, decl.body, (keyword) => `'${keyword}' in static methods (it names the RECEIVER class — a dynamic value; reference the class by name instead)`, false, info.staticReceiver !== undefined);
|
|
1437
1573
|
}
|
|
1438
1574
|
const params = [];
|
|
1575
|
+
const receiverInit = [];
|
|
1576
|
+
if (info.staticReceiver) {
|
|
1577
|
+
const value = lowerer.classValueRef(info.staticReceiver, decl);
|
|
1578
|
+
const local = lowerer.declareThis(value.type);
|
|
1579
|
+
receiverInit.push({ kind: "varDecl", localId: local.id, init: value, loc: locOf(decl) });
|
|
1580
|
+
}
|
|
1439
1581
|
if (cls && info.member.kind === "method") {
|
|
1440
1582
|
// Instance methods take `this` as param 0, exactly like plain
|
|
1441
1583
|
// `%C.method` functions (lowerClassMethodMemberInner).
|
|
@@ -1447,12 +1589,13 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1447
1589
|
// threaded — a default mentioning T resolves like any body expression.
|
|
1448
1590
|
const declared = lowerer.declareParams(decl.parameters, inst.params);
|
|
1449
1591
|
params.push(...declared.params);
|
|
1450
|
-
const body = [...declared.prologue];
|
|
1592
|
+
const body = [...receiverInit, ...declared.prologue];
|
|
1451
1593
|
const bodyBlock = blockBodyOf(decl);
|
|
1452
1594
|
if (bodyBlock) {
|
|
1453
1595
|
body.push(...lowerer.lowerStmts(bodyBlock.statements));
|
|
1454
1596
|
if (fnCtx.inferReturn) {
|
|
1455
1597
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1598
|
+
inst.returnType = bodyReturn;
|
|
1456
1599
|
}
|
|
1457
1600
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1458
1601
|
}
|
|
@@ -1466,6 +1609,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1466
1609
|
if (value.type.kind === "void") {
|
|
1467
1610
|
body.push({ kind: "exprStmt", expr: value, loc: locOf(decl.body) });
|
|
1468
1611
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1612
|
+
inst.returnType = bodyReturn;
|
|
1469
1613
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
1470
1614
|
}
|
|
1471
1615
|
else {
|
|
@@ -1473,6 +1617,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1473
1617
|
fnCtx.inferReturn.entries.push({ stmt, node: decl.body });
|
|
1474
1618
|
body.push(stmt);
|
|
1475
1619
|
bodyReturn = resolveInferredReturn(lowerer, inst, fnCtx.inferReturn, body, decl);
|
|
1620
|
+
inst.returnType = bodyReturn;
|
|
1476
1621
|
}
|
|
1477
1622
|
}
|
|
1478
1623
|
else {
|
|
@@ -1490,6 +1635,8 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1490
1635
|
}
|
|
1491
1636
|
const fn = {
|
|
1492
1637
|
name: inst.name,
|
|
1638
|
+
sourceName: info.baseName,
|
|
1639
|
+
...(!isAsync && !decl.asteriskToken && (ts.isFunctionDeclaration(decl) || ts.isFunctionExpression(decl)) ? { ownsPrototype: true } : {}),
|
|
1493
1640
|
params,
|
|
1494
1641
|
returnType: bodyReturn,
|
|
1495
1642
|
locals: lowerer.ctx.locals,
|
|
@@ -1509,6 +1656,7 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1509
1656
|
lowerer.typeParamTsBindings = prevTsBindings;
|
|
1510
1657
|
lowerer.implicitParamTypes = prevImplicit;
|
|
1511
1658
|
lowerer.instantiationContext = prevContext;
|
|
1659
|
+
lowerer.localClassInstantiations.pop();
|
|
1512
1660
|
lowerer.suppressStats = prevSuppress;
|
|
1513
1661
|
}
|
|
1514
1662
|
}
|
|
@@ -1524,14 +1672,15 @@ export function lowerGenericInstance(lowerer, info, inst) {
|
|
|
1524
1672
|
* adds JS's undefined; DYN when returns disagree (the checked-dynamic
|
|
1525
1673
|
* result slot — today's shape). Same-key recursion PINNED the fallback
|
|
1526
1674
|
* type mid-lowering (callers already hold it), so a pinned instance
|
|
1527
|
-
* keeps it and the wrap pass coerces every return to the pin.
|
|
1675
|
+
* keeps it and the wrap pass coerces every return to the pin. Callers
|
|
1676
|
+
* store the settled type on their full instance; this narrower view
|
|
1677
|
+
* can be a structural copy in native builds. */
|
|
1528
1678
|
function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
1529
1679
|
// The conservative completion test appendImplicitUndefinedReturn uses:
|
|
1530
1680
|
// a body whose last statement isn't a terminator may complete without
|
|
1531
1681
|
// returning — JS answers undefined.
|
|
1532
1682
|
const last = body[body.length - 1];
|
|
1533
1683
|
const mayFallThrough = !last || !(last.kind === "return" || last.kind === "throw" || last.kind === "rethrow" || last.kind === "runtimeFence");
|
|
1534
|
-
const valued = infer.entries.filter((e) => e.stmt.kind === "return" && e.stmt.value !== null && e.stmt.value !== undefined);
|
|
1535
1684
|
const sawBare = mayFallThrough || infer.entries.some((e) => e.stmt.kind === "return" && (e.stmt.value === null || e.stmt.value === undefined));
|
|
1536
1685
|
let final;
|
|
1537
1686
|
if (inst.returnPinned) {
|
|
@@ -1539,43 +1688,46 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
|
1539
1688
|
}
|
|
1540
1689
|
else {
|
|
1541
1690
|
const distinct = [];
|
|
1542
|
-
for (const e of
|
|
1543
|
-
if (
|
|
1544
|
-
|
|
1691
|
+
for (const e of infer.entries) {
|
|
1692
|
+
if (e.stmt.kind !== "return" || e.stmt.value === null || e.stmt.value === undefined)
|
|
1693
|
+
continue;
|
|
1694
|
+
const type = e.stmt.value.type;
|
|
1695
|
+
if (!distinct.some((t) => typeEquals(t, type)))
|
|
1696
|
+
distinct.push(type);
|
|
1545
1697
|
}
|
|
1546
1698
|
if (distinct.length === 0) {
|
|
1547
1699
|
final = DYN; // no valued return: JS completes with undefined — the dyn undefined, today's slot
|
|
1548
1700
|
}
|
|
1549
1701
|
else if (distinct.length === 1) {
|
|
1550
1702
|
const t = distinct[0];
|
|
1551
|
-
final = !sawBare ? t : t.kind === "dyn" ? DYN : (lowerer.withUndefinedArmOf(t) ?? DYN);
|
|
1703
|
+
final = isUnitType(t) ? DYN : !sawBare ? t : t.kind === "dyn" ? DYN : (lowerer.withUndefinedArmOf(t) ?? DYN);
|
|
1552
1704
|
}
|
|
1553
1705
|
else {
|
|
1554
1706
|
final = DYN; // disagreeing returns: the checked-dynamic join
|
|
1555
1707
|
}
|
|
1556
|
-
inst.returnType = final;
|
|
1557
1708
|
}
|
|
1558
1709
|
// The wrap pass: settle every recorded return onto `final`, in place.
|
|
1710
|
+
// Write through the stored union arm: optional-field widening on a
|
|
1711
|
+
// local alias can otherwise introduce a record copy in native builds.
|
|
1559
1712
|
for (const e of infer.entries) {
|
|
1560
1713
|
if (e.stmt.kind !== "return")
|
|
1561
1714
|
continue;
|
|
1562
|
-
const st = e.stmt;
|
|
1563
1715
|
const diagsBefore = lowerer.diags.length;
|
|
1564
1716
|
try {
|
|
1565
|
-
if (
|
|
1717
|
+
if (e.stmt.value === null || e.stmt.value === undefined) {
|
|
1566
1718
|
if (final.kind === "dyn")
|
|
1567
|
-
|
|
1719
|
+
e.stmt.value = dynUndefinedExpr(e.stmt.loc);
|
|
1568
1720
|
else if (final.kind === "union") {
|
|
1569
|
-
const wrapped = lowerer.wrappedUndefined(final,
|
|
1721
|
+
const wrapped = lowerer.wrappedUndefined(final, e.stmt.loc);
|
|
1570
1722
|
if (!wrapped) {
|
|
1571
1723
|
lowerer.unsupported("SC1090", e.node ?? decl, `bare 'return' in a function whose inferred return type is '${lowerer.fmt(final)}'`);
|
|
1572
1724
|
}
|
|
1573
|
-
|
|
1725
|
+
e.stmt.value = wrapped;
|
|
1574
1726
|
}
|
|
1575
1727
|
// void final: bare return stands as-is
|
|
1576
1728
|
}
|
|
1577
|
-
else if (!typeEquals(
|
|
1578
|
-
|
|
1729
|
+
else if (!typeEquals(e.stmt.value.type, final)) {
|
|
1730
|
+
e.stmt.value = lowerer.coerceInto(e.node ?? decl, e.stmt.value, final);
|
|
1579
1731
|
}
|
|
1580
1732
|
}
|
|
1581
1733
|
catch (err) {
|
|
@@ -1590,7 +1742,7 @@ function resolveInferredReturn(lowerer, inst, infer, body, decl) {
|
|
|
1590
1742
|
lowerer.diags.push(...ice);
|
|
1591
1743
|
lowerer.runtimeFences.push(...captured.filter((d) => d.code !== "SC9001"));
|
|
1592
1744
|
const first = captured.find((d) => d.code !== "SC9001");
|
|
1593
|
-
const mutable =
|
|
1745
|
+
const mutable = e.stmt;
|
|
1594
1746
|
delete mutable["value"];
|
|
1595
1747
|
mutable["kind"] = "runtimeFence";
|
|
1596
1748
|
mutable["code"] = first?.code ?? "SC1090";
|
|
@@ -1848,10 +2000,12 @@ function broadPromiseParam(lowerer, type) {
|
|
|
1848
2000
|
}
|
|
1849
2001
|
/** The implicit-type-parameter slots of a JS function-like: parallel to
|
|
1850
2002
|
* decl.parameters, the param SYMBOL where the slot is a bindable
|
|
1851
|
-
* implicit
|
|
1852
|
-
* rest/optional/defaulted, never written), null elsewhere.
|
|
1853
|
-
*
|
|
1854
|
-
|
|
2003
|
+
* implicit param (identifier-named, broad inferred/JSDoc type, not
|
|
2004
|
+
* rest/optional/defaulted, never written), null elsewhere. Package JS
|
|
2005
|
+
* methods may also specialize class parameters: JSDoc names a nominal
|
|
2006
|
+
* class even when the body accepts other objects with the same members.
|
|
2007
|
+
* Null overall when nothing qualifies — the declaration keeps its ABI. */
|
|
2008
|
+
export function implicitAnyParamSymbolsOf(lowerer, decl, classParams = false) {
|
|
1855
2009
|
if (!decl.body)
|
|
1856
2010
|
return null;
|
|
1857
2011
|
if (decl.asteriskToken)
|
|
@@ -1877,7 +2031,9 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
|
|
|
1877
2031
|
const broadFunction = lowerer.checker.typeToString(t) === "Function";
|
|
1878
2032
|
const broadArray = lowerer.checkerAnyArrayType(t);
|
|
1879
2033
|
const broadPromise = broadPromiseParam(lowerer, t);
|
|
1880
|
-
|
|
2034
|
+
const declaredKind = classParams ? lowerer.mapTypeOf(t)?.kind : undefined;
|
|
2035
|
+
const classParam = classParams && (declaredKind === "object" || declaredKind === "array");
|
|
2036
|
+
if ((t.flags & ts.TypeFlags.Any) === 0 && !broadFunction && !broadArray && !broadPromise && !classParam)
|
|
1881
2037
|
return null;
|
|
1882
2038
|
const sym = lowerer.checker.getSymbolAtLocation(param.name);
|
|
1883
2039
|
if (!sym)
|
|
@@ -1896,6 +2052,11 @@ export function implicitAnyParamSymbolsOf(lowerer, decl) {
|
|
|
1896
2052
|
* selects return INFERENCE with DYN as the recursion pin. */
|
|
1897
2053
|
function implicitDeclaredReturn(lowerer, info) {
|
|
1898
2054
|
try {
|
|
2055
|
+
// Static JS helpers can accept a structurally compatible class despite
|
|
2056
|
+
// narrower JSDoc (for example a Vector2 target documented as Vector3).
|
|
2057
|
+
// Infer their result from the specialized body as well.
|
|
2058
|
+
if (info.member?.kind === "static" && info.decl.parameters.some((param, index) => info.implicitParams?.[index] && lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "object"))
|
|
2059
|
+
return null;
|
|
1899
2060
|
const broadCallbackSymbols = new Set(info.decl.parameters.flatMap((param, index) => {
|
|
1900
2061
|
const symbol = info.implicitParams?.[index];
|
|
1901
2062
|
return symbol !== null && symbol !== undefined &&
|
|
@@ -1915,7 +2076,10 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
1915
2076
|
expression = expression.expression;
|
|
1916
2077
|
if (ts.isCallExpression(expression) &&
|
|
1917
2078
|
ts.isIdentifier(expression.expression) &&
|
|
1918
|
-
|
|
2079
|
+
(() => {
|
|
2080
|
+
const symbol = lowerer.checker.getSymbolAtLocation(expression.expression);
|
|
2081
|
+
return symbol !== undefined && broadCallbackSymbols.has(symbol);
|
|
2082
|
+
})()) {
|
|
1919
2083
|
returnsBroadCallback = true;
|
|
1920
2084
|
return "stop";
|
|
1921
2085
|
}
|
|
@@ -1930,7 +2094,12 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
1930
2094
|
const retTs = lowerer.checker.getReturnTypeOfSignature(declSig);
|
|
1931
2095
|
if (retTs.flags & ts.TypeFlags.Any)
|
|
1932
2096
|
return null;
|
|
2097
|
+
if (retTs.flags & (ts.TypeFlags.Null | ts.TypeFlags.Undefined))
|
|
2098
|
+
return DYN;
|
|
1933
2099
|
if (lowerer.checker.isArrayType(retTs)) {
|
|
2100
|
+
if (info.decl.parameters.some((param, index) => info.implicitParams?.[index] &&
|
|
2101
|
+
lowerer.mapTypeOf(lowerer.typeOf(param.name))?.kind === "array"))
|
|
2102
|
+
return null;
|
|
1934
2103
|
const elem = lowerer.checker.getTypeArguments(retTs)[0];
|
|
1935
2104
|
// An implicit-any parameter poisons an inferred array result to
|
|
1936
2105
|
// any[] even when this instance's body produces one concrete
|
|
@@ -1941,6 +2110,38 @@ function implicitDeclaredReturn(lowerer, info) {
|
|
|
1941
2110
|
return null;
|
|
1942
2111
|
}
|
|
1943
2112
|
const mapped = lowerer.mapTypeOf(retTs);
|
|
2113
|
+
if (mapped?.kind === "symbol" && !hasExplicitJsDocReturn(info.decl))
|
|
2114
|
+
return null;
|
|
2115
|
+
if (mapped?.kind === "date" && !hasExplicitJsDocReturn(info.decl))
|
|
2116
|
+
return DYN;
|
|
2117
|
+
if (!hasExplicitJsDocReturn(info.decl) && info.decl.body) {
|
|
2118
|
+
let openReturn = false;
|
|
2119
|
+
ts.walkPreorder(info.decl.body, (node) => {
|
|
2120
|
+
if (node !== info.decl.body && ts.isFunctionLike(node))
|
|
2121
|
+
return "skip";
|
|
2122
|
+
if (!ts.isReturnStatement(node) || !node.expression || !ts.isIdentifier(node.expression))
|
|
2123
|
+
return undefined;
|
|
2124
|
+
const symbol = lowerer.resolveValueSymbol(node.expression);
|
|
2125
|
+
if (symbol && lowerer.checker.declarationsOf(symbol).some((decl) => ts.isVariableDeclaration(decl) && jsBindingHasOpenWrites(lowerer, decl)))
|
|
2126
|
+
openReturn = true;
|
|
2127
|
+
return undefined;
|
|
2128
|
+
});
|
|
2129
|
+
if (openReturn)
|
|
2130
|
+
return null;
|
|
2131
|
+
}
|
|
2132
|
+
// A JavaScript result inferred from an initial record can later
|
|
2133
|
+
// carry additional fields. Settle its representation from the
|
|
2134
|
+
// lowered returns instead of copying it back into that initial shape.
|
|
2135
|
+
const resultArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms : mapped ? [mapped] : [];
|
|
2136
|
+
if (resultArms?.some((arm) => arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2137
|
+
resultArms.every((arm) => isUnitType(arm) || arm.kind === "record" || arm.kind === "object" || arm.kind === "classval") &&
|
|
2138
|
+
!hasExplicitJsDocReturn(info.decl))
|
|
2139
|
+
return null;
|
|
2140
|
+
// Inferred variadic results carry runtime argument packs. Their
|
|
2141
|
+
// factory must retain the lowered callable rather than extracting a
|
|
2142
|
+
// fixed native signature from a checked value.
|
|
2143
|
+
if (mapped?.kind === "func" && mapped.rest === true && mapped.restAbi === undefined && !hasExplicitJsDocReturn(info.decl))
|
|
2144
|
+
return null;
|
|
1944
2145
|
if (mapped !== null && promiseCarriesDyn(lowerer, mapped) && !hasExplicitJsDocReturn(info.decl))
|
|
1945
2146
|
return null;
|
|
1946
2147
|
return mapped;
|
|
@@ -1972,6 +2173,54 @@ function bindableImplicitIr(t) {
|
|
|
1972
2173
|
t.kind !== "void" && t.kind !== "dyn" && t.kind !== "jsval" &&
|
|
1973
2174
|
t.kind !== "caught" && t.kind !== "undefinedT" && t.kind !== "nullT");
|
|
1974
2175
|
}
|
|
2176
|
+
/** A represented binding or direct callable result can be wider than the
|
|
2177
|
+
* checker's inferred shape. Preserve that boundary when specializing JS. */
|
|
2178
|
+
function storedImplicitArgumentType(lowerer, arg) {
|
|
2179
|
+
while (ts.isParenthesizedExpression(arg))
|
|
2180
|
+
arg = arg.expression;
|
|
2181
|
+
if (isJsSourceFile(arg.getSourceFile()) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg))) {
|
|
2182
|
+
const saved = lowerer.diagSink;
|
|
2183
|
+
const diagnostics = [];
|
|
2184
|
+
lowerer.diagSink = diagnostics;
|
|
2185
|
+
let value;
|
|
2186
|
+
try {
|
|
2187
|
+
value = tryLowerExpression(lowerer, arg);
|
|
2188
|
+
}
|
|
2189
|
+
finally {
|
|
2190
|
+
lowerer.diagSink = saved;
|
|
2191
|
+
}
|
|
2192
|
+
// Direct inferred helpers can receive native callbacks even when their
|
|
2193
|
+
// result is an opaque handle that cannot cross checked storage.
|
|
2194
|
+
if (diagnostics.length === 0 && value?.type.kind === "func")
|
|
2195
|
+
return value.type;
|
|
2196
|
+
}
|
|
2197
|
+
if (arg.kind === ts.SyntaxKind.ThisKeyword)
|
|
2198
|
+
return lowerer.resolveThis()?.type ?? null;
|
|
2199
|
+
if (ts.isAwaitExpression(arg)) {
|
|
2200
|
+
const awaited = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2201
|
+
return awaited?.kind === "promise" ? awaited.inner : awaited;
|
|
2202
|
+
}
|
|
2203
|
+
if (ts.isObjectLiteralExpression(arg) && isJsSourceFile(arg.getSourceFile()) &&
|
|
2204
|
+
(arg.properties.length === 0 || arg.properties.some((property) => ts.isMethodDeclaration(property) || ts.isAccessor(property) ||
|
|
2205
|
+
!ts.isSpreadAssignment(property) && property.name !== undefined && ts.isComputedPropertyName(property.name))))
|
|
2206
|
+
return DYN;
|
|
2207
|
+
if (ts.isIdentifier(arg))
|
|
2208
|
+
return lowerer.peekLocal(arg)?.type ?? lowerer.globalOf(arg)?.type ?? null;
|
|
2209
|
+
if (ts.isCallExpression(arg) && ts.isIdentifier(arg.expression)) {
|
|
2210
|
+
if (isJsSourceFile(arg.getSourceFile())) {
|
|
2211
|
+
const represented = tryLowerExpression(lowerer, arg);
|
|
2212
|
+
if (represented?.type.kind === "dyn" || represented?.type.kind === "func")
|
|
2213
|
+
return represented.type;
|
|
2214
|
+
}
|
|
2215
|
+
const callee = storedImplicitArgumentType(lowerer, arg.expression);
|
|
2216
|
+
if (callee?.kind === "dyn")
|
|
2217
|
+
return DYN;
|
|
2218
|
+
if (callee?.kind === "func")
|
|
2219
|
+
return callee.ret;
|
|
2220
|
+
return lowerer.fnSigOf(arg.expression)?.returnType ?? null;
|
|
2221
|
+
}
|
|
2222
|
+
return null;
|
|
2223
|
+
}
|
|
1975
2224
|
/** The instance a CALL of an implicit-any function-like names: each
|
|
1976
2225
|
* bindable implicit param takes the call's WIDENED argument checker type
|
|
1977
2226
|
* when it maps statically (DYN otherwise — today's slot), typed params
|
|
@@ -1994,19 +2243,74 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
1994
2243
|
bound = declared.type;
|
|
1995
2244
|
const arg = call.arguments[i];
|
|
1996
2245
|
if (arg && !ts.isSpreadElement(arg)) {
|
|
1997
|
-
const
|
|
1998
|
-
if (
|
|
2246
|
+
const stored = storedImplicitArgumentType(lowerer, arg);
|
|
2247
|
+
if (stored?.kind === "dyn") {
|
|
1999
2248
|
bound = DYN;
|
|
2000
2249
|
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2001
2250
|
shapes.push({ type: bound, mode: "required" });
|
|
2002
2251
|
return;
|
|
2003
2252
|
}
|
|
2253
|
+
// A represented native array must keep its storage when a direct
|
|
2254
|
+
// inferred helper receives it. Re-boxing a checker-any array would
|
|
2255
|
+
// copy it, losing writes (and attempting to read unfilled slots).
|
|
2256
|
+
if (stored?.kind === "array") {
|
|
2257
|
+
argTypes.set(sym, lowerer.typeOf(arg));
|
|
2258
|
+
shapes.push({ type: stored, mode: "required" });
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
if (stored?.kind === "func") {
|
|
2262
|
+
// The lowered closure may have an inferred JS destructuring
|
|
2263
|
+
// parameter widened from the checker's exact tuple to dyn.
|
|
2264
|
+
// Preserve that signature throughout the specialization.
|
|
2265
|
+
const checkerType = lowerer.mapTypeOf(lowerer.typeOf(arg));
|
|
2266
|
+
argTypes.set(sym, checkerType && typeEquals(checkerType, stored)
|
|
2267
|
+
? lowerer.typeOf(arg) : lowerer.checker.getUnknownType());
|
|
2268
|
+
shapes.push({ type: stored, mode: "required" });
|
|
2269
|
+
return;
|
|
2270
|
+
}
|
|
2004
2271
|
// The argument's own checker type, literal-widened ('add' binds
|
|
2005
2272
|
// string) — typeOf consults the ACTIVE instance's bindings, so a
|
|
2006
2273
|
// bound param forwarded into another implicit call transitively
|
|
2007
2274
|
// instantiates it (this._initCommandGroup(command)).
|
|
2008
2275
|
const t = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(arg));
|
|
2009
|
-
const mapped = lowerer.mapTypeOf(t) ?? dynFallbackType(lowerer, arg, t);
|
|
2276
|
+
const mapped = (neverTaintedJsType(lowerer, arg, t) ? null : lowerer.mapTypeOf(t)) ?? dynFallbackType(lowerer, arg, t);
|
|
2277
|
+
if (isJsSourceFile(arg.getSourceFile()) && ts.isArrayLiteralExpression(arg) && mapped?.kind === "array" &&
|
|
2278
|
+
(mapped.elem.kind === "classval" || mapped.elem.kind === "union" &&
|
|
2279
|
+
lowerer.unions.get(mapped.elem.unionId)?.arms.every((arm) => arm.kind === "classval"))) {
|
|
2280
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2281
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2284
|
+
// JavaScript arguments-based callables travel as checked functions.
|
|
2285
|
+
// Specializing a parameter to the inferred rest signature would
|
|
2286
|
+
// require extracting a native variadic ABI that the value does not
|
|
2287
|
+
// expose. Its checked invocation preserves the complete argument pack.
|
|
2288
|
+
if (mapped?.kind === "func" && mapped.rest === true && mapped.restAbi === undefined) {
|
|
2289
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2290
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2291
|
+
return;
|
|
2292
|
+
}
|
|
2293
|
+
// JS inference can absorb heterogeneous loop values into `{}`.
|
|
2294
|
+
// That checker supertype is not an empty-record runtime layout:
|
|
2295
|
+
// preserve represented arms through the checked boundary instead
|
|
2296
|
+
// of specializing a call to a union that would discard them.
|
|
2297
|
+
if (isJsSourceFile(arg.getSourceFile()) && mapped?.kind === "func" && !lowerer.dynConvertible(mapped)) {
|
|
2298
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2299
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
const mappedArms = mapped?.kind === "union" ? lowerer.unions.get(mapped.unionId)?.arms ?? [] : mapped ? [mapped] : [];
|
|
2303
|
+
const hasTopObject = mappedArms.some((arm) => {
|
|
2304
|
+
const shape = arm.kind === "record" ? lowerer.shapes.get(arm.shapeId) : undefined;
|
|
2305
|
+
return shape && !shape.tuple && !shape.indexValue && shape.fields.length === 0;
|
|
2306
|
+
});
|
|
2307
|
+
if (stored?.kind === "union" && hasTopObject && lowerer.dynConvertible(stored) &&
|
|
2308
|
+
lowerer.unions.get(stored.unionId)?.arms.some((arm) => !isUnitType(arm) &&
|
|
2309
|
+
!mappedArms.some((target) => lowerer.widthLiftPlan(arm, target) !== null))) {
|
|
2310
|
+
argTypes.set(sym, lowerer.checker.getUnknownType());
|
|
2311
|
+
shapes.push({ type: DYN, mode: "required" });
|
|
2312
|
+
return;
|
|
2313
|
+
}
|
|
2010
2314
|
if (ts.isArrowFunction(arg) &&
|
|
2011
2315
|
arg.type === undefined &&
|
|
2012
2316
|
mapped?.kind === "func" &&
|
|
@@ -2031,15 +2335,32 @@ export function implicitCallInstance(lowerer, call, info) {
|
|
|
2031
2335
|
/** The all-dyn DEFAULT instance — today's compiled body exactly: what a
|
|
2032
2336
|
* VALUE reference of an implicit-any function names (indirect calls
|
|
2033
2337
|
* carry no per-site types to bind). */
|
|
2034
|
-
function implicitDefaultInstance(lowerer, blame, info) {
|
|
2338
|
+
export function implicitDefaultInstance(lowerer, blame, info) {
|
|
2035
2339
|
const shapes = info.decl.parameters.map((param, i) => info.implicitParams[i] ? { type: DYN, mode: "required" } : lowerer.paramShape(param));
|
|
2036
|
-
|
|
2340
|
+
const argTypes = new Map();
|
|
2341
|
+
// Newly bindable nominal class parameters must not retain their JSDoc
|
|
2342
|
+
// receiver type in the checked fallback. Keep existing broad JS inference.
|
|
2343
|
+
for (let i = 0; i < info.decl.parameters.length; i++) {
|
|
2344
|
+
const symbol = info.implicitParams?.[i];
|
|
2345
|
+
const kind = lowerer.mapTypeOf(lowerer.typeOf(info.decl.parameters[i].name))?.kind;
|
|
2346
|
+
if (symbol && (kind === "object" || kind === "array")) {
|
|
2347
|
+
argTypes.set(symbol, lowerer.checker.getUnknownType());
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return internImplicitInstance(lowerer, blame, info, shapes, argTypes);
|
|
2037
2351
|
}
|
|
2038
2352
|
function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
|
|
2039
2353
|
const key = shapes.map((s) => typeKey(s.type)).join(",");
|
|
2040
2354
|
let inst = info.instances.get(key);
|
|
2041
|
-
if (inst)
|
|
2355
|
+
if (inst?.implicitState === "failed")
|
|
2356
|
+
lowerer.unsupported("SC1090", blame, `the failed specialization of '${info.baseName}'`);
|
|
2357
|
+
if (inst) {
|
|
2358
|
+
// A recursive caller has observed this ABI before inference settles.
|
|
2359
|
+
// Keep the promised return slot and coerce the completed body's returns.
|
|
2360
|
+
if (inst.implicitState === "lowering")
|
|
2361
|
+
inst.returnPinned = true;
|
|
2042
2362
|
return inst;
|
|
2363
|
+
}
|
|
2043
2364
|
if (info.instances.size >= MAX_GENERIC_INSTANCES) {
|
|
2044
2365
|
lowerer.unsupported("SC1090", blame, `unbounded implicit-any instantiation ('${info.baseName}' exceeded ` +
|
|
2045
2366
|
`${MAX_GENERIC_INSTANCES} instances — polymorphic recursion?)`);
|
|
@@ -2065,11 +2386,15 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
|
|
|
2065
2386
|
...(declared === null ? { implicitInferReturn: true } : {}),
|
|
2066
2387
|
};
|
|
2067
2388
|
info.instances.set(key, inst);
|
|
2068
|
-
//
|
|
2069
|
-
//
|
|
2070
|
-
//
|
|
2071
|
-
|
|
2072
|
-
//
|
|
2389
|
+
// Eager lowering settles the return ABI before callers use it. A failed
|
|
2390
|
+
// JS body must still have a throwing implementation: later references
|
|
2391
|
+
// (including recursive ones) can already hold its cached signature.
|
|
2392
|
+
const diagsBefore = lowerer.diags.length;
|
|
2393
|
+
// The instance is cached even when a receiver probe requested it.
|
|
2394
|
+
// Its body must retain statement fences instead of dropping failures
|
|
2395
|
+
// into that probe's temporary diagnostic sink and caching empty code.
|
|
2396
|
+
const previousSink = lowerer.diagSink;
|
|
2397
|
+
lowerer.diagSink = null;
|
|
2073
2398
|
try {
|
|
2074
2399
|
// Implicit-any instances lower EAGERLY at the call site so their
|
|
2075
2400
|
// inferred return type is available immediately. They therefore do
|
|
@@ -2087,8 +2412,20 @@ function internImplicitInstance(lowerer, blame, info, shapes, argTypes) {
|
|
|
2087
2412
|
catch (e) {
|
|
2088
2413
|
if (!(e instanceof PoisonError))
|
|
2089
2414
|
throw e;
|
|
2090
|
-
inst.implicitState = "
|
|
2091
|
-
|
|
2415
|
+
inst.implicitState = "failed";
|
|
2416
|
+
const types = shapes.map((shape) => shape.type);
|
|
2417
|
+
if (info.member?.kind === "method")
|
|
2418
|
+
types.unshift({ kind: "object", className: info.member.cls.def.name });
|
|
2419
|
+
const fn = lowerer.deferToRuntimeFence(diagsBefore, info.decl, {
|
|
2420
|
+
kind: "function", name: inst.name, returnType: inst.returnType,
|
|
2421
|
+
params: types.map((type, index) => ({ localId: `p.${index}`, name: `p${index}`, type })),
|
|
2422
|
+
});
|
|
2423
|
+
if (!fn)
|
|
2424
|
+
throw e;
|
|
2425
|
+
lowerer.implicitFns.push(fn);
|
|
2426
|
+
}
|
|
2427
|
+
finally {
|
|
2428
|
+
lowerer.diagSink = previousSink;
|
|
2092
2429
|
}
|
|
2093
2430
|
inst.implicitState = "done";
|
|
2094
2431
|
return inst;
|
|
@@ -2194,11 +2531,11 @@ export function implicitLocalFnInfoOf(lowerer, decl, fnNode) {
|
|
|
2194
2531
|
const implicit = implicitAnyParamSymbolsOf(lowerer, fnNode);
|
|
2195
2532
|
if (!implicit)
|
|
2196
2533
|
lowerer.unsupported("SC1090", fnNode, "this function form"); // defensive: the probe proved it
|
|
2197
|
-
const stmt = decl.parent
|
|
2534
|
+
const stmt = decl.parent?.parent;
|
|
2198
2535
|
const info = {
|
|
2199
2536
|
decl: fnNode,
|
|
2200
2537
|
baseName: name,
|
|
2201
|
-
qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt, decl) + `${name}%l${decl.getStart()}`),
|
|
2538
|
+
qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt ?? decl, decl) + `${name}%l${decl.getStart()}`),
|
|
2202
2539
|
typeParams: [],
|
|
2203
2540
|
instances: new Map(),
|
|
2204
2541
|
implicitParams: implicit,
|
|
@@ -2409,6 +2746,7 @@ function makeTimerArgsThunk(lowerer, cbNode, argNodes, what, loc) {
|
|
|
2409
2746
|
kind: "dynCall",
|
|
2410
2747
|
callee: { kind: "varRef", localId: "f.0", type: DYN, loc },
|
|
2411
2748
|
calleeName: "callback",
|
|
2749
|
+
receiver: { kind: "libCall", fn: "dyn.this", args: [], type: DYN, loc },
|
|
2412
2750
|
args: args.map((_, i) => ({ kind: "varRef", localId: `a${i}.0`, type: DYN, loc })),
|
|
2413
2751
|
type: DYN,
|
|
2414
2752
|
loc,
|
|
@@ -2506,7 +2844,15 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
|
|
|
2506
2844
|
if (expr.arguments.length !== 1) {
|
|
2507
2845
|
lowerer.noLowering(`clearTimeout with ${expr.arguments.length} arguments`, expr);
|
|
2508
2846
|
}
|
|
2509
|
-
|
|
2847
|
+
let handle = lowerer.lowerExpr(expr.arguments[0]);
|
|
2848
|
+
if (handle.type.kind === "dyn" && isJsSourceFile(expr.getSourceFile())) {
|
|
2849
|
+
const stored = lowerer.declareHiddenLocal("%timer.clear", DYN);
|
|
2850
|
+
const ref = varRef(stored.id, DYN, loc);
|
|
2851
|
+
handle = { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: stored.id, init: handle, loc }], result: {
|
|
2852
|
+
kind: "ternary", cond: { kind: "dynTest", test: "number", value: ref, type: BOOL, loc },
|
|
2853
|
+
then: lowerer.coerceInto(expr.arguments[0], ref, F64), else_: numLit(0, loc), type: F64, loc,
|
|
2854
|
+
}, type: F64, loc };
|
|
2855
|
+
}
|
|
2510
2856
|
if (handle.type.kind !== "f64") {
|
|
2511
2857
|
lowerer.noLowering(`clearTimeout of '${lowerer.fmt(handle.type)}' handles`, expr.arguments[0], "the handle is the Timeout setTimeout returned (narrow 'Timeout | null' first)");
|
|
2512
2858
|
}
|
|
@@ -2573,7 +2919,12 @@ export function lowerTimersMemberCall(lowerer, expr, member, loc) {
|
|
|
2573
2919
|
return null;
|
|
2574
2920
|
}
|
|
2575
2921
|
function ffiSourceParams(binding) {
|
|
2576
|
-
|
|
2922
|
+
const params = [];
|
|
2923
|
+
for (const param of binding.params) {
|
|
2924
|
+
if (!isFfiContextParam(param))
|
|
2925
|
+
params.push(param);
|
|
2926
|
+
}
|
|
2927
|
+
return params;
|
|
2577
2928
|
}
|
|
2578
2929
|
function ffiParamDisplay(param) {
|
|
2579
2930
|
return isFfiCallbackParam(param)
|
|
@@ -2590,7 +2941,11 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
|
|
|
2590
2941
|
const signatures = lowerer.checker.getCallSignatures(callbackType);
|
|
2591
2942
|
if (signatures.length !== 1)
|
|
2592
2943
|
return null;
|
|
2593
|
-
const nativeParams =
|
|
2944
|
+
const nativeParams = [];
|
|
2945
|
+
for (const param of descriptor.callback.params) {
|
|
2946
|
+
if (!isFfiContextParam(param))
|
|
2947
|
+
nativeParams.push(param);
|
|
2948
|
+
}
|
|
2594
2949
|
let nativeIndex = 0;
|
|
2595
2950
|
const params = signatures[0].getParameters();
|
|
2596
2951
|
for (let i = 0; i < params.length; i++) {
|
|
@@ -2608,12 +2963,13 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
|
|
|
2608
2963
|
}
|
|
2609
2964
|
if (nativeClass === "bytes")
|
|
2610
2965
|
continue;
|
|
2611
|
-
const
|
|
2966
|
+
const wide = nativeClass === "i64" || nativeClass === "u64" || nativeClass === "pointer";
|
|
2967
|
+
const domain = wide ? "bigint" : nativeClass === "bool"
|
|
2612
2968
|
? "boolean"
|
|
2613
2969
|
: nativeClass === "cstring" || nativeClass === "string"
|
|
2614
2970
|
? "string"
|
|
2615
2971
|
: "number";
|
|
2616
|
-
const coversDomain = nativeClass === "bool"
|
|
2972
|
+
const coversDomain = wide ? (paramType.flags & ts.TypeFlags.BigInt) !== 0 : nativeClass === "bool"
|
|
2617
2973
|
? (paramType.flags & ts.TypeFlags.Boolean) !== 0
|
|
2618
2974
|
: nativeClass === "cstring" || nativeClass === "string"
|
|
2619
2975
|
? (paramType.flags & ts.TypeFlags.String) !== 0
|
|
@@ -2636,8 +2992,9 @@ function ffiCallbackInputDiagnostic(lowerer, descriptor, callbackType) {
|
|
|
2636
2992
|
function ffiReturnDomainDiagnostic(lowerer, nativeClass, returnType) {
|
|
2637
2993
|
if (nativeClass === "void")
|
|
2638
2994
|
return null;
|
|
2639
|
-
const
|
|
2640
|
-
const
|
|
2995
|
+
const wide = nativeClass === "i64" || nativeClass === "u64" || nativeClass === "pointer";
|
|
2996
|
+
const domain = wide ? "bigint" : nativeClass === "bool" ? "boolean" : "number";
|
|
2997
|
+
const coversDomain = wide ? (returnType.flags & ts.TypeFlags.BigInt) !== 0 : nativeClass === "bool"
|
|
2641
2998
|
? (returnType.flags & ts.TypeFlags.Boolean) !== 0
|
|
2642
2999
|
: (returnType.flags & ts.TypeFlags.Number) !== 0;
|
|
2643
3000
|
return coversDomain
|
|
@@ -2745,7 +3102,7 @@ function libraryCallbackOwnsFile(lowerer, file) {
|
|
|
2745
3102
|
export function validateFfiImports(lowerer) {
|
|
2746
3103
|
const diagnostics = [];
|
|
2747
3104
|
const symbolsByName = new Map();
|
|
2748
|
-
const configuredNames = new Set(lowerer.ffiImports.map((binding) => binding.name));
|
|
3105
|
+
const configuredNames = new Set(lowerer.ffiImports.filter(binding => binding.library === undefined).map((binding) => binding.name));
|
|
2749
3106
|
const candidates = new Map();
|
|
2750
3107
|
if (configuredNames.size === 0)
|
|
2751
3108
|
return { diagnostics, symbolsByName };
|
|
@@ -2775,6 +3132,8 @@ export function validateFfiImports(lowerer) {
|
|
|
2775
3132
|
});
|
|
2776
3133
|
}
|
|
2777
3134
|
for (const binding of lowerer.ffiImports) {
|
|
3135
|
+
if (binding.library !== undefined)
|
|
3136
|
+
continue;
|
|
2778
3137
|
const bySymbol = candidates.get(binding.name);
|
|
2779
3138
|
if (bySymbol === undefined || bySymbol.size === 0) {
|
|
2780
3139
|
// A native-manifest binding with no declaration is a broken build
|
|
@@ -2822,6 +3181,8 @@ export function lowerFfiCall(lowerer, expr) {
|
|
|
2822
3181
|
if (!ts.isIdentifier(expr.expression))
|
|
2823
3182
|
return null;
|
|
2824
3183
|
const binding = lowerer.ffiImportsByName.get(expr.expression.text);
|
|
3184
|
+
if (binding?.library !== undefined)
|
|
3185
|
+
return null;
|
|
2825
3186
|
if (binding === undefined) {
|
|
2826
3187
|
// LIBRARY mode with a declared callback surface: a CALL of a
|
|
2827
3188
|
// program-authored signature-only ambient function that names no
|
|
@@ -2855,7 +3216,8 @@ export function lowerFfiCall(lowerer, expr) {
|
|
|
2855
3216
|
lowerer.pushDiag(signatureFlavor(binding.name, detail, loc));
|
|
2856
3217
|
throw new PoisonError();
|
|
2857
3218
|
};
|
|
2858
|
-
const symbol = lowerer.resolveValueSymbol(expr.expression)
|
|
3219
|
+
const symbol = lowerer.resolveValueSymbol(expr.expression);
|
|
3220
|
+
if (!symbol)
|
|
2859
3221
|
bindingError("the call has no resolved TypeScript symbol");
|
|
2860
3222
|
if (lowerer.ffiBindingSymbols !== null) {
|
|
2861
3223
|
const validSymbols = lowerer.ffiBindingSymbols.get(binding.name);
|
|
@@ -2938,7 +3300,7 @@ export function lowerFfiCall(lowerer, expr) {
|
|
|
2938
3300
|
}
|
|
2939
3301
|
// An inline function value at a RELEASE site can never match:
|
|
2940
3302
|
// lifted lambdas always carry a captures list (even an empty one),
|
|
2941
|
-
// so
|
|
3303
|
+
// so the backend creates a fresh closure per evaluation of the
|
|
2942
3304
|
// expression — the release argument is a pointer no registration
|
|
2943
3305
|
// holds, a guaranteed runtime trap. Declared functions stay valid
|
|
2944
3306
|
// here — their value is the interned immortal closure (captures
|
|
@@ -3017,6 +3379,14 @@ function lowerProjectedBuiltinCall(lowerer, expr, bi, loc) {
|
|
|
3017
3379
|
}
|
|
3018
3380
|
export function lowerCall(lowerer, expr) {
|
|
3019
3381
|
const loc = locOf(expr);
|
|
3382
|
+
// Object's checker return type is `any`. Claim known object inputs
|
|
3383
|
+
// before generic checked-dynamic dispatch tries to load the constructor.
|
|
3384
|
+
if (ts.isIdentifier(expr.expression) && expr.expression.text === "Object" &&
|
|
3385
|
+
lowerer.isStdlibGlobal(expr.expression, "Object")) {
|
|
3386
|
+
const object = lowerObjectConstructor(lowerer, expr.arguments, loc);
|
|
3387
|
+
if (object)
|
|
3388
|
+
return object;
|
|
3389
|
+
}
|
|
3020
3390
|
// A call whose chain ROOTS at an ambient-undefined name (`declare
|
|
3021
3391
|
// const value: Y | undefined; value?.foo("a")`, `declare function
|
|
3022
3392
|
// chain...; chain(o).mapValues(f).value()`, a trap binding's read):
|
|
@@ -3126,7 +3496,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3126
3496
|
// `a?.m()` (the token on the member access). The handled markers keep
|
|
3127
3497
|
// the chain lowering's re-entrant dispatch from looping.
|
|
3128
3498
|
if ((expr.questionDotToken && !lowerer.chainHandled.has(expr)) ||
|
|
3129
|
-
(ts.isPropertyAccessExpression(expr.expression) &&
|
|
3499
|
+
((ts.isPropertyAccessExpression(expr.expression) || ts.isElementAccessExpression(expr.expression)) &&
|
|
3130
3500
|
expr.expression.questionDotToken &&
|
|
3131
3501
|
!lowerer.chainHandled.has(expr.expression))) {
|
|
3132
3502
|
return lowerer.lowerOptionalChain(expr);
|
|
@@ -3135,6 +3505,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
3135
3505
|
// top-level statement (its field-initializer ordering lives there);
|
|
3136
3506
|
// any other position would misorder initialization — rejected.
|
|
3137
3507
|
if (expr.expression.kind === ts.SyntaxKind.SuperKeyword) {
|
|
3508
|
+
const superCall = lowerer.ctx.superCall;
|
|
3509
|
+
if (superCall)
|
|
3510
|
+
return superCall(expr);
|
|
3138
3511
|
lowerer.unsupported("SC1090", expr, "super() calls anywhere but as a top-level constructor statement");
|
|
3139
3512
|
}
|
|
3140
3513
|
// super.method(...): a DIRECT (never virtual) call of the base chain's
|
|
@@ -3145,6 +3518,18 @@ export function lowerCall(lowerer, expr) {
|
|
|
3145
3518
|
}
|
|
3146
3519
|
const consoleMember = lowerer.consoleCallMember(expr);
|
|
3147
3520
|
if (consoleMember !== null) {
|
|
3521
|
+
// A namespace returned by user code must evaluate before the log
|
|
3522
|
+
// arguments. Only the global and literal builtin require plumbing
|
|
3523
|
+
// have no receiver evaluation to preserve.
|
|
3524
|
+
const access = ts.isPropertyAccessExpression(expr.expression) ? expr.expression : null;
|
|
3525
|
+
const created = access && ts.isCallExpression(access.expression) ? createRequireSpecOf(lowerer, access.expression) : null;
|
|
3526
|
+
const receiver = access && !lowerer.isStdlibGlobal(access.expression, "console") &&
|
|
3527
|
+
requireSpecOf(access.expression) === null &&
|
|
3528
|
+
created?.spec !== "node:console" && created?.spec !== "console"
|
|
3529
|
+
? lowerer.lowerExpr(access.expression) : null;
|
|
3530
|
+
const withReceiver = (result) => receiver === null ? result : {
|
|
3531
|
+
kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: receiver, loc }], result, type: result.type, loc,
|
|
3532
|
+
};
|
|
3148
3533
|
// console.log/info/debug write stdout; console.error and console.warn
|
|
3149
3534
|
// are one stream in Node (warn IS error, info and debug ARE log) and
|
|
3150
3535
|
// write stderr with the exact same formatting. Node's formatter is
|
|
@@ -3166,13 +3551,13 @@ export function lowerCall(lowerer, expr) {
|
|
|
3166
3551
|
(ts.isStringLiteral(expr.arguments[0]) || ts.isNoSubstitutionTemplateLiteral(expr.arguments[0])) &&
|
|
3167
3552
|
/%[sdifjoOc%]/.test(expr.arguments[0].text)) {
|
|
3168
3553
|
const formatted = lowerFormatCall(lowerer, expr, loc, false);
|
|
3169
|
-
return {
|
|
3554
|
+
return withReceiver({
|
|
3170
3555
|
kind: "intrinsic",
|
|
3171
3556
|
name: stdoutMember ? "console.log" : "console.error",
|
|
3172
3557
|
args: [formatted],
|
|
3173
3558
|
type: VOID,
|
|
3174
3559
|
loc,
|
|
3175
|
-
};
|
|
3560
|
+
});
|
|
3176
3561
|
}
|
|
3177
3562
|
const args = expr.arguments.map((a) => {
|
|
3178
3563
|
const lowered = lowerer.lowerExpr(a);
|
|
@@ -3233,13 +3618,20 @@ export function lowerCall(lowerer, expr) {
|
|
|
3233
3618
|
// render fence honestly with the reason.
|
|
3234
3619
|
return lowerConsoleInspectArg(lowerer, a, lowered, surface, loc);
|
|
3235
3620
|
});
|
|
3236
|
-
return {
|
|
3621
|
+
return withReceiver({
|
|
3237
3622
|
kind: "intrinsic",
|
|
3238
3623
|
name: stdoutMember ? "console.log" : "console.error",
|
|
3239
3624
|
args,
|
|
3240
3625
|
type: VOID,
|
|
3241
3626
|
loc,
|
|
3242
|
-
};
|
|
3627
|
+
});
|
|
3628
|
+
}
|
|
3629
|
+
if (ts.isPropertyAccessExpression(expr.expression) &&
|
|
3630
|
+
TIMER_MODULE_MEMBERS.has(expr.expression.name.text) &&
|
|
3631
|
+
lowerer.stdlibGlobalMember(expr.expression, "globalThis") === expr.expression.name.text) {
|
|
3632
|
+
const served = lowerTimersMemberCall(lowerer, expr, expr.expression.name.text, loc);
|
|
3633
|
+
if (served)
|
|
3634
|
+
return served;
|
|
3243
3635
|
}
|
|
3244
3636
|
// The timer globals — setTimeout/clearTimeout, setInterval/
|
|
3245
3637
|
// clearInterval, setImmediate/clearImmediate. Provenance-checked (a
|
|
@@ -3383,40 +3775,24 @@ export function lowerCall(lowerer, expr) {
|
|
|
3383
3775
|
// Provenance-checked like setTimeout; zero-arg forms are the JS
|
|
3384
3776
|
// constants ("", false, 0). Wrapper objects stay fenced except where
|
|
3385
3777
|
// the receiver is immediately converted by a direct String method call.
|
|
3386
|
-
if (
|
|
3387
|
-
expr.expression.text === "BigInt" &&
|
|
3388
|
-
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
3778
|
+
if (lowerer.isStdlibGlobal(expr.expression, "BigInt")) {
|
|
3389
3779
|
if (expr.arguments.length !== 1) {
|
|
3390
3780
|
lowerer.noLowering(`BigInt with ${expr.arguments.length} arguments`, expr);
|
|
3391
3781
|
}
|
|
3392
3782
|
const argNode = expr.arguments[0];
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
if (arg.type.kind === "f64") {
|
|
3400
|
-
return { kind: "libCall", fn: "bigint.fromF64", args: [arg], type: BIGINT_T, loc };
|
|
3401
|
-
}
|
|
3402
|
-
if (arg.type.kind === "bool") {
|
|
3403
|
-
return {
|
|
3404
|
-
kind: "ternary",
|
|
3405
|
-
cond: arg,
|
|
3406
|
-
then: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "1", type: STRING, loc }], type: BIGINT_T, loc },
|
|
3407
|
-
else_: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "0", type: STRING, loc }], type: BIGINT_T, loc },
|
|
3408
|
-
type: BIGINT_T,
|
|
3409
|
-
loc,
|
|
3410
|
-
};
|
|
3411
|
-
}
|
|
3783
|
+
// Captured optional storage can change after TypeScript's guard.
|
|
3784
|
+
// BigInt consumes the stored value, including its nullish tag.
|
|
3785
|
+
const arg = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3786
|
+
const converted = lowerBigIntConstructorValue(lowerer, arg, loc);
|
|
3787
|
+
if (converted)
|
|
3788
|
+
return converted;
|
|
3412
3789
|
lowerer.noLowering(`BigInt of ${lowerer.fmt(arg.type)} values`, argNode, "string, number, boolean, and bigint arguments are supported");
|
|
3413
3790
|
}
|
|
3414
|
-
if (
|
|
3415
|
-
(expr.expression
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
const name = expr.expression.text;
|
|
3791
|
+
if (lowerer.isStdlibGlobal(expr.expression, "String") ||
|
|
3792
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ||
|
|
3793
|
+
lowerer.isStdlibGlobal(expr.expression, "Number")) {
|
|
3794
|
+
const name = lowerer.isStdlibGlobal(expr.expression, "String") ? "String" :
|
|
3795
|
+
lowerer.isStdlibGlobal(expr.expression, "Boolean") ? "Boolean" : "Number";
|
|
3420
3796
|
if (expr.arguments.length > 1) {
|
|
3421
3797
|
lowerer.noLowering(`${name} with ${expr.arguments.length} arguments`, expr);
|
|
3422
3798
|
}
|
|
@@ -3446,6 +3822,10 @@ export function lowerCall(lowerer, expr) {
|
|
|
3446
3822
|
if (name === "Number")
|
|
3447
3823
|
return lowerNumberConstructorValue(lowerer, argNode, loc);
|
|
3448
3824
|
const arg = lowerer.lowerExpr(argNode);
|
|
3825
|
+
if (name === "String" && (arg.type.kind === "dyn" || arg.type.kind === "union" &&
|
|
3826
|
+
lowerer.unions.get(arg.type.unionId)?.arms.some((arm) => arm.kind === "symbol") && lowerer.dynConvertible(arg.type))) {
|
|
3827
|
+
return { kind: "libCall", fn: "dyn.stringConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: STRING, loc };
|
|
3828
|
+
}
|
|
3449
3829
|
if (name === "String")
|
|
3450
3830
|
return lowerer.ensureString(arg, argNode);
|
|
3451
3831
|
}
|
|
@@ -3463,6 +3843,30 @@ export function lowerCall(lowerer, expr) {
|
|
|
3463
3843
|
const code = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
|
|
3464
3844
|
return { kind: "libCall", fn: "island.eval", args: [code], type: STRING, loc };
|
|
3465
3845
|
}
|
|
3846
|
+
// Computed calls preserve their evaluated receiver just like dotted
|
|
3847
|
+
// calls, including when the property is keyed by a native symbol.
|
|
3848
|
+
if (ts.isElementAccessExpression(expr.expression) && !lowerer.chainBlocked(expr, expr.expression)) {
|
|
3849
|
+
const access = expr.expression;
|
|
3850
|
+
lowerer.fenceStaticResponseMember(access, "call");
|
|
3851
|
+
lowerer.fenceStaticHeadersMember(access, "call");
|
|
3852
|
+
lowerer.fenceStaticReadableStreamMember(access, "call");
|
|
3853
|
+
const source = tryLowerExpression(lowerer, access.expression);
|
|
3854
|
+
if (source && (source.type.kind === "dyn" || source.type.kind === "func" ||
|
|
3855
|
+
(source.type.kind === "map" || source.type.kind === "set") && lowerer.dynConvertible(source.type) || isDynTypedRefType(source.type) &&
|
|
3856
|
+
lowerer.foldedStringKeyOf(access.argumentExpression) === null &&
|
|
3857
|
+
lowerer.mapTypeOf(lowerer.typeOf(access.argumentExpression))?.kind !== "symbol")) {
|
|
3858
|
+
const local = lowerer.declareHiddenLocal("%computedReceiver", DYN);
|
|
3859
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
3860
|
+
const key = lowerer.lowerExprExpecting(access.argumentExpression, DYN);
|
|
3861
|
+
const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
|
|
3862
|
+
const args = expr.arguments.map((arg) => lowerer.lowerExprExpecting(ts.isSpreadElement(arg) ? arg.expression : arg, DYN));
|
|
3863
|
+
const spreads = expr.arguments.flatMap((arg, index) => ts.isSpreadElement(arg) ? [{ arg: index, what: arg.expression.getText() }] : []);
|
|
3864
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: lowerer.coerceToExpected(source, DYN), loc }], result: {
|
|
3865
|
+
kind: "dynCall", callee, receiver, calleeName: access.getText(), args,
|
|
3866
|
+
...(spreads.length > 0 ? { spreads } : {}), type: DYN, loc,
|
|
3867
|
+
}, type: DYN, loc };
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3466
3870
|
// Island calls. A property-access callee whose receiver is an 'any'
|
|
3467
3871
|
// value is an engine method call (this = receiver, JS-exact); any other
|
|
3468
3872
|
// 'any'-typed callee is an engine function call. Arguments marshal in;
|
|
@@ -3851,6 +4255,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
3851
4255
|
// string-only argument rule.
|
|
3852
4256
|
if ((expr.expression.text === "encodeURIComponent" ||
|
|
3853
4257
|
expr.expression.text === "encodeURI" ||
|
|
4258
|
+
expr.expression.text === "decodeURI" ||
|
|
3854
4259
|
expr.expression.text === "decodeURIComponent") &&
|
|
3855
4260
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(expr.expression) ?? undefined)) {
|
|
3856
4261
|
const name = expr.expression.text;
|
|
@@ -3859,10 +4264,10 @@ export function lowerCall(lowerer, expr) {
|
|
|
3859
4264
|
}
|
|
3860
4265
|
const loc = locOf(expr);
|
|
3861
4266
|
const argNode = expr.arguments[0];
|
|
3862
|
-
if (name === "decodeURIComponent") {
|
|
4267
|
+
if (name === "decodeURIComponent" || name === "decodeURI") {
|
|
3863
4268
|
const d = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3864
4269
|
const s = lowerer.ensureString(d, argNode);
|
|
3865
|
-
return { kind: "libCall", fn: "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
4270
|
+
return { kind: "libCall", fn: name === "decodeURI" ? "str.decodeUri" : "str.decodeUriComponent", args: [s], type: STRING, loc };
|
|
3866
4271
|
}
|
|
3867
4272
|
const value = optionalCallValue(lowerer, argNode) ?? lowerer.lowerExpr(argNode);
|
|
3868
4273
|
const s = lowerer.ensureString(value, argNode);
|
|
@@ -4061,6 +4466,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
4061
4466
|
let callee = lowerer.lowerExpr(nsMember);
|
|
4062
4467
|
if (callee.type.kind === "record")
|
|
4063
4468
|
callee = lowerer.hybridCallUnwrap(callee);
|
|
4469
|
+
const checked = lowerCheckedCallableValue(lowerer, expr, callee, loc);
|
|
4470
|
+
if (checked)
|
|
4471
|
+
return checked;
|
|
4064
4472
|
if (callee.type.kind !== "func")
|
|
4065
4473
|
lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
|
|
4066
4474
|
const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
|
|
@@ -4114,6 +4522,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
4114
4522
|
let callee = lowerer.lowerExpr(nameId);
|
|
4115
4523
|
if (callee.type.kind === "record")
|
|
4116
4524
|
callee = lowerer.hybridCallUnwrap(callee);
|
|
4525
|
+
const checked = lowerCheckedCallableValue(lowerer, expr, callee, loc);
|
|
4526
|
+
if (checked)
|
|
4527
|
+
return checked;
|
|
4117
4528
|
if (callee.type.kind !== "func")
|
|
4118
4529
|
lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
|
|
4119
4530
|
const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
|
|
@@ -4137,7 +4548,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4137
4548
|
lowerer.lowerJsonMethodCall(expr, expr.expression) ??
|
|
4138
4549
|
// Reflect.apply of a builtin rest-parameter fn (fixtures.js's
|
|
4139
4550
|
// fixturesPath idiom) — before the stdlib member fence claims it.
|
|
4140
|
-
|
|
4551
|
+
lowerReflectCall(lowerer, expr, expr.expression) ??
|
|
4552
|
+
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4141
4553
|
lowerer.lowerNumberStaticCall(expr, expr.expression) ??
|
|
4142
4554
|
lowerer.lowerDateCall(expr, expr.expression) ??
|
|
4143
4555
|
lowerer.lowerTextCodecCall(expr, expr.expression) ??
|
|
@@ -4193,6 +4605,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4193
4605
|
// TestContext surface (t.test/t.skip/t.diagnostic), t.assert.*.
|
|
4194
4606
|
lowerer.lowerTestMethodCall(expr, expr.expression) ??
|
|
4195
4607
|
lowerer.lowerTimeoutMethodCall(expr, expr.expression) ??
|
|
4608
|
+
lowerArrayPrototypeBorrowCall(lowerer, expr, expr.expression) ??
|
|
4196
4609
|
lowerObjectOwnPrototypeCall(lowerer, expr, expr.expression) ??
|
|
4197
4610
|
lowerObjectPrototypeCall(lowerer, expr, expr.expression) ??
|
|
4198
4611
|
lowerStringPrototypeCall(lowerer, expr, expr.expression) ??
|
|
@@ -4200,6 +4613,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4200
4613
|
// Typed-array/Buffer receivers and the Buffer statics — before the
|
|
4201
4614
|
// island path (bytes never cross the boundary).
|
|
4202
4615
|
lowerer.lowerBytesMethodCall(expr, expr.expression) ??
|
|
4616
|
+
lowerBytesStaticCall(lowerer, expr, expr.expression) ??
|
|
4203
4617
|
lowerBufferStaticCallWithNarrowedArg(lowerer, expr, expr.expression) ??
|
|
4204
4618
|
// URL.revokeObjectURL's zero-argument contract (the one-argument
|
|
4205
4619
|
// form keeps the fence — createObjectURL does too).
|
|
@@ -4207,8 +4621,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4207
4621
|
// Readable.from — the stream classes' one static (before the
|
|
4208
4622
|
// stdlib chokepoint claims the member).
|
|
4209
4623
|
lowerStreamStaticCall(lowerer, expr, expr.expression) ??
|
|
4210
|
-
//
|
|
4211
|
-
//
|
|
4624
|
+
// Primitive toString calls, including numeric radices, use the
|
|
4625
|
+
// native formatters before the island method path.
|
|
4212
4626
|
lowerNumberToStringCall(lowerer, expr, expr.expression) ??
|
|
4213
4627
|
// Union receivers whose every arm has a text — the ngrok
|
|
4214
4628
|
// `(chunk: Buffer | string) => chunk.toString()` idiom.
|
|
@@ -4248,7 +4662,6 @@ export function lowerCall(lowerer, expr) {
|
|
|
4248
4662
|
// by the receiver's own element.
|
|
4249
4663
|
lowerer.lowerFilterNarrowCall(expr, expr.expression) ??
|
|
4250
4664
|
lowerArrayIsArrayCall(lowerer, expr, expr.expression) ??
|
|
4251
|
-
lowerBigIntStaticCall(lowerer, expr, expr.expression) ??
|
|
4252
4665
|
lowerBigIntMethodCall(lowerer, expr, expr.expression) ??
|
|
4253
4666
|
lowerSymbolStaticCall(lowerer, expr, expr.expression) ??
|
|
4254
4667
|
lowerSymbolMethodCall(lowerer, expr, expr.expression) ??
|
|
@@ -4267,8 +4680,8 @@ export function lowerCall(lowerer, expr) {
|
|
|
4267
4680
|
lowerArrayFromCall(lowerer, expr, expr.expression) ??
|
|
4268
4681
|
lowerArrayOfCall(lowerer, expr, expr.expression) ??
|
|
4269
4682
|
lowerer.lowerArrayMethodCall(expr, expr.expression) ??
|
|
4270
|
-
//
|
|
4271
|
-
//
|
|
4683
|
+
// Tuple reads preserve the receiver through argument evaluation;
|
|
4684
|
+
// callbacks read each position when visited.
|
|
4272
4685
|
lowerTupleReadMethodCall(lowerer, expr, expr.expression) ??
|
|
4273
4686
|
lowerGenMethodCall(lowerer, expr, expr.expression) ??
|
|
4274
4687
|
lowerer.lowerMapMethodCall(expr, expr.expression) ??
|
|
@@ -4283,6 +4696,25 @@ export function lowerCall(lowerer, expr) {
|
|
|
4283
4696
|
lowerObjLitGenericMethodCall(lowerer, expr, expr.expression);
|
|
4284
4697
|
if (intrinsic)
|
|
4285
4698
|
return intrinsic;
|
|
4699
|
+
if (isJsSourceFile(expr.getSourceFile())) {
|
|
4700
|
+
const staticField = lowerStaticFieldRead(lowerer, expr.expression);
|
|
4701
|
+
if (staticField?.type.kind === "dyn" && !expr.arguments.some(ts.isSpreadElement)) {
|
|
4702
|
+
return { kind: "dynCall", callee: staticField, receiver: lowerer.lowerExprExpecting(expr.expression.expression, DYN), calleeName: expr.expression.getText(),
|
|
4703
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc: locOf(expr) };
|
|
4704
|
+
}
|
|
4705
|
+
}
|
|
4706
|
+
const accessorTarget = lowerer.fieldTarget(expr.expression);
|
|
4707
|
+
if (accessorTarget?.container === "accessor") {
|
|
4708
|
+
const callee = lowerer.fieldGetExpr(accessorTarget, locOf(expr.expression), expr.expression);
|
|
4709
|
+
if (callee.type.kind === "func") {
|
|
4710
|
+
const args = completeFuncValueArgs(lowerer, expr, callee.type, locOf(expr));
|
|
4711
|
+
return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(expr) };
|
|
4712
|
+
}
|
|
4713
|
+
if (callee.type.kind === "dyn" && !expr.arguments.some((arg) => ts.isSpreadElement(arg))) {
|
|
4714
|
+
const args = expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
|
|
4715
|
+
return { kind: "dynCall", callee, calleeName: expr.expression.getText(), args, type: DYN, loc: locOf(expr) };
|
|
4716
|
+
}
|
|
4717
|
+
}
|
|
4286
4718
|
// A method call rooted at an initializer-less ambient `declare
|
|
4287
4719
|
// const/var` whose declared type has no mapping: Node throws the
|
|
4288
4720
|
// catchable ReferenceError at the ROOT read before the member, the
|
|
@@ -4332,6 +4764,9 @@ export function lowerCall(lowerer, expr) {
|
|
|
4332
4764
|
// The element spelling of an unsupported native Web method must fence
|
|
4333
4765
|
// before lowering the callee into a checked-dynamic keyed read.
|
|
4334
4766
|
if (ts.isElementAccessExpression(expr.expression)) {
|
|
4767
|
+
const symbolMethod = lowerClassSymbolMethodCall(lowerer, expr);
|
|
4768
|
+
if (symbolMethod)
|
|
4769
|
+
return symbolMethod;
|
|
4335
4770
|
const headersIterator = lowerer.lowerDynamicHeadersIteratorCall(expr, expr.expression);
|
|
4336
4771
|
if (headersIterator)
|
|
4337
4772
|
return headersIterator;
|
|
@@ -4340,6 +4775,30 @@ export function lowerCall(lowerer, expr) {
|
|
|
4340
4775
|
lowerer.fenceStaticHeadersMember(expr.expression, "call");
|
|
4341
4776
|
lowerer.fenceStaticReadableStreamMember(expr.expression, "call");
|
|
4342
4777
|
}
|
|
4778
|
+
// Computed native members retain their original receiver and resolve
|
|
4779
|
+
// the function before argument effects, just like dotted calls.
|
|
4780
|
+
if (ts.isElementAccessExpression(expr.expression) && !expr.expression.questionDotToken && !expr.questionDotToken &&
|
|
4781
|
+
!symbolFieldInfo(lowerer, expr.expression)) {
|
|
4782
|
+
const access = expr.expression;
|
|
4783
|
+
const value = tryLowerExpression(lowerer, access.expression);
|
|
4784
|
+
if (value?.type.kind === "dyn" || value?.type.kind === "generator" ||
|
|
4785
|
+
value && ["array", "bytes", "map", "set"].includes(value.type.kind) && lowerer.dynConvertible(value.type) ||
|
|
4786
|
+
value?.type.kind === "string" && !ts.isStringLiteralLike(access.argumentExpression) && lowerer.dynConvertible(value.type) ||
|
|
4787
|
+
value?.type.kind === "object" && !lowerer.classes.get(value.type.className)?.def.runtime) {
|
|
4788
|
+
const local = lowerer.declareHiddenLocal("%computedReceiver", value.type);
|
|
4789
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
4790
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
4791
|
+
const raw = lowerer.lowerExpr(access.argumentExpression);
|
|
4792
|
+
const key = raw.type.kind === "string" ? raw : lowerer.coerceInto(access.argumentExpression, raw, DYN);
|
|
4793
|
+
const callee = { kind: "dynKeyGet", value: receiver, key, type: DYN, loc };
|
|
4794
|
+
const spread = expr.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, expr, callee, loc) : null;
|
|
4795
|
+
if (spread && spread.kind !== "dynCall")
|
|
4796
|
+
lowerer.unsupported("SC1090", expr, "computed native method spread arguments");
|
|
4797
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
4798
|
+
calleeName: access.getText(), args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4799
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4343
4802
|
// The ELEMENT spelling of a primitive method call — `x['toString']()`,
|
|
4344
4803
|
// `s['charAt'](0)`: JS resolves it exactly like the dot form, so the
|
|
4345
4804
|
// literal-keyed shapes with a static lowering route there before the
|
|
@@ -4347,8 +4806,41 @@ export function lowerCall(lowerer, expr) {
|
|
|
4347
4806
|
if (ts.isElementAccessExpression(expr.expression) &&
|
|
4348
4807
|
!expr.expression.questionDotToken &&
|
|
4349
4808
|
!expr.questionDotToken &&
|
|
4350
|
-
ts.isStringLiteralLike(expr.expression.argumentExpression)) {
|
|
4351
|
-
const memberName = expr.expression.argumentExpression
|
|
4809
|
+
(ts.isStringLiteralLike(expr.expression.argumentExpression) || ts.isNumericLiteral(expr.expression.argumentExpression))) {
|
|
4810
|
+
const memberName = ts.isNumericLiteral(expr.expression.argumentExpression)
|
|
4811
|
+
? String(Number(expr.expression.argumentExpression.text))
|
|
4812
|
+
: expr.expression.argumentExpression.text;
|
|
4813
|
+
const receiverType = lowerer.mapTypeOf(lowerer.typeOf(expr.expression.expression));
|
|
4814
|
+
if (receiverType?.kind === "object") {
|
|
4815
|
+
const info = lowerer.classes.get(receiverType.className);
|
|
4816
|
+
const found = info ? lowerer.findMethodOn(info, memberName) : null;
|
|
4817
|
+
if (info && found) {
|
|
4818
|
+
if (found.declarer.builtinError)
|
|
4819
|
+
return errorToStringCall(lowerer, lowerer.lowerExpr(expr.expression.expression));
|
|
4820
|
+
const virtual = lowerer.overrideBelow(info, memberName);
|
|
4821
|
+
if (found.sig.abstract === true && !virtual) {
|
|
4822
|
+
lowerer.unsupported("SC1090", expr, `calls of the abstract method '${memberName}' with no concrete implementation below the receiver's static class`);
|
|
4823
|
+
}
|
|
4824
|
+
if (virtual)
|
|
4825
|
+
lowerer.noteVirtualEdge(info, memberName);
|
|
4826
|
+
else
|
|
4827
|
+
lowerer.noteEdge(`%${found.declarer.def.name}.${memberName}`);
|
|
4828
|
+
const receiver = lowerer.lowerExpr(expr.expression.expression);
|
|
4829
|
+
const args = lowerer.completeArgs(expr.arguments, found.sig.params, locOf(expr), expr);
|
|
4830
|
+
const callArgs = [lowerer.upcastTo(receiver, virtual ? info.def.name : found.declarer.def.name), ...args];
|
|
4831
|
+
const loc = locOf(expr);
|
|
4832
|
+
if (virtual) {
|
|
4833
|
+
return reconcileOverloadReturn(lowerer, expr, {
|
|
4834
|
+
kind: "virtualCall", className: info.def.name, method: memberName,
|
|
4835
|
+
args: callArgs, type: found.sig.ret, loc,
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4838
|
+
return reconcileOverloadReturn(lowerer, expr, {
|
|
4839
|
+
kind: "call", callee: `%${found.declarer.def.name}.${memberName}`,
|
|
4840
|
+
args: callArgs, type: found.sig.ret, loc,
|
|
4841
|
+
});
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4352
4844
|
// ts7's getSymbolAtLocation does not resolve element accesses; the
|
|
4353
4845
|
// member symbol comes from the receiver's (apparent) type instead —
|
|
4354
4846
|
// same provenance answer as the dot spelling's name symbol.
|
|
@@ -4392,6 +4884,11 @@ export function lowerCall(lowerer, expr) {
|
|
|
4392
4884
|
: "value";
|
|
4393
4885
|
return { kind: "dynCall", callee, calleeName, args, type: DYN, loc };
|
|
4394
4886
|
}
|
|
4887
|
+
if (callee.type.kind === "union" && lowerer.dynConvertible(callee.type) &&
|
|
4888
|
+
lowerer.unions.get(callee.type.unionId)?.arms.some((arm) => arm.kind === "func")) {
|
|
4889
|
+
return { kind: "dynCall", callee: lowerer.coerceToExpected(callee, DYN), calleeName: expr.expression.getText(),
|
|
4890
|
+
args: expr.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
4891
|
+
}
|
|
4395
4892
|
if (callee.type.kind !== "func") {
|
|
4396
4893
|
lowerer.badType(expr.expression, lowerer.typeOf(expr.expression));
|
|
4397
4894
|
}
|
|
@@ -4446,7 +4943,7 @@ export function lowerCall(lowerer, expr) {
|
|
|
4446
4943
|
// JS arity exactly (the thunk ignores extras). Result dyn, checked
|
|
4447
4944
|
// per use like every any-origin value.
|
|
4448
4945
|
if ((expr.arguments.length > callee.type.params.length || callee.type.rest === true) &&
|
|
4449
|
-
isJsSourceFile(expr.getSourceFile()) &&
|
|
4946
|
+
(isJsSourceFile(expr.getSourceFile()) || callee.type.rest === true && callee.type.restAbi === undefined) &&
|
|
4450
4947
|
!expr.arguments.some((a) => ts.isSpreadElement(a)) &&
|
|
4451
4948
|
canBoxFuncIntoDyn(callee.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
4452
4949
|
const args = expr.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
@@ -4457,6 +4954,29 @@ export function lowerCall(lowerer, expr) {
|
|
|
4457
4954
|
const args = completeFuncValueArgs(lowerer, expr, callee.type, loc);
|
|
4458
4955
|
return { kind: "callValue", callee, args, type: callee.type.ret, loc };
|
|
4459
4956
|
}
|
|
4957
|
+
/** Exported checked and variadic callables use the same runtime-arity ABI
|
|
4958
|
+
* whether the caller spells a bare import or a namespace member. */
|
|
4959
|
+
function lowerCheckedCallableValue(lowerer, call, value, loc) {
|
|
4960
|
+
let callee = value;
|
|
4961
|
+
if (callee.type.kind !== "dyn") {
|
|
4962
|
+
if (callee.type.kind !== "func" ||
|
|
4963
|
+
!(callee.type.rest === true && callee.type.restAbi === undefined ||
|
|
4964
|
+
isJsSourceFile(call.getSourceFile()) && call.arguments.length > callee.type.params.length) ||
|
|
4965
|
+
!lowerer.dynConvertible(callee.type))
|
|
4966
|
+
return null;
|
|
4967
|
+
callee = { kind: "dynFrom", value: callee, type: DYN, loc };
|
|
4968
|
+
}
|
|
4969
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
4970
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
4971
|
+
if (spread)
|
|
4972
|
+
return spread;
|
|
4973
|
+
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
4974
|
+
}
|
|
4975
|
+
return {
|
|
4976
|
+
kind: "dynCall", callee, calleeName: call.expression.getText(),
|
|
4977
|
+
args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
|
|
4978
|
+
};
|
|
4979
|
+
}
|
|
4460
4980
|
function lowerRegexMethodCallWithOptionalArg(lowerer, call, access) {
|
|
4461
4981
|
const lowered = lowerer.lowerRegexMethodCall(call, access);
|
|
4462
4982
|
if (lowered?.kind !== "regexIntrinsic" || lowered.method !== "test" || call.arguments.length !== 1)
|
|
@@ -4478,9 +4998,13 @@ function optionalCallValue(lowerer, node) {
|
|
|
4478
4998
|
return lowerer.runtimeOptionalIdentifierValue(node)?.value ?? lowerAbsenceProbe(lowerer, node);
|
|
4479
4999
|
}
|
|
4480
5000
|
function lowerBufferStaticCallWithNarrowedArg(lowerer, call, access) {
|
|
4481
|
-
const
|
|
5001
|
+
const result = lowerer.lowerBufferStaticCall(call, access);
|
|
5002
|
+
// The Buffer brand wraps the constructor result. Normalize its source
|
|
5003
|
+
// before restoring that wrapper so narrowed unions never reach bytesNew.
|
|
5004
|
+
const branded = result?.kind === "libCall" && result.fn === "buffer.brand" ? result : null;
|
|
5005
|
+
const lowered = branded ? branded.args[0] : result;
|
|
4482
5006
|
if (lowered?.kind !== "bytesNew" || !lowered.source || lowered.source.type.kind !== "union")
|
|
4483
|
-
return
|
|
5007
|
+
return result;
|
|
4484
5008
|
// A callback can store a wider union than the checker sees at this use
|
|
4485
5009
|
// (including an added undefined arm). Extract the exact arm proven by
|
|
4486
5010
|
// control-flow narrowing, not merely the union with undefined removed.
|
|
@@ -4496,10 +5020,11 @@ function lowerBufferStaticCallWithNarrowedArg(lowerer, call, access) {
|
|
|
4496
5020
|
if (!helper) {
|
|
4497
5021
|
lowerer.unsupported("SC1090", call.arguments[0], "a Buffer constructor argument whose narrowed type is not a stored source arm");
|
|
4498
5022
|
}
|
|
4499
|
-
|
|
5023
|
+
const narrowedValue = {
|
|
4500
5024
|
...lowered,
|
|
4501
5025
|
source: { kind: "call", callee: helper, args: [lowered.source], type: narrowed, loc: lowered.source.loc },
|
|
4502
5026
|
};
|
|
5027
|
+
return branded ? { ...branded, args: [narrowedValue] } : narrowedValue;
|
|
4503
5028
|
}
|
|
4504
5029
|
function lowerOptionalNumberDefault(lowerer, value, dflt, loc) {
|
|
4505
5030
|
const widened = lowerer.runtimeOptionalWidening(value.type, F64);
|
|
@@ -4554,6 +5079,8 @@ function lowerStringMethodCallWithOptionalArgs(lowerer, call, access, receiver,
|
|
|
4554
5079
|
? [1]
|
|
4555
5080
|
: [];
|
|
4556
5081
|
for (const index of zeroDefaultArgs) {
|
|
5082
|
+
if (index === undefined)
|
|
5083
|
+
continue;
|
|
4557
5084
|
const value = args[index];
|
|
4558
5085
|
if (!value)
|
|
4559
5086
|
continue;
|
|
@@ -4599,6 +5126,12 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4599
5126
|
}
|
|
4600
5127
|
if (arg.type.kind === "string")
|
|
4601
5128
|
return { kind: "libCall", fn: "num.fromString", args: [arg], type: F64, loc };
|
|
5129
|
+
if (arg.type.kind === "dyn")
|
|
5130
|
+
return { kind: "libCall", fn: "dyn.numberConstructor", args: [arg], type: F64, loc };
|
|
5131
|
+
if (arg.type.kind === "union" && lowerer.dynConvertible(arg.type))
|
|
5132
|
+
return {
|
|
5133
|
+
kind: "libCall", fn: "dyn.numberConstructor", args: [lowerer.coerceToExpected(arg, DYN)], type: F64, loc,
|
|
5134
|
+
};
|
|
4602
5135
|
const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc);
|
|
4603
5136
|
if (optionalNumber)
|
|
4604
5137
|
return optionalNumber;
|
|
@@ -4609,6 +5142,63 @@ function lowerNumberConstructorValue(lowerer, argNode, loc) {
|
|
|
4609
5142
|
? "unions of numbers, booleans, strings, null, and undefined lower — narrow other arms first"
|
|
4610
5143
|
: undefined);
|
|
4611
5144
|
}
|
|
5145
|
+
/** A runtime-optional local retains its full tagged storage even after a
|
|
5146
|
+
* checker guard. Dispatch BigInt by the actual value, including nullish
|
|
5147
|
+
* TypeErrors, rather than interpreting that storage as the narrowed arm. */
|
|
5148
|
+
function lowerBigIntConstructorValue(lowerer, arg, loc) {
|
|
5149
|
+
if (arg.type.kind === "dyn")
|
|
5150
|
+
return { kind: "libCall", fn: "dyn.bigintConstructor", args: [arg], type: BIGINT_T, loc };
|
|
5151
|
+
if (arg.type.kind === "bigint")
|
|
5152
|
+
return arg;
|
|
5153
|
+
if (arg.type.kind === "string")
|
|
5154
|
+
return { kind: "libCall", fn: "bigint.parse", args: [arg], type: BIGINT_T, loc };
|
|
5155
|
+
if (arg.type.kind === "f64")
|
|
5156
|
+
return { kind: "libCall", fn: "bigint.fromF64", args: [arg], type: BIGINT_T, loc };
|
|
5157
|
+
if (arg.type.kind === "bool") {
|
|
5158
|
+
return {
|
|
5159
|
+
kind: "ternary", cond: arg,
|
|
5160
|
+
then: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "1", type: STRING, loc }], type: BIGINT_T, loc },
|
|
5161
|
+
else_: { kind: "libCall", fn: "bigint.parse", args: [{ kind: "strLit", value: "0", type: STRING, loc }], type: BIGINT_T, loc },
|
|
5162
|
+
type: BIGINT_T, loc,
|
|
5163
|
+
};
|
|
5164
|
+
}
|
|
5165
|
+
if (isUnitType(arg.type)) {
|
|
5166
|
+
const name = arg.type.kind === "nullT" ? "null" : "undefined";
|
|
5167
|
+
return defaultAfterUndefined(arg, nodeThrowExpr(1, "", `Cannot convert ${name} to a BigInt`, BIGINT_T, loc));
|
|
5168
|
+
}
|
|
5169
|
+
if (arg.type.kind !== "union")
|
|
5170
|
+
return null;
|
|
5171
|
+
const unionId = arg.type.unionId;
|
|
5172
|
+
const arms = lowerer.unions.get(unionId)?.arms;
|
|
5173
|
+
if (!arms || !arms.every((arm) => arm.kind === "bigint" || arm.kind === "string" || arm.kind === "f64" || arm.kind === "bool" || isUnitType(arm)))
|
|
5174
|
+
return null;
|
|
5175
|
+
const key = `bigint.scalar:${unionId}`;
|
|
5176
|
+
let helper = lowerer.widthHelpers.get(key);
|
|
5177
|
+
if (!helper) {
|
|
5178
|
+
helper = `%bigint.scalar.${lowerer.widthHelpers.size}`;
|
|
5179
|
+
lowerer.widthHelpers.set(key, helper);
|
|
5180
|
+
const value = varRef("value.0", arg.type, loc);
|
|
5181
|
+
const body = [];
|
|
5182
|
+
arms.forEach((arm, tag) => {
|
|
5183
|
+
const narrowed = isUnitType(arm)
|
|
5184
|
+
? { kind: "unitLit", unit: arm.kind === "nullT" ? "null" : "undefined", type: arm, loc }
|
|
5185
|
+
: { kind: "unionNarrow", unionId, tag, value, type: arm, loc };
|
|
5186
|
+
const converted = lowerBigIntConstructorValue(lowerer, narrowed, loc);
|
|
5187
|
+
if (!converted)
|
|
5188
|
+
throw new InternalCompilerError("BigInt scalar union has an unsupported arm");
|
|
5189
|
+
const ret = { kind: "return", value: converted, loc };
|
|
5190
|
+
body.push(tag === arms.length - 1 ? ret : {
|
|
5191
|
+
kind: "if", cond: { kind: "unionIsTag", unionId, tag, negated: false, value, type: BOOL, loc },
|
|
5192
|
+
then: [ret], else_: null, loc,
|
|
5193
|
+
});
|
|
5194
|
+
});
|
|
5195
|
+
lowerer.liftedFns.push({
|
|
5196
|
+
name: helper, params: [{ localId: "value.0", name: "value", type: arg.type }],
|
|
5197
|
+
returnType: BIGINT_T, locals: [{ id: "value.0", name: "value", type: arg.type, mutable: false }], body, loc,
|
|
5198
|
+
});
|
|
5199
|
+
}
|
|
5200
|
+
return { kind: "call", callee: helper, args: [arg], type: BIGINT_T, loc };
|
|
5201
|
+
}
|
|
4612
5202
|
function immediatePrimitiveWrapperToString(lowerer, node) {
|
|
4613
5203
|
const stringValue = stringWrapperToString(lowerer, node);
|
|
4614
5204
|
if (stringValue)
|
|
@@ -4631,24 +5221,6 @@ function immediatePrimitiveWrapperToString(lowerer, node) {
|
|
|
4631
5221
|
: args.length ? lowerNumberConstructorValue(lowerer, args[0], loc) : { kind: "numLit", value: 0, type: F64, loc };
|
|
4632
5222
|
return lowerer.ensureString(primitive, wrapped);
|
|
4633
5223
|
}
|
|
4634
|
-
function plainObjectCoercionReceiver(lowerer, node) {
|
|
4635
|
-
const plainLiteral = (literal) => literal.properties.every((prop) => ts.isPropertyAssignment(prop) &&
|
|
4636
|
-
(ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name) || ts.isNumericLiteral(prop.name)) &&
|
|
4637
|
-
prop.name.text !== "__proto__");
|
|
4638
|
-
let value = node;
|
|
4639
|
-
while (ts.isParenthesizedExpression(value))
|
|
4640
|
-
value = value.expression;
|
|
4641
|
-
if (ts.isObjectLiteralExpression(value))
|
|
4642
|
-
return plainLiteral(value);
|
|
4643
|
-
if (!ts.isIdentifier(value))
|
|
4644
|
-
return false;
|
|
4645
|
-
const symbol = lowerer.resolveValueSymbol(value);
|
|
4646
|
-
const decl = symbol ? lowerer.checker.valueDeclarationOf(symbol) : undefined;
|
|
4647
|
-
if (!symbol || !decl || !ts.isVariableDeclaration(decl) || !decl.initializer ||
|
|
4648
|
-
!ts.isObjectLiteralExpression(decl.initializer) || !plainLiteral(decl.initializer))
|
|
4649
|
-
return false;
|
|
4650
|
-
return bindingNeverReassigned(lowerer, symbol, decl);
|
|
4651
|
-
}
|
|
4652
5224
|
function objectToStringTag(lowerer, type) {
|
|
4653
5225
|
switch (type.kind) {
|
|
4654
5226
|
case "undefinedT":
|
|
@@ -4669,7 +5241,7 @@ function objectToStringTag(lowerer, type) {
|
|
|
4669
5241
|
case "set": return "Set";
|
|
4670
5242
|
case "promise": return "Promise";
|
|
4671
5243
|
case "bytes":
|
|
4672
|
-
return
|
|
5244
|
+
return BYTES_ELEMENT_NAME[type.elem];
|
|
4673
5245
|
case "object":
|
|
4674
5246
|
return type.className === "%Error" || lowerer.isSubclassOf(type.className, "%Error") ? "Error" : null;
|
|
4675
5247
|
default: return null;
|
|
@@ -4691,6 +5263,10 @@ function immediateObjectTagReceiver(lowerer, node) {
|
|
|
4691
5263
|
lowerer.isStdlibSymbol(lowerer.resolveValueSymbol(value.expression) ?? undefined)) {
|
|
4692
5264
|
const name = value.expression.text;
|
|
4693
5265
|
const args = value.arguments ?? [];
|
|
5266
|
+
// JavaScript dates use checked native handles, so their IR type alone
|
|
5267
|
+
// cannot recover the tag through an immediate Object(...) wrapper.
|
|
5268
|
+
if (name === "Date")
|
|
5269
|
+
return { tag: "Date", effect: lowerer.lowerExpr(value) };
|
|
4694
5270
|
if (args.length <= 1 && !args.some(ts.isSpreadElement)) {
|
|
4695
5271
|
if (name === "String") {
|
|
4696
5272
|
const effect = stringWrapperToString(lowerer, value);
|
|
@@ -4738,6 +5314,36 @@ function immediateObjectTagReceiver(lowerer, node) {
|
|
|
4738
5314
|
}
|
|
4739
5315
|
return null;
|
|
4740
5316
|
}
|
|
5317
|
+
const ARRAY_BORROW_METHODS = new Set([
|
|
5318
|
+
"at", "every", "filter", "find", "findIndex", "findLast", "findLastIndex", "forEach", "includes",
|
|
5319
|
+
"indexOf", "lastIndexOf", "map", "reduce", "reduceRight", "slice", "some",
|
|
5320
|
+
]);
|
|
5321
|
+
function lowerArrayPrototypeBorrowCall(lowerer, call, access) {
|
|
5322
|
+
if (lowerer.dynamic || !isJsSourceFile(call.getSourceFile()) || call.questionDotToken ||
|
|
5323
|
+
access.questionDotToken || access.name.text !== "call" ||
|
|
5324
|
+
!ts.isPropertyAccessExpression(access.expression) ||
|
|
5325
|
+
call.arguments.some(ts.isSpreadElement))
|
|
5326
|
+
return null;
|
|
5327
|
+
const method = access.expression;
|
|
5328
|
+
if (method.questionDotToken || !ARRAY_BORROW_METHODS.has(method.name.text) ||
|
|
5329
|
+
!ts.isPropertyAccessExpression(method.expression) ||
|
|
5330
|
+
method.expression.questionDotToken || method.expression.name.text !== "prototype" ||
|
|
5331
|
+
!lowerer.isStdlibGlobal(method.expression.expression, "Array") ||
|
|
5332
|
+
!lowerer.isStdlibMember(method))
|
|
5333
|
+
return null;
|
|
5334
|
+
const loc = locOf(call);
|
|
5335
|
+
const receiver = call.arguments[0]
|
|
5336
|
+
? lowerer.lowerExprExpecting(call.arguments[0], DYN)
|
|
5337
|
+
: { kind: "dynFrom", value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, type: DYN, loc };
|
|
5338
|
+
const args = call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN));
|
|
5339
|
+
return {
|
|
5340
|
+
kind: "libCall", fn: "dyn.arrayProtoCall", args: [
|
|
5341
|
+
receiver,
|
|
5342
|
+
{ kind: "strLit", value: method.name.text, type: STRING, loc },
|
|
5343
|
+
{ kind: "dynArrLit", elems: args, type: DYN, loc },
|
|
5344
|
+
], type: DYN, loc,
|
|
5345
|
+
};
|
|
5346
|
+
}
|
|
4741
5347
|
function lowerObjectOwnPrototypeCall(lowerer, call, access) {
|
|
4742
5348
|
if (lowerer.dynamic || access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
|
|
4743
5349
|
return null;
|
|
@@ -4756,10 +5362,31 @@ function lowerObjectOwnMethodCall(lowerer, call, access) {
|
|
|
4756
5362
|
const method = access.name.text;
|
|
4757
5363
|
if (lowerer.dynamic || call.questionDotToken || access.questionDotToken ||
|
|
4758
5364
|
(method !== "hasOwnProperty" && method !== "propertyIsEnumerable") ||
|
|
4759
|
-
|
|
5365
|
+
call.arguments.some(ts.isSpreadElement))
|
|
4760
5366
|
return null;
|
|
5367
|
+
if (!lowerer.isStdlibMember(access)) {
|
|
5368
|
+
const receiver = tryLowerExpression(lowerer, access.expression);
|
|
5369
|
+
if (receiver?.type.kind !== "dyn")
|
|
5370
|
+
return null;
|
|
5371
|
+
}
|
|
4761
5372
|
return lowerObjectOwnCall(lowerer, call, access.expression, call.arguments[0], call.arguments.slice(1), method);
|
|
4762
5373
|
}
|
|
5374
|
+
/** ToPropertyKey for the scalar keys represented by native own-key
|
|
5375
|
+
* probes. A lowered array-loop key may carry an undefined arm even when
|
|
5376
|
+
* its checker type is string; that arm spells "undefined" at runtime. */
|
|
5377
|
+
function ownPropertyKey(lowerer, key) {
|
|
5378
|
+
if (key.type.kind === "string")
|
|
5379
|
+
return key;
|
|
5380
|
+
if (key.type.kind === "bigint") {
|
|
5381
|
+
return { kind: "libCall", fn: "bigint.toString", args: [key, numLit(10, key.loc)], type: STRING, loc: key.loc };
|
|
5382
|
+
}
|
|
5383
|
+
const scalar = (type) => type.kind === "string" || type.kind === "f64" || type.kind === "bool" || isUnitType(type);
|
|
5384
|
+
if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn" ||
|
|
5385
|
+
(key.type.kind === "union" && lowerer.unions.get(key.type.unionId)?.arms.every(scalar))) {
|
|
5386
|
+
return { kind: "toString", operand: key, type: STRING, loc: key.loc };
|
|
5387
|
+
}
|
|
5388
|
+
return null;
|
|
5389
|
+
}
|
|
4763
5390
|
function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, method) {
|
|
4764
5391
|
const enumerable = method === "propertyIsEnumerable";
|
|
4765
5392
|
const loc = locOf(call);
|
|
@@ -4792,14 +5419,19 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
|
|
|
4792
5419
|
stmts.push({ kind: "exprStmt", expr: effect, loc: locOf(extra) });
|
|
4793
5420
|
}
|
|
4794
5421
|
let key = keyRef;
|
|
5422
|
+
if (lowerer.dynConvertible(receiverRef.type) && keyRef && (receiverRef.type.kind === "object" || keyRef.type.kind === "symbol" || keyRef.type.kind === "dyn" ||
|
|
5423
|
+
keyRef.type.kind === "union" && lowerer.dynConvertible(keyRef.type))) {
|
|
5424
|
+
const result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerableComputed" : "dyn.hasOwnComputed", args: [lowerer.coerceToExpected(receiverRef, DYN), lowerer.coerceToExpected(keyRef, DYN)], type: BOOL, loc };
|
|
5425
|
+
return { kind: "seqExpr", stmts, result, type: BOOL, loc };
|
|
5426
|
+
}
|
|
4795
5427
|
if (!keyNode || rawKey?.type.kind === "undefinedT" || rawKey?.type.kind === "void") {
|
|
4796
5428
|
key = { kind: "strLit", value: "undefined", type: STRING, loc };
|
|
4797
5429
|
}
|
|
4798
5430
|
else if (rawKey?.type.kind === "nullT") {
|
|
4799
5431
|
key = { kind: "strLit", value: "null", type: STRING, loc };
|
|
4800
5432
|
}
|
|
4801
|
-
else if (key
|
|
4802
|
-
key =
|
|
5433
|
+
else if (key) {
|
|
5434
|
+
key = ownPropertyKey(lowerer, key);
|
|
4803
5435
|
}
|
|
4804
5436
|
if (!key || key.type.kind !== "string") {
|
|
4805
5437
|
lowerer.noLowering("Object.prototype." + method + " with this property key", keyNode ?? call);
|
|
@@ -4811,13 +5443,13 @@ function lowerObjectOwnCall(lowerer, call, receiverNode, keyNode, extraNodes, me
|
|
|
4811
5443
|
}
|
|
4812
5444
|
else if (type.kind === "record") {
|
|
4813
5445
|
const shape = lowerer.shapes.get(type.shapeId);
|
|
4814
|
-
if (!shape || shape.tuple ||
|
|
5446
|
+
if (!shape || shape.tuple || shapeHasAccessorSlots(shape)) {
|
|
4815
5447
|
lowerer.noLowering("Object.prototype." + method + " over this record shape", receiverNode ?? call);
|
|
4816
5448
|
}
|
|
4817
5449
|
result = { kind: "call", callee: recordHasOwnHelper(lowerer, type.shapeId, loc), args: [receiverRef, key], type: BOOL, loc };
|
|
4818
5450
|
}
|
|
4819
|
-
else if (type.kind === "dyn"
|
|
4820
|
-
result = { kind: "libCall", fn: "dyn.hasOwn", args: [receiverRef, key], type: BOOL, loc };
|
|
5451
|
+
else if (type.kind === "dyn") {
|
|
5452
|
+
result = { kind: "libCall", fn: enumerable ? "dyn.propertyIsEnumerable" : "dyn.hasOwn", args: [receiverRef, key], type: BOOL, loc };
|
|
4821
5453
|
}
|
|
4822
5454
|
else if (type.kind === "string" || type.kind === "array") {
|
|
4823
5455
|
const needleLocal = lowerer.declareHiddenLocal("%ownIndex", F64);
|
|
@@ -4886,6 +5518,52 @@ function lowerObjectPrototypeCall(lowerer, call, access) {
|
|
|
4886
5518
|
: { kind: "strLit", value: "[object " + tag + "]", type: STRING, loc };
|
|
4887
5519
|
return { kind: "seqExpr", stmts, result, type: STRING, loc };
|
|
4888
5520
|
}
|
|
5521
|
+
/** Function.call evaluates all arguments before RequireObjectCoercible and
|
|
5522
|
+
* ToString. Stabilize them before reusing the ordinary string method lowering,
|
|
5523
|
+
* so a boxed nullish receiver or a coercion hook cannot reorder effects. */
|
|
5524
|
+
function lowerDynamicStringPrototypeCall(lowerer, call, methodAccess, receiver, method) {
|
|
5525
|
+
const loc = locOf(call);
|
|
5526
|
+
const receiverLocal = lowerer.declareHiddenLocal("%stringCallReceiver", receiver.type);
|
|
5527
|
+
const stmts = [{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc }];
|
|
5528
|
+
const receiverRef = varRef(receiverLocal.id, receiver.type, loc);
|
|
5529
|
+
const converted = {
|
|
5530
|
+
kind: "ternary",
|
|
5531
|
+
cond: { kind: "dynTest", test: "nullish", value: receiverRef, type: BOOL, loc },
|
|
5532
|
+
then: nodeThrowExpr(1, "", `String.prototype.${method} called on null or undefined`, STRING, loc),
|
|
5533
|
+
else_: { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverRef], type: STRING, loc },
|
|
5534
|
+
type: STRING, loc,
|
|
5535
|
+
};
|
|
5536
|
+
const overrides = [];
|
|
5537
|
+
try {
|
|
5538
|
+
for (const node of call.arguments.slice(1)) {
|
|
5539
|
+
const undefinedValue = lowerStaticallyUndefinedArgument(lowerer, node);
|
|
5540
|
+
const value = undefinedValue ?? lowerer.lowerExpr(node);
|
|
5541
|
+
let ref;
|
|
5542
|
+
if (undefinedValue || isUnitType(value.type) || value.type.kind === "void") {
|
|
5543
|
+
stmts.push({ kind: "exprStmt", expr: value, loc: value.loc });
|
|
5544
|
+
const nullUnit = !undefinedValue && value.type.kind === "nullT";
|
|
5545
|
+
ref = { kind: "unitLit", unit: nullUnit ? "null" : "undefined", type: nullUnit ? value.type : UNDEFINED_T, loc: value.loc };
|
|
5546
|
+
}
|
|
5547
|
+
else {
|
|
5548
|
+
const local = lowerer.declareHiddenLocal("%stringCallArg", value.type);
|
|
5549
|
+
stmts.push({ kind: "varDecl", localId: local.id, init: value, loc: value.loc });
|
|
5550
|
+
ref = varRef(local.id, value.type, value.loc);
|
|
5551
|
+
}
|
|
5552
|
+
overrides.push({ node, previous: lowerer.chainRecvByNode.get(node) });
|
|
5553
|
+
lowerer.chainRecvByNode.set(node, ref);
|
|
5554
|
+
}
|
|
5555
|
+
const result = lowerStringMethodCallWithOptionalArgs(lowerer, call, methodAccess, () => converted, call.arguments.slice(1));
|
|
5556
|
+
return result ? { kind: "seqExpr", stmts, result, type: result.type, loc } : null;
|
|
5557
|
+
}
|
|
5558
|
+
finally {
|
|
5559
|
+
for (const override of overrides) {
|
|
5560
|
+
if (override.previous)
|
|
5561
|
+
lowerer.chainRecvByNode.set(override.node, override.previous);
|
|
5562
|
+
else
|
|
5563
|
+
lowerer.chainRecvByNode.delete(override.node);
|
|
5564
|
+
}
|
|
5565
|
+
}
|
|
5566
|
+
}
|
|
4889
5567
|
function lowerStringPrototypeCall(lowerer, call, access) {
|
|
4890
5568
|
if (access.name.text !== "call" || !ts.isPropertyAccessExpression(access.expression))
|
|
4891
5569
|
return null;
|
|
@@ -4928,6 +5606,9 @@ function lowerStringPrototypeCall(lowerer, call, access) {
|
|
|
4928
5606
|
loc,
|
|
4929
5607
|
};
|
|
4930
5608
|
}
|
|
5609
|
+
if (receiverType.kind === "dyn") {
|
|
5610
|
+
return lowerDynamicStringPrototypeCall(lowerer, call, methodAccess, receiverValue, method);
|
|
5611
|
+
}
|
|
4931
5612
|
const padding = entry?.method === "padStart" || entry?.method === "padEnd";
|
|
4932
5613
|
const scalar = receiverType.kind === "string" || receiverType.kind === "f64" ||
|
|
4933
5614
|
receiverType.kind === "bool" || receiverType.kind === "bigint" ||
|
|
@@ -4936,10 +5617,11 @@ function lowerStringPrototypeCall(lowerer, call, access) {
|
|
|
4936
5617
|
// padding uses a helper that delays conversion until every argument is ready.
|
|
4937
5618
|
const objectWithoutMethodArgs = entry?.maxArgs === 0 && call.arguments.length === 1 &&
|
|
4938
5619
|
(receiverType.kind === "record" || receiverType.kind === "array" || receiverType.kind === "object");
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
5620
|
+
if (padding && !scalar && lowerer.dynConvertible(receiverType)) {
|
|
5621
|
+
return lowerStringPaddingCall(lowerer, call, entry.method, lowerer.coerceToExpected(receiverValue, DYN), receiverNode, call.arguments.slice(1));
|
|
5622
|
+
}
|
|
5623
|
+
if (!scalar && !objectWithoutMethodArgs) {
|
|
5624
|
+
lowerer.noLowering(`String.prototype.${methodAccess.name.text}.call with ${lowerer.fmt(receiverType)} receivers`, call);
|
|
4943
5625
|
}
|
|
4944
5626
|
if (indexMethod)
|
|
4945
5627
|
return lowerStringIndexCall(lowerer, call, indexMethod, receiverValue, receiverNode, call.arguments.slice(1));
|
|
@@ -4951,9 +5633,7 @@ function lowerStringPrototypeCall(lowerer, call, access) {
|
|
|
4951
5633
|
if (entry.method === "split") {
|
|
4952
5634
|
return lowerStringSplitCall(lowerer, call, receiverValue, receiverNode, call.arguments.slice(1));
|
|
4953
5635
|
}
|
|
4954
|
-
const receiver =
|
|
4955
|
-
? { kind: "libCall", fn: "dyn.toStringCoerce", args: [receiverValue], type: STRING, loc }
|
|
4956
|
-
: lowerer.ensureString(receiverValue, receiverNode);
|
|
5636
|
+
const receiver = lowerer.ensureString(receiverValue, receiverNode);
|
|
4957
5637
|
return lowerStringMethodCallWithOptionalArgs(lowerer, call, methodAccess, () => receiver, call.arguments.slice(1));
|
|
4958
5638
|
}
|
|
4959
5639
|
function lowerScalarUnionNumber(lowerer, arg, node, loc) {
|
|
@@ -5127,13 +5807,18 @@ function spreadNeedsRuntimeArity(lowerer, shapes, argNodes) {
|
|
|
5127
5807
|
position += tuple.fields.length;
|
|
5128
5808
|
continue;
|
|
5129
5809
|
}
|
|
5130
|
-
if (restAt < 0 || position < restAt || shapes[restAt].mode !== "rest")
|
|
5131
|
-
return
|
|
5810
|
+
if (restAt < 0 || position < restAt || shapes[restAt].mode !== "rest") {
|
|
5811
|
+
return !canCompleteRuntimeSpread(lowerer, shapes);
|
|
5812
|
+
}
|
|
5132
5813
|
}
|
|
5133
5814
|
position++;
|
|
5134
5815
|
}
|
|
5135
5816
|
return false;
|
|
5136
5817
|
}
|
|
5818
|
+
function canCompleteRuntimeSpread(lowerer, shapes) {
|
|
5819
|
+
return shapes.length > 0 && shapes.every((shape) => shape.mode !== "islandRest" && shape.callDefault === undefined &&
|
|
5820
|
+
canDynCheckTo(shape.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)));
|
|
5821
|
+
}
|
|
5137
5822
|
/** METHOD calls on dyn receivers (`pkg.name.replace(...)`, `rawName.split`,
|
|
5138
5823
|
* `ws.packages.filter(...)` — JSON.parse-derived values): validate the
|
|
5139
5824
|
* receiver's dyn kind, extract, and ride the STATIC method machinery — the
|
|
@@ -5171,18 +5856,70 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5171
5856
|
// tsc types the return by the evolved shape, the binding lowered
|
|
5172
5857
|
// dyn): probe the lowering and claim exactly the dyn results.
|
|
5173
5858
|
const probed = tryLowerExpression(lowerer, access.expression);
|
|
5859
|
+
if (probed?.type.kind === "func" && stdlibGlobalNameOf(lowerer, access.expression) === null &&
|
|
5860
|
+
!["call", "apply", "bind", "toString", "valueOf", "constructor"].includes(access.name.text) &&
|
|
5861
|
+
canBoxFuncIntoDyn(probed.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
5862
|
+
const loc = locOf(call);
|
|
5863
|
+
const fnName = jsFuncNameOf(access.expression);
|
|
5864
|
+
const boxed = { kind: "dynFrom", value: probed, type: DYN, loc, ...(fnName !== null ? { fnName } : {}) };
|
|
5865
|
+
const local = lowerer.declareHiddenLocal("%callableReceiver", DYN);
|
|
5866
|
+
const receiver = { kind: "varRef", localId: local.id, type: DYN, loc };
|
|
5867
|
+
const member = {
|
|
5868
|
+
kind: "dynKeyGet", value: receiver,
|
|
5869
|
+
key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc,
|
|
5870
|
+
};
|
|
5871
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
5872
|
+
lowerer.unsupported("SC1090", call, "spread arguments in callable property calls");
|
|
5873
|
+
}
|
|
5874
|
+
return {
|
|
5875
|
+
kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: boxed, loc }],
|
|
5876
|
+
result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(),
|
|
5877
|
+
args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc }, type: DYN, loc,
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
if (probed?.type.kind === "classval") {
|
|
5881
|
+
const info = lowerer.classes.get(probed.type.className);
|
|
5882
|
+
if (info && (info.callableBase || hasRuntimeStatics(info)))
|
|
5883
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5884
|
+
}
|
|
5174
5885
|
if (probed?.type.kind !== "dyn")
|
|
5175
5886
|
return null;
|
|
5176
5887
|
recv = probed;
|
|
5177
5888
|
}
|
|
5889
|
+
// A factory may return a constructor more precise than its inferred
|
|
5890
|
+
// checker result. Runtime static members live on that constructor.
|
|
5891
|
+
if (recv.type.kind === "classval") {
|
|
5892
|
+
const info = lowerer.classes.get(recv.type.className);
|
|
5893
|
+
if (info && (info.callableBase || hasRuntimeStatics(info)))
|
|
5894
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5895
|
+
}
|
|
5178
5896
|
// A checker-`any` receiver that already lowered to a real STRING (the
|
|
5179
5897
|
// chained form — `cfg.host.trim().toLowerCase()`, where the first step
|
|
5180
5898
|
// extracted): no validation needed, ride the string tables directly.
|
|
5899
|
+
if (recv.type.kind === "union" && lowerer.stripUndefinedArm(recv.type).kind === "string") {
|
|
5900
|
+
const present = lowerer.runtimeOptionalPropertyReceiver(access.expression, recv, STRING, access.name.text);
|
|
5901
|
+
if (present)
|
|
5902
|
+
recv = present;
|
|
5903
|
+
}
|
|
5181
5904
|
if (recv.type.kind === "string") {
|
|
5182
5905
|
return lowerRegexMethodCall(lowerer, call, access, () => recv) ?? lowerStringMethodCall(lowerer, call, access, () => recv);
|
|
5183
5906
|
}
|
|
5184
5907
|
if (recv.type.kind !== "dyn")
|
|
5185
5908
|
return null;
|
|
5909
|
+
if (lowerer.mapTypeOf(recvTs)?.kind === "classval") {
|
|
5910
|
+
return lowerStaticMethodCall(lowerer, call, access);
|
|
5911
|
+
}
|
|
5912
|
+
const ownCallable = !checkerUntyped && (() => {
|
|
5913
|
+
const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
|
|
5914
|
+
if (prop === undefined)
|
|
5915
|
+
return false;
|
|
5916
|
+
// getPropertyOfType includes inherited Object.prototype members.
|
|
5917
|
+
// Those are not stored members of a checked-dynamic object, so
|
|
5918
|
+
// dynKeyGet cannot stand in for JavaScript's prototype lookup. Only
|
|
5919
|
+
// an authored declaration can justify the own-member path.
|
|
5920
|
+
const authored = lowerer.checker.declarationsOf(prop).some((decl) => !lowerer.isStdlibFile(decl.getSourceFile()));
|
|
5921
|
+
return authored && lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(prop)).length > 0;
|
|
5922
|
+
})();
|
|
5186
5923
|
// Typed-destination filter first (validated extraction into a real
|
|
5187
5924
|
// T[]); an untyped destination falls through to the runtime dispatch
|
|
5188
5925
|
// below (the survivors stay dyn values).
|
|
@@ -5198,34 +5935,21 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5198
5935
|
// these, "the receiver is a string, or the call throws V8's TypeError"
|
|
5199
5936
|
// IS Node's semantics for every possible dyn value. Shared names would
|
|
5200
5937
|
// need a receiver-kind dispatch — they keep the fence.
|
|
5201
|
-
if (DYN_STRING_ONLY_METHODS.has(access.name.text)) {
|
|
5938
|
+
if (DYN_STRING_ONLY_METHODS.has(access.name.text) && !ownCallable) {
|
|
5202
5939
|
const checked = () => dynStringReceiver(lowerer, recv, access);
|
|
5203
5940
|
return lowerRegexMethodCall(lowerer, call, access, checked) ?? lowerStringMethodCall(lowerer, call, access, checked);
|
|
5204
5941
|
}
|
|
5205
|
-
//
|
|
5206
|
-
//
|
|
5207
|
-
// decode per the encoding — a stream chunk's common consumption —
|
|
5208
|
-
// and strings/numbers/booleans/arrays/objects answer JS-exactly).
|
|
5209
|
-
// The optional argument is a literal encoding (meaningful for bytes;
|
|
5210
|
-
// JS ignores extra toString arguments on the other kinds, and so
|
|
5211
|
-
// does the runtime dispatch).
|
|
5942
|
+
// The argument is a radix for bigint and an encoding for Buffer.
|
|
5943
|
+
// Preserve its runtime value so receiver dispatch can choose correctly.
|
|
5212
5944
|
if (access.name.text === "toString" && call.arguments.length <= 1) {
|
|
5213
|
-
const
|
|
5214
|
-
? bufEncoding(lowerer, "toString", call.arguments[0])
|
|
5215
|
-
: "utf8";
|
|
5216
|
-
// The source spelling rides along for the ONE receiver whose
|
|
5217
|
-
// prototype lacks toString: a null-prototype dictionary throws
|
|
5218
|
-
// Node's "<spelling> is not a function" at runtime.
|
|
5945
|
+
const argument = call.arguments[0];
|
|
5219
5946
|
return {
|
|
5220
|
-
kind: "libCall",
|
|
5221
|
-
fn: "dyn.toString",
|
|
5222
|
-
args: [
|
|
5947
|
+
kind: "libCall", fn: "dyn.toString", args: [
|
|
5223
5948
|
recv,
|
|
5224
|
-
|
|
5949
|
+
argument ? lowerer.lowerExprExpecting(argument, DYN)
|
|
5950
|
+
: dynUndefinedExpr(locOf(call)),
|
|
5225
5951
|
{ kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
|
|
5226
|
-
],
|
|
5227
|
-
type: STRING,
|
|
5228
|
-
loc: locOf(call),
|
|
5952
|
+
], type: STRING, loc: locOf(call),
|
|
5229
5953
|
};
|
|
5230
5954
|
}
|
|
5231
5955
|
// SHARED prototype names with a runtime dispatch (scr_dyn_invoke):
|
|
@@ -5237,7 +5961,13 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5237
5961
|
// unimplemented methods throw a LOUD not-supported Error; names the
|
|
5238
5962
|
// kind's prototype lacks throw Node's "x.y is not a function"; OBJ
|
|
5239
5963
|
// receivers call the own member.
|
|
5240
|
-
|
|
5964
|
+
// A stored callback must be read before argument effects, and called
|
|
5965
|
+
// with the original receiver rather than a materialized property view.
|
|
5966
|
+
const callbackProperty = (() => {
|
|
5967
|
+
const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
|
|
5968
|
+
return prop !== undefined && lowerer.checker.declarationsOf(prop).some((decl) => ts.isPropertyDeclaration(decl) || ts.isPropertySignature(decl));
|
|
5969
|
+
})();
|
|
5970
|
+
const dispatched = callbackProperty ? null : lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver);
|
|
5241
5971
|
if (dispatched)
|
|
5242
5972
|
return dispatched;
|
|
5243
5973
|
// Names NO dyn-representable prototype declares: the member can only
|
|
@@ -5256,17 +5986,6 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5256
5986
|
// its name overlaps a primitive prototype (`colors.bold(...)`): the
|
|
5257
5987
|
// source value was compiled from that object shape, while genuinely
|
|
5258
5988
|
// untyped/any receivers retain the runtime-kind ambiguity and fence.
|
|
5259
|
-
const ownCallable = !checkerUntyped && (() => {
|
|
5260
|
-
const prop = lowerer.checker.getPropertyOfType(recvTs, access.name.text);
|
|
5261
|
-
if (prop === undefined)
|
|
5262
|
-
return false;
|
|
5263
|
-
// getPropertyOfType includes inherited Object.prototype members.
|
|
5264
|
-
// Those are not stored members of a checked-dynamic object, so
|
|
5265
|
-
// dynKeyGet cannot stand in for JavaScript's prototype lookup. Only
|
|
5266
|
-
// an authored declaration can justify the own-member path.
|
|
5267
|
-
const authored = lowerer.checker.declarationsOf(prop).some((decl) => !lowerer.isStdlibFile(decl.getSourceFile()));
|
|
5268
|
-
return authored && lowerer.checker.getCallSignatures(lowerer.checker.getTypeOfSymbol(prop)).length > 0;
|
|
5269
|
-
})();
|
|
5270
5989
|
if (DYN_PROTO_METHOD_NAMES.has(access.name.text) && !ownCallable)
|
|
5271
5990
|
return null;
|
|
5272
5991
|
// Optional forms (`obj.cb?.()`, `obj?.cb()`) belong to the chain
|
|
@@ -5274,18 +5993,28 @@ function lowerDynReceiverMethodCall(lowerer, call, access) {
|
|
|
5274
5993
|
if (call.questionDotToken || access.questionDotToken)
|
|
5275
5994
|
return null;
|
|
5276
5995
|
const loc = locOf(call);
|
|
5277
|
-
|
|
5278
|
-
|
|
5279
|
-
}
|
|
5996
|
+
const receiverLocal = lowerer.declareHiddenLocal("%dynCallReceiver", DYN);
|
|
5997
|
+
const receiver = { kind: "varRef", localId: receiverLocal.id, type: DYN, loc };
|
|
5280
5998
|
const member = {
|
|
5281
5999
|
kind: "dynKeyGet",
|
|
5282
6000
|
key: { kind: "strLit", value: access.name.text, type: STRING, loc: locOf(access) },
|
|
5283
|
-
value:
|
|
6001
|
+
value: receiver,
|
|
5284
6002
|
type: DYN,
|
|
5285
6003
|
loc: locOf(access),
|
|
5286
6004
|
};
|
|
6005
|
+
if (call.arguments.some(ts.isSpreadElement)) {
|
|
6006
|
+
const spread = lowerSpreadArgsCall(lowerer, call, member, loc);
|
|
6007
|
+
if (spread?.kind === "dynCall")
|
|
6008
|
+
return { kind: "seqExpr",
|
|
6009
|
+
stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
|
|
6010
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
6011
|
+
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
6012
|
+
}
|
|
5287
6013
|
const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
5288
|
-
return {
|
|
6014
|
+
return {
|
|
6015
|
+
kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: recv, loc }],
|
|
6016
|
+
result: { kind: "dynCall", callee: member, receiver, calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
|
|
6017
|
+
};
|
|
5289
6018
|
}
|
|
5290
6019
|
/** Prototype method names of the checked-dynamic tree-representable kinds (String, Array,
|
|
5291
6020
|
* Object, Function, Number prototypes): a dyn receiver call on one of
|
|
@@ -5312,7 +6041,8 @@ const DYN_PROTO_METHOD_NAMES = new Set([
|
|
|
5312
6041
|
* is-not-a-function where the kind's prototype lacks the name, and
|
|
5313
6042
|
* fences LOUDLY on real-but-unimplemented pairs. */
|
|
5314
6043
|
const DYN_DISPATCH_METHODS = new Set([
|
|
5315
|
-
"
|
|
6044
|
+
"segment", "containing", "resolvedOptions", "test", "exec",
|
|
6045
|
+
"apply", "bind", "call",
|
|
5316
6046
|
"push", "pop", "shift", "unshift", "slice", "at",
|
|
5317
6047
|
"indexOf", "lastIndexOf", "includes", "join", "concat", "reverse", "sort",
|
|
5318
6048
|
"forEach", "map", "filter", "some", "every", "find", "findIndex",
|
|
@@ -5330,7 +6060,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5330
6060
|
"setEncoding", "setDefaultEncoding", "setTimeout", "read", "isPaused",
|
|
5331
6061
|
"writeHead", "setHeader", "getHeader", "hasHeader", "removeHeader",
|
|
5332
6062
|
"getHeaders", "getHeaderNames", "appendHeader", "flushHeaders",
|
|
5333
|
-
"append", "delete", "get", "getSetCookie", "has", "set",
|
|
6063
|
+
"add", "append", "delete", "get", "getSetCookie", "has", "set", "clear", "keys", "values", "entries", "next",
|
|
5334
6064
|
"writeContinue", "writeEarlyHints", "cork", "uncork", "addTrailers",
|
|
5335
6065
|
"ref", "unref", "address", "setNoDelay", "setKeepAlive", "connect",
|
|
5336
6066
|
"resetAndDestroy", "destroySoon",
|
|
@@ -5351,7 +6081,7 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5351
6081
|
"dispatchEvent",
|
|
5352
6082
|
"preventDefault", "stopPropagation", "stopImmediatePropagation",
|
|
5353
6083
|
"composedPath",
|
|
5354
|
-
"json", "text", "bytes",
|
|
6084
|
+
"json", "text", "bytes", "arrayBuffer",
|
|
5355
6085
|
// Promise.prototype (SCR_DYN_PROMISE receivers): the reaction trio
|
|
5356
6086
|
// rides the fiber machinery (scr_dyn_promise_then); on every other dyn
|
|
5357
6087
|
// kind then/catch/finally answer the stored-member path (OBJ own
|
|
@@ -5368,9 +6098,20 @@ const DYN_DISPATCH_METHODS = new Set([
|
|
|
5368
6098
|
]);
|
|
5369
6099
|
export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayReceiver) {
|
|
5370
6100
|
const method = access.name.text;
|
|
5371
|
-
if (!DYN_DISPATCH_METHODS.has(method)
|
|
6101
|
+
if ((!DYN_DISPATCH_METHODS.has(method) && !isJsSourceFile(call.getSourceFile())) || lowerer.chainBlocked(call, access))
|
|
5372
6102
|
return null;
|
|
5373
6103
|
if (call.arguments.some((arg) => ts.isSpreadElement(arg))) {
|
|
6104
|
+
const loc = locOf(call);
|
|
6105
|
+
const local = lowerer.declareHiddenLocal("%spreadReceiver", DYN);
|
|
6106
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
6107
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
6108
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
6109
|
+
const spread = lowerSpreadArgsCall(lowerer, call, callee, loc);
|
|
6110
|
+
if (spread?.kind === "dynCall")
|
|
6111
|
+
return { kind: "seqExpr",
|
|
6112
|
+
stmts: [{ kind: "varDecl", localId: local.id, init: recv, loc },
|
|
6113
|
+
{ kind: "exprStmt", expr: { kind: "libCall", fn: "dyn.arrayPrototype", args: [], type: DYN, loc }, loc }],
|
|
6114
|
+
result: { ...spread, receiver }, type: DYN, loc };
|
|
5374
6115
|
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
5375
6116
|
}
|
|
5376
6117
|
const predicate = method === "filter" && call.arguments[0]
|
|
@@ -5444,7 +6185,12 @@ export function lowerDynDispatchMethodCall(lowerer, call, access, recv, arrayRec
|
|
|
5444
6185
|
}
|
|
5445
6186
|
}
|
|
5446
6187
|
}
|
|
5447
|
-
const args = call.arguments.map((arg, i) =>
|
|
6188
|
+
const args = call.arguments.map((arg, i) => {
|
|
6189
|
+
if (i === 0 && predicate)
|
|
6190
|
+
return lowerer.coerceInto(arg, predicate, DYN);
|
|
6191
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, arg);
|
|
6192
|
+
return undefinedArg ? defaultAfterUndefined(undefinedArg, dynUndefinedExpr(locOf(arg))) : lowerer.lowerExprExpecting(arg, DYN);
|
|
6193
|
+
});
|
|
5448
6194
|
return {
|
|
5449
6195
|
kind: "dynInvoke",
|
|
5450
6196
|
recv,
|
|
@@ -5494,7 +6240,8 @@ function lowerArrayIsArrayCall(lowerer, call, access) {
|
|
|
5494
6240
|
// over side-effect-free reads (the operand re-evaluates/drops, the
|
|
5495
6241
|
// `in`-operator fold discipline). dyn/caught/jsval arms have no
|
|
5496
6242
|
// static tag answer and keep the narrow-first fence.
|
|
5497
|
-
const
|
|
6243
|
+
const unionId = arg.type.unionId;
|
|
6244
|
+
const def = lowerer.unions.get(unionId);
|
|
5498
6245
|
const opaque = !def || def.arms.some((a) => a.kind === "dyn" || a.kind === "caught" || a.kind === "jsval");
|
|
5499
6246
|
const arrayTags = lowerer.arrayValueTags(arg.type.unionId);
|
|
5500
6247
|
const freeRead = arg.kind === "varRef" || arg.kind === "recordGet" || arg.kind === "fieldGet";
|
|
@@ -5506,7 +6253,7 @@ function lowerArrayIsArrayCall(lowerer, call, access) {
|
|
|
5506
6253
|
}
|
|
5507
6254
|
if (!opaque && freeRead && arrayTags.length > 1) {
|
|
5508
6255
|
return arrayTags
|
|
5509
|
-
.map((tag) => ({ kind: "unionIsTag", unionId:
|
|
6256
|
+
.map((tag) => ({ kind: "unionIsTag", unionId: unionId, tag, negated: false, value: arg, type: BOOL, loc }))
|
|
5510
6257
|
.reduce((left, right) => ({ kind: "logical", op: "||", left, right, type: BOOL, loc }));
|
|
5511
6258
|
}
|
|
5512
6259
|
lowerer.unsupported("SC1090", argNode, `Array.isArray on '${lowerer.fmt(arg.type)}' values (narrow first: check a discriminant field, or compare with '!== undefined'/'!== null' for unit arms)`);
|
|
@@ -5569,13 +6316,13 @@ function lowerCaughtPredicateCall(lowerer, call, caughtLocal) {
|
|
|
5569
6316
|
* and String(n) lower to (Number::toString with radix 10 IS that
|
|
5570
6317
|
* conversion, per spec) — booleans the "true"/"false" texts, and strings
|
|
5571
6318
|
* the identity read (String.prototype.toString returns `this`). The
|
|
5572
|
-
* explicit-radix number form
|
|
6319
|
+
* explicit-radix number form uses the native radix formatter;
|
|
5573
6320
|
* null for other receivers, argument shapes, or non-lib members (a
|
|
5574
6321
|
* user's own `.toString` takes the ordinary paths). */
|
|
5575
6322
|
function lowerNumberToStringCall(lowerer, call, access) {
|
|
5576
6323
|
if (lowerer.chainBlocked(call, access))
|
|
5577
6324
|
return null;
|
|
5578
|
-
if (access.name.text !== "toString" || call.arguments.length
|
|
6325
|
+
if (access.name.text !== "toString" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
|
|
5579
6326
|
return null;
|
|
5580
6327
|
const recvKind = lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind;
|
|
5581
6328
|
if (recvKind !== "f64" && recvKind !== "bool" && recvKind !== "string")
|
|
@@ -5583,6 +6330,22 @@ function lowerNumberToStringCall(lowerer, call, access) {
|
|
|
5583
6330
|
if (!lowerer.isStdlibMember(access))
|
|
5584
6331
|
return null;
|
|
5585
6332
|
const operand = lowerer.lowerExpr(access.expression);
|
|
6333
|
+
// JavaScript array and typed-array reads can still be undefined even
|
|
6334
|
+
// when the checker declares a number. Preserve that runtime value and
|
|
6335
|
+
// let native method dispatch format numbers or throw for missing data.
|
|
6336
|
+
if (operand.type.kind === "dyn") {
|
|
6337
|
+
return {
|
|
6338
|
+
kind: "libCall", fn: "dyn.toString", args: [operand,
|
|
6339
|
+
call.arguments[0] ? lowerer.lowerExprExpecting(call.arguments[0], DYN) : dynUndefinedExpr(locOf(call)),
|
|
6340
|
+
{ kind: "strLit", value: access.getText(), type: STRING, loc: locOf(call) },
|
|
6341
|
+
], type: STRING, loc: locOf(call),
|
|
6342
|
+
};
|
|
6343
|
+
}
|
|
6344
|
+
if (call.arguments.length === 1) {
|
|
6345
|
+
if (operand.type.kind !== "f64")
|
|
6346
|
+
return null;
|
|
6347
|
+
return { kind: "libCall", fn: "num.toStringRadix", args: [operand, lowerer.lowerExprExpecting(call.arguments[0], DYN)], type: STRING, loc: locOf(call) };
|
|
6348
|
+
}
|
|
5586
6349
|
if (operand.type.kind === "string")
|
|
5587
6350
|
return operand; // identity, receiver evaluated
|
|
5588
6351
|
if (operand.type.kind !== "f64" && operand.type.kind !== "bool")
|
|
@@ -5727,6 +6490,13 @@ function lowerClassHasOwnPropertyCall(lowerer, call, access) {
|
|
|
5727
6490
|
else
|
|
5728
6491
|
return null; // computed static names — the answer isn't static
|
|
5729
6492
|
}
|
|
6493
|
+
if (!own.has(key)) {
|
|
6494
|
+
const loc = locOf(call);
|
|
6495
|
+
const data = classStaticDataFor(lowerer, info, key, loc);
|
|
6496
|
+
if (data)
|
|
6497
|
+
return { kind: "libCall", fn: "dyn.hasOwn", args: [data,
|
|
6498
|
+
{ kind: "strLit", value: key, type: STRING, loc }], type: BOOL, loc };
|
|
6499
|
+
}
|
|
5730
6500
|
return { kind: "boolLit", value: own.has(key), type: BOOL, loc: locOf(call) };
|
|
5731
6501
|
}
|
|
5732
6502
|
/** Side-effect-free receiver test for the CONSTANT primitive-prototype
|
|
@@ -5941,6 +6711,12 @@ function implicitReceiverOverloadReturn(lowerer, expr) {
|
|
|
5941
6711
|
function reconcileOverloadReturn(lowerer, expr, call) {
|
|
5942
6712
|
const rsig = lowerer.checker.getResolvedSignature(expr);
|
|
5943
6713
|
const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
|
|
6714
|
+
// Fluent JS overrides share the base's return ABI, but their result
|
|
6715
|
+
// still has the receiver's subclass layout at the call site.
|
|
6716
|
+
if (call.type.kind === "object" && rdecl && ts.isMethodDeclaration(rdecl) &&
|
|
6717
|
+
isJsSourceFile(rdecl.getSourceFile()) && returnsOnlyThis(rdecl)) {
|
|
6718
|
+
call = lowerer.maybeNarrow(call, expr);
|
|
6719
|
+
}
|
|
5944
6720
|
const resolvedOverload = rsig && rdecl &&
|
|
5945
6721
|
(ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) &&
|
|
5946
6722
|
!rdecl.body
|
|
@@ -6032,15 +6808,14 @@ function templateEscapesValid(raw) {
|
|
|
6032
6808
|
* maps to string[] (type-mapper.ts), so the array rides the ordinary
|
|
6033
6809
|
* slot-directed coercion into whatever the tag's first parameter wants
|
|
6034
6810
|
* — string[] exactly, an `any` slot through the dyn boundary, a rest
|
|
6035
|
-
* pack's first element.
|
|
6036
|
-
*
|
|
6037
|
-
*
|
|
6811
|
+
* pack's first element. Checked tags receive frozen cooked and raw
|
|
6812
|
+
* arrays with the standard nonenumerable `.raw` descriptor. Typed direct
|
|
6813
|
+
* tags retain the string-array representation.
|
|
6038
6814
|
*
|
|
6039
6815
|
* Tag forms: a top-level declared function (the direct-call fast path —
|
|
6040
6816
|
* overload sets reconcile through the resolved signature exactly like
|
|
6041
6817
|
* plain calls), an island value under --dynamic (engine method/function
|
|
6042
|
-
* call
|
|
6043
|
-
* `.raw` there answers undefined where Node carries the raw spans), and
|
|
6818
|
+
* call with the engine's cooked/raw template object), and
|
|
6044
6819
|
* a checked-dynamic value (the dynCall boundary — a non-function tag
|
|
6045
6820
|
* throws Node's catchable TypeError). Everything else — generic tags,
|
|
6046
6821
|
* method tags, function-value bindings — fences by name. */
|
|
@@ -6100,10 +6875,11 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6100
6875
|
if (ts.isIdentifier(expr.tag) && !lowerer.isSelfReference(expr.tag)) {
|
|
6101
6876
|
if (lowerer.isTopLevelFnSymbol(expr.tag) && !lowerer.peekLocal(expr.tag)) {
|
|
6102
6877
|
fenceEarlyAliasUse(lowerer, expr.tag, expr);
|
|
6103
|
-
|
|
6878
|
+
const genericTag = lowerer.genericFnOf(expr.tag);
|
|
6879
|
+
if (genericTag && !genericTag.implicitParams) {
|
|
6104
6880
|
lowerer.unsupported("SC1090", expr, "tagged templates with generic tag functions");
|
|
6105
6881
|
}
|
|
6106
|
-
const sig = lowerer.fnSigOf(expr.tag);
|
|
6882
|
+
const sig = genericTag ? null : lowerer.fnSigOf(expr.tag);
|
|
6107
6883
|
if (sig) {
|
|
6108
6884
|
lowerer.noteEdge(sig.name);
|
|
6109
6885
|
const args = completeArgs(lowerer, values, sig.params, loc, expr, [strings()]);
|
|
@@ -6130,10 +6906,13 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6130
6906
|
// Checked-dynamic tags (`var f: any; f\`abc\``, dyn property chains):
|
|
6131
6907
|
// the dynCall boundary — arguments convert into dyn, a non-function
|
|
6132
6908
|
// tag throws Node's catchable "<name> is not a function" TypeError.
|
|
6133
|
-
|
|
6909
|
+
let callee = lowerer.lowerExpr(expr.tag);
|
|
6910
|
+
if (callee.type.kind === "func" && isJsSourceFile(expr.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
|
|
6911
|
+
callee = { kind: "dynFrom", value: callee, type: DYN, loc };
|
|
6912
|
+
}
|
|
6134
6913
|
if (callee.type.kind === "dyn") {
|
|
6135
6914
|
const args = [
|
|
6136
|
-
lowerer
|
|
6915
|
+
loweredTemplateStrings(lowerer, expr, pieces.map((piece) => piece.text), loc, pieces.map(templateRawTextOf)),
|
|
6137
6916
|
...values.map((a) => lowerer.lowerExprExpecting(a, DYN)),
|
|
6138
6917
|
];
|
|
6139
6918
|
const calleeName = ts.isPropertyAccessExpression(expr.tag) || ts.isElementAccessExpression(expr.tag)
|
|
@@ -6145,12 +6924,15 @@ export function lowerTaggedTemplate(lowerer, expr) {
|
|
|
6145
6924
|
}
|
|
6146
6925
|
lowerer.unsupported("SC1090", expr, "tagged templates with this tag form (top-level functions and dynamic values tag; call the function directly otherwise)");
|
|
6147
6926
|
}
|
|
6148
|
-
function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
6927
|
+
function loweredTemplateStrings(lowerer, expr, cooked, loc, raw) {
|
|
6149
6928
|
// Normal runtime construction keeps this array aligned with the current
|
|
6150
|
-
// ScrArr layout in
|
|
6929
|
+
// ScrArr layout in the backend. The old static-header IR node encoded the
|
|
6151
6930
|
// pre-sparse layout in LLVM and crashed as soon as a tag read its strings.
|
|
6152
|
-
const type = arrayOf(STRING);
|
|
6153
|
-
const
|
|
6931
|
+
const type = raw ? DYN : arrayOf(STRING);
|
|
6932
|
+
const array = (values) => ({ kind: "dynArrLit", elems: values.map((value) => ({ kind: "dynFrom", value: { kind: "strLit", value, type: STRING, loc }, type: DYN, loc })), type: DYN, loc });
|
|
6933
|
+
const freeze = (value) => ({ kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc });
|
|
6934
|
+
const checked = raw ? freeze({ kind: "libCall", fn: "dyn.defineProperty", args: [array(cooked), { kind: "dynFrom", value: { kind: "strLit", value: "raw", type: STRING, loc }, type: DYN, loc }, { kind: "dynObjLit", fields: [{ key: { kind: "strLit", value: "value", type: STRING, loc }, value: freeze(array(raw)) }], type: DYN, loc }], type: DYN, loc }) : null;
|
|
6935
|
+
const key = `templateStringsGlobal:${loc.file}:${expr.template.getStart()}:${raw ? "checked" : "typed"}`;
|
|
6154
6936
|
let getter = lowerer.widthHelpers.get(key);
|
|
6155
6937
|
if (!getter) {
|
|
6156
6938
|
const site = lowerer.globalsList.length;
|
|
@@ -6172,7 +6954,7 @@ function loweredTemplateStrings(lowerer, expr, cooked, loc) {
|
|
|
6172
6954
|
{
|
|
6173
6955
|
kind: "assign",
|
|
6174
6956
|
localId: globalId,
|
|
6175
|
-
value: {
|
|
6957
|
+
value: checked ?? {
|
|
6176
6958
|
kind: "arrayLit",
|
|
6177
6959
|
elems: cooked.map((value) => ({ kind: "strLit", value, type: STRING, loc })),
|
|
6178
6960
|
type,
|
|
@@ -6204,7 +6986,7 @@ export function isTopLevelFnSymbol(lowerer, ident) {
|
|
|
6204
6986
|
const decl = symbol ? lowerer.checker.declarationsOf(symbol)[0] : undefined;
|
|
6205
6987
|
return (!!decl &&
|
|
6206
6988
|
ts.isFunctionDeclaration(decl) &&
|
|
6207
|
-
(ts.isSourceFile(decl.parent) || lowerer.nsBlocks.get(decl.parent) === "flattened"));
|
|
6989
|
+
(ts.isSourceFile(decl.parent) || (decl.parent !== undefined && lowerer.nsBlocks.get(decl.parent) === "flattened")));
|
|
6208
6990
|
}
|
|
6209
6991
|
/** Nested `function name(...) {...}`: declare the mutable function binding
|
|
6210
6992
|
* before lowering its body, then initialize it with the lifted closure.
|
|
@@ -6246,6 +7028,22 @@ export function lowerNestedFunctionDecl(lowerer, stmt) {
|
|
|
6246
7028
|
export function lambdaSignature(lowerer, node) {
|
|
6247
7029
|
if (!node.body)
|
|
6248
7030
|
lowerer.unsupported("SC1090", node, "function overload signatures");
|
|
7031
|
+
// A JS replacement of a native stream's write method receives the
|
|
7032
|
+
// actual call tuple, including overloads and omitted arguments. Node's
|
|
7033
|
+
// contextual overload signature cannot define this closure's ABI.
|
|
7034
|
+
if (isJsSourceFile(node.getSourceFile()) && !node.type &&
|
|
7035
|
+
(ts.isFunctionExpression(node) || ts.isArrowFunction(node)) &&
|
|
7036
|
+
node.parameters.every((param) => !param.type && !param.dotDotDotToken && !param.initializer) &&
|
|
7037
|
+
ts.isBinaryExpression(node.parent) && node.parent.right === node &&
|
|
7038
|
+
node.parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
|
|
7039
|
+
ts.isPropertyAccessExpression(node.parent.left) && node.parent.left.name.text === "write" &&
|
|
7040
|
+
lowerer.isStdlibMember(node.parent.left)) {
|
|
7041
|
+
const receiver = lowerer.lowerExpr(node.parent.left.expression);
|
|
7042
|
+
if (receiver.type.kind === "dyn") {
|
|
7043
|
+
const shapes = node.parameters.map(() => ({ type: DYN, mode: "required" }));
|
|
7044
|
+
return { shapes, funcType: funcTypeFromParamShapes(shapes, DYN) };
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
6249
7047
|
if (node.typeParameters) {
|
|
6250
7048
|
// Generic function-like forms monomorphize only where a static home
|
|
6251
7049
|
// exists: top-level generic function declarations, generic methods
|
|
@@ -6261,6 +7059,23 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6261
7059
|
: "generic arrow/function expressions outside a never-reassigned module-scope binding (only `const f = <T>(x: T) => ...` bindings and top-level generic function declarations monomorphize)");
|
|
6262
7060
|
}
|
|
6263
7061
|
const shapes = lowerer.paramShapes(node.parameters);
|
|
7062
|
+
// Error-first callbacks captured by native filesystem adapters receive
|
|
7063
|
+
// the selected runtime overload. Ambient contextual inference can pick
|
|
7064
|
+
// the string overload even when options request a Buffer.
|
|
7065
|
+
if ((ts.isArrowFunction(node) || ts.isFunctionExpression(node)) && ts.isCallExpression(node.parent) &&
|
|
7066
|
+
node.parent.arguments.at(-1) === node) {
|
|
7067
|
+
const builtin = ts.isPropertyAccessExpression(node.parent.expression) ? lowerer.builtinMemberOf(node.parent.expression)
|
|
7068
|
+
: ts.isIdentifier(node.parent.expression) ? lowerer.builtinImportOf(node.parent.expression) : null;
|
|
7069
|
+
if (builtin?.module === "fs" && builtin.member !== "rename" && builtinModuleFnOf(lowerer, builtin.module, builtin.member)?.fn === "fs.callbackCall") {
|
|
7070
|
+
for (let index = 0; index < shapes.length; index++) {
|
|
7071
|
+
if (!node.parameters[index]?.type) {
|
|
7072
|
+
shapes[index].type = DYN;
|
|
7073
|
+
if (shapes[index].bodyType)
|
|
7074
|
+
shapes[index].bodyType = DYN;
|
|
7075
|
+
}
|
|
7076
|
+
}
|
|
7077
|
+
}
|
|
7078
|
+
}
|
|
6264
7079
|
// A concise arrow over an h2-only stream/session call (`() =>
|
|
6265
7080
|
// req.stream.destroy()`): the call ALWAYS throws on this lowering
|
|
6266
7081
|
// (stream is undefined — the streamUndefCall precedent), so the body
|
|
@@ -6271,8 +7086,8 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6271
7086
|
: lowerer.declaredReturnType(node, node);
|
|
6272
7087
|
ret = lowerer.runtimeOptionalFunctionReturnType(node, ret);
|
|
6273
7088
|
// A contextually-typed arrow/function EXPRESSION whose slot signature
|
|
6274
|
-
// returns a
|
|
6275
|
-
// return as its ABI: `(n) => work()` (inferring Promise<void>) against
|
|
7089
|
+
// returns a composite type the inferred return doesn't spell adopts
|
|
7090
|
+
// the slot's return as its ABI: `(n) => work()` (inferring Promise<void>) against
|
|
6276
7091
|
// an `(n) => Promise<void> | void` field must RETURN that union — the
|
|
6277
7092
|
// body's returns coerce into it per return site (arm values wrap;
|
|
6278
7093
|
// width-coercible records rebuild into their arm — the runJobs
|
|
@@ -6286,6 +7101,9 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6286
7101
|
// returns coerce; the spawn-wrapper ABI still returns a promise).
|
|
6287
7102
|
// jsval-returning bodies stay out (adoption would force validated
|
|
6288
7103
|
// exits the writer never asked for).
|
|
7104
|
+
// Array and record returns also need the destination during literal
|
|
7105
|
+
// construction: a callback building IrStmt[] must wrap each element at
|
|
7106
|
+
// that recursive layout instead of first inferring narrower arrays.
|
|
6289
7107
|
const isAsyncLike = !ts.isMethodDeclaration(node) &&
|
|
6290
7108
|
node.modifiers?.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) === true;
|
|
6291
7109
|
const innerRet = isAsyncLike && ret.kind === "promise" ? ret.inner : ret;
|
|
@@ -6310,8 +7128,8 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6310
7128
|
? lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(ctxSigs[0]))
|
|
6311
7129
|
: null;
|
|
6312
7130
|
const ctxRet = isAsyncLike && ctxRetRaw?.kind === "promise" ? ctxRetRaw.inner : ctxRetRaw;
|
|
6313
|
-
if (ctxRet?.kind === "union" &&
|
|
6314
|
-
(innerRet.kind
|
|
7131
|
+
if ((ctxRet?.kind === "union" || ctxRet?.kind === "array" || ctxRet?.kind === "record") &&
|
|
7132
|
+
(innerRet.kind !== "void" || (ctxRet.kind === "union" && lowerer.armTag(ctxRet.unionId, UNDEFINED_T) >= 0))) {
|
|
6315
7133
|
ret = isAsyncLike ? { kind: "promise", inner: ctxRet } : ctxRet;
|
|
6316
7134
|
}
|
|
6317
7135
|
// A VOID slot discards the callback's result (TS's void-returning
|
|
@@ -6331,38 +7149,48 @@ export function lambdaSignature(lowerer, node) {
|
|
|
6331
7149
|
ret = VOID;
|
|
6332
7150
|
}
|
|
6333
7151
|
}
|
|
7152
|
+
ret = lowerer.contextualFunctionReturns.get(node) ?? ret;
|
|
6334
7153
|
// A plain JS function reading `arguments` receives one hidden dyn
|
|
6335
7154
|
// array. With named parameters, the array contains every actual
|
|
6336
7155
|
// argument and only ES modules are admitted: sloppy-mode arguments
|
|
6337
7156
|
// alias named parameters. Arrows inherit the enclosing `arguments`.
|
|
6338
7157
|
const hasRest = shapes.some((s) => s.mode === "rest" || s.mode === "dynRest" || s.mode === "islandRest");
|
|
6339
7158
|
const usesArguments = !hasRest &&
|
|
6340
|
-
(ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node)) &&
|
|
7159
|
+
(ts.isFunctionExpression(node) || ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) &&
|
|
6341
7160
|
isJsSourceFile(node.getSourceFile()) &&
|
|
6342
7161
|
bodyReadsArguments(node);
|
|
6343
|
-
if (usesArguments
|
|
6344
|
-
if (
|
|
6345
|
-
|
|
7162
|
+
if (usesArguments) {
|
|
7163
|
+
if (node.parameters.length > 0 || ts.isMethodDeclaration(node)) {
|
|
7164
|
+
const classMethod = ts.isMethodDeclaration(node) &&
|
|
7165
|
+
(ts.isClassDeclaration(node.parent) || ts.isClassExpression(node.parent));
|
|
7166
|
+
if (!classMethod && !isNodeEsmFile(node.getSourceFile(), lowerer.program)) {
|
|
7167
|
+
lowerer.unsupported("SC1090", node, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)");
|
|
7168
|
+
}
|
|
6346
7169
|
}
|
|
6347
7170
|
shapes.push({ type: DYN, mode: "arguments" });
|
|
6348
7171
|
}
|
|
6349
7172
|
const funcType = funcTypeFromParamShapes(shapes, ret);
|
|
6350
|
-
if (usesArguments)
|
|
6351
|
-
funcType.rest = true;
|
|
6352
7173
|
return { shapes, funcType };
|
|
6353
7174
|
}
|
|
6354
7175
|
/** Lifts an arrow function / function expression / nested declaration /
|
|
6355
7176
|
* object-literal shorthand method to a module-level function and yields
|
|
6356
7177
|
* the `closure` expression creating it. */
|
|
6357
7178
|
export function lowerLambda(lowerer, node) {
|
|
7179
|
+
const prepared = (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) ? lowerer.preparedClassFactories.get(node) : undefined;
|
|
7180
|
+
if (prepared)
|
|
7181
|
+
return prepared;
|
|
6358
7182
|
const loc = locOf(node);
|
|
6359
|
-
const
|
|
7183
|
+
const signature = lowerer.lambdaSignature(node);
|
|
7184
|
+
const { shapes } = signature;
|
|
7185
|
+
let { funcType } = signature;
|
|
6360
7186
|
// A lambda IS a value: the completed-ABI rule applies at birth. The
|
|
6361
7187
|
// contextual (target) type decides — `(x?: number) => void` may flow
|
|
6362
7188
|
// into a slot annotated `(x: number | undefined) => void` (same ABI
|
|
6363
7189
|
// signature), anything else is fenced. Nested function declarations and
|
|
6364
7190
|
// object-literal shorthand methods aren't expressions — always fenced.
|
|
6365
|
-
|
|
7191
|
+
if (!(ts.isMethodDeclaration(node) && isJsSourceFile(node.getSourceFile()) &&
|
|
7192
|
+
canBoxFuncIntoDyn(funcType, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))))
|
|
7193
|
+
lowerer.requireExactArityValue(node, ts.isArrowFunction(node) || ts.isFunctionExpression(node) ? node : null, shapes, funcType);
|
|
6366
7194
|
const nameIdent = !ts.isArrowFunction(node) && node.name && ts.isIdentifier(node.name) ? node.name : null;
|
|
6367
7195
|
const baseName = nameIdent ? nameIdent.text : "";
|
|
6368
7196
|
const fnName = `%fn${lowerer.lambdaCounter++}${baseName ? `_${baseName}` : ""}`;
|
|
@@ -6386,10 +7214,18 @@ export function lowerLambda(lowerer, node) {
|
|
|
6386
7214
|
if (isGenerator &&
|
|
6387
7215
|
(funcType.ret.kind !== "generator" || (funcType.ret.async === true) !== isAsync))
|
|
6388
7216
|
lowerer.badType(node, lowerer.typeOf(node));
|
|
6389
|
-
|
|
7217
|
+
let bodyReturn = isGenerator
|
|
6390
7218
|
? lowerer.genBodyReturnType(funcType.ret)
|
|
6391
7219
|
: lowerer.bodyReturnType(isAsync, funcType.ret);
|
|
6392
7220
|
const fnCtx = newFnCtx(true, selfSymbol, funcType, bodyReturn);
|
|
7221
|
+
const inferredSignature = isJsSourceFile(node.getSourceFile()) && !node.type ? lowerer.checker.getSignatureFromDeclaration(node) : undefined;
|
|
7222
|
+
const returnsConstructor = inferredSignature && producesConstructor(lowerer, lowerer.checker.getReturnTypeOfSignature(inferredSignature));
|
|
7223
|
+
if (isJsSourceFile(node.getSourceFile()) && !node.type && !isAsync && !isGenerator &&
|
|
7224
|
+
(bodyReturn.kind === "classval" || bodyReturn.kind === "date" || bodyReturn.kind === "symbol" || bodyReturn.kind === "record" ||
|
|
7225
|
+
(bodyReturn.kind === "dyn" || bodyReturn.kind === "func") && returnsConstructor)) {
|
|
7226
|
+
fnCtx.inferReturn = { entries: [] };
|
|
7227
|
+
}
|
|
7228
|
+
fnCtx.inheritsArguments = ts.isArrowFunction(node);
|
|
6393
7229
|
fnCtx.isAsync = isAsync;
|
|
6394
7230
|
if (isGenerator && funcType.ret.kind === "generator") {
|
|
6395
7231
|
fnCtx.generator = generatorMeta(lowerer, funcType.ret);
|
|
@@ -6398,14 +7234,30 @@ export function lowerLambda(lowerer, node) {
|
|
|
6398
7234
|
lowerer.fnStack.push(fnCtx);
|
|
6399
7235
|
try {
|
|
6400
7236
|
const { params, prologue } = lowerer.declareParams(node.parameters, shapes);
|
|
7237
|
+
// Checked JavaScript functions take their receiver from the call site.
|
|
7238
|
+
// Store it as this function's binding so escaping arrows capture it,
|
|
7239
|
+
// and a method nested inside another method never captures its owner.
|
|
7240
|
+
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node)) {
|
|
7241
|
+
const receiver = lowerer.declareThis(DYN);
|
|
7242
|
+
prologue.unshift({ kind: "varDecl", localId: receiver.id, init: { kind: "libCall", fn: isGenerator ? "dyn.generatorThis" : "dyn.this", args: [], type: DYN, loc }, loc });
|
|
7243
|
+
}
|
|
6401
7244
|
// The synthetic trailing dyn-array param carries `arguments`.
|
|
6402
7245
|
// Parameterized functions receive all actual arguments; zero-param
|
|
6403
7246
|
// functions receive the same array through their rest ABI.
|
|
6404
|
-
if (funcType.rest && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
|
|
7247
|
+
if (funcType.rest && funcType.restAbi === undefined && !shapes.some((s) => s.mode === "dynRest" || s.mode === "islandRest")) {
|
|
6405
7248
|
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
6406
7249
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
6407
7250
|
fnCtx.argumentsLocal = argsLocal;
|
|
6408
7251
|
}
|
|
7252
|
+
if (isJsSourceFile(node.getSourceFile()) && !ts.isArrowFunction(node) &&
|
|
7253
|
+
shapes.length === 1 && shapes[0]?.mode === "dynRest" && bodyReadsArguments(node)) {
|
|
7254
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
7255
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
7256
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, loc), method: "slice",
|
|
7257
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc,
|
|
7258
|
+
}, loc });
|
|
7259
|
+
fnCtx.argumentsLocal = argsLocal;
|
|
7260
|
+
}
|
|
6409
7261
|
let body;
|
|
6410
7262
|
if (ts.isBlock(node.body)) {
|
|
6411
7263
|
body = lowerer.lowerStmts(node.body.statements);
|
|
@@ -6438,7 +7290,9 @@ export function lowerLambda(lowerer, node) {
|
|
|
6438
7290
|
}
|
|
6439
7291
|
}
|
|
6440
7292
|
else {
|
|
6441
|
-
|
|
7293
|
+
// Concise and block bodies use the same destination layout for
|
|
7294
|
+
// fresh literals. Async bodies must inspect promises first.
|
|
7295
|
+
let value = isAsync || fnCtx.inferReturn ? lowerer.lowerExpr(bodyExpr) : lowerer.lowerExprExpecting(bodyExpr, bodyReturn);
|
|
6442
7296
|
// An async concise body whose value is itself a promise
|
|
6443
7297
|
// (`async () => p`): the async machinery RESOLVES the returned
|
|
6444
7298
|
// thenable into the function's own promise — lowerReturnValue's
|
|
@@ -6452,22 +7306,32 @@ export function lowerLambda(lowerer, node) {
|
|
|
6452
7306
|
: [
|
|
6453
7307
|
{
|
|
6454
7308
|
kind: "return",
|
|
6455
|
-
value: lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
7309
|
+
value: fnCtx.inferReturn ? value : lowerer.coerceInto(bodyExpr, value, bodyReturn),
|
|
6456
7310
|
loc: locOf(node.body),
|
|
6457
7311
|
},
|
|
6458
7312
|
];
|
|
7313
|
+
if (fnCtx.inferReturn && body[0]?.kind === "return")
|
|
7314
|
+
fnCtx.inferReturn.entries.push({ stmt: body[0], node: bodyExpr });
|
|
6459
7315
|
}
|
|
6460
7316
|
}
|
|
7317
|
+
if (fnCtx.inferReturn) {
|
|
7318
|
+
bodyReturn = resolveInferredReturn(lowerer, { returnType: bodyReturn }, fnCtx.inferReturn, body, node);
|
|
7319
|
+
funcType = { ...funcType, ret: bodyReturn };
|
|
7320
|
+
fnCtx.returnType = bodyReturn;
|
|
7321
|
+
}
|
|
6461
7322
|
body = [...prologue, ...body];
|
|
6462
7323
|
// Bare-expression bodies never pass through lowerStmts, so the
|
|
6463
7324
|
// lib-boundary chokepoint runs here (idempotent for block bodies,
|
|
6464
7325
|
// whose statements were already walked). A fence poisons the
|
|
6465
7326
|
// enclosing statement — the lambda IS part of it.
|
|
7327
|
+
body = lowerSurplusCalls(lowerer, body);
|
|
6466
7328
|
enforceLibBoundary(lowerer, body);
|
|
6467
7329
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, loc);
|
|
6468
7330
|
const ctx = lowerer.ctx;
|
|
6469
7331
|
const lifted = {
|
|
6470
7332
|
name: fnName,
|
|
7333
|
+
sourceName: jsFuncNameOf(node) ?? "<anonymous>",
|
|
7334
|
+
...(!isAsync && !isGenerator && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node)) ? { ownsPrototype: true } : {}),
|
|
6471
7335
|
params,
|
|
6472
7336
|
returnType: bodyReturn,
|
|
6473
7337
|
locals: ctx.locals,
|
|
@@ -6614,7 +7478,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
6614
7478
|
const member = access.name.text;
|
|
6615
7479
|
if (member !== "then" && member !== "catch" && member !== "finally")
|
|
6616
7480
|
return null;
|
|
6617
|
-
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
7481
|
+
let recvT = lowerer.mapTypeOf(lowerer.typeOf(access.expression)) ?? dynFallbackType(lowerer, access.expression, lowerer.typeOf(access.expression));
|
|
6618
7482
|
// A dynamic-import promise under an unmappable checker type
|
|
6619
7483
|
// (`Promise<typeof import("./m")>` — module-namespace types have no
|
|
6620
7484
|
// static mapping): the BINDING holds the island promise
|
|
@@ -6667,6 +7531,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
6667
7531
|
loc,
|
|
6668
7532
|
};
|
|
6669
7533
|
}
|
|
7534
|
+
if (receiver.type.kind === "dyn" && lowerer.dynConvertible(recvT))
|
|
7535
|
+
receiver = lowerer.coerceInto(access.expression, receiver, recvT);
|
|
6670
7536
|
if (receiver.type.kind !== "promise") {
|
|
6671
7537
|
// mapTypeOf said promise but the value lowered as something else —
|
|
6672
7538
|
// a lowering gap, named rather than ICEd on.
|
|
@@ -6810,10 +7676,12 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
6810
7676
|
}));
|
|
6811
7677
|
}
|
|
6812
7678
|
else {
|
|
7679
|
+
if (settled.type.kind !== "dyn" &&
|
|
7680
|
+
!canConvertToDyn(settled.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
7681
|
+
lowerer.unsupported("SC1090", fulfilledNode, "then fulfillment values that cannot cross the checked-dynamic boundary");
|
|
7682
|
+
}
|
|
6813
7683
|
const arg = settled.type.kind === "dyn" ? settled
|
|
6814
|
-
:
|
|
6815
|
-
? { kind: "dynFrom", value: settled, type: DYN, loc }
|
|
6816
|
-
: lowerer.unsupported("SC1090", fulfilledNode, "then fulfillment values that cannot cross the checked-dynamic boundary");
|
|
7684
|
+
: { kind: "dynFrom", value: settled, type: DYN, loc };
|
|
6817
7685
|
body.push(...resultOf({
|
|
6818
7686
|
kind: "dynCall",
|
|
6819
7687
|
callee: { kind: "varRef", localId: fLocal.id, type: DYN, loc },
|
|
@@ -6957,7 +7825,7 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
6957
7825
|
lowerer.unsupported("SC1090", call.arguments[0], "then handlers with more than one parameter (the two-argument onRejected form has no lowering — chain .catch(...) instead)");
|
|
6958
7826
|
}
|
|
6959
7827
|
const param = cb.type.params[0];
|
|
6960
|
-
if (param !== undefined && !typeEquals(param, inner)) {
|
|
7828
|
+
if (param !== undefined && !typeEquals(param, inner) && !(inner.kind === "void" && param.kind === "dyn")) {
|
|
6961
7829
|
lowerer.unsupported("SC1090", call.arguments[0], `then handlers whose parameter is not the settled value's type (expected '${lowerer.fmt(inner)}', got '${lowerer.fmt(param)}')`);
|
|
6962
7830
|
}
|
|
6963
7831
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
@@ -6991,6 +7859,8 @@ export function lowerPromiseMethodCall(lowerer, call, access) {
|
|
|
6991
7859
|
}
|
|
6992
7860
|
else {
|
|
6993
7861
|
body.push({ kind: "exprStmt", expr: awaitE, loc });
|
|
7862
|
+
if (param !== undefined)
|
|
7863
|
+
handlerArgs = [dynUndefinedExpr(loc)];
|
|
6994
7864
|
}
|
|
6995
7865
|
const handlerCall = {
|
|
6996
7866
|
kind: "callValue",
|
|
@@ -7677,7 +8547,8 @@ export function recordKeysArrayCall(lowerer, receiver, argIr, shape, loc) {
|
|
|
7677
8547
|
loc,
|
|
7678
8548
|
};
|
|
7679
8549
|
const finalize = () => {
|
|
7680
|
-
const
|
|
8550
|
+
const latest = lowerer.shapes.get(argIr.shapeId);
|
|
8551
|
+
const current = latest !== undefined ? latest : shape;
|
|
7681
8552
|
const body = [
|
|
7682
8553
|
{ kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: resultT, loc }, loc },
|
|
7683
8554
|
];
|
|
@@ -7727,10 +8598,11 @@ export function recordKeysArrayCall(lowerer, receiver, argIr, shape, loc) {
|
|
|
7727
8598
|
return { kind: "call", callee: helper, args: [receiver], type: resultT, loc };
|
|
7728
8599
|
}
|
|
7729
8600
|
/** Interned `%obj.hasOwn.<n>(r, k)` — Object.hasOwn's membership walk
|
|
7730
|
-
* over a
|
|
8601
|
+
* over a record shape: the key compares against each
|
|
7731
8602
|
* declared field name, undefined-armed fields answering by their tag
|
|
7732
8603
|
* (a key is own exactly when Object.keys would list it — the two share
|
|
7733
|
-
* the guard), everything else true
|
|
8604
|
+
* the guard), everything else true. Unmatched keys probe the overflow
|
|
8605
|
+
* map when present, so explicit undefined values remain own keys. */
|
|
7734
8606
|
function recordHasOwnHelper(lowerer, shapeId, loc) {
|
|
7735
8607
|
const key = `obj.hasOwn:${shapeId}`;
|
|
7736
8608
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
@@ -7764,7 +8636,10 @@ function recordHasOwnHelper(lowerer, shapeId, loc) {
|
|
|
7764
8636
|
loc,
|
|
7765
8637
|
});
|
|
7766
8638
|
}
|
|
7767
|
-
|
|
8639
|
+
const fallback = shape.indexValue
|
|
8640
|
+
? { kind: "recordOvfHas", obj: rRef, shapeId, key: kRef, type: BOOL, loc }
|
|
8641
|
+
: { kind: "boolLit", value: false, type: BOOL, loc };
|
|
8642
|
+
body.push({ kind: "return", value: fallback, loc });
|
|
7768
8643
|
lowerer.liftedFns.push({
|
|
7769
8644
|
name: helper,
|
|
7770
8645
|
params: [
|
|
@@ -7944,6 +8819,44 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
7944
8819
|
if (!lowerer.isStdlibGlobal(access.expression, "Object"))
|
|
7945
8820
|
return null;
|
|
7946
8821
|
const member = access.name.text;
|
|
8822
|
+
if ((member === "getOwnPropertyNames" || member === "getOwnPropertySymbols" || member === "getOwnPropertyDescriptors") && call.arguments.length === 1 &&
|
|
8823
|
+
!call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
|
|
8824
|
+
let object = lowerer.lowerExpr(call.arguments[0]);
|
|
8825
|
+
if (object.type.kind === "string" || object.type.kind === "f64" ||
|
|
8826
|
+
object.type.kind === "bool" || isUnitType(object.type))
|
|
8827
|
+
object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call) };
|
|
8828
|
+
if (object.type.kind === "dyn")
|
|
8829
|
+
return { kind: "libCall", fn: member === "getOwnPropertyNames" ? "dyn.getOwnPropertyNames" : member === "getOwnPropertySymbols" ? "dyn.getOwnPropertySymbols" : "dyn.getOwnPropertyDescriptors", args: [object], type: DYN, loc: locOf(call) };
|
|
8830
|
+
}
|
|
8831
|
+
if ((member === "getPrototypeOf" || member === "setPrototypeOf") &&
|
|
8832
|
+
call.arguments.length === (member === "getPrototypeOf" ? 1 : 2) &&
|
|
8833
|
+
!call.arguments.some(ts.isSpreadElement) && !lowerer.dynamic) {
|
|
8834
|
+
let object = lowerer.lowerExpr(call.arguments[0]);
|
|
8835
|
+
if (object.type.kind === "func") {
|
|
8836
|
+
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
8837
|
+
object = { kind: "dynFrom", value: object, type: DYN, loc: locOf(call),
|
|
8838
|
+
...(fnName !== null ? { fnName } : {}) };
|
|
8839
|
+
}
|
|
8840
|
+
if (object.type.kind !== "dyn" && canConvertToDyn(object.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
|
|
8841
|
+
object = lowerer.coerceInto(call.arguments[0], object, DYN);
|
|
8842
|
+
if (object.type.kind === "dyn") {
|
|
8843
|
+
const loc = locOf(call);
|
|
8844
|
+
if (member === "getPrototypeOf")
|
|
8845
|
+
return { kind: "libCall", fn: "dyn.getPrototype", args: [object], type: DYN, loc };
|
|
8846
|
+
const prototype = lowerer.lowerExprExpecting(call.arguments[1], DYN);
|
|
8847
|
+
if (prototype.type.kind === "dyn")
|
|
8848
|
+
return { kind: "libCall", fn: "dyn.setPrototype", args: [object, prototype], type: DYN, loc };
|
|
8849
|
+
}
|
|
8850
|
+
}
|
|
8851
|
+
if (member === "getOwnPropertyDescriptor" && call.arguments.length === 2) {
|
|
8852
|
+
const [receiver, key] = call.arguments;
|
|
8853
|
+
if (receiver && key && ts.isPropertyAccessExpression(receiver) && receiver.name.text === "prototype" &&
|
|
8854
|
+
lowerer.isStdlibGlobal(receiver.expression, "ArrayBuffer") && ts.isStringLiteral(key) && key.text === "byteLength") {
|
|
8855
|
+
const loc = locOf(call);
|
|
8856
|
+
const getter = lowerer.lowerNativeCallableValue({ fn: "arrayBuffer.byteLengthGetter", params: [], result: F64, valueParams: [] }, "get ArrayBuffer.prototype.byteLength", loc);
|
|
8857
|
+
return { kind: "libCall", fn: "arrayBuffer.byteLengthDescriptor", args: [lowerer.coerceToExpected(getter, DYN)], type: DYN, loc };
|
|
8858
|
+
}
|
|
8859
|
+
}
|
|
7947
8860
|
const cacheKeys = lowerRequireCacheKeys(lowerer, call, member);
|
|
7948
8861
|
if (cacheKeys)
|
|
7949
8862
|
return cacheKeys;
|
|
@@ -7982,7 +8895,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
7982
8895
|
if (unitTest)
|
|
7983
8896
|
return unitTest;
|
|
7984
8897
|
if (lk === "dyn" || rk === "dyn" || lk === "jsval" || rk === "jsval") {
|
|
7985
|
-
|
|
8898
|
+
return { kind: "libCall", fn: "dyn.sameValue", args: [lowerer.coerceInto(leftNode, left, DYN), lowerer.coerceInto(rightNode, right, DYN)], type: BOOL, loc };
|
|
7986
8899
|
}
|
|
7987
8900
|
if (left.type.kind === "union" || right.type.kind === "union") {
|
|
7988
8901
|
const ut = left.type.kind === "union" ? left.type : right.type;
|
|
@@ -8045,23 +8958,14 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8045
8958
|
}
|
|
8046
8959
|
lowerer.noLowering(`Object.is over '${lowerer.fmt(left.type)}' and '${lowerer.fmt(right.type)}' operands`, call, "the operands must share one comparable kind (numbers, strings, booleans, units, one union shape, or one reference type)");
|
|
8047
8960
|
}
|
|
8048
|
-
//
|
|
8049
|
-
//
|
|
8050
|
-
//
|
|
8051
|
-
// Object.create for engine-held prototypes. Everything else is a
|
|
8052
|
-
// NAMED fence: the compiled representations have no prototype chain,
|
|
8053
|
-
// and the own-copy stand-in would answer WRONG observably — Node's
|
|
8054
|
-
// Object.keys/inspect/JSON of the created object list NO own keys,
|
|
8055
|
-
// and mutating the prototype afterwards is visible through the
|
|
8056
|
-
// created object (live delegation), which no copy can honor.
|
|
8961
|
+
// Native checked objects retain a live prototype and can install an
|
|
8962
|
+
// own-property descriptor table during creation. Engine-held values
|
|
8963
|
+
// use the engine's Object.create path below.
|
|
8057
8964
|
if (member === "create") {
|
|
8058
8965
|
if (call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
8059
8966
|
lowerer.noLowering("Object.create with spread arguments", call);
|
|
8060
8967
|
}
|
|
8061
|
-
if (call.arguments.length
|
|
8062
|
-
lowerer.noLowering("Object.create with a properties-descriptor argument", call, "create first, then assign: const o = Object.create(null); o.k = v");
|
|
8063
|
-
}
|
|
8064
|
-
if (call.arguments.length !== 1) {
|
|
8968
|
+
if (call.arguments.length < 1 || call.arguments.length > 2) {
|
|
8065
8969
|
lowerer.noLowering(`Object.create with ${call.arguments.length} arguments`, call);
|
|
8066
8970
|
}
|
|
8067
8971
|
const loc = locOf(call);
|
|
@@ -8070,6 +8974,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8070
8974
|
protoNode = protoNode.expression;
|
|
8071
8975
|
const nullProto = protoNode.kind === ts.SyntaxKind.NullKeyword;
|
|
8072
8976
|
if (lowerer.dynamic) {
|
|
8977
|
+
if (call.arguments.length === 2)
|
|
8978
|
+
lowerer.noLowering("Object.create with properties under --dynamic", call);
|
|
8073
8979
|
// The checker types the result `any` — an ENGINE value under
|
|
8074
8980
|
// --dynamic — and the engine's own Object.create answers with
|
|
8075
8981
|
// REAL prototype semantics: reads delegate LIVE, writes shadow,
|
|
@@ -8090,15 +8996,41 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8090
8996
|
}
|
|
8091
8997
|
lowerer.noLowering(`Object.create over '${lowerer.fmt(proto.type)}' prototypes`, call, "prototype reads delegate LIVE in Node (mutating the prototype shows through the created object), which the boundary's deep copy cannot honor — only null and engine-held ('any') prototypes lower");
|
|
8092
8998
|
}
|
|
8093
|
-
if (nullProto) {
|
|
8999
|
+
if (nullProto && call.arguments.length === 1) {
|
|
8094
9000
|
return { kind: "libCall", fn: "dyn.objCreateNullProto", args: [], type: DYN, loc };
|
|
8095
9001
|
}
|
|
8096
|
-
|
|
8097
|
-
|
|
9002
|
+
let proto = nullProto
|
|
9003
|
+
? { kind: "dynFrom", value: { kind: "unitLit", unit: "null", type: NULL_T, loc }, type: DYN, loc }
|
|
9004
|
+
: ts.isObjectLiteralExpression(protoNode)
|
|
9005
|
+
? lowerer.lowerExprExpecting(protoNode, DYN)
|
|
9006
|
+
: lowerer.lowerExpr(protoNode);
|
|
9007
|
+
if (isUnitType(proto.type) || proto.type.kind === "f64" || proto.type.kind === "bool" || proto.type.kind === "string")
|
|
9008
|
+
proto = { kind: "dynFrom", value: proto, type: DYN, loc };
|
|
9009
|
+
if (proto.type.kind === "dyn") {
|
|
9010
|
+
if (call.arguments.length === 1)
|
|
9011
|
+
return { kind: "libCall", fn: "dyn.objCreate", args: [proto], type: DYN, loc };
|
|
9012
|
+
const descriptors = lowerer.lowerExprExpecting(call.arguments[1], DYN);
|
|
9013
|
+
if (descriptors.type.kind === "dyn")
|
|
9014
|
+
return { kind: "libCall", fn: "dyn.objCreateWithProperties", args: [proto, descriptors], type: DYN, loc };
|
|
9015
|
+
}
|
|
9016
|
+
lowerer.noLowering(`Object.create over '${lowerer.fmt(proto.type)}' prototypes`, call);
|
|
8098
9017
|
}
|
|
8099
9018
|
// `Object.assign(fn, { props })` whose RESULT type maps to the hybrid
|
|
8100
9019
|
// (function-with-properties) record: the chalk-shape CONSTRUCTOR.
|
|
8101
9020
|
if (member === "assign") {
|
|
9021
|
+
const prototype = lowerClassPrototypeAssign(lowerer, call);
|
|
9022
|
+
if (prototype)
|
|
9023
|
+
return prototype;
|
|
9024
|
+
if (isJsSourceFile(call.getSourceFile()) && call.arguments.length > 0 && !call.arguments.some(ts.isSpreadElement)) {
|
|
9025
|
+
const target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9026
|
+
if (target && ((target.type.kind === "func" && lowerer.dynConvertible(target.type)) ||
|
|
9027
|
+
(target.type.kind === "object" && lowerer.errorHierarchyClassOf(target.type.className)))) {
|
|
9028
|
+
const loc = locOf(call);
|
|
9029
|
+
return { kind: "libCall", fn: "dyn.assignAll", args: [lowerer.coerceToExpected(target, DYN),
|
|
9030
|
+
{ kind: "dynArrLit", elems: call.arguments.slice(1).map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc },
|
|
9031
|
+
], type: DYN, loc };
|
|
9032
|
+
}
|
|
9033
|
+
}
|
|
8102
9034
|
const hybrid = lowerObjectAssignHybrid(lowerer, call);
|
|
8103
9035
|
if (hybrid)
|
|
8104
9036
|
return hybrid;
|
|
@@ -8145,7 +9077,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8145
9077
|
if (tProbe?.type.kind === "dyn") {
|
|
8146
9078
|
const loc = locOf(call);
|
|
8147
9079
|
const target = lowerer.lowerExpr(call.arguments[0]);
|
|
8148
|
-
const
|
|
9080
|
+
const rawSource = lowerer.lowerExpr(call.arguments[1]);
|
|
9081
|
+
fenceSymbolFieldCopy(lowerer, call.arguments[1], rawSource.type);
|
|
9082
|
+
const source = lowerer.coerceToExpected(rawSource, DYN);
|
|
8149
9083
|
if (target.type.kind === "dyn" && source.type.kind === "dyn") {
|
|
8150
9084
|
return { kind: "libCall", fn: "dyn.assign", args: [target, source], type: DYN, loc };
|
|
8151
9085
|
}
|
|
@@ -8222,7 +9156,9 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8222
9156
|
const argNode = sources[i];
|
|
8223
9157
|
const spread = ts.isSpreadElement(argNode);
|
|
8224
9158
|
const srcNode = spread ? argNode.expression : argNode;
|
|
8225
|
-
const
|
|
9159
|
+
const rawSource = lowerer.lowerExpr(srcNode);
|
|
9160
|
+
fenceSymbolFieldCopy(lowerer, srcNode, rawSource.type, spread);
|
|
9161
|
+
const src = lowerer.coerceToExpected(rawSource, DYN);
|
|
8226
9162
|
if (src.type.kind !== "dyn") {
|
|
8227
9163
|
ok = false;
|
|
8228
9164
|
break;
|
|
@@ -8259,22 +9195,82 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8259
9195
|
}
|
|
8260
9196
|
return null;
|
|
8261
9197
|
}
|
|
9198
|
+
if ((member === "defineProperty" && call.arguments.length === 3) ||
|
|
9199
|
+
(member === "getOwnPropertyDescriptor" && call.arguments.length === 2)) {
|
|
9200
|
+
if (call.arguments.some((a) => ts.isSpreadElement(a)))
|
|
9201
|
+
return null;
|
|
9202
|
+
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9203
|
+
const targetNode = call.arguments[0];
|
|
9204
|
+
// The checker gives C.prototype the instance type, but its lowered
|
|
9205
|
+
// value is the shared prototype table, not an instance to unbox.
|
|
9206
|
+
const prototypeTarget = ts.isPropertyAccessExpression(targetNode) && targetNode.name.text === "prototype" &&
|
|
9207
|
+
(exactClassOfReceiver(lowerer, targetNode.expression) !== null || storedClassValueType(lowerer, targetNode.expression)?.kind === "classval");
|
|
9208
|
+
const declaredTarget = target?.type.kind === "dyn" && !prototypeTarget && !isJsSourceFile(targetNode.getSourceFile()) ? lowerer.mapTypeOf(lowerer.typeOf(targetNode)) : null;
|
|
9209
|
+
if (target && declaredTarget && isDynTypedRefType(declaredTarget))
|
|
9210
|
+
target = lowerer.coerceToExpected(target, declaredTarget);
|
|
9211
|
+
if (target && member === "defineProperty") {
|
|
9212
|
+
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
9213
|
+
if (native)
|
|
9214
|
+
return native;
|
|
9215
|
+
}
|
|
9216
|
+
if (target && member === "getOwnPropertyDescriptor" && isDynTypedRefType(target.type)) {
|
|
9217
|
+
const descriptor = lowerClassDescriptorRead(lowerer, call, target);
|
|
9218
|
+
if (descriptor)
|
|
9219
|
+
return descriptor;
|
|
9220
|
+
target = lowerer.coerceToExpected(target, DYN);
|
|
9221
|
+
}
|
|
9222
|
+
// Error instances share a live property table with their checked view.
|
|
9223
|
+
const keyNode = call.arguments[1];
|
|
9224
|
+
if (target?.type.kind === "object" && target.type.className !== "%DOMException" && lowerer.errorHierarchyClassOf(target.type.className) &&
|
|
9225
|
+
((ts.isStringLiteral(keyNode) && (keyNode.text === "cause" || keyNode.text === "message")) || lowerer.mapTypeOf(lowerer.typeOf(keyNode))?.kind === "symbol")) {
|
|
9226
|
+
target = lowerer.coerceToExpected(target, DYN);
|
|
9227
|
+
}
|
|
9228
|
+
if (target?.type.kind === "func" && lowerer.dynConvertible(target.type)) {
|
|
9229
|
+
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9230
|
+
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
9231
|
+
}
|
|
9232
|
+
const descriptorPrimitive = member === "getOwnPropertyDescriptor" && target &&
|
|
9233
|
+
(target.type.kind === "bool" || target.type.kind === "f64" || target.type.kind === "string");
|
|
9234
|
+
if (!target || (target.type.kind !== "dyn" && !isUnitType(target.type) && !descriptorPrimitive))
|
|
9235
|
+
return null;
|
|
9236
|
+
if (target.type.kind !== "dyn")
|
|
9237
|
+
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]) };
|
|
9238
|
+
const key = lowerer.lowerExprExpecting(call.arguments[1], DYN);
|
|
9239
|
+
if (key.type.kind !== "dyn")
|
|
9240
|
+
return null;
|
|
9241
|
+
if (member === "getOwnPropertyDescriptor") {
|
|
9242
|
+
return { kind: "libCall", fn: "dyn.getOwnPropertyDescriptor", args: [target, key], type: DYN, loc: locOf(call) };
|
|
9243
|
+
}
|
|
9244
|
+
const descriptor = lowerer.lowerExprExpecting(call.arguments[2], DYN);
|
|
9245
|
+
if (descriptor.type.kind !== "dyn")
|
|
9246
|
+
return null;
|
|
9247
|
+
return { kind: "libCall", fn: "dyn.defineProperty", args: [target, key, descriptor], type: DYN, loc: locOf(call) };
|
|
9248
|
+
}
|
|
8262
9249
|
// Object.defineProperties over a CHECKED-DYNAMIC target (test/common's
|
|
8263
9250
|
// _mustCallInner copying name/length onto the mustCall wrapper): the
|
|
8264
|
-
// runtime turns each descriptor's `value` into
|
|
8265
|
-
// the dyn node (OBJ members; FUNC nodes carry an
|
|
8266
|
-
//
|
|
9251
|
+
// runtime turns each descriptor's `value` into an own property on
|
|
9252
|
+
// the dyn node (OBJ members preserve attributes; FUNC nodes carry an
|
|
9253
|
+
// own-property table). Accessors use the target as their receiver.
|
|
8267
9254
|
// The result is the target, like JS. Typed targets keep the fence:
|
|
8268
9255
|
// static shapes have no property table to extend.
|
|
8269
9256
|
if (member === "defineProperties" && call.arguments.length === 2 &&
|
|
8270
9257
|
!call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
8271
9258
|
let target = tryLowerExpression(lowerer, call.arguments[0]);
|
|
9259
|
+
if (target) {
|
|
9260
|
+
const native = lowerClassDataDescriptor(lowerer, call, member, target);
|
|
9261
|
+
if (native)
|
|
9262
|
+
return native;
|
|
9263
|
+
}
|
|
8272
9264
|
// A FUNCTION-typed target boxes through the dyn boundary: the
|
|
8273
9265
|
// property table lives on the CLOSURE (shared by every box of this
|
|
8274
9266
|
// function value), so defining through a fresh box sticks — the
|
|
8275
9267
|
// wrapper returned later reads the same table.
|
|
8276
9268
|
if (target && target.type.kind === "func" &&
|
|
8277
9269
|
canBoxFuncIntoDyn(target.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id))) {
|
|
9270
|
+
const fnName = jsFuncNameOf(call.arguments[0]);
|
|
9271
|
+
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]), ...(fnName !== null ? { fnName } : {}) };
|
|
9272
|
+
}
|
|
9273
|
+
if (target && isUnitType(target.type)) {
|
|
8278
9274
|
target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments[0]) };
|
|
8279
9275
|
}
|
|
8280
9276
|
if (target?.type.kind === "dyn") {
|
|
@@ -8285,12 +9281,39 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8285
9281
|
}
|
|
8286
9282
|
return null;
|
|
8287
9283
|
}
|
|
9284
|
+
if (["preventExtensions", "isExtensible", "seal", "isSealed"].includes(member) &&
|
|
9285
|
+
call.arguments.length === 1 && !ts.isSpreadElement(call.arguments[0])) {
|
|
9286
|
+
const value = lowerer.lowerExpr(call.arguments[0]);
|
|
9287
|
+
if (value.type.kind === "string" || value.type.kind === "f64" ||
|
|
9288
|
+
value.type.kind === "bool" || value.type.kind === "symbol" || isUnitType(value.type)) {
|
|
9289
|
+
if (member === "preventExtensions" || member === "seal")
|
|
9290
|
+
return value;
|
|
9291
|
+
const loc = locOf(call);
|
|
9292
|
+
const answer = { kind: "boolLit", value: member !== "isExtensible", type: BOOL, loc };
|
|
9293
|
+
return isSafeToDiscard(value) ? answer : {
|
|
9294
|
+
kind: "seqExpr", stmts: [{ kind: "exprStmt", expr: value, loc: value.loc }],
|
|
9295
|
+
result: answer, type: BOOL, loc,
|
|
9296
|
+
};
|
|
9297
|
+
}
|
|
9298
|
+
if (value.type.kind === "dyn") {
|
|
9299
|
+
const operation = {
|
|
9300
|
+
preventExtensions: "dyn.preventExtensions", isExtensible: "dyn.isExtensible",
|
|
9301
|
+
seal: "dyn.seal", isSealed: "dyn.isSealed",
|
|
9302
|
+
};
|
|
9303
|
+
const fn = operation[member];
|
|
9304
|
+
return { kind: "libCall", fn, args: [value], type: member.startsWith("is") ? BOOL : DYN, loc: locOf(call) };
|
|
9305
|
+
}
|
|
9306
|
+
}
|
|
8288
9307
|
// Object.freeze: on a FRESH literal (object or array) the result IS
|
|
8289
9308
|
// the argument — no alias exists, so the frozen bit is unobservable
|
|
8290
9309
|
// (writes through the Readonly<T> result are compile errors, and no
|
|
8291
9310
|
// other reference can write). Primitives pass through per ES2015.
|
|
8292
9311
|
// Aliased objects keep a fence: a later write through the original
|
|
8293
9312
|
// reference would need the runtime frozen bit (strict mode throws).
|
|
9313
|
+
if (member === "isFrozen" && call.arguments.length === 1) {
|
|
9314
|
+
const value = lowerer.lowerExprExpecting(call.arguments[0], DYN);
|
|
9315
|
+
return { kind: "libCall", fn: "dyn.isFrozen", args: [value], type: BOOL, loc: locOf(call) };
|
|
9316
|
+
}
|
|
8294
9317
|
if (member === "freeze") {
|
|
8295
9318
|
if (call.arguments.length !== 1 || ts.isSpreadElement(call.arguments[0])) {
|
|
8296
9319
|
lowerer.noLowering(`Object.freeze with ${call.arguments.length} arguments`, call);
|
|
@@ -8300,14 +9323,18 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8300
9323
|
while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner))
|
|
8301
9324
|
inner = inner.expression;
|
|
8302
9325
|
const value = lowerer.lowerExpr(argNode);
|
|
9326
|
+
if (value.type.kind === "dyn")
|
|
9327
|
+
return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) };
|
|
8303
9328
|
if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) {
|
|
8304
9329
|
return value; // fresh — freeze is identity here, honestly
|
|
8305
9330
|
}
|
|
8306
9331
|
if (value.type.kind === "string" || value.type.kind === "f64" ||
|
|
8307
|
-
value.type.kind === "bool" || value.type.kind === "symbol" ||
|
|
9332
|
+
value.type.kind === "bool" || value.type.kind === "symbol" || value.type.kind === "bigint" ||
|
|
8308
9333
|
isUnitType(value.type)) {
|
|
8309
9334
|
return value; // ES2015: freeze of a primitive is the primitive
|
|
8310
9335
|
}
|
|
9336
|
+
if (value.type.kind === "union" && lowerer.unions.get(value.type.unionId)?.arms.every((arm) => isUnitType(arm) || arm.kind === "f64" || arm.kind === "bigint" || arm.kind === "bool" || arm.kind === "string" || arm.kind === "symbol"))
|
|
9337
|
+
return value;
|
|
8311
9338
|
lowerer.noLowering("Object.freeze of a possibly-aliased value", call, "freeze of a FRESH object/array literal (and of primitives) compiles — frozen-ness is unobservable there; an aliased target's later writes would need the runtime frozen bit");
|
|
8312
9339
|
}
|
|
8313
9340
|
// `Object.hasOwn(r, k)` over a RECORD receiver: a record's own-key set
|
|
@@ -8316,44 +9343,46 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8316
9343
|
// fields answer by their runtime tag — the explicit-undefined-is-absent
|
|
8317
9344
|
// stance: an omitted optional field holds the undefined arm and reads
|
|
8318
9345
|
// as NOT own, exactly Node's absent key (an EXPLICIT `k: undefined`
|
|
8319
|
-
// diverges — documented next to the child-env/JSON rule). Tuple
|
|
8320
|
-
//
|
|
8321
|
-
//
|
|
9346
|
+
// diverges — documented next to the child-env/JSON rule). Tuple
|
|
9347
|
+
// and accessor-carrying shapes keep the SC2020 fence. Index-signature
|
|
9348
|
+
// records additionally probe the overflow map; non-record receivers
|
|
8322
9349
|
// do too.
|
|
8323
9350
|
if (member === "hasOwn" && call.arguments.length === 2 && !call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
8324
9351
|
const recvNode = call.arguments[0];
|
|
8325
9352
|
const keyNode = call.arguments[1];
|
|
8326
9353
|
const probed = tryLowerExpression(lowerer, recvNode);
|
|
9354
|
+
const constructor = probed?.type.kind === "classval" ? lowerer.classes.get(probed.type.className) : undefined;
|
|
8327
9355
|
// A CHECKED-DYNAMIC receiver (the JS file-scope object-literal
|
|
8328
9356
|
// identity story): the runtime dyn probe — OBJ member presence, ARR
|
|
8329
9357
|
// index bounds, Node's ToObject TypeError on nullish.
|
|
8330
|
-
if (probed?.type.kind === "dyn")
|
|
9358
|
+
if (probed?.type.kind === "dyn" || (probed && isDynTypedRefType(probed.type)) ||
|
|
9359
|
+
(probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) ||
|
|
9360
|
+
(probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) ||
|
|
9361
|
+
(probed?.type.kind === "func" && lowerer.dynConvertible(probed.type))) {
|
|
8331
9362
|
const loc = locOf(call);
|
|
8332
|
-
const receiver = lowerer.
|
|
8333
|
-
|
|
8334
|
-
if (
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
9363
|
+
const receiver = lowerer.coerceToExpected(probed, DYN);
|
|
9364
|
+
const rawKey = lowerer.lowerExpr(keyNode);
|
|
9365
|
+
if (rawKey.type.kind === "dyn" || rawKey.type.kind === "symbol" ||
|
|
9366
|
+
rawKey.type.kind === "union" && lowerer.dynConvertible(rawKey.type))
|
|
9367
|
+
return {
|
|
9368
|
+
kind: "libCall", fn: "dyn.hasOwnComputed", args: [receiver, lowerer.coerceToExpected(rawKey, DYN)], type: BOOL, loc,
|
|
9369
|
+
};
|
|
9370
|
+
const key = ownPropertyKey(lowerer, rawKey);
|
|
9371
|
+
if (!key)
|
|
8338
9372
|
return null;
|
|
8339
9373
|
return { kind: "libCall", fn: "dyn.hasOwn", args: [receiver, key], type: BOOL, loc };
|
|
8340
9374
|
}
|
|
8341
9375
|
if (probed?.type.kind !== "record")
|
|
8342
9376
|
return null;
|
|
8343
9377
|
const shape = lowerer.shapes.get(probed.type.shapeId);
|
|
8344
|
-
if (!shape || shape.tuple ||
|
|
9378
|
+
if (!shape || shape.tuple || shapeHasAccessorSlots(shape))
|
|
8345
9379
|
return null;
|
|
8346
9380
|
const loc = locOf(call);
|
|
8347
9381
|
const receiver = lowerer.lowerExpr(recvNode);
|
|
8348
9382
|
if (receiver.type.kind !== "record")
|
|
8349
9383
|
return null; // probe/lower drift: keep the fence
|
|
8350
|
-
|
|
8351
|
-
|
|
8352
|
-
// path's rule; symbol and composite keys keep the fence.
|
|
8353
|
-
if (key.type.kind === "f64" || key.type.kind === "bool" || key.type.kind === "dyn") {
|
|
8354
|
-
key = { kind: "toString", operand: key, type: STRING, loc: locOf(keyNode) };
|
|
8355
|
-
}
|
|
8356
|
-
if (key.type.kind !== "string")
|
|
9384
|
+
const key = ownPropertyKey(lowerer, lowerer.lowerExpr(keyNode));
|
|
9385
|
+
if (!key)
|
|
8357
9386
|
return null;
|
|
8358
9387
|
const helper = recordHasOwnHelper(lowerer, receiver.type.shapeId, loc);
|
|
8359
9388
|
return { kind: "call", callee: helper, args: [receiver, key], type: BOOL, loc };
|
|
@@ -8415,8 +9444,12 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8415
9444
|
const isDyn = probed?.type.kind === "dyn";
|
|
8416
9445
|
// Unit-typed arguments (Object.keys(null)) ride the same runtime
|
|
8417
9446
|
// walk: it throws Node's catchable TypeError.
|
|
8418
|
-
const
|
|
8419
|
-
|
|
9447
|
+
const isFunction = probed?.type.kind === "func" && lowerer.dynConvertible(probed.type);
|
|
9448
|
+
const isPrimitive = probed !== null && probed !== undefined &&
|
|
9449
|
+
(isUnitType(probed.type) || probed.type.kind === "string" ||
|
|
9450
|
+
probed.type.kind === "f64" || probed.type.kind === "bool");
|
|
9451
|
+
const isJsUnion = probed?.type.kind === "union" && isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(probed.type);
|
|
9452
|
+
if (isDyn || isPrimitive || isFunction || isJsUnion || (probed && isDynTypedRefType(probed.type))) {
|
|
8420
9453
|
const fn = member === "keys" ? "dyn.objKeys" : member === "values" ? "dyn.objValues" : "dyn.objEntries";
|
|
8421
9454
|
let v = lowerer.lowerExpr(argNode);
|
|
8422
9455
|
if (v.type.kind !== "dyn")
|
|
@@ -8445,6 +9478,19 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8445
9478
|
if (shapeHasAccessorSlots(shape)) {
|
|
8446
9479
|
lowerer.unsupported("SC1090", call, `Object.${member} over a shape carrying get/set accessor properties (Node lists the accessor names${member === "keys" ? "" : " and invokes the getters"} — the static key walk cannot; read the properties explicitly)`);
|
|
8447
9480
|
}
|
|
9481
|
+
// unknown[] uses the checked-dynamic array representation. Enumerate
|
|
9482
|
+
// a live view of the record so values retain their identities and the
|
|
9483
|
+
// result never pretends to be a native vector or an island array.
|
|
9484
|
+
const enumerationType = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
9485
|
+
if ((member === "values" || member === "entries") &&
|
|
9486
|
+
(enumerationType?.kind === "dyn" || enumerationType === null && isJsSourceFile(call.getSourceFile()))) {
|
|
9487
|
+
let receiver = lowerer.coerceToExpected(lowerer.lowerExpr(argNode), DYN);
|
|
9488
|
+
if (receiver.type.kind !== "dyn")
|
|
9489
|
+
lowerer.badType(argNode, lowerer.typeOf(argNode));
|
|
9490
|
+
if (receiver.kind === "dynFrom" && receiver.value.type.kind === "record")
|
|
9491
|
+
receiver = { ...receiver, liveRef: true };
|
|
9492
|
+
return { kind: "libCall", fn: member === "values" ? "dyn.objValues" : "dyn.objEntries", args: [receiver], type: DYN, loc: locOf(call) };
|
|
9493
|
+
}
|
|
8448
9494
|
if (shape.indexValue) {
|
|
8449
9495
|
// Index-signature (overflow-carrying) shapes: the runtime walk —
|
|
8450
9496
|
// declared fields first, then the overflow in JS own-key order
|
|
@@ -8455,7 +9501,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8455
9501
|
const resultT = lowerer.irTypeOf(call);
|
|
8456
9502
|
if (resultT.kind !== "array")
|
|
8457
9503
|
lowerer.badType(call, lowerer.typeOf(call)); // defensive
|
|
8458
|
-
const receiver = lowerer.lowerExpr(argNode);
|
|
9504
|
+
const receiver = objectEnumerationReceiver(lowerer, lowerer.lowerExpr(argNode), argIr, loc);
|
|
8459
9505
|
if (member === "keys") {
|
|
8460
9506
|
// The keys walk is shared with for-in (which iterates exactly the
|
|
8461
9507
|
// keys Object.keys answers — one construction, one intern key).
|
|
@@ -8484,7 +9530,6 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8484
9530
|
const recT = argIr;
|
|
8485
9531
|
const ref = { kind: "varRef", localId: "r.0", type: recT, loc };
|
|
8486
9532
|
const outRef = { kind: "varRef", localId: "out.0", type: resultT, loc };
|
|
8487
|
-
lowerer.arrHofHelpers.set(key, helper);
|
|
8488
9533
|
const fn = {
|
|
8489
9534
|
name: helper,
|
|
8490
9535
|
params: [{ localId: "r.0", name: "r", type: recT }],
|
|
@@ -8497,7 +9542,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8497
9542
|
loc,
|
|
8498
9543
|
};
|
|
8499
9544
|
const finalize = () => {
|
|
8500
|
-
const
|
|
9545
|
+
const latest = lowerer.shapes.get(argIr.shapeId);
|
|
9546
|
+
const current = latest !== undefined ? latest : shape;
|
|
8501
9547
|
const body = [
|
|
8502
9548
|
{ kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: resultT, loc }, loc },
|
|
8503
9549
|
];
|
|
@@ -8512,6 +9558,8 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8512
9558
|
return null;
|
|
8513
9559
|
if (typeEquals(vt, valueT))
|
|
8514
9560
|
return value;
|
|
9561
|
+
if (valueT.kind === "dyn" && lowerer.dynConvertible(vt))
|
|
9562
|
+
return lowerer.coerceToExpected(value, DYN);
|
|
8515
9563
|
if (valueT.kind === "union" && vt.kind !== "union") {
|
|
8516
9564
|
const tag = lowerer.armTag(valueT.unionId, vt);
|
|
8517
9565
|
if (tag >= 0) {
|
|
@@ -8531,7 +9579,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8531
9579
|
guardUndefTag = undefTag;
|
|
8532
9580
|
const arms = lowerer.unions.get(f.type.unionId)?.arms ?? [];
|
|
8533
9581
|
const others = arms.filter((a) => a.kind !== "undefinedT");
|
|
8534
|
-
if (typeEquals(f.type, valueT ?? f.type)) {
|
|
9582
|
+
if (valueT?.kind === "dyn" || typeEquals(f.type, valueT ?? f.type)) {
|
|
8535
9583
|
// The field union IS the result union (single-field shapes):
|
|
8536
9584
|
// push the raw box — but then the undefined skip must NOT
|
|
8537
9585
|
// narrow. Handled below via vt === valueT.
|
|
@@ -8555,7 +9603,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8555
9603
|
"cannot re-tag into the result element type — read the fields directly)");
|
|
8556
9604
|
}
|
|
8557
9605
|
}
|
|
8558
|
-
else if (!typeEquals(f.type, valueT ?? f.type)) {
|
|
9606
|
+
else if (valueT?.kind !== "dyn" && !typeEquals(f.type, valueT ?? f.type)) {
|
|
8559
9607
|
lowerer.unsupported("SC1090", call, `Object.${member} over '${lowerer.fmt(argIr)}' (field '${f.name}' is a union that cannot ` +
|
|
8560
9608
|
"re-tag into the result element type — read the fields directly)");
|
|
8561
9609
|
}
|
|
@@ -8595,6 +9643,7 @@ function lowerObjectStaticCall(lowerer, call, access) {
|
|
|
8595
9643
|
fn.body = body;
|
|
8596
9644
|
};
|
|
8597
9645
|
finalize();
|
|
9646
|
+
lowerer.arrHofHelpers.set(key, helper);
|
|
8598
9647
|
lowerer.shapeOrderHelperFinalizers.push(finalize);
|
|
8599
9648
|
lowerer.liftedFns.push(fn);
|
|
8600
9649
|
}
|
|
@@ -8643,6 +9692,15 @@ export function lowerFunction(lowerer, decl) {
|
|
|
8643
9692
|
params.push({ localId: argsLocal.id, name: "%arguments", type: DYN });
|
|
8644
9693
|
ctx.argumentsLocal = argsLocal;
|
|
8645
9694
|
}
|
|
9695
|
+
if (isJsSourceFile(decl.getSourceFile()) && sig.params.length === 1 &&
|
|
9696
|
+
sig.params[0]?.mode === "dynRest" && bodyReadsArguments(decl)) {
|
|
9697
|
+
const argsLocal = lowerer.declareHiddenLocal("%arguments", DYN);
|
|
9698
|
+
prologue.push({ kind: "varDecl", localId: argsLocal.id, init: {
|
|
9699
|
+
kind: "dynInvoke", recv: varRef(params[0].localId, DYN, locOf(decl)), method: "slice",
|
|
9700
|
+
calleeName: "Array.prototype.slice", args: [], type: DYN, loc: locOf(decl),
|
|
9701
|
+
}, loc: locOf(decl) });
|
|
9702
|
+
ctx.argumentsLocal = argsLocal;
|
|
9703
|
+
}
|
|
8646
9704
|
const bodyBlock = blockBodyOf(decl);
|
|
8647
9705
|
if (!bodyBlock) {
|
|
8648
9706
|
lowerer.unsupported("SC1090", decl, "function declarations whose block body the frontend cannot locate");
|
|
@@ -8651,6 +9709,8 @@ export function lowerFunction(lowerer, decl) {
|
|
|
8651
9709
|
appendImplicitUndefinedReturn(lowerer, body, bodyReturn, locOf(decl));
|
|
8652
9710
|
const fn = {
|
|
8653
9711
|
name: sig.name,
|
|
9712
|
+
sourceName: decl.name?.text ?? "<anonymous>",
|
|
9713
|
+
...(!sig.isAsync && !sig.generator ? { ownsPrototype: true } : {}),
|
|
8654
9714
|
params,
|
|
8655
9715
|
returnType: bodyReturn,
|
|
8656
9716
|
locals: lowerer.ctx.locals,
|
|
@@ -8775,8 +9835,27 @@ function lowerObjectAssignHybrid(lowerer, call) {
|
|
|
8775
9835
|
export function lowerRecordFieldCall(lowerer, call, access) {
|
|
8776
9836
|
if (lowerer.chainBlocked(call))
|
|
8777
9837
|
return null;
|
|
8778
|
-
|
|
8779
|
-
|
|
9838
|
+
const stored = ts.isIdentifier(access.expression)
|
|
9839
|
+
? lowerer.peekLocal(access.expression)?.type ?? lowerer.globalOf(access.expression)?.type : undefined;
|
|
9840
|
+
const receiverType = stored?.kind === "record" ? stored : lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
9841
|
+
if (receiverType?.kind !== "record" && receiverType?.kind !== "union")
|
|
9842
|
+
return null;
|
|
9843
|
+
// A union of records can share a closure-valued field. Its normal
|
|
9844
|
+
// property read performs the tag dispatch before arguments evaluate.
|
|
9845
|
+
// Class methods retain their vtable path and must not lose `this`.
|
|
9846
|
+
if (receiverType.kind === "union") {
|
|
9847
|
+
const arms = lowerer.unions.get(receiverType.unionId)?.arms;
|
|
9848
|
+
if (!arms?.every((arm) => arm.kind === "record"))
|
|
9849
|
+
return null;
|
|
9850
|
+
if (!arms.every((arm) => arm.kind === "record" &&
|
|
9851
|
+
lowerer.shapes.get(arm.shapeId)?.fields.some((field) => field.name === access.name.text && field.type.kind === "func")))
|
|
9852
|
+
return null;
|
|
9853
|
+
const callee = lowerer.lowerUnionProperty(access);
|
|
9854
|
+
if (callee?.type.kind !== "func")
|
|
9855
|
+
return null;
|
|
9856
|
+
const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
|
|
9857
|
+
return { kind: "callValue", callee, args, type: callee.type.ret, loc: locOf(call) };
|
|
9858
|
+
}
|
|
8780
9859
|
const target = lowerer.fieldTarget(access);
|
|
8781
9860
|
let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
|
|
8782
9861
|
if (!callee)
|
|
@@ -8975,7 +10054,7 @@ function nullishValueUnitOf(lowerer, sym) {
|
|
|
8975
10054
|
// the no-storage family never claims it.
|
|
8976
10055
|
if (!decl || !ts.isVariableDeclaration(decl) || !ts.isIdentifier(decl.name) ||
|
|
8977
10056
|
decl.getSourceFile().isDeclarationFile || decl.initializer === undefined ||
|
|
8978
|
-
!ts.isVariableStatement(decl.parent
|
|
10057
|
+
!ts.isVariableStatement(decl.parent?.parent)) {
|
|
8979
10058
|
return null;
|
|
8980
10059
|
}
|
|
8981
10060
|
const unit = nullishExprUnitOf(lowerer, decl.initializer);
|
|
@@ -9161,7 +10240,7 @@ export function deadUnmappableBinding(lowerer, sym, decl) {
|
|
|
9161
10240
|
// lowerVarDeclList's contract requires a lowered statement for it, so
|
|
9162
10241
|
// the no-storage family never claims it (catch bindings sit outside a
|
|
9163
10242
|
// variable statement too and stay out the same way).
|
|
9164
|
-
if (!ts.isVariableStatement(decl.parent
|
|
10243
|
+
if (!ts.isVariableStatement(decl.parent?.parent))
|
|
9165
10244
|
return false;
|
|
9166
10245
|
const sf = decl.getSourceFile();
|
|
9167
10246
|
if (sf.isDeclarationFile || isJsSourceFile(sf))
|
|
@@ -9339,11 +10418,11 @@ export function bindingGenericFnInfoOf(lowerer, decl, fnNode) {
|
|
|
9339
10418
|
lowerer.unsupported("SC1031", param);
|
|
9340
10419
|
}
|
|
9341
10420
|
}
|
|
9342
|
-
const stmt = decl.parent
|
|
10421
|
+
const stmt = decl.parent?.parent; // declarator → list → statement (nsPathPrefix wants the statement)
|
|
9343
10422
|
const info = {
|
|
9344
10423
|
decl: fnNode,
|
|
9345
10424
|
baseName: name,
|
|
9346
|
-
qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt, decl) + name),
|
|
10425
|
+
qualifiedName: lowerer.qualify(decl.getSourceFile(), nsPathPrefix(stmt ?? decl, decl) + name),
|
|
9347
10426
|
typeParams,
|
|
9348
10427
|
instances: new Map(),
|
|
9349
10428
|
};
|
|
@@ -9475,6 +10554,88 @@ function arrowSignatureOf(lowerer, node) {
|
|
|
9475
10554
|
const declaration = lowerer.checker.signatureDeclaration(signatures[0]);
|
|
9476
10555
|
return declaration !== undefined && ts.isArrowFunction(declaration) ? signatures[0] : null;
|
|
9477
10556
|
}
|
|
10557
|
+
/** An inline arrow has lexical `this` and no observable own properties
|
|
10558
|
+
* before binding. With no preset arguments, a fresh forwarding closure
|
|
10559
|
+
* preserves its completed ABI, defaults and captured environment. Keep
|
|
10560
|
+
* other receivers and rest/preset-argument forms on the named fence. */
|
|
10561
|
+
function lowerInlineArrowBind(lowerer, call, access) {
|
|
10562
|
+
if (access.name.text !== "bind" || call.arguments.length > 1 || call.arguments.some(ts.isSpreadElement))
|
|
10563
|
+
return null;
|
|
10564
|
+
let arrow = access.expression;
|
|
10565
|
+
while (ts.isParenthesizedExpression(arrow))
|
|
10566
|
+
arrow = arrow.expression;
|
|
10567
|
+
if (!ts.isArrowFunction(arrow))
|
|
10568
|
+
return null;
|
|
10569
|
+
const callee = lowerer.lowerExpr(access.expression);
|
|
10570
|
+
if (callee.type.kind !== "func" || callee.type.rest ||
|
|
10571
|
+
!canBoxFuncIntoDyn(callee.type, (id) => lowerer.shapes.get(id), (id) => lowerer.unions.get(id)))
|
|
10572
|
+
return null;
|
|
10573
|
+
const type = callee.type;
|
|
10574
|
+
const loc = locOf(call);
|
|
10575
|
+
const firstDefault = arrow.parameters.findIndex((p) => p.initializer !== undefined);
|
|
10576
|
+
const length = firstDefault < 0 ? arrow.parameters.length : firstDefault;
|
|
10577
|
+
const key = `arrow.bind:${typeKey(type)}:${length}`;
|
|
10578
|
+
const existing = lowerer.arrHofHelpers.get(key);
|
|
10579
|
+
const name = existing ?? `%arrow.bind.${lowerer.arrHofHelpers.size}`;
|
|
10580
|
+
if (!existing) {
|
|
10581
|
+
lowerer.arrHofHelpers.set(key, name);
|
|
10582
|
+
lowerer.freshClosureAdapters.add(name);
|
|
10583
|
+
const impl = `${name}.impl`;
|
|
10584
|
+
const captured = { id: "f.0", name: "f", type, mutable: false, boxed: true };
|
|
10585
|
+
const params = type.params.map((type, i) => ({ localId: `p.${i}`, name: `p${i}`, type }));
|
|
10586
|
+
const invoked = {
|
|
10587
|
+
kind: "callValue",
|
|
10588
|
+
callee: { kind: "varRef", localId: captured.id, type, loc },
|
|
10589
|
+
args: params.map((p) => ({ kind: "varRef", localId: p.localId, type: p.type, loc })),
|
|
10590
|
+
type: type.ret,
|
|
10591
|
+
loc,
|
|
10592
|
+
};
|
|
10593
|
+
lowerer.liftedFns.push({
|
|
10594
|
+
name: impl,
|
|
10595
|
+
params,
|
|
10596
|
+
returnType: type.ret,
|
|
10597
|
+
captures: [{ localId: captured.id, name: captured.name, type }],
|
|
10598
|
+
locals: [captured, ...params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false }))],
|
|
10599
|
+
body: [type.ret.kind === "void" ? { kind: "exprStmt", expr: invoked, loc } : { kind: "return", value: invoked, loc }],
|
|
10600
|
+
loc,
|
|
10601
|
+
});
|
|
10602
|
+
const bound = { kind: "varRef", localId: "bound.0", type, loc };
|
|
10603
|
+
const str = (value) => ({ kind: "strLit", value, type: STRING, loc });
|
|
10604
|
+
const descriptor = (value) => ({
|
|
10605
|
+
kind: "dynObjLit", fields: [{ key: str("value"), value: { kind: "dynFrom", value, type: DYN, loc } }], type: DYN, loc,
|
|
10606
|
+
});
|
|
10607
|
+
lowerer.liftedFns.push({
|
|
10608
|
+
name,
|
|
10609
|
+
params: [{ localId: captured.id, name: captured.name, type }],
|
|
10610
|
+
returnType: type,
|
|
10611
|
+
locals: [captured, { id: "bound.0", name: "bound", type, mutable: false }],
|
|
10612
|
+
body: [
|
|
10613
|
+
{ kind: "varDecl", localId: "bound.0", init: { kind: "closure", fnName: impl, captures: [captured.id], type, loc }, loc },
|
|
10614
|
+
// Store metadata on the closure so aliases and repeated dyn boxes
|
|
10615
|
+
// observe the bound name and source arity, including defaults.
|
|
10616
|
+
{ kind: "exprStmt", expr: {
|
|
10617
|
+
kind: "libCall", fn: "dyn.defineProps", args: [
|
|
10618
|
+
{ kind: "dynFrom", value: bound, type: DYN, loc },
|
|
10619
|
+
{ kind: "dynObjLit", fields: [
|
|
10620
|
+
{ key: str("name"), value: descriptor(str("bound ")) },
|
|
10621
|
+
{ key: str("length"), value: descriptor({ kind: "numLit", value: length, type: F64, loc }) },
|
|
10622
|
+
], type: DYN, loc },
|
|
10623
|
+
], type: DYN, loc,
|
|
10624
|
+
}, loc },
|
|
10625
|
+
{ kind: "return", value: bound, loc },
|
|
10626
|
+
],
|
|
10627
|
+
loc,
|
|
10628
|
+
});
|
|
10629
|
+
}
|
|
10630
|
+
const saved = lowerer.declareHiddenLocal("%bindFn", type);
|
|
10631
|
+
const stmts = [{ kind: "varDecl", localId: saved.id, init: callee, loc }];
|
|
10632
|
+
// The receiver is ignored by the arrow, but its effects and throws
|
|
10633
|
+
// happen after creating the arrow and before returning the bound value.
|
|
10634
|
+
if (call.arguments[0])
|
|
10635
|
+
stmts.push(lowerer.lowerExprStatement(call.arguments[0]));
|
|
10636
|
+
const result = { kind: "call", callee: name, args: [{ kind: "varRef", localId: saved.id, type, loc }], type, loc };
|
|
10637
|
+
return { kind: "seqExpr", stmts, result, type, loc };
|
|
10638
|
+
}
|
|
9478
10639
|
/** `arrow.apply(thisArg, dynArgs)` for a fixed-arity compiled arrow. Arrows
|
|
9479
10640
|
* ignore `thisArg` and surplus arguments by language definition; declared
|
|
9480
10641
|
* parameters validate from the dynamic array in order. */
|
|
@@ -9553,7 +10714,6 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
9553
10714
|
thisT.kind !== "dyn" &&
|
|
9554
10715
|
thisT.kind !== "jsval" &&
|
|
9555
10716
|
(!thisArg || ts.isIdentifier(thisArg) || ts.isLiteralExpression(thisArg) ||
|
|
9556
|
-
thisArg.kind === ts.SyntaxKind.UndefinedKeyword ||
|
|
9557
10717
|
thisArg.kind === ts.SyntaxKind.NullKeyword ||
|
|
9558
10718
|
isUnitType(thisT));
|
|
9559
10719
|
if (provablyNot) {
|
|
@@ -9564,6 +10724,14 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
9564
10724
|
const propSym = lowerer.checker.getPropertyOfType(recvT, name);
|
|
9565
10725
|
if (!propSym)
|
|
9566
10726
|
return null;
|
|
10727
|
+
const propertyDecl = lowerer.checker.valueDeclarationOf(propSym);
|
|
10728
|
+
if (propertyDecl && ts.isShorthandPropertyAssignment(propertyDecl) && ts.isIdentifier(propertyDecl.name) && ts.isObjectLiteralExpression(propertyDecl.parent)) {
|
|
10729
|
+
requireObjLitGenericReceiver(lowerer, call, access.expression, propertyDecl.parent, name);
|
|
10730
|
+
const targetSymbol = lowerer.checker.getShorthandAssignmentValueSymbol(propertyDecl);
|
|
10731
|
+
const target = targetSymbol ? lowerer.genericFnsBySymbol.get((targetSymbol.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(targetSymbol) : targetSymbol)) : undefined;
|
|
10732
|
+
if (target)
|
|
10733
|
+
return lowerer.lowerGenericCall(call, target);
|
|
10734
|
+
}
|
|
9567
10735
|
if (!isGenericCallableMemberType(lowerer.checker.getTypeOfSymbol(propSym), lowerer.checker))
|
|
9568
10736
|
return null;
|
|
9569
10737
|
// CLASS members belong to the class path (lowerClassGenericMethodCall
|
|
@@ -9592,19 +10760,25 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
9592
10760
|
}
|
|
9593
10761
|
const found = objLitGenericFnNodeOf(lowerer, propSym);
|
|
9594
10762
|
if (!found) {
|
|
10763
|
+
const arrowBind = lowerInlineArrowBind(lowerer, call, access);
|
|
10764
|
+
if (arrowBind !== null)
|
|
10765
|
+
return arrowBind;
|
|
9595
10766
|
const arrowApply = lowerArrowFunctionApply(lowerer, call, access);
|
|
9596
10767
|
if (arrowApply !== null)
|
|
9597
10768
|
return arrowApply;
|
|
9598
|
-
//
|
|
9599
|
-
//
|
|
9600
|
-
// `this`/arguments object to re-route — name the working spelling
|
|
9601
|
-
// instead of a class-receiver hint (or an SC2020 recitation) no
|
|
9602
|
-
// function value can follow. Before the stdlib decline: these ARE
|
|
9603
|
-
// stdlib members (CallableFunction), but the pointed message is
|
|
9604
|
-
// the honest one.
|
|
10769
|
+
// Convertible native callables use the checked invocation boundary
|
|
10770
|
+
// for Function.prototype methods, including their call-time receiver.
|
|
9605
10771
|
if ((name === "apply" || name === "call" || name === "bind") &&
|
|
9606
10772
|
lowerer.checker.getCallSignatures(recvT).length > 0) {
|
|
9607
|
-
|
|
10773
|
+
const value = tryLowerExpression(lowerer, access.expression);
|
|
10774
|
+
if (value?.type.kind === "func" && lowerer.dynConvertible(value.type) && !call.arguments.some(ts.isSpreadElement)) {
|
|
10775
|
+
const loc = locOf(call);
|
|
10776
|
+
return {
|
|
10777
|
+
kind: "dynInvoke", recv: { kind: "dynFrom", value, type: DYN, loc }, method: name,
|
|
10778
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc,
|
|
10779
|
+
};
|
|
10780
|
+
}
|
|
10781
|
+
lowerer.unsupported("SC1090", call, `Function.prototype.${name} on a function whose signature cannot cross the checked-value boundary (call '${access.expression.getText()}(...)' directly)`);
|
|
9608
10782
|
}
|
|
9609
10783
|
// STANDARD-LIBRARY generic members (Promise.then, Object.
|
|
9610
10784
|
// defineProperty, Array-augmentation methods) are the lib fence's
|
|
@@ -9641,12 +10815,27 @@ function lowerObjLitGenericMethodCall(lowerer, call, access) {
|
|
|
9641
10815
|
export function lowerObjectMethodCall(lowerer, call, access) {
|
|
9642
10816
|
if (lowerer.chainBlocked(access, call))
|
|
9643
10817
|
return null;
|
|
9644
|
-
|
|
10818
|
+
let mappedReceiver = lowerer.mapTypeOf(lowerer.typeOf(access.expression));
|
|
10819
|
+
// A specialized JS parameter can expose a native field whose checker
|
|
10820
|
+
// type still belongs to the unspecialized body (plane.normal.dot()).
|
|
10821
|
+
// Use the lowered receiver's representation and retain its evaluation.
|
|
10822
|
+
const probe = mappedReceiver?.kind !== "object" && (lowerer.implicitParamTypes !== null || ts.isNewExpression(access.expression) ||
|
|
10823
|
+
isJsSourceFile(call.getSourceFile()) && ts.isCallExpression(access.expression))
|
|
10824
|
+
? tryLowerExpression(lowerer, access.expression) : null;
|
|
10825
|
+
const specializedReceiver = probe?.type.kind === "object" ? probe : null;
|
|
10826
|
+
if (specializedReceiver)
|
|
10827
|
+
mappedReceiver = specializedReceiver.type;
|
|
9645
10828
|
if (mappedReceiver?.kind === "union") {
|
|
9646
10829
|
const dispatched = lowerUnionObjectMethodCall(lowerer, call, access, mappedReceiver) ??
|
|
9647
10830
|
lowerUnionObjectDynFieldCall(lowerer, call, access, mappedReceiver);
|
|
9648
10831
|
if (dispatched)
|
|
9649
10832
|
return dispatched;
|
|
10833
|
+
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms;
|
|
10834
|
+
if (isJsSourceFile(call.getSourceFile()) && arms?.every((arm) => arm.kind === "object" &&
|
|
10835
|
+
!lowerer.classes.get(arm.className)?.def.runtime) && lowerer.dynConvertible(mappedReceiver)) {
|
|
10836
|
+
const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN);
|
|
10837
|
+
return lowerDynDispatchMethodCall(lowerer, call, access, receiver, false);
|
|
10838
|
+
}
|
|
9650
10839
|
}
|
|
9651
10840
|
const receiverIr = mappedReceiver?.kind === "object"
|
|
9652
10841
|
? mappedReceiver
|
|
@@ -9654,15 +10843,16 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
9654
10843
|
? (() => {
|
|
9655
10844
|
const arms = lowerer.unions.get(mappedReceiver.unionId)?.arms ?? [];
|
|
9656
10845
|
const objects = arms.filter((arm) => arm.kind === "object");
|
|
9657
|
-
|
|
9658
|
-
|
|
10846
|
+
const object = objects[0];
|
|
10847
|
+
return objects.length === 1 && object?.kind === "object" && arms.every((arm) => arm.kind === "object" || isUnitType(arm))
|
|
10848
|
+
? object
|
|
9659
10849
|
: null;
|
|
9660
10850
|
})()
|
|
9661
10851
|
: null;
|
|
9662
10852
|
if (receiverIr === null)
|
|
9663
10853
|
return null;
|
|
9664
10854
|
const lowerReceiver = () => {
|
|
9665
|
-
const receiver = lowerer.lowerExpr(access.expression);
|
|
10855
|
+
const receiver = specializedReceiver ?? lowerer.lowerExpr(access.expression);
|
|
9666
10856
|
const optional = lowerer.runtimeOptionalPropertyReceiver(access.expression, receiver, receiverIr, access.name.text);
|
|
9667
10857
|
if (optional !== null)
|
|
9668
10858
|
return optional;
|
|
@@ -9671,7 +10861,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
9671
10861
|
if (helper !== null)
|
|
9672
10862
|
return { kind: "call", callee: helper, args: [receiver], type: receiverIr, loc: locOf(access.expression) };
|
|
9673
10863
|
}
|
|
9674
|
-
return receiver;
|
|
10864
|
+
return receiver.type.kind === "dyn" ? lowerer.coerceInto(access.expression, receiver, receiverIr) : receiver;
|
|
9675
10865
|
};
|
|
9676
10866
|
const info = lowerer.classes.get(receiverIr.className);
|
|
9677
10867
|
if (!info)
|
|
@@ -9698,7 +10888,7 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
9698
10888
|
if (info && !found) {
|
|
9699
10889
|
const gfound = findGenericMethodOn(lowerer, info, access.name.text);
|
|
9700
10890
|
if (gfound)
|
|
9701
|
-
return lowerClassGenericMethodCall(lowerer, call, access, info, gfound);
|
|
10891
|
+
return lowerClassGenericMethodCall(lowerer, call, access, info, gfound, lowerReceiver());
|
|
9702
10892
|
}
|
|
9703
10893
|
// A FUNC-, nullable-FUNC-, or DYN-typed FIELD in call position:
|
|
9704
10894
|
// `this.cb()` — the ctor-assigned callback field (countdown.js's
|
|
@@ -9714,13 +10904,22 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
9714
10904
|
? (() => {
|
|
9715
10905
|
const arms = lowerer.unions.get(fieldType.unionId)?.arms ?? [];
|
|
9716
10906
|
const funcs = arms.filter((arm) => arm.kind === "func");
|
|
9717
|
-
|
|
9718
|
-
|
|
10907
|
+
const func = funcs[0];
|
|
10908
|
+
return funcs.length === 1 && func?.kind === "func" && arms.every((arm) => arm.kind === "func" || isUnitType(arm))
|
|
10909
|
+
? func
|
|
9719
10910
|
: null;
|
|
9720
10911
|
})()
|
|
9721
10912
|
: null;
|
|
9722
10913
|
if (fieldType && (callableType !== null || fieldType.kind === "dyn")) {
|
|
9723
10914
|
const target = lowerer.fieldTarget(access);
|
|
10915
|
+
if (!target)
|
|
10916
|
+
return null;
|
|
10917
|
+
const loc = locOf(call);
|
|
10918
|
+
const receiverLocal = lowerer.declareHiddenLocal("%callReceiver", target.obj.type);
|
|
10919
|
+
const init = { kind: "varDecl", localId: receiverLocal.id, init: target.obj, loc };
|
|
10920
|
+
target.obj = { kind: "varRef", localId: receiverLocal.id, type: receiverLocal.type, loc };
|
|
10921
|
+
const receiver = lowerer.coerceToExpected(target.obj, DYN);
|
|
10922
|
+
const finish = (result) => ({ kind: "seqExpr", stmts: [init], result, type: result.type, loc });
|
|
9724
10923
|
let callee = target ? lowerer.fieldGetExpr(target, locOf(access), access) : null;
|
|
9725
10924
|
if (callee?.type.kind === "union" && callableType !== null) {
|
|
9726
10925
|
const helper = lowerer.narrowedArmHelper(callee.type.unionId, callableType, locOf(access));
|
|
@@ -9729,34 +10928,65 @@ export function lowerObjectMethodCall(lowerer, call, access) {
|
|
|
9729
10928
|
}
|
|
9730
10929
|
}
|
|
9731
10930
|
if (callee?.type.kind === "func") {
|
|
10931
|
+
if ((callee.type.rest === true && callee.type.restAbi === undefined || call.arguments.length > callee.type.params.length) &&
|
|
10932
|
+
isJsSourceFile(call.getSourceFile()) && lowerer.dynConvertible(callee.type)) {
|
|
10933
|
+
const boxed = { kind: "dynFrom", value: callee, type: DYN, loc };
|
|
10934
|
+
const spread = lowerSpreadArgsCall(lowerer, call, boxed, loc);
|
|
10935
|
+
if (spread?.kind === "dynCall")
|
|
10936
|
+
return finish({ ...spread, receiver });
|
|
10937
|
+
const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
|
|
10938
|
+
return finish({ kind: "dynCall", callee: boxed, receiver, calleeName: access.getText(), args, type: DYN, loc });
|
|
10939
|
+
}
|
|
9732
10940
|
const args = completeFuncValueArgs(lowerer, call, callee.type, locOf(call));
|
|
9733
|
-
return { kind: "callValue", callee, args, type: callee.type.ret, loc
|
|
10941
|
+
return finish({ kind: "callValue", callee, receiver, args, type: callee.type.ret, loc });
|
|
9734
10942
|
}
|
|
9735
10943
|
if (callee?.type.kind === "dyn") {
|
|
9736
10944
|
if (call.arguments.some((a) => ts.isSpreadElement(a))) {
|
|
9737
10945
|
lowerer.unsupported("SC1090", call, "spread arguments in calls through 'unknown' values");
|
|
9738
10946
|
}
|
|
9739
10947
|
const args = call.arguments.map((a) => lowerer.lowerExprExpecting(a, DYN));
|
|
9740
|
-
return { kind: "dynCall", callee, calleeName: access.getText(), args, type: DYN, loc
|
|
10948
|
+
return finish({ kind: "dynCall", callee, receiver, calleeName: access.getText(), args, type: DYN, loc });
|
|
9741
10949
|
}
|
|
9742
10950
|
}
|
|
10951
|
+
if (!fieldType && isJsSourceFile(call.getSourceFile()) && !info.def.runtime && !info.builtinError && !info.builtinEmitter && !info.builtinStream) {
|
|
10952
|
+
const loc = locOf(call);
|
|
10953
|
+
const value = lowerReceiver();
|
|
10954
|
+
const local = lowerer.declareHiddenLocal("%callReceiver", value.type);
|
|
10955
|
+
const reference = { kind: "varRef", localId: local.id, type: value.type, loc };
|
|
10956
|
+
const receiver = lowerer.coerceToExpected(reference, DYN);
|
|
10957
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
10958
|
+
key: { kind: "strLit", value: access.name.text, type: STRING, loc }, type: DYN, loc };
|
|
10959
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
10960
|
+
if (spread && spread.kind !== "dynCall")
|
|
10961
|
+
lowerer.unsupported("SC1090", call, "native property call spread arguments");
|
|
10962
|
+
const result = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
10963
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
10964
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], result, type: DYN, loc };
|
|
10965
|
+
}
|
|
9743
10966
|
return null;
|
|
9744
10967
|
}
|
|
9745
10968
|
if (!info || !found)
|
|
9746
10969
|
return null;
|
|
9747
10970
|
const method = access.name.text;
|
|
9748
|
-
if (
|
|
9749
|
-
|
|
9750
|
-
// implementation called directly (overriding it is fenced, so no
|
|
9751
|
-
// dispatch can ever be needed). Receiver BORROWED by the libCall.
|
|
10971
|
+
if (isClassCallback(lowerer, info, method)) {
|
|
10972
|
+
const loc = locOf(call);
|
|
9752
10973
|
const receiver = lowerReceiver();
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
10974
|
+
const local = lowerer.declareHiddenLocal("%callbackReceiver", receiver.type);
|
|
10975
|
+
const value = { kind: "varRef", localId: local.id, type: receiver.type, loc };
|
|
10976
|
+
const args = lowerer.completeArgs(call.arguments, found.sig.params, loc, call);
|
|
10977
|
+
const virtual = lowerer.overrideBelow(info, method);
|
|
10978
|
+
if (virtual)
|
|
10979
|
+
lowerer.noteVirtualEdge(info, method);
|
|
10980
|
+
else
|
|
10981
|
+
lowerer.noteEdge(`%${found.declarer.def.name}.${method}`);
|
|
10982
|
+
const fallback = virtual
|
|
10983
|
+
? { kind: "virtualCall", className: info.def.name, method, args: [lowerer.upcastTo(value, info.def.name), ...args], type: found.sig.ret, loc }
|
|
10984
|
+
: { kind: "call", callee: `%${found.declarer.def.name}.${method}`, args: [lowerer.upcastTo(value, found.declarer.def.name), ...args], type: found.sig.ret, loc };
|
|
10985
|
+
const result = classCallbackCall(lowerer, value, method, call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), fallback, loc);
|
|
10986
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id, init: receiver, loc }], result, type: result.type, loc };
|
|
10987
|
+
}
|
|
10988
|
+
if (found.declarer.builtinError) {
|
|
10989
|
+
return errorToStringCall(lowerer, lowerReceiver());
|
|
9760
10990
|
}
|
|
9761
10991
|
// An ABSTRACT nearest declaration with no concrete override below the
|
|
9762
10992
|
// static class: no implementation exists for a direct call to target.
|
|
@@ -9815,6 +11045,22 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
|
|
|
9815
11045
|
plans.push({ arm, info, found });
|
|
9816
11046
|
}
|
|
9817
11047
|
const shapes = plans[0].found.sig.params;
|
|
11048
|
+
if (plans.some((plan) => isClassCallback(lowerer, plan.info, method))) {
|
|
11049
|
+
const loc = locOf(call);
|
|
11050
|
+
const local = lowerer.declareHiddenLocal("%unionMethodReceiver", DYN);
|
|
11051
|
+
const receiver = varRef(local.id, DYN, loc);
|
|
11052
|
+
const callee = { kind: "dynKeyGet", value: receiver,
|
|
11053
|
+
key: { kind: "strLit", value: method, type: STRING, loc }, type: DYN, loc };
|
|
11054
|
+
const spread = call.arguments.some(ts.isSpreadElement) ? lowerSpreadArgsCall(lowerer, call, callee, loc) : null;
|
|
11055
|
+
if (spread && spread.kind !== "dynCall")
|
|
11056
|
+
lowerer.unsupported("SC1090", call, "union method spread arguments");
|
|
11057
|
+
const value = spread !== null ? { ...spread, receiver } : { kind: "dynCall", callee, receiver,
|
|
11058
|
+
calleeName: access.getText(), args: call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), type: DYN, loc };
|
|
11059
|
+
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
11060
|
+
const result = resultT && !isUnitType(resultT) ? lowerer.coerceToExpected(value, resultT) : value;
|
|
11061
|
+
return { kind: "seqExpr", stmts: [{ kind: "varDecl", localId: local.id,
|
|
11062
|
+
init: lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), DYN), loc }], result, type: result.type, loc };
|
|
11063
|
+
}
|
|
9818
11064
|
if (!plans.every((plan) => paramAbisEqual(shapes, plan.found.sig.params)))
|
|
9819
11065
|
return null;
|
|
9820
11066
|
const resultT = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
@@ -9829,7 +11075,10 @@ function lowerUnionObjectMethodCall(lowerer, call, access, receiverT) {
|
|
|
9829
11075
|
function paramAbisEqual(left, right) {
|
|
9830
11076
|
return left.length === right.length && left.every((shape, i) => {
|
|
9831
11077
|
const other = right[i];
|
|
9832
|
-
return other !== undefined &&
|
|
11078
|
+
return other !== undefined && typeEquals(shape.type, other.type) &&
|
|
11079
|
+
(shape.mode === other.mode || shape.type.kind === "dyn" &&
|
|
11080
|
+
(shape.mode === "required" || shape.mode === "omittable") &&
|
|
11081
|
+
(other.mode === "required" || other.mode === "omittable"));
|
|
9833
11082
|
});
|
|
9834
11083
|
}
|
|
9835
11084
|
/** The JS-class sibling of union method dispatch: every arm stores the
|
|
@@ -9854,6 +11103,8 @@ function lowerUnionObjectDynFieldCall(lowerer, call, access, receiverT) {
|
|
|
9854
11103
|
const loc = locOf(call);
|
|
9855
11104
|
const receiver = lowerer.coerceInto(access.expression, lowerer.lowerExpr(access.expression), receiverT);
|
|
9856
11105
|
const key = `${receiverT.unionId}:dyn-field:${field}`;
|
|
11106
|
+
const receiverLocal = lowerer.declareHiddenLocal("%unionCallReceiver", receiverT);
|
|
11107
|
+
const receiverRef = varRef(receiverLocal.id, receiverT, loc);
|
|
9857
11108
|
let helper = lowerer.unionCallHelpers.get(key);
|
|
9858
11109
|
if (!helper) {
|
|
9859
11110
|
helper = `%union.call.${lowerer.unionCallHelpers.size}`;
|
|
@@ -9906,9 +11157,12 @@ function lowerUnionObjectDynFieldCall(lowerer, call, access, receiverT) {
|
|
|
9906
11157
|
const locals = params.map((param) => ({ id: param.localId, name: param.name, type: param.type, mutable: false }));
|
|
9907
11158
|
lowerer.liftedFns.push({ name: helper, params, returnType: DYN, locals, body, loc });
|
|
9908
11159
|
}
|
|
9909
|
-
const callee = { kind: "call", callee: helper, args: [
|
|
11160
|
+
const callee = { kind: "call", callee: helper, args: [receiverRef], type: DYN, loc };
|
|
9910
11161
|
const args = call.arguments.map((arg) => lowerer.lowerExprExpecting(arg, DYN));
|
|
9911
|
-
return {
|
|
11162
|
+
return {
|
|
11163
|
+
kind: "seqExpr", stmts: [{ kind: "varDecl", localId: receiverLocal.id, init: receiver, loc }],
|
|
11164
|
+
result: { kind: "dynCall", callee, receiver: lowerer.coerceToExpected(receiverRef, DYN), calleeName: access.getText(), args, type: DYN, loc }, type: DYN, loc,
|
|
11165
|
+
};
|
|
9912
11166
|
}
|
|
9913
11167
|
function unionObjectMethodHelper(lowerer, sourceCall, receiverT, method, plans, shapes, resultT, loc) {
|
|
9914
11168
|
const key = `${receiverT.unionId}:${method}:${shapes.map((shape) => `${shape.mode}:${typeKey(shape.type)}`).join(",")}:${typeKey(resultT)}`;
|
|
@@ -9930,13 +11184,7 @@ function unionObjectMethodHelper(lowerer, sourceCall, receiverT, method, plans,
|
|
|
9930
11184
|
};
|
|
9931
11185
|
let invoke;
|
|
9932
11186
|
if (plan.found.declarer.builtinError) {
|
|
9933
|
-
invoke =
|
|
9934
|
-
kind: "libCall",
|
|
9935
|
-
fn: "error.toString",
|
|
9936
|
-
args: [lowerer.upcastTo(concrete, plan.found.declarer.def.name)],
|
|
9937
|
-
type: STRING,
|
|
9938
|
-
loc,
|
|
9939
|
-
};
|
|
11187
|
+
invoke = errorToStringCall(lowerer, concrete);
|
|
9940
11188
|
}
|
|
9941
11189
|
else if (lowerer.overrideBelow(plan.info, method)) {
|
|
9942
11190
|
lowerer.noteVirtualEdge(plan.info, method);
|