@scriptc/compiler 0.2.5 → 0.2.7
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 +62 -48
- package/dist/backend/cycle-analysis.d.ts +21 -9
- package/dist/backend/cycle-analysis.js +139 -67
- package/dist/backend/cycle-analysis.js.map +1 -1
- package/dist/backend/cycle-analysis.test.js +283 -3
- package/dist/backend/cycle-analysis.test.js.map +1 -1
- package/dist/backend/cycle-mutability.d.ts +39 -0
- package/dist/backend/cycle-mutability.js +205 -0
- package/dist/backend/cycle-mutability.js.map +1 -0
- package/dist/backend/executable-features.js +1 -0
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/link-plan-core.d.ts +4 -1
- package/dist/backend/link-plan-core.js +16 -3
- package/dist/backend/link-plan-core.js.map +1 -1
- package/dist/backend/link-plan.d.ts +3 -1
- package/dist/backend/link-plan.js +3 -0
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/alloc.d.ts +40 -0
- package/dist/backend/llvm/alloc.js +205 -0
- package/dist/backend/llvm/alloc.js.map +1 -0
- package/dist/backend/llvm/alloc.test.d.ts +1 -0
- package/dist/backend/llvm/alloc.test.js +102 -0
- package/dist/backend/llvm/alloc.test.js.map +1 -0
- package/dist/backend/llvm/byte-numbers.js +32 -4
- package/dist/backend/llvm/byte-numbers.js.map +1 -1
- package/dist/backend/llvm/byte-windows.d.ts +31 -0
- package/dist/backend/llvm/byte-windows.js +334 -0
- package/dist/backend/llvm/byte-windows.js.map +1 -0
- package/dist/backend/llvm/byte-windows.test.d.ts +1 -0
- package/dist/backend/llvm/byte-windows.test.js +244 -0
- package/dist/backend/llvm/byte-windows.test.js.map +1 -0
- package/dist/backend/llvm/call-lifetimes.d.ts +17 -5
- package/dist/backend/llvm/call-lifetimes.js +58 -24
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.test.js +170 -0
- package/dist/backend/llvm/call-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +18 -2
- package/dist/backend/llvm/classes.js +115 -41
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.d.ts +1 -0
- package/dist/backend/llvm/classes.test.js +132 -0
- package/dist/backend/llvm/classes.test.js.map +1 -0
- package/dist/backend/llvm/common.d.ts +13 -0
- package/dist/backend/llvm/common.js +30 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +27 -0
- package/dist/backend/llvm/constant-callbacks.js +450 -0
- package/dist/backend/llvm/constant-callbacks.js.map +1 -0
- package/dist/backend/llvm/constant-callbacks.test.d.ts +1 -0
- package/dist/backend/llvm/constant-callbacks.test.js +261 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -0
- package/dist/backend/llvm/dense-array-access.d.ts +29 -0
- package/dist/backend/llvm/dense-array-access.js +335 -0
- package/dist/backend/llvm/dense-array-access.js.map +1 -0
- package/dist/backend/llvm/dense-array-access.test.d.ts +1 -0
- package/dist/backend/llvm/dense-array-access.test.js +149 -0
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +35 -1
- package/dist/backend/llvm/dyn.js +196 -35
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +143 -4
- package/dist/backend/llvm/emitter.js +882 -136
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +82 -14
- package/dist/backend/llvm/emitter.test.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +58 -4
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-async.test.d.ts +1 -0
- package/dist/backend/llvm/expr-async.test.js +62 -0
- package/dist/backend/llvm/expr-async.test.js.map +1 -0
- package/dist/backend/llvm/expr-bytes.js +11 -0
- package/dist/backend/llvm/expr-bytes.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +151 -25
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +37 -14
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-control.js +92 -2
- package/dist/backend/llvm/expr-control.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +2 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +210 -28
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +58 -23
- 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.js +3 -3
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +59 -2
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.test.js +1 -1
- package/dist/backend/llvm/integer-remainder.d.ts +18 -0
- package/dist/backend/llvm/integer-remainder.js +117 -0
- package/dist/backend/llvm/integer-remainder.js.map +1 -0
- package/dist/backend/llvm/layouts.d.ts +2 -1
- package/dist/backend/llvm/layouts.js +4 -3
- package/dist/backend/llvm/layouts.js.map +1 -1
- package/dist/backend/llvm/lazy-captures.d.ts +16 -0
- package/dist/backend/llvm/lazy-captures.js +96 -0
- package/dist/backend/llvm/lazy-captures.js.map +1 -0
- package/dist/backend/llvm/lazy-captures.test.d.ts +1 -0
- package/dist/backend/llvm/lazy-captures.test.js +78 -0
- package/dist/backend/llvm/lazy-captures.test.js.map +1 -0
- package/dist/backend/llvm/lib-abi.js +7 -0
- package/dist/backend/llvm/lib-abi.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +7 -22
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +3 -4
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +15 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +13 -3
- package/dist/backend/llvm/local-array-reads.js +159 -77
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +105 -4
- package/dist/backend/llvm/local-array-reads.test.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.d.ts +5 -1
- package/dist/backend/llvm/local-union-storage.js +48 -6
- package/dist/backend/llvm/local-union-storage.js.map +1 -1
- package/dist/backend/llvm/local-union-storage.test.js +91 -4
- package/dist/backend/llvm/local-union-storage.test.js.map +1 -1
- package/dist/backend/llvm/loop-array-borrows.d.ts +11 -0
- package/dist/backend/llvm/loop-array-borrows.js +70 -0
- package/dist/backend/llvm/loop-array-borrows.js.map +1 -0
- package/dist/backend/llvm/loop-array-borrows.test.d.ts +1 -0
- package/dist/backend/llvm/loop-array-borrows.test.js +145 -0
- package/dist/backend/llvm/loop-array-borrows.test.js.map +1 -0
- package/dist/backend/llvm/map-read-lifetimes.d.ts +5 -0
- package/dist/backend/llvm/map-read-lifetimes.js +20 -5
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +1 -1
- package/dist/backend/llvm/nullable-fields.d.ts +28 -0
- package/dist/backend/llvm/nullable-fields.js +45 -0
- package/dist/backend/llvm/nullable-fields.js.map +1 -0
- package/dist/backend/llvm/nullable-fields.test.d.ts +1 -0
- package/dist/backend/llvm/nullable-fields.test.js +48 -0
- package/dist/backend/llvm/nullable-fields.test.js.map +1 -0
- package/dist/backend/llvm/reference-effects.d.ts +2 -1
- package/dist/backend/llvm/reference-effects.js +7 -0
- package/dist/backend/llvm/reference-effects.js.map +1 -1
- package/dist/backend/llvm/serialized-ir-emission.test.d.ts +1 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js +52 -0
- package/dist/backend/llvm/serialized-ir-emission.test.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +73 -3
- package/dist/backend/llvm/shapes.js +281 -34
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +114 -5
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/split-loops.d.ts +48 -0
- package/dist/backend/llvm/split-loops.js +183 -0
- package/dist/backend/llvm/split-loops.js.map +1 -0
- package/dist/backend/llvm/split.js +0 -7
- package/dist/backend/llvm/split.js.map +1 -1
- package/dist/backend/llvm/split.test.js +66 -2
- package/dist/backend/llvm/split.test.js.map +1 -1
- package/dist/backend/llvm/stack-callbacks.d.ts +14 -0
- package/dist/backend/llvm/stack-callbacks.js +72 -0
- package/dist/backend/llvm/stack-callbacks.js.map +1 -0
- package/dist/backend/llvm/stack-captures.d.ts +27 -0
- package/dist/backend/llvm/stack-captures.js +152 -0
- package/dist/backend/llvm/stack-captures.js.map +1 -0
- package/dist/backend/llvm/stack-unions.test.js +38 -1
- package/dist/backend/llvm/stack-unions.test.js.map +1 -1
- package/dist/backend/llvm/string-construction.test.js +1 -1
- package/dist/backend/llvm/string-key-hash.d.ts +8 -0
- package/dist/backend/llvm/string-key-hash.js +59 -0
- package/dist/backend/llvm/string-key-hash.js.map +1 -0
- package/dist/backend/llvm/string-key-hash.test.d.ts +1 -0
- package/dist/backend/llvm/string-key-hash.test.js +34 -0
- package/dist/backend/llvm/string-key-hash.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +48 -7
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/string-slices.d.ts +20 -0
- package/dist/backend/llvm/string-slices.js +87 -0
- package/dist/backend/llvm/string-slices.js.map +1 -0
- package/dist/backend/llvm/string-slices.test.d.ts +1 -0
- package/dist/backend/llvm/string-slices.test.js +98 -0
- package/dist/backend/llvm/string-slices.test.js.map +1 -0
- package/dist/backend/llvm/switch-dispatch.js +1 -1
- package/dist/backend/llvm/switch-dispatch.js.map +1 -1
- package/dist/backend/llvm/switch-dispatch.test.js +2 -2
- package/dist/backend/llvm/switch-dispatch.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +4 -14
- package/dist/backend/llvm/walkers.js +53 -311
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +4 -1
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/may-throw.test.js +1 -1
- package/dist/backend/native/cache-warm.d.ts +2 -1
- package/dist/backend/native/cache-warm.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +5 -2
- package/dist/backend/native/contracts.js.map +1 -1
- package/dist/backend/native/executable.js +12 -4
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +3 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +7 -0
- package/dist/backend/native-codegen-core.js +21 -0
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +9 -0
- package/dist/backend/native-codegen.js +38 -18
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +70 -2
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +4 -2
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-link-info.d.ts +2 -1
- package/dist/backend/native-link-info.js.map +1 -1
- package/dist/backend/native-link-info.test.js +2 -2
- package/dist/backend/native-link-info.test.js.map +1 -1
- package/dist/backend/native-tools.d.ts +6 -2
- package/dist/backend/native-tools.js +6 -5
- package/dist/backend/native-tools.js.map +1 -1
- package/dist/backend/optimization.d.ts +25 -0
- package/dist/backend/optimization.js +21 -0
- package/dist/backend/optimization.js.map +1 -0
- package/dist/backend/optimization.test.d.ts +1 -0
- package/dist/backend/optimization.test.js +24 -0
- package/dist/backend/optimization.test.js.map +1 -0
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-core.d.ts +16 -4
- package/dist/backend/runtime-pack-core.js +31 -13
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack-native.d.ts +7 -3
- package/dist/backend/runtime-pack-native.js +0 -3
- package/dist/backend/runtime-pack-native.js.map +1 -1
- package/dist/backend/runtime-pack-targets.test.js +41 -4
- package/dist/backend/runtime-pack-targets.test.js.map +1 -1
- package/dist/backend/runtime-pack.d.ts +20 -2
- package/dist/backend/runtime-pack.js +23 -0
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +125 -2
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/target-diagnostics.test.js +1 -1
- package/dist/backend/targets.d.ts +2 -1
- package/dist/backend/targets.js +1 -1
- package/dist/backend/targets.js.map +1 -1
- package/dist/cli/command.js +5 -4
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/host.d.ts +2 -1
- package/dist/cli/usage.d.ts +1 -1
- package/dist/cli/usage.js +5 -2
- package/dist/cli/usage.js.map +1 -1
- package/dist/compile-types.d.ts +5 -2
- package/dist/diagnostics/diagnostic.js +10 -8
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +3 -2
- package/dist/executable/executable-cache.js +8 -4
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +35 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- package/dist/frontend/fork-target.d.ts +5 -0
- package/dist/frontend/fork-target.js +40 -8
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/fork-target.test.d.ts +1 -0
- package/dist/frontend/fork-target.test.js +59 -0
- package/dist/frontend/fork-target.test.js.map +1 -0
- package/dist/frontend/lowering/abstract-equality.js +5 -49
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/array-values.d.ts +23 -0
- package/dist/frontend/lowering/array-values.js +129 -0
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/binding-analysis.js +2 -2
- package/dist/frontend/lowering/binding-analysis.js.map +1 -1
- package/dist/frontend/lowering/builtins/atomics.d.ts +2 -11
- package/dist/frontend/lowering/builtins/atomics.js +64 -28
- package/dist/frontend/lowering/builtins/atomics.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +17 -2
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +3 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +51 -4
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-calls.js +6 -1
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.d.ts +6 -17
- package/dist/frontend/lowering/builtins/process.js +56 -29
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.d.ts +5 -0
- package/dist/frontend/lowering/builtins/workers.js +65 -0
- package/dist/frontend/lowering/builtins/workers.js.map +1 -0
- package/dist/frontend/lowering/caught-value-dispatch.d.ts +11 -0
- package/dist/frontend/lowering/caught-value-dispatch.js +87 -0
- package/dist/frontend/lowering/caught-value-dispatch.js.map +1 -0
- package/dist/frontend/lowering/class-assertions.d.ts +11 -0
- package/dist/frontend/lowering/class-assertions.js +104 -0
- package/dist/frontend/lowering/class-assertions.js.map +1 -0
- package/dist/frontend/lowering/class-callbacks.d.ts +3 -3
- package/dist/frontend/lowering/class-callbacks.js +18 -5
- package/dist/frontend/lowering/class-callbacks.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.d.ts +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +4 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-method-mutations.d.ts +5 -0
- package/dist/frontend/lowering/class-method-mutations.js +472 -0
- package/dist/frontend/lowering/class-method-mutations.js.map +1 -0
- package/dist/frontend/lowering/class-method-values.js +25 -5
- package/dist/frontend/lowering/class-method-values.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +17 -0
- package/dist/frontend/lowering/class-protocols.js +126 -0
- package/dist/frontend/lowering/class-protocols.js.map +1 -0
- package/dist/frontend/lowering/class-prototypes.js +8 -2
- package/dist/frontend/lowering/class-prototypes.js.map +1 -1
- package/dist/frontend/lowering/class-unions.d.ts +16 -0
- package/dist/frontend/lowering/class-unions.js +127 -0
- package/dist/frontend/lowering/class-unions.js.map +1 -0
- package/dist/frontend/lowering/coercions/builders.js +8 -1
- package/dist/frontend/lowering/coercions/builders.js.map +1 -1
- package/dist/frontend/lowering/coercions/function-adapters.js +2 -0
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/identity.d.ts +7 -0
- package/dist/frontend/lowering/coercions/identity.js +26 -0
- package/dist/frontend/lowering/coercions/identity.js.map +1 -0
- package/dist/frontend/lowering/coercions/structural.js +9 -6
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/collection-narrowing.d.ts +6 -0
- package/dist/frontend/lowering/collection-narrowing.js +31 -0
- package/dist/frontend/lowering/collection-narrowing.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callback-call.d.ts +7 -0
- package/dist/frontend/lowering/containers/array-callback-call.js +52 -0
- package/dist/frontend/lowering/containers/array-callback-call.js.map +1 -0
- package/dist/frontend/lowering/containers/array-callbacks.d.ts +8 -12
- package/dist/frontend/lowering/containers/array-callbacks.js +415 -136
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/array-concat.d.ts +7 -0
- package/dist/frontend/lowering/containers/array-concat.js +130 -0
- package/dist/frontend/lowering/containers/array-concat.js.map +1 -0
- package/dist/frontend/lowering/containers/array-construction.d.ts +2 -0
- package/dist/frontend/lowering/containers/array-construction.js +95 -3
- package/dist/frontend/lowering/containers/array-construction.js.map +1 -1
- package/dist/frontend/lowering/containers/array-methods.d.ts +1 -11
- package/dist/frontend/lowering/containers/array-methods.js +43 -132
- package/dist/frontend/lowering/containers/array-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +12 -34
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +10 -1
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.js +56 -70
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/containers/string-and-regexp.js +22 -3
- package/dist/frontend/lowering/containers/string-and-regexp.js.map +1 -1
- package/dist/frontend/lowering/cycle-initialization.d.ts +41 -0
- package/dist/frontend/lowering/cycle-initialization.js +277 -0
- package/dist/frontend/lowering/cycle-initialization.js.map +1 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js +4 -0
- package/dist/frontend/lowering/expressions/evaluation-safety.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +140 -38
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-field-write.d.ts +4 -4
- package/dist/frontend/lowering/expressions/union-field-write.js +54 -44
- package/dist/frontend/lowering/expressions/union-field-write.js.map +1 -1
- package/dist/frontend/lowering/generic-functions.d.ts +2 -5
- package/dist/frontend/lowering/generic-functions.js +13 -10
- package/dist/frontend/lowering/generic-functions.js.map +1 -1
- package/dist/frontend/lowering/instantiation-path.d.ts +8 -0
- package/dist/frontend/lowering/instantiation-path.js +10 -0
- package/dist/frontend/lowering/instantiation-path.js.map +1 -0
- package/dist/frontend/lowering/instantiation-path.test.d.ts +1 -0
- package/dist/frontend/lowering/instantiation-path.test.js +23 -0
- package/dist/frontend/lowering/instantiation-path.test.js.map +1 -0
- package/dist/frontend/lowering/iterator-adapters.d.ts +20 -0
- package/dist/frontend/lowering/iterator-adapters.js +605 -0
- package/dist/frontend/lowering/iterator-adapters.js.map +1 -0
- package/dist/frontend/lowering/lower-array-sort.d.ts +1 -1
- package/dist/frontend/lowering/lower-array-sort.js +44 -5
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.test.d.ts +1 -0
- package/dist/frontend/lowering/lower-array-sort.test.js +31 -0
- package/dist/frontend/lowering/lower-array-sort.test.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.js +7 -0
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.js +12 -7
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +3 -3
- package/dist/frontend/lowering/lower-calls.js +198 -124
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +7 -0
- package/dist/frontend/lowering/lower-classes.js +166 -96
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +9 -2
- package/dist/frontend/lowering/lower-exprs.js +421 -167
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.d.ts +1 -1
- package/dist/frontend/lowering/lower-functions.js +33 -20
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +26 -2
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.js +1 -1
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +1 -0
- package/dist/frontend/lowering/lower-modules.js +54 -11
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +59 -69
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +1 -1
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +50 -1
- package/dist/frontend/lowering/lowerer.js +333 -26
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/native-ffi.js +3 -1
- package/dist/frontend/lowering/native-ffi.js.map +1 -1
- package/dist/frontend/lowering/runtime-optional-provenance.d.ts +15 -0
- package/dist/frontend/lowering/runtime-optional-provenance.js +40 -0
- package/dist/frontend/lowering/runtime-optional-provenance.js.map +1 -0
- package/dist/frontend/lowering/sanitize-class-types.test.js +2 -2
- package/dist/frontend/lowering/split-consumers.d.ts +7 -0
- package/dist/frontend/lowering/split-consumers.js +64 -0
- package/dist/frontend/lowering/split-consumers.js.map +1 -0
- package/dist/frontend/lowering/strict-equality.d.ts +9 -0
- package/dist/frontend/lowering/strict-equality.js +116 -0
- package/dist/frontend/lowering/strict-equality.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -4
- package/dist/frontend/lowering/surfaces.js +38 -7
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/union-comparison.d.ts +5 -0
- package/dist/frontend/lowering/union-comparison.js +47 -0
- package/dist/frontend/lowering/union-comparison.js.map +1 -0
- package/dist/frontend/module-source-candidates.d.ts +10 -0
- package/dist/frontend/module-source-candidates.js +40 -0
- package/dist/frontend/module-source-candidates.js.map +1 -0
- package/dist/frontend/module-source-candidates.test.d.ts +1 -0
- package/dist/frontend/module-source-candidates.test.js +53 -0
- package/dist/frontend/module-source-candidates.test.js.map +1 -0
- package/dist/frontend/pipeline.js +2 -2
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +2 -0
- package/dist/frontend/program-analysis.js +2 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.d.ts +38 -2
- package/dist/frontend/program.js +457 -88
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +59 -6
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/ts7/ast-node.js +6 -8
- package/dist/frontend/ts7/ast-node.js.map +1 -1
- package/dist/frontend/ts7/ast-node.test.js +42 -1
- package/dist/frontend/ts7/ast-node.test.js.map +1 -1
- package/dist/frontend/ts7/ast-wire.d.ts +4 -0
- package/dist/frontend/ts7/ast-wire.js +28 -0
- package/dist/frontend/ts7/ast-wire.js.map +1 -1
- package/dist/frontend/ts7/ast.d.ts +2 -1
- package/dist/frontend/ts7/ast.js +8 -4
- package/dist/frontend/ts7/ast.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +8 -2
- package/dist/frontend/ts7/checker.js +41 -5
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.js +42 -0
- package/dist/frontend/ts7/checker.test.js.map +1 -1
- package/dist/frontend/ts7/program-host.d.ts +7 -0
- package/dist/frontend/ts7/program-host.js +26 -2
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/program-host.test.js +29 -0
- package/dist/frontend/ts7/program-host.test.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +4 -1
- package/dist/frontend/type-mapper.js +133 -16
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/frontend/type-mapper.test.js +15 -3
- package/dist/frontend/type-mapper.test.js.map +1 -1
- package/dist/frontend/worker-target.d.ts +6 -0
- package/dist/frontend/worker-target.js +108 -0
- package/dist/frontend/worker-target.js.map +1 -0
- package/dist/frontend/worker-target.test.d.ts +1 -0
- package/dist/frontend/worker-target.test.js +71 -0
- package/dist/frontend/worker-target.test.js.map +1 -0
- package/dist/index.js +47 -14
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +3 -1
- package/dist/ir/analysis.js +4 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/builtin-effects.js +12 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +15 -15
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/constant-tables.test.js +1 -1
- package/dist/ir/initializer-bindings.test.js +1 -1
- package/dist/ir/ir.d.ts +85 -23
- package/dist/ir/ir.js +20 -6
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/numeric-call-specialization.d.ts +8 -0
- package/dist/ir/numeric-call-specialization.js +198 -0
- package/dist/ir/numeric-call-specialization.js.map +1 -0
- package/dist/ir/runtime-features.js +4 -3
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/scalar-records.test.js +1 -1
- package/dist/ir/serialize.d.ts +1 -1
- package/dist/ir/serialize.js +3 -3
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/traverse.js +8 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +207 -43
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +356 -8
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/fence-eval.test.js +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/ir-policy.js +2 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/dist/library/library-cache.test.js +5 -5
- package/dist/library/library-profile.d.ts +2 -1
- package/dist/library/library-profile.js +4 -3
- package/dist/library/library-profile.js.map +1 -1
- package/dist/native/compiler.js +24 -11
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +7 -3
- package/dist/native/compiler.test.js.map +1 -1
- package/dist/native/library.d.ts +2 -1
- package/dist/native/library.js.map +1 -1
- package/dist/native/prepare.js +29 -3
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.d.ts +3 -2
- package/dist/native/sanitizer.js +3 -13
- package/dist/native/sanitizer.js.map +1 -1
- package/dist/native/sanitizer.test.js +1 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +37 -3
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { boolLit, countedFor, numLit, varRef } from "../../../ir/build.js";
|
|
2
|
+
import { transformStmtList } from "../../../ir/traverse.js";
|
|
2
3
|
import { InternalCompilerError } from "../../../errors.js";
|
|
4
|
+
import { canAssertClassValue, checkedClassAssertion } from "../class-assertions.js";
|
|
3
5
|
import * as ts from "../../ts7/adapter.js";
|
|
4
|
-
import {
|
|
6
|
+
import { PoisonError } from "../lowerer.js";
|
|
7
|
+
import { BOOL, DYN, F64, STRING, UNDEFINED_T, VOID, arrayOf, funcOf, isSortValuesElement, isUnitType, typeEquals, } from "../../../ir/ir.js";
|
|
5
8
|
import { isJsSourceFile, locOf } from "../../program.js";
|
|
6
9
|
import { buildArraySortFn } from "../lower-array-sort.js";
|
|
7
10
|
import { arrayIndexPresent, arrayValueRead, arrayValueStore, arrayValueType, currentArrayIndexPresent, } from "../array-values.js";
|
|
@@ -9,6 +12,7 @@ import { typeKey } from "../../type-mapper.js";
|
|
|
9
12
|
import { lowerArrayCallback, requireProducedArrayElement, callbackArrayElement, } from "./callback-arguments.js";
|
|
10
13
|
import { reverseArrayLoop, arrayLengthDeclaration, arrayCallbackParams, arrayCallbackLocals, callArrayCallback, } from "./array-iteration.js";
|
|
11
14
|
import { dynamicReceiverThrows } from "./dynamic-receivers.js";
|
|
15
|
+
import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "../optional-arguments.js";
|
|
12
16
|
/** `a.map(fn)` / `a.filter(fn)` / `a.forEach(fn)` desugar to a direct
|
|
13
17
|
* call of a synthetic module function — one per method + element/result
|
|
14
18
|
* type + callback-arity combination, interned — whose body is a plain
|
|
@@ -69,9 +73,19 @@ export function lowerArrayHofCall(lowerer, call, access, method, elem) {
|
|
|
69
73
|
const outElem = method === "filter"
|
|
70
74
|
? filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter)
|
|
71
75
|
: callbackArrayElement(lowerer, call, fnRet);
|
|
72
|
-
|
|
76
|
+
// A filter that re-tags its elements keeps the single union-typed visit.
|
|
77
|
+
const fast = booleanFilter || (method === "filter" && !typeEquals(outElem, elem))
|
|
78
|
+
? null
|
|
79
|
+
: lowerFastCallback(lowerer, argNode, [valueT], 0, elem, arrayOf(elem), callback);
|
|
80
|
+
const helper = arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem, callbackSite(fast ?? fnArg), fast?.type ?? null);
|
|
73
81
|
const resultType = method === "map" || method === "filter" ? arrayOf(outElem) : VOID;
|
|
74
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
kind: "call",
|
|
84
|
+
callee: helper,
|
|
85
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
86
|
+
type: resultType,
|
|
87
|
+
loc,
|
|
88
|
+
};
|
|
75
89
|
}
|
|
76
90
|
/** The checker-selected element of a filter result, with the same trust
|
|
77
91
|
* boundary as the historical narrowing filter: an inferred inline type
|
|
@@ -111,13 +125,15 @@ function filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter) {
|
|
|
111
125
|
`unchecked assertion nothing validates at runtime — ${annotateEscape})`);
|
|
112
126
|
}
|
|
113
127
|
}
|
|
114
|
-
|
|
128
|
+
const classRefinement = !booleanFilter && outElem.kind === "object" && canAssertClassValue(lowerer, valueT, outElem);
|
|
129
|
+
if (!classRefinement &&
|
|
130
|
+
(valueT.kind !== "union" || lowerer.armTag(valueT.unionId, outElem) < 0)) {
|
|
115
131
|
const multiArm = outElem.kind === "union";
|
|
116
132
|
lowerer.unsupported("SC1090", call, `'.filter' narrowing '${lowerer.fmt(elem)}' elements to ` +
|
|
117
133
|
`${multiArm ? `the multi-arm '${lowerer.fmt(outElem)}'` : `'${lowerer.fmt(outElem)}'`} ` +
|
|
118
134
|
`(${multiArm ? "only a SINGLE arm re-tags" : "only a single runtime arm re-tags"} — ${annotateEscape})`);
|
|
119
135
|
}
|
|
120
|
-
if (booleanFilter) {
|
|
136
|
+
if (booleanFilter && valueT.kind === "union") {
|
|
121
137
|
const arms = lowerer.unions.get(valueT.unionId)?.arms ?? [];
|
|
122
138
|
if (arms.some((arm) => !typeEquals(arm, outElem) && !isUnitType(arm))) {
|
|
123
139
|
lowerer.unsupported("SC1090", call, `'.filter(Boolean)' narrowing '${lowerer.fmt(elem)}' to '${lowerer.fmt(outElem)}' ` +
|
|
@@ -193,18 +209,193 @@ function filterCond(call, fnRet, loc) {
|
|
|
193
209
|
// the runtime's kind-aware ToBoolean.
|
|
194
210
|
return { kind: "toBool", operand: call, type: BOOL, loc };
|
|
195
211
|
}
|
|
212
|
+
/** Nested HOFs inside a fast lowering keep their single union visit, so
|
|
213
|
+
* duplication stays linear in nesting depth. */
|
|
214
|
+
let fastLoweringDepth = 0;
|
|
215
|
+
/** Array reads widen elements with undefined so holes and present
|
|
216
|
+
* undefined stay observable, which makes every callback parameter a boxed
|
|
217
|
+
* `T | undefined`. For an inline arrow over a plain element type, lower the
|
|
218
|
+
* callback a second time with the element type itself. The helper then
|
|
219
|
+
* splits each visit on the element state: a present value calls this fast
|
|
220
|
+
* closure with the plain element (no union box, no per-use undefined
|
|
221
|
+
* test), and a hole or present undefined calls the original closure with
|
|
222
|
+
* the undefined arm. Both closures share the same capture boxes and body,
|
|
223
|
+
* so every observable effect is the same; arrows have no own `this`,
|
|
224
|
+
* `arguments` or self binding that could tell the two apart. Any refusal
|
|
225
|
+
* in the second lowering is discarded and keeps the single visit. */
|
|
226
|
+
function lowerFastCallback(lowerer, argNode, lead, elemIndex, elem, arrT, slow, bindUntyped = false, expectedReturn) {
|
|
227
|
+
const valueT = lead[elemIndex];
|
|
228
|
+
if (fastLoweringDepth > 0 ||
|
|
229
|
+
slow.arity <= elemIndex ||
|
|
230
|
+
!ts.isArrowFunction(argNode) ||
|
|
231
|
+
isJsSourceFile(argNode.getSourceFile()) ||
|
|
232
|
+
valueT?.kind !== "union" ||
|
|
233
|
+
typeEquals(valueT, elem) ||
|
|
234
|
+
elem.kind === "union" ||
|
|
235
|
+
elem.kind === "dyn" ||
|
|
236
|
+
elem.kind === "jsval" ||
|
|
237
|
+
isUnitType(elem))
|
|
238
|
+
return null;
|
|
239
|
+
const fastLead = lead.slice();
|
|
240
|
+
fastLead[elemIndex] = elem;
|
|
241
|
+
// The optional-read prepass binds an unannotated element parameter to
|
|
242
|
+
// the array's runtime value type. Rebind it to the plain element for
|
|
243
|
+
// this lowering only.
|
|
244
|
+
const param = argNode.parameters[elemIndex];
|
|
245
|
+
if (!param || param.initializer || param.dotDotDotToken || !ts.isIdentifier(param.name))
|
|
246
|
+
return null;
|
|
247
|
+
const symbol = param.type ? undefined : lowerer.checker.getSymbolAtLocation(param.name);
|
|
248
|
+
const previousBinding = symbol ? lowerer.runtimeOptionalBindingTypes.get(symbol) : undefined;
|
|
249
|
+
if (symbol)
|
|
250
|
+
lowerer.runtimeOptionalBindingTypes.set(symbol, elem);
|
|
251
|
+
const sink = [];
|
|
252
|
+
const previousSink = lowerer.diagSink;
|
|
253
|
+
lowerer.diagSink = sink;
|
|
254
|
+
fastLoweringDepth++;
|
|
255
|
+
let fast;
|
|
256
|
+
try {
|
|
257
|
+
fast = lowerArrayCallback(lowerer, argNode, fastLead, arrT, bindUntyped, expectedReturn);
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
if (e instanceof PoisonError)
|
|
261
|
+
return null;
|
|
262
|
+
throw e;
|
|
263
|
+
}
|
|
264
|
+
finally {
|
|
265
|
+
fastLoweringDepth--;
|
|
266
|
+
lowerer.diagSink = previousSink;
|
|
267
|
+
if (symbol) {
|
|
268
|
+
if (previousBinding === undefined)
|
|
269
|
+
lowerer.runtimeOptionalBindingTypes.delete(symbol);
|
|
270
|
+
else
|
|
271
|
+
lowerer.runtimeOptionalBindingTypes.set(symbol, previousBinding);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const fastT = fast.fnArg.type;
|
|
275
|
+
const slowT = slow.fnArg.type;
|
|
276
|
+
if (fast.fnArg.kind !== "closure" ||
|
|
277
|
+
fast.arity !== slow.arity ||
|
|
278
|
+
!typeEquals(fastT.ret, slowT.ret) ||
|
|
279
|
+
!fastT.params.every((param, i) => typeEquals(param, i === elemIndex ? elem : slowT.params[i])))
|
|
280
|
+
return null;
|
|
281
|
+
return fast.fnArg;
|
|
282
|
+
}
|
|
283
|
+
/** `a[i]` holds a value (array state 1): neither a hole nor a present
|
|
284
|
+
* undefined. */
|
|
285
|
+
function presentValue(arr, index, loc) {
|
|
286
|
+
return {
|
|
287
|
+
kind: "bin",
|
|
288
|
+
op: "===",
|
|
289
|
+
left: { kind: "arrayState", arr, index, type: F64, loc },
|
|
290
|
+
right: numLit(1, loc),
|
|
291
|
+
type: BOOL,
|
|
292
|
+
loc,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
/** Route a helper's callback calls through the split visit: every
|
|
296
|
+
* `f(<arrayValueRead a[i]>, ...)` becomes
|
|
297
|
+
* `state(a, i) === 1 ? fast(a[i], ...) : f(undefined, ...)`. The read is
|
|
298
|
+
* the call's only effectful operand (the rest are the loop's index and
|
|
299
|
+
* array locals), so evaluation order is unchanged. The fast closure is an
|
|
300
|
+
* extra trailing parameter. */
|
|
301
|
+
function withFastCallback(fn, fastT, elem) {
|
|
302
|
+
if (!fastT)
|
|
303
|
+
return fn;
|
|
304
|
+
const isValueRead = (e) => e.kind === "ternary" &&
|
|
305
|
+
e.cond.kind === "bin" &&
|
|
306
|
+
e.cond.op === "===" &&
|
|
307
|
+
e.cond.left.kind === "arrayState" &&
|
|
308
|
+
e.cond.right.kind === "numLit" &&
|
|
309
|
+
e.cond.right.value === 1;
|
|
310
|
+
const split = (e) => {
|
|
311
|
+
if (e.kind !== "callValue" || e.callee.kind !== "varRef" || e.callee.localId !== "f.0")
|
|
312
|
+
return null;
|
|
313
|
+
const at = e.args.findIndex(isValueRead);
|
|
314
|
+
if (at < 0)
|
|
315
|
+
return null;
|
|
316
|
+
const read = e.args[at];
|
|
317
|
+
if (read.kind !== "ternary")
|
|
318
|
+
return null;
|
|
319
|
+
const condition = read.cond;
|
|
320
|
+
if (condition.kind !== "bin")
|
|
321
|
+
return null;
|
|
322
|
+
const state = condition.left;
|
|
323
|
+
if (state.kind !== "arrayState")
|
|
324
|
+
return null;
|
|
325
|
+
const fastArgs = e.args.slice();
|
|
326
|
+
fastArgs[at] = {
|
|
327
|
+
kind: "arrayGet",
|
|
328
|
+
arr: state.arr,
|
|
329
|
+
index: state.index,
|
|
330
|
+
type: elem,
|
|
331
|
+
loc: read.loc,
|
|
332
|
+
};
|
|
333
|
+
const slowArgs = e.args.slice();
|
|
334
|
+
slowArgs[at] = read.else_;
|
|
335
|
+
return {
|
|
336
|
+
cond: read.cond,
|
|
337
|
+
fast: { ...e, callee: varRef("fast.0", fastT, e.callee.loc), args: fastArgs },
|
|
338
|
+
slow: { ...e, args: slowArgs },
|
|
339
|
+
};
|
|
340
|
+
};
|
|
341
|
+
const body = transformStmtList(fn.body, {
|
|
342
|
+
stmt: (stmt) => {
|
|
343
|
+
if (stmt.kind !== "exprStmt")
|
|
344
|
+
return stmt;
|
|
345
|
+
const parts = split(stmt.expr);
|
|
346
|
+
if (!parts)
|
|
347
|
+
return stmt;
|
|
348
|
+
return {
|
|
349
|
+
kind: "if",
|
|
350
|
+
cond: parts.cond,
|
|
351
|
+
then: [{ kind: "exprStmt", expr: parts.fast, loc: stmt.loc }],
|
|
352
|
+
else_: [{ kind: "exprStmt", expr: parts.slow, loc: stmt.loc }],
|
|
353
|
+
loc: stmt.loc,
|
|
354
|
+
};
|
|
355
|
+
},
|
|
356
|
+
expr: (expr) => {
|
|
357
|
+
const parts = split(expr);
|
|
358
|
+
if (!parts)
|
|
359
|
+
return expr;
|
|
360
|
+
return {
|
|
361
|
+
kind: "ternary",
|
|
362
|
+
cond: parts.cond,
|
|
363
|
+
then: parts.fast,
|
|
364
|
+
else_: parts.slow,
|
|
365
|
+
type: expr.type,
|
|
366
|
+
loc: expr.loc,
|
|
367
|
+
};
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
return {
|
|
371
|
+
...fn,
|
|
372
|
+
params: [...fn.params, { localId: "fast.0", name: "fast", type: fastT }],
|
|
373
|
+
locals: [...fn.locals, { id: "fast.0", name: "fast", type: fastT, mutable: true }],
|
|
374
|
+
body,
|
|
375
|
+
};
|
|
376
|
+
}
|
|
377
|
+
/** The interning suffix for a callback argument. A literal closure (an
|
|
378
|
+
* inline arrow or function expression) gets a helper of its own, so the
|
|
379
|
+
* helper's only incoming callback is one known function: the backend's
|
|
380
|
+
* constant-callback census then calls it directly and LLVM can inline the
|
|
381
|
+
* callback into the loop (TurboFan's builtin+callback inlining). Callback
|
|
382
|
+
* values keep the shared, type-interned helper. */
|
|
383
|
+
function callbackSite(fnArg) {
|
|
384
|
+
return fnArg.kind === "closure" ? `@${fnArg.fnName}` : "";
|
|
385
|
+
}
|
|
196
386
|
/** Interned synthetic loop function for one (method, elem, fnRet, arity)
|
|
197
387
|
* combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
|
|
198
388
|
* namespace); rides `liftedFns` into the module like a lifted lambda (it
|
|
199
389
|
* is a plain function — no captures). */
|
|
200
|
-
function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet) {
|
|
201
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}:${typeKey(outElem)}`;
|
|
390
|
+
function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet, site = "", fastT = null) {
|
|
391
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}:${typeKey(outElem)}${site}${fastT ? ":split" : ""}`;
|
|
202
392
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
203
393
|
if (existing)
|
|
204
394
|
return existing;
|
|
205
395
|
const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
|
|
206
396
|
lowerer.arrHofHelpers.set(key, name);
|
|
207
|
-
|
|
397
|
+
const fn = buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT);
|
|
398
|
+
lowerer.liftedFns.push(fastT ? withFastCallback(fn, fastT, elem) : fn);
|
|
208
399
|
return name;
|
|
209
400
|
}
|
|
210
401
|
/** The TS 5.2+ callable-union array rule: a `T[] | U[]` receiver exposes
|
|
@@ -362,7 +553,7 @@ function arrayUnionHofHelper(lowerer, method, receiverT, arrays, callbackT, arit
|
|
|
362
553
|
* `arity` is the callback's declared parameter count (1–3): the loop
|
|
363
554
|
* passes the index and the receiver itself after the element when the
|
|
364
555
|
* callback names them, exactly the arguments JS supplies. */
|
|
365
|
-
function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem) {
|
|
556
|
+
function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT = null) {
|
|
366
557
|
const arrT = arrayOf(elem);
|
|
367
558
|
const valueT = arrayValueType(lowerer, elem);
|
|
368
559
|
const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
|
|
@@ -427,22 +618,111 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
|
|
|
427
618
|
{ kind: "return", value: varRef("out.0", outT, loc), loc },
|
|
428
619
|
];
|
|
429
620
|
}
|
|
621
|
+
else if (method === "filter" && fastT) {
|
|
622
|
+
// Split visit (outElem === elem): a present value goes to the fast
|
|
623
|
+
// callback as a plain element and is kept as-is; a present undefined
|
|
624
|
+
// goes to the original callback and is kept as undefined.
|
|
625
|
+
const outT = arrayOf(outElem);
|
|
626
|
+
locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "e.0", name: "e", type: elem, mutable: false });
|
|
627
|
+
returnType = outT;
|
|
628
|
+
const a = varRef("a.0", arrT, loc);
|
|
629
|
+
const i = varRef("i.0", F64, loc);
|
|
630
|
+
const outLength = {
|
|
631
|
+
kind: "arrIntrinsic",
|
|
632
|
+
method: "length",
|
|
633
|
+
receiver: varRef("out.0", outT, loc),
|
|
634
|
+
args: [],
|
|
635
|
+
type: F64,
|
|
636
|
+
loc,
|
|
637
|
+
};
|
|
638
|
+
const missing = getElem.else_;
|
|
639
|
+
const callFast = (arg) => ({
|
|
640
|
+
kind: "callValue",
|
|
641
|
+
callee: varRef("fast.0", fastT, loc),
|
|
642
|
+
args: [arg, i, a].slice(0, arity),
|
|
643
|
+
type: fnRet,
|
|
644
|
+
loc,
|
|
645
|
+
});
|
|
646
|
+
body = [
|
|
647
|
+
{
|
|
648
|
+
kind: "varDecl",
|
|
649
|
+
localId: "out.0",
|
|
650
|
+
init: { kind: "arrayLit", elems: [], type: outT, loc },
|
|
651
|
+
loc,
|
|
652
|
+
},
|
|
653
|
+
readLen,
|
|
654
|
+
forLoop([
|
|
655
|
+
{
|
|
656
|
+
kind: "if",
|
|
657
|
+
cond: hasElem,
|
|
658
|
+
then: [
|
|
659
|
+
{
|
|
660
|
+
kind: "if",
|
|
661
|
+
cond: presentValue(a, i, loc),
|
|
662
|
+
then: [
|
|
663
|
+
{
|
|
664
|
+
kind: "varDecl",
|
|
665
|
+
localId: "e.0",
|
|
666
|
+
init: { kind: "arrayGet", arr: a, index: i, type: elem, loc },
|
|
667
|
+
loc,
|
|
668
|
+
},
|
|
669
|
+
{
|
|
670
|
+
kind: "if",
|
|
671
|
+
cond: filterCond(callFast(varRef("e.0", elem, loc)), fnRet, loc),
|
|
672
|
+
then: [
|
|
673
|
+
arrayValueStore(lowerer, varRef("out.0", outT, loc), outLength, varRef("e.0", elem, loc), outElem, loc),
|
|
674
|
+
],
|
|
675
|
+
else_: null,
|
|
676
|
+
loc,
|
|
677
|
+
},
|
|
678
|
+
],
|
|
679
|
+
else_: [
|
|
680
|
+
{
|
|
681
|
+
kind: "if",
|
|
682
|
+
cond: filterCond(callF(missing), fnRet, loc),
|
|
683
|
+
then: [
|
|
684
|
+
{
|
|
685
|
+
kind: "arraySetUndefined",
|
|
686
|
+
arr: varRef("out.0", outT, loc),
|
|
687
|
+
index: outLength,
|
|
688
|
+
loc,
|
|
689
|
+
},
|
|
690
|
+
],
|
|
691
|
+
else_: null,
|
|
692
|
+
loc,
|
|
693
|
+
},
|
|
694
|
+
],
|
|
695
|
+
loc,
|
|
696
|
+
},
|
|
697
|
+
],
|
|
698
|
+
else_: null,
|
|
699
|
+
loc,
|
|
700
|
+
},
|
|
701
|
+
]),
|
|
702
|
+
{ kind: "return", value: varRef("out.0", outT, loc), loc },
|
|
703
|
+
];
|
|
704
|
+
}
|
|
430
705
|
else if (method === "filter") {
|
|
431
706
|
const outT = arrayOf(outElem);
|
|
432
707
|
locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "v.0", name: "v", type: valueT, mutable: false });
|
|
433
708
|
returnType = outT;
|
|
709
|
+
const classView = !typeEquals(outElem, elem) && outElem.kind === "object"
|
|
710
|
+
? checkedClassAssertion(lowerer, varRef("v.0", valueT, loc), outElem, loc)
|
|
711
|
+
: null;
|
|
434
712
|
const retained = typeEquals(outElem, elem)
|
|
435
713
|
? varRef("v.0", valueT, loc)
|
|
436
|
-
:
|
|
437
|
-
?
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
714
|
+
: classView !== null
|
|
715
|
+
? classView
|
|
716
|
+
: valueT.kind === "union"
|
|
717
|
+
? {
|
|
718
|
+
kind: "unionNarrow",
|
|
719
|
+
unionId: valueT.unionId,
|
|
720
|
+
tag: lowerer.armTag(valueT.unionId, outElem),
|
|
721
|
+
value: varRef("v.0", valueT, loc),
|
|
722
|
+
type: outElem,
|
|
723
|
+
loc,
|
|
724
|
+
}
|
|
725
|
+
: varRef("v.0", valueT, loc);
|
|
446
726
|
body = [
|
|
447
727
|
{
|
|
448
728
|
kind: "varDecl",
|
|
@@ -538,13 +818,15 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
|
|
|
538
818
|
method === "every" ||
|
|
539
819
|
method === "findIndex" ||
|
|
540
820
|
method === "findLastIndex") {
|
|
821
|
+
const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity }, bindUntyped);
|
|
822
|
+
const fastT = fast?.type ?? null;
|
|
541
823
|
const helper = method === "findIndex" || method === "findLastIndex"
|
|
542
|
-
? findIndexHelper(lowerer, elem, fnRet, arity, last, loc)
|
|
543
|
-
: someEveryHelper(lowerer, method, elem, fnRet, arity, loc);
|
|
824
|
+
? findIndexHelper(lowerer, elem, fnRet, arity, last, loc, callbackSite(fast ?? fnArg), fastT)
|
|
825
|
+
: someEveryHelper(lowerer, method, elem, fnRet, arity, loc, callbackSite(fast ?? fnArg), fastT);
|
|
544
826
|
return {
|
|
545
827
|
kind: "call",
|
|
546
828
|
callee: helper,
|
|
547
|
-
args: [receiver, fnArg],
|
|
829
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
548
830
|
type: method === "findIndex" || method === "findLastIndex" ? F64 : BOOL,
|
|
549
831
|
loc,
|
|
550
832
|
};
|
|
@@ -580,10 +862,12 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
|
|
|
580
862
|
lowerer.unsupported("SC1090", call, `'.${method}' result narrowing without a predicate over its element`);
|
|
581
863
|
}
|
|
582
864
|
retag = lowerer.narrowedRetagHelper(call, valueT.unionId, resultT.unionId, loc);
|
|
583
|
-
|
|
865
|
+
const present = lowerer.stripUndefinedArm(resultT);
|
|
866
|
+
if (retag === null &&
|
|
867
|
+
!(present.kind === "object" && canAssertClassValue(lowerer, valueT, present)))
|
|
584
868
|
lowerer.unsupported("SC1090", call, `'.${method}' narrowing to an incompatible result layout`);
|
|
585
869
|
}
|
|
586
|
-
const helper = findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag);
|
|
870
|
+
const helper = findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, callbackSite(fnArg));
|
|
587
871
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
|
|
588
872
|
}
|
|
589
873
|
/** ToBoolean of a predicate result inside a synthesized HOF helper — the
|
|
@@ -602,9 +886,9 @@ function predicateToBoolean(e) {
|
|
|
602
886
|
* for (i = 0; i < n; i++) { v = a[i]; if (f(v)) return <v as result arm>; }
|
|
603
887
|
* return <undefined arm>;
|
|
604
888
|
*/
|
|
605
|
-
function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag) {
|
|
889
|
+
function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, site = "") {
|
|
606
890
|
const method = last ? "findLast" : "find";
|
|
607
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}`;
|
|
891
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}${site}`;
|
|
608
892
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
609
893
|
if (existing)
|
|
610
894
|
return existing;
|
|
@@ -614,8 +898,14 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
|
|
|
614
898
|
const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
|
|
615
899
|
const valueT = arrayValueType(lowerer, elem);
|
|
616
900
|
const v = varRef("v.0", valueT, loc);
|
|
901
|
+
const present = lowerer.stripUndefinedArm(resultT);
|
|
902
|
+
// A successful inferred class predicate may select a descendant of a
|
|
903
|
+
// stored base arm. Keep the value read before the callback mutated the array.
|
|
904
|
+
const classView = retag === null && !lowerer.coercibleValue(valueT, resultT) && present.kind === "object"
|
|
905
|
+
? checkedClassAssertion(lowerer, v, present, loc)
|
|
906
|
+
: null;
|
|
617
907
|
const found = retag === null
|
|
618
|
-
? lowerer.coerceToExpected(v, resultT)
|
|
908
|
+
? lowerer.coerceToExpected(classView ?? v, resultT)
|
|
619
909
|
: { kind: "call", callee: retag, args: [v], type: resultT, loc };
|
|
620
910
|
const miss = {
|
|
621
911
|
kind: "unionWrap",
|
|
@@ -667,9 +957,9 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
|
|
|
667
957
|
*
|
|
668
958
|
* n = a.length; for (...) if (f(a[i], i, a)) return i; return -1;
|
|
669
959
|
*/
|
|
670
|
-
function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
960
|
+
function findIndexHelper(lowerer, elem, fnRet, arity, last, loc, site = "", fastT = null) {
|
|
671
961
|
const method = last ? "findLastIndex" : "findIndex";
|
|
672
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
|
|
962
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
|
|
673
963
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
674
964
|
if (existing)
|
|
675
965
|
return existing;
|
|
@@ -694,14 +984,14 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
|
694
984
|
loop,
|
|
695
985
|
{ kind: "return", value: { kind: "numLit", value: -1, type: F64, loc }, loc },
|
|
696
986
|
];
|
|
697
|
-
lowerer.liftedFns.push({
|
|
987
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
698
988
|
name,
|
|
699
989
|
params: arrayCallbackParams(arrT, fnT),
|
|
700
990
|
returnType: F64,
|
|
701
991
|
locals: [...arrayCallbackLocals(arrT, fnT)],
|
|
702
992
|
body,
|
|
703
993
|
loc,
|
|
704
|
-
});
|
|
994
|
+
}, fastT, elem));
|
|
705
995
|
return name;
|
|
706
996
|
}
|
|
707
997
|
/** The some/every loops — short-circuit early returns, JS-exact:
|
|
@@ -709,8 +999,8 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
|
709
999
|
* some: n = a.length; for (...) if (f(a[i])) return true; return false;
|
|
710
1000
|
* every: n = a.length; for (...) if (!f(a[i])) return false; return true;
|
|
711
1001
|
*/
|
|
712
|
-
function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
|
|
713
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
|
|
1002
|
+
function someEveryHelper(lowerer, method, elem, fnRet, arity, loc, site = "", fastT = null) {
|
|
1003
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
|
|
714
1004
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
715
1005
|
if (existing)
|
|
716
1006
|
return existing;
|
|
@@ -742,14 +1032,14 @@ function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
|
|
|
742
1032
|
]),
|
|
743
1033
|
{ kind: "return", value: boolLit(method !== "some", loc), loc },
|
|
744
1034
|
];
|
|
745
|
-
lowerer.liftedFns.push({
|
|
1035
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
746
1036
|
name,
|
|
747
1037
|
params: arrayCallbackParams(arrT, fnT),
|
|
748
1038
|
returnType: BOOL,
|
|
749
1039
|
locals: [...arrayCallbackLocals(arrT, fnT)],
|
|
750
1040
|
body,
|
|
751
1041
|
loc,
|
|
752
|
-
});
|
|
1042
|
+
}, fastT, elem));
|
|
753
1043
|
return name;
|
|
754
1044
|
}
|
|
755
1045
|
/** `a.flatMap(f)` — map plus a one-level flatten. A callback returning
|
|
@@ -793,11 +1083,28 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
|
|
|
793
1083
|
lowerer.badType(call, lowerer.typeOf(call));
|
|
794
1084
|
requireProducedArrayElement(lowerer, call, "'.flatMap()'", fnRet);
|
|
795
1085
|
const outElem = callbackArrayElement(lowerer, call, fnRet);
|
|
796
|
-
const
|
|
797
|
-
|
|
1086
|
+
const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity });
|
|
1087
|
+
const helper = arrayHofHelper(lowerer, "flatMap", elem, fnRet, arity, loc, outElem, callbackSite(fast ?? fnArg), fast?.type ?? null);
|
|
1088
|
+
return {
|
|
1089
|
+
kind: "call",
|
|
1090
|
+
callee: helper,
|
|
1091
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
1092
|
+
type: arrayOf(outElem),
|
|
1093
|
+
loc,
|
|
1094
|
+
};
|
|
798
1095
|
}
|
|
799
|
-
const
|
|
800
|
-
|
|
1096
|
+
const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, {
|
|
1097
|
+
fnArg,
|
|
1098
|
+
arity,
|
|
1099
|
+
});
|
|
1100
|
+
const helper = flatMapHelper(lowerer, elem, fnRet, arity, loc, callbackSite(fast ?? fnArg), fast?.type ?? null);
|
|
1101
|
+
return {
|
|
1102
|
+
kind: "call",
|
|
1103
|
+
callee: helper,
|
|
1104
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
1105
|
+
type: fnRet,
|
|
1106
|
+
loc,
|
|
1107
|
+
};
|
|
801
1108
|
}
|
|
802
1109
|
/** The flatMap loop (array-returning callback), from existing IR nodes:
|
|
803
1110
|
*
|
|
@@ -808,8 +1115,8 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
|
|
|
808
1115
|
* }
|
|
809
1116
|
* return out;
|
|
810
1117
|
*/
|
|
811
|
-
function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
812
|
-
const key = `flatMap:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
|
|
1118
|
+
function flatMapHelper(lowerer, elem, fnRet, arity, loc, site = "", fastT = null) {
|
|
1119
|
+
const key = `flatMap:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
|
|
813
1120
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
814
1121
|
if (existing)
|
|
815
1122
|
return existing;
|
|
@@ -908,7 +1215,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
|
908
1215
|
]),
|
|
909
1216
|
{ kind: "return", value: varRef("out.0", fnRet, loc), loc },
|
|
910
1217
|
];
|
|
911
|
-
lowerer.liftedFns.push({
|
|
1218
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
912
1219
|
name,
|
|
913
1220
|
params: arrayCallbackParams(arrT, fnT),
|
|
914
1221
|
returnType: fnRet,
|
|
@@ -922,7 +1229,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
|
922
1229
|
],
|
|
923
1230
|
body,
|
|
924
1231
|
loc,
|
|
925
|
-
});
|
|
1232
|
+
}, fastT, elem));
|
|
926
1233
|
return name;
|
|
927
1234
|
}
|
|
928
1235
|
/** `a.reduce(f)` / `a.reduce(f, init)` and reduceRight — both declared
|
|
@@ -943,10 +1250,15 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
|
|
|
943
1250
|
if (accT.kind === "void" || accT.kind === "func")
|
|
944
1251
|
lowerer.badType(call, lowerer.typeOf(call));
|
|
945
1252
|
const { fnArg, arity } = lowerArrayCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], arrT, false, accT);
|
|
946
|
-
const
|
|
1253
|
+
const fast = lowerFastCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], 1, elem, arrT, { fnArg, arity }, false, accT);
|
|
1254
|
+
const helper = reduceHelper(lowerer, method, elem, accT, fnArg.type.ret, arity, hasInit, loc, callbackSite(fast ?? fnArg), fast?.type ?? null);
|
|
947
1255
|
const args = [receiver, fnArg];
|
|
948
1256
|
if (hasInit)
|
|
949
1257
|
args.push(lowerer.lowerExprExpecting(call.arguments[1], accT));
|
|
1258
|
+
// The fast closure is created last; making a closure has no observable
|
|
1259
|
+
// effect, so the initial value still evaluates right after the callback.
|
|
1260
|
+
if (fast)
|
|
1261
|
+
args.push(fast);
|
|
950
1262
|
return { kind: "call", callee: helper, args, type: accT, loc };
|
|
951
1263
|
}
|
|
952
1264
|
/** The reduce/reduceRight loops, from existing IR nodes:
|
|
@@ -959,8 +1271,8 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
|
|
|
959
1271
|
* reduce walks 0→n-1, reduceRight n-1→0; the seed without an initial
|
|
960
1272
|
* value is a[0] / a[n-1] and the loop starts one past it. The empty-array
|
|
961
1273
|
* TypeError message is Node's, byte for byte. */
|
|
962
|
-
function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
|
|
963
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(accT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : "seed"}`;
|
|
1274
|
+
function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc, site = "", fastT = null) {
|
|
1275
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(accT)}:${typeKey(fnRet)}:${arity}:${hasInit ? "init" : "seed"}${site}${fastT ? ":split" : ""}`;
|
|
964
1276
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
965
1277
|
if (existing)
|
|
966
1278
|
return existing;
|
|
@@ -1100,53 +1412,77 @@ function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
|
|
|
1100
1412
|
loop,
|
|
1101
1413
|
{ kind: "return", value: varRef("acc.0", accT, loc), loc },
|
|
1102
1414
|
];
|
|
1103
|
-
lowerer.liftedFns.push({ name, params, returnType: accT, locals, body, loc });
|
|
1415
|
+
lowerer.liftedFns.push(withFastCallback({ name, params, returnType: accT, locals, body, loc }, fastT, elem));
|
|
1104
1416
|
return name;
|
|
1105
1417
|
}
|
|
1106
1418
|
/** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic
|
|
1107
1419
|
* function like the other array HOFs. sort mutates and returns the receiver;
|
|
1108
1420
|
* toSorted takes its shallow snapshot INSIDE the helper, after the receiver
|
|
1109
1421
|
* and comparator expressions have both been evaluated, then sorts and
|
|
1110
|
-
* returns that copy without touching the receiver. The helper
|
|
1111
|
-
*
|
|
1112
|
-
*
|
|
1113
|
-
* even when every boundary is already ordered. During a merge, an element
|
|
1422
|
+
* returns that copy without touching the receiver. The helper merges stable
|
|
1423
|
+
* natural runs, reversing only strict descending runs and extending short
|
|
1424
|
+
* runs with insertion sort. Ordered boundaries skip merging. During a merge, an element
|
|
1114
1425
|
* moves right only while cmp(left, right) > 0, so a NaN or 0 result keeps
|
|
1115
1426
|
* the left element first. Undefined values sink without reaching the user
|
|
1116
1427
|
* comparator. The callback sequence differs from V8's TimSort, so exact
|
|
1117
1428
|
* order and count parity are not claimed; results agree for consistent
|
|
1118
|
-
* comparators.
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
*
|
|
1122
|
-
* operators. For numbers that default is the notorious string sort
|
|
1123
|
-
* ([10, 9, 1] → [1, 10, 9]), deliberately fenced toward an explicit
|
|
1124
|
-
* comparator. */
|
|
1429
|
+
* comparators. Without a comparator, string, number and boolean arrays use
|
|
1430
|
+
* native stable ordering: their String conversions cannot call user code.
|
|
1431
|
+
* Strings compare UTF-16 units; numbers compare their decimal spellings
|
|
1432
|
+
* ([10, 9, 1] → [1, 10, 9]). Other element types still need a comparator. */
|
|
1125
1433
|
export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
|
|
1126
1434
|
const loc = locOf(call);
|
|
1127
1435
|
const method = access.name.text === "toSorted" ? "toSorted" : "sort";
|
|
1128
1436
|
const copyFirst = method === "toSorted";
|
|
1129
|
-
if (call.arguments.length === 0 &&
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
const fnArg = { kind: "closure", fnName: cmp, captures: [], type: fnT, loc };
|
|
1141
|
-
return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
|
|
1437
|
+
if (call.arguments.length === 0 &&
|
|
1438
|
+
(elem.kind === "string" || elem.kind === "f64" || elem.kind === "bool")) {
|
|
1439
|
+
return {
|
|
1440
|
+
kind: "arrIntrinsic",
|
|
1441
|
+
method: copyFirst ? "toSortedPrimitive" : "sortPrimitive",
|
|
1442
|
+
receiver: lowerer.lowerExpr(access.expression),
|
|
1443
|
+
args: [],
|
|
1444
|
+
type: arrT,
|
|
1445
|
+
loc,
|
|
1446
|
+
};
|
|
1142
1447
|
}
|
|
1143
1448
|
if (call.arguments.length !== 1) {
|
|
1144
|
-
lowerer.noLowering(`.${method} with ${call.arguments.length} arguments`, call, "
|
|
1145
|
-
`${method}((a, b) => a - b) for numbers`);
|
|
1449
|
+
lowerer.noLowering(`.${method} with ${call.arguments.length} arguments`, call, "default ordering supports string[], number[] and boolean[]; other element types need a comparator");
|
|
1146
1450
|
}
|
|
1147
1451
|
const receiver = lowerer.lowerExpr(access.expression);
|
|
1148
1452
|
const argNode = call.arguments[0];
|
|
1149
|
-
|
|
1453
|
+
const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, argNode);
|
|
1454
|
+
let unwrappedArg = argNode;
|
|
1455
|
+
while (ts.isParenthesizedExpression(unwrappedArg) ||
|
|
1456
|
+
ts.isAsExpression(unwrappedArg) ||
|
|
1457
|
+
ts.isTypeAssertion(unwrappedArg) ||
|
|
1458
|
+
ts.isSatisfiesExpression(unwrappedArg))
|
|
1459
|
+
unwrappedArg = unwrappedArg.expression;
|
|
1460
|
+
if (undefinedArg?.type.kind === "void" && !ts.isVoidExpression(unwrappedArg)) {
|
|
1461
|
+
lowerer.noLowering(`.${method} with an erased comparator result`, argNode, "pass the comparator directly, or use void expression to explicitly select default ordering");
|
|
1462
|
+
}
|
|
1463
|
+
if (undefinedArg !== null &&
|
|
1464
|
+
(undefinedArg.type.kind === "undefinedT" || ts.isVoidExpression(unwrappedArg)) &&
|
|
1465
|
+
(elem.kind === "string" || elem.kind === "f64" || elem.kind === "bool")) {
|
|
1466
|
+
// A type assertion alone cannot turn a function value into undefined.
|
|
1467
|
+
// The explicit undefined expression can mutate or replace the receiver.
|
|
1468
|
+
// Keep its original value alive and run the argument before sorting.
|
|
1469
|
+
const saved = lowerer.declareHiddenLocal("%sortReceiver", arrT);
|
|
1470
|
+
return {
|
|
1471
|
+
kind: "seqExpr",
|
|
1472
|
+
stmts: [{ kind: "varDecl", localId: saved.id, init: receiver, loc }],
|
|
1473
|
+
result: defaultAfterUndefined(undefinedArg, {
|
|
1474
|
+
kind: "arrIntrinsic",
|
|
1475
|
+
method: copyFirst ? "toSortedPrimitive" : "sortPrimitive",
|
|
1476
|
+
receiver: varRef(saved.id, arrT, loc),
|
|
1477
|
+
args: [],
|
|
1478
|
+
type: arrT,
|
|
1479
|
+
loc,
|
|
1480
|
+
}),
|
|
1481
|
+
type: arrT,
|
|
1482
|
+
loc,
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
let fnArg = undefinedArg ?? lowerer.lowerExpr(argNode);
|
|
1150
1486
|
// Reusable JS comparators often accept checked values. Adapt the array's
|
|
1151
1487
|
// element ABI just as other array callbacks do before sorting.
|
|
1152
1488
|
if (fnArg.type.kind === "func" &&
|
|
@@ -1171,76 +1507,19 @@ export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
|
|
|
1171
1507
|
lowerer.badType(argNode, lowerer.typeOf(argNode));
|
|
1172
1508
|
}
|
|
1173
1509
|
const arity = fnArg.type.params.length;
|
|
1174
|
-
|
|
1510
|
+
// The runtime sorts raw slots without per-move reference counting; this
|
|
1511
|
+
// beats the IR merge sort even when its comparator call becomes direct.
|
|
1512
|
+
const native = isSortValuesElement(elem, elem.kind === "union" ? lowerer.unions.get(elem.unionId)?.arms : undefined);
|
|
1513
|
+
const key = `${method}:${typeKey(elem)}:${arity}${native ? ":native" : ""}`;
|
|
1175
1514
|
let helper = lowerer.arrHofHelpers.get(key);
|
|
1176
1515
|
if (!helper) {
|
|
1177
1516
|
helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
|
|
1178
1517
|
lowerer.arrHofHelpers.set(key, helper);
|
|
1179
1518
|
const undefinedTag = elem.kind === "union" ? lowerer.armTag(elem.unionId, UNDEFINED_T) : -1;
|
|
1180
|
-
lowerer.liftedFns.push(buildArraySortFn(helper, elem, arity, copyFirst, undefinedTag >= 0 ? undefinedTag : null, loc));
|
|
1519
|
+
lowerer.liftedFns.push(buildArraySortFn(helper, elem, arity, copyFirst, undefinedTag >= 0 ? undefinedTag : null, loc, native));
|
|
1181
1520
|
}
|
|
1182
1521
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
|
|
1183
1522
|
}
|
|
1184
|
-
/** JS's default sort comparator for STRING elements, interned once:
|
|
1185
|
-
*
|
|
1186
|
-
* (a, b) => a < b ? -1 : a > b ? 1 : 0
|
|
1187
|
-
*
|
|
1188
|
-
* The dedicated UTF-16 comparison flag keeps this exact across
|
|
1189
|
-
* supplementary-plane code points and U+E000..U+FFFF, where the runtime's
|
|
1190
|
-
* ordinary code-point relational order deliberately differs. */
|
|
1191
|
-
function defaultStringCmpHelper(lowerer, loc) {
|
|
1192
|
-
const key = "sortCmpStr";
|
|
1193
|
-
const existing = lowerer.arrHofHelpers.get(key);
|
|
1194
|
-
if (existing)
|
|
1195
|
-
return existing;
|
|
1196
|
-
const name = `%arr.sortCmpStr`;
|
|
1197
|
-
lowerer.arrHofHelpers.set(key, name);
|
|
1198
|
-
const cmp = (op) => ({
|
|
1199
|
-
kind: "strCmp",
|
|
1200
|
-
op,
|
|
1201
|
-
left: varRef("a.0", STRING, loc),
|
|
1202
|
-
right: varRef("b.0", STRING, loc),
|
|
1203
|
-
utf16: true,
|
|
1204
|
-
type: BOOL,
|
|
1205
|
-
loc,
|
|
1206
|
-
});
|
|
1207
|
-
const body = [
|
|
1208
|
-
{
|
|
1209
|
-
kind: "return",
|
|
1210
|
-
value: {
|
|
1211
|
-
kind: "ternary",
|
|
1212
|
-
cond: cmp("<"),
|
|
1213
|
-
then: numLit(-1, loc),
|
|
1214
|
-
else_: {
|
|
1215
|
-
kind: "ternary",
|
|
1216
|
-
cond: cmp(">"),
|
|
1217
|
-
then: numLit(1, loc),
|
|
1218
|
-
else_: numLit(0, loc),
|
|
1219
|
-
type: F64,
|
|
1220
|
-
loc,
|
|
1221
|
-
},
|
|
1222
|
-
type: F64,
|
|
1223
|
-
loc,
|
|
1224
|
-
},
|
|
1225
|
-
loc,
|
|
1226
|
-
},
|
|
1227
|
-
];
|
|
1228
|
-
lowerer.liftedFns.push({
|
|
1229
|
-
name,
|
|
1230
|
-
params: [
|
|
1231
|
-
{ localId: "a.0", name: "a", type: STRING },
|
|
1232
|
-
{ localId: "b.0", name: "b", type: STRING },
|
|
1233
|
-
],
|
|
1234
|
-
returnType: F64,
|
|
1235
|
-
locals: [
|
|
1236
|
-
{ id: "a.0", name: "a", type: STRING, mutable: true },
|
|
1237
|
-
{ id: "b.0", name: "b", type: STRING, mutable: true },
|
|
1238
|
-
],
|
|
1239
|
-
body,
|
|
1240
|
-
loc,
|
|
1241
|
-
});
|
|
1242
|
-
return name;
|
|
1243
|
-
}
|
|
1244
1523
|
/** `d.filter(pred)` on a dyn receiver: the receiver must BE a dyn array
|
|
1245
1524
|
* (else the Node-shaped TypeError above); the predicate runs per element
|
|
1246
1525
|
* over the dyn value, and each SURVIVOR is validated-extracted into the
|