@scriptc/compiler 0.2.6 → 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 +5 -18
- 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/link-plan-core.d.ts +2 -1
- package/dist/backend/link-plan-core.js +15 -3
- package/dist/backend/link-plan-core.js.map +1 -1
- package/dist/backend/link-plan.d.ts +2 -1
- 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/call-lifetimes.d.ts +15 -3
- package/dist/backend/llvm/call-lifetimes.js +42 -18
- 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 +4 -1
- package/dist/backend/llvm/classes.js +35 -32
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +36 -3
- package/dist/backend/llvm/classes.test.js.map +1 -1
- 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 +19 -3
- package/dist/backend/llvm/constant-callbacks.js +289 -52
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +140 -3
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- 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 +34 -0
- package/dist/backend/llvm/dyn.js +189 -1
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +124 -4
- package/dist/backend/llvm/emitter.js +623 -105
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/emitter.test.js +68 -6
- 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-calls.js +64 -6
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +16 -5
- 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 +174 -25
- 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 +52 -24
- 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 +11 -0
- package/dist/backend/llvm/integer-remainder.js +91 -0
- package/dist/backend/llvm/integer-remainder.js.map +1 -1
- package/dist/backend/llvm/layouts.d.ts +2 -1
- package/dist/backend/llvm/layouts.js +3 -2
- 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-filesystem.js +3 -4
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.d.ts +5 -1
- package/dist/backend/llvm/local-array-reads.js +78 -17
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.test.js +78 -1
- 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/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/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 +69 -2
- package/dist/backend/llvm/shapes.js +259 -27
- 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/stack-callbacks.js +2 -3
- package/dist/backend/llvm/stack-callbacks.js.map +1 -1
- package/dist/backend/llvm/stack-captures.d.ts +3 -1
- package/dist/backend/llvm/stack-captures.js +5 -3
- package/dist/backend/llvm/stack-captures.js.map +1 -1
- 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 +41 -4
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- 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/may-throw.js +3 -0
- 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 +3 -2
- package/dist/backend/native/contracts.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +2 -1
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +5 -0
- package/dist/backend/native-codegen.js +4 -0
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +23 -0
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +3 -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 +3 -1
- package/dist/backend/native-tools.js +0 -1
- 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 +15 -4
- package/dist/backend/runtime-pack-core.js +23 -12
- 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 +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 +115 -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 +2 -2
- package/dist/executable/executable-cache.js +7 -4
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/executable-cache.test.js +20 -0
- package/dist/executable/executable-cache.test.js.map +1 -1
- 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/builtins/errors.js +17 -2
- package/dist/frontend/lowering/builtins/errors.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/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 +4 -0
- package/dist/frontend/lowering/class-assertions.js +12 -4
- package/dist/frontend/lowering/class-assertions.js.map +1 -1
- 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-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 +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +363 -49
- 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/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/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 +138 -32
- 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/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 +1 -0
- 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 +162 -121
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +2 -0
- package/dist/frontend/lowering/lower-classes.js +45 -43
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +9 -2
- package/dist/frontend/lowering/lower-exprs.js +390 -157
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +32 -19
- 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-modules.js +10 -2
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +46 -58
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +37 -0
- package/dist/frontend/lowering/lowerer.js +283 -18
- 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/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.js +3 -0
- 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/program.d.ts +38 -2
- package/dist/frontend/program.js +440 -59
- 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/type-mapper.d.ts +1 -1
- package/dist/frontend/type-mapper.js +89 -14
- 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/index.js +25 -9
- 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-signatures.js +2 -3
- 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 +78 -15
- package/dist/ir/ir.js +20 -6
- package/dist/ir/ir.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 +118 -20
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +269 -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/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.map +1 -1
- package/dist/native/compiler.test.js +2 -2
- package/dist/native/library.d.ts +2 -1
- package/dist/native/library.js.map +1 -1
- package/dist/native/prepare.js +27 -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/package.json +20 -20
- package/surface-manifest.json +8 -2
|
@@ -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";
|
|
@@ -70,9 +73,19 @@ export function lowerArrayHofCall(lowerer, call, access, method, elem) {
|
|
|
70
73
|
const outElem = method === "filter"
|
|
71
74
|
? filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter)
|
|
72
75
|
: callbackArrayElement(lowerer, call, fnRet);
|
|
73
|
-
|
|
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);
|
|
74
81
|
const resultType = method === "map" || method === "filter" ? arrayOf(outElem) : VOID;
|
|
75
|
-
return {
|
|
82
|
+
return {
|
|
83
|
+
kind: "call",
|
|
84
|
+
callee: helper,
|
|
85
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
86
|
+
type: resultType,
|
|
87
|
+
loc,
|
|
88
|
+
};
|
|
76
89
|
}
|
|
77
90
|
/** The checker-selected element of a filter result, with the same trust
|
|
78
91
|
* boundary as the historical narrowing filter: an inferred inline type
|
|
@@ -112,13 +125,15 @@ function filterResultElem(lowerer, call, argNode, elem, valueT, booleanFilter) {
|
|
|
112
125
|
`unchecked assertion nothing validates at runtime — ${annotateEscape})`);
|
|
113
126
|
}
|
|
114
127
|
}
|
|
115
|
-
|
|
128
|
+
const classRefinement = !booleanFilter && outElem.kind === "object" && canAssertClassValue(lowerer, valueT, outElem);
|
|
129
|
+
if (!classRefinement &&
|
|
130
|
+
(valueT.kind !== "union" || lowerer.armTag(valueT.unionId, outElem) < 0)) {
|
|
116
131
|
const multiArm = outElem.kind === "union";
|
|
117
132
|
lowerer.unsupported("SC1090", call, `'.filter' narrowing '${lowerer.fmt(elem)}' elements to ` +
|
|
118
133
|
`${multiArm ? `the multi-arm '${lowerer.fmt(outElem)}'` : `'${lowerer.fmt(outElem)}'`} ` +
|
|
119
134
|
`(${multiArm ? "only a SINGLE arm re-tags" : "only a single runtime arm re-tags"} — ${annotateEscape})`);
|
|
120
135
|
}
|
|
121
|
-
if (booleanFilter) {
|
|
136
|
+
if (booleanFilter && valueT.kind === "union") {
|
|
122
137
|
const arms = lowerer.unions.get(valueT.unionId)?.arms ?? [];
|
|
123
138
|
if (arms.some((arm) => !typeEquals(arm, outElem) && !isUnitType(arm))) {
|
|
124
139
|
lowerer.unsupported("SC1090", call, `'.filter(Boolean)' narrowing '${lowerer.fmt(elem)}' to '${lowerer.fmt(outElem)}' ` +
|
|
@@ -194,18 +209,193 @@ function filterCond(call, fnRet, loc) {
|
|
|
194
209
|
// the runtime's kind-aware ToBoolean.
|
|
195
210
|
return { kind: "toBool", operand: call, type: BOOL, loc };
|
|
196
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
|
+
}
|
|
197
386
|
/** Interned synthetic loop function for one (method, elem, fnRet, arity)
|
|
198
387
|
* combo. Named `%arr.<method>.<n>` ('%' keeps it out of the user
|
|
199
388
|
* namespace); rides `liftedFns` into the module like a lifted lambda (it
|
|
200
389
|
* is a plain function — no captures). */
|
|
201
|
-
function arrayHofHelper(lowerer, method, elem, fnRet, arity, loc, outElem = fnRet) {
|
|
202
|
-
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" : ""}`;
|
|
203
392
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
204
393
|
if (existing)
|
|
205
394
|
return existing;
|
|
206
395
|
const name = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
|
|
207
396
|
lowerer.arrHofHelpers.set(key, name);
|
|
208
|
-
|
|
397
|
+
const fn = buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT);
|
|
398
|
+
lowerer.liftedFns.push(fastT ? withFastCallback(fn, fastT, elem) : fn);
|
|
209
399
|
return name;
|
|
210
400
|
}
|
|
211
401
|
/** The TS 5.2+ callable-union array rule: a `T[] | U[]` receiver exposes
|
|
@@ -363,7 +553,7 @@ function arrayUnionHofHelper(lowerer, method, receiverT, arrays, callbackT, arit
|
|
|
363
553
|
* `arity` is the callback's declared parameter count (1–3): the loop
|
|
364
554
|
* passes the index and the receiver itself after the element when the
|
|
365
555
|
* callback names them, exactly the arguments JS supplies. */
|
|
366
|
-
function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem) {
|
|
556
|
+
function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem, fastT = null) {
|
|
367
557
|
const arrT = arrayOf(elem);
|
|
368
558
|
const valueT = arrayValueType(lowerer, elem);
|
|
369
559
|
const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
|
|
@@ -428,22 +618,111 @@ function buildArrayHofFn(lowerer, name, method, elem, fnRet, arity, loc, outElem
|
|
|
428
618
|
{ kind: "return", value: varRef("out.0", outT, loc), loc },
|
|
429
619
|
];
|
|
430
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
|
+
}
|
|
431
705
|
else if (method === "filter") {
|
|
432
706
|
const outT = arrayOf(outElem);
|
|
433
707
|
locals.push({ id: "out.0", name: "out", type: outT, mutable: false }, { id: "v.0", name: "v", type: valueT, mutable: false });
|
|
434
708
|
returnType = outT;
|
|
709
|
+
const classView = !typeEquals(outElem, elem) && outElem.kind === "object"
|
|
710
|
+
? checkedClassAssertion(lowerer, varRef("v.0", valueT, loc), outElem, loc)
|
|
711
|
+
: null;
|
|
435
712
|
const retained = typeEquals(outElem, elem)
|
|
436
713
|
? varRef("v.0", valueT, loc)
|
|
437
|
-
:
|
|
438
|
-
?
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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);
|
|
447
726
|
body = [
|
|
448
727
|
{
|
|
449
728
|
kind: "varDecl",
|
|
@@ -539,13 +818,15 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
|
|
|
539
818
|
method === "every" ||
|
|
540
819
|
method === "findIndex" ||
|
|
541
820
|
method === "findLastIndex") {
|
|
821
|
+
const fast = lowerFastCallback(lowerer, argNode, [arrayValueType(lowerer, elem)], 0, elem, arrT, { fnArg, arity }, bindUntyped);
|
|
822
|
+
const fastT = fast?.type ?? null;
|
|
542
823
|
const helper = method === "findIndex" || method === "findLastIndex"
|
|
543
|
-
? findIndexHelper(lowerer, elem, fnRet, arity, last, loc)
|
|
544
|
-
: 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);
|
|
545
826
|
return {
|
|
546
827
|
kind: "call",
|
|
547
828
|
callee: helper,
|
|
548
|
-
args: [receiver, fnArg],
|
|
829
|
+
args: [receiver, fnArg, ...(fast ? [fast] : [])],
|
|
549
830
|
type: method === "findIndex" || method === "findLastIndex" ? F64 : BOOL,
|
|
550
831
|
loc,
|
|
551
832
|
};
|
|
@@ -581,10 +862,12 @@ export function lowerArrayFindLikeCall(lowerer, call, access, method, elem, bind
|
|
|
581
862
|
lowerer.unsupported("SC1090", call, `'.${method}' result narrowing without a predicate over its element`);
|
|
582
863
|
}
|
|
583
864
|
retag = lowerer.narrowedRetagHelper(call, valueT.unionId, resultT.unionId, loc);
|
|
584
|
-
|
|
865
|
+
const present = lowerer.stripUndefinedArm(resultT);
|
|
866
|
+
if (retag === null &&
|
|
867
|
+
!(present.kind === "object" && canAssertClassValue(lowerer, valueT, present)))
|
|
585
868
|
lowerer.unsupported("SC1090", call, `'.${method}' narrowing to an incompatible result layout`);
|
|
586
869
|
}
|
|
587
|
-
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));
|
|
588
871
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: resultT, loc };
|
|
589
872
|
}
|
|
590
873
|
/** ToBoolean of a predicate result inside a synthesized HOF helper — the
|
|
@@ -603,9 +886,9 @@ function predicateToBoolean(e) {
|
|
|
603
886
|
* for (i = 0; i < n; i++) { v = a[i]; if (f(v)) return <v as result arm>; }
|
|
604
887
|
* return <undefined arm>;
|
|
605
888
|
*/
|
|
606
|
-
function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag) {
|
|
889
|
+
function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, retag, site = "") {
|
|
607
890
|
const method = last ? "findLast" : "find";
|
|
608
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}`;
|
|
891
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(resultT)}:${typeKey(fnRet)}:${arity}${site}`;
|
|
609
892
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
610
893
|
if (existing)
|
|
611
894
|
return existing;
|
|
@@ -615,8 +898,14 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
|
|
|
615
898
|
const fnT = funcOf([arrayValueType(lowerer, elem), F64, arrT].slice(0, arity), fnRet);
|
|
616
899
|
const valueT = arrayValueType(lowerer, elem);
|
|
617
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;
|
|
618
907
|
const found = retag === null
|
|
619
|
-
? lowerer.coerceToExpected(v, resultT)
|
|
908
|
+
? lowerer.coerceToExpected(classView ?? v, resultT)
|
|
620
909
|
: { kind: "call", callee: retag, args: [v], type: resultT, loc };
|
|
621
910
|
const miss = {
|
|
622
911
|
kind: "unionWrap",
|
|
@@ -668,9 +957,9 @@ function findHelper(lowerer, elem, resultT, undefTag, fnRet, arity, last, loc, r
|
|
|
668
957
|
*
|
|
669
958
|
* n = a.length; for (...) if (f(a[i], i, a)) return i; return -1;
|
|
670
959
|
*/
|
|
671
|
-
function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
960
|
+
function findIndexHelper(lowerer, elem, fnRet, arity, last, loc, site = "", fastT = null) {
|
|
672
961
|
const method = last ? "findLastIndex" : "findIndex";
|
|
673
|
-
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}`;
|
|
962
|
+
const key = `${method}:${typeKey(elem)}:${typeKey(fnRet)}:${arity}${site}${fastT ? ":split" : ""}`;
|
|
674
963
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
675
964
|
if (existing)
|
|
676
965
|
return existing;
|
|
@@ -695,14 +984,14 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
|
695
984
|
loop,
|
|
696
985
|
{ kind: "return", value: { kind: "numLit", value: -1, type: F64, loc }, loc },
|
|
697
986
|
];
|
|
698
|
-
lowerer.liftedFns.push({
|
|
987
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
699
988
|
name,
|
|
700
989
|
params: arrayCallbackParams(arrT, fnT),
|
|
701
990
|
returnType: F64,
|
|
702
991
|
locals: [...arrayCallbackLocals(arrT, fnT)],
|
|
703
992
|
body,
|
|
704
993
|
loc,
|
|
705
|
-
});
|
|
994
|
+
}, fastT, elem));
|
|
706
995
|
return name;
|
|
707
996
|
}
|
|
708
997
|
/** The some/every loops — short-circuit early returns, JS-exact:
|
|
@@ -710,8 +999,8 @@ function findIndexHelper(lowerer, elem, fnRet, arity, last, loc) {
|
|
|
710
999
|
* some: n = a.length; for (...) if (f(a[i])) return true; return false;
|
|
711
1000
|
* every: n = a.length; for (...) if (!f(a[i])) return false; return true;
|
|
712
1001
|
*/
|
|
713
|
-
function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
|
|
714
|
-
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" : ""}`;
|
|
715
1004
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
716
1005
|
if (existing)
|
|
717
1006
|
return existing;
|
|
@@ -743,14 +1032,14 @@ function someEveryHelper(lowerer, method, elem, fnRet, arity, loc) {
|
|
|
743
1032
|
]),
|
|
744
1033
|
{ kind: "return", value: boolLit(method !== "some", loc), loc },
|
|
745
1034
|
];
|
|
746
|
-
lowerer.liftedFns.push({
|
|
1035
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
747
1036
|
name,
|
|
748
1037
|
params: arrayCallbackParams(arrT, fnT),
|
|
749
1038
|
returnType: BOOL,
|
|
750
1039
|
locals: [...arrayCallbackLocals(arrT, fnT)],
|
|
751
1040
|
body,
|
|
752
1041
|
loc,
|
|
753
|
-
});
|
|
1042
|
+
}, fastT, elem));
|
|
754
1043
|
return name;
|
|
755
1044
|
}
|
|
756
1045
|
/** `a.flatMap(f)` — map plus a one-level flatten. A callback returning
|
|
@@ -794,11 +1083,28 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
|
|
|
794
1083
|
lowerer.badType(call, lowerer.typeOf(call));
|
|
795
1084
|
requireProducedArrayElement(lowerer, call, "'.flatMap()'", fnRet);
|
|
796
1085
|
const outElem = callbackArrayElement(lowerer, call, fnRet);
|
|
797
|
-
const
|
|
798
|
-
|
|
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
|
+
};
|
|
799
1095
|
}
|
|
800
|
-
const
|
|
801
|
-
|
|
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
|
+
};
|
|
802
1108
|
}
|
|
803
1109
|
/** The flatMap loop (array-returning callback), from existing IR nodes:
|
|
804
1110
|
*
|
|
@@ -809,8 +1115,8 @@ export function lowerArrayFlatMapCall(lowerer, call, access, elem) {
|
|
|
809
1115
|
* }
|
|
810
1116
|
* return out;
|
|
811
1117
|
*/
|
|
812
|
-
function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
813
|
-
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" : ""}`;
|
|
814
1120
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
815
1121
|
if (existing)
|
|
816
1122
|
return existing;
|
|
@@ -909,7 +1215,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
|
909
1215
|
]),
|
|
910
1216
|
{ kind: "return", value: varRef("out.0", fnRet, loc), loc },
|
|
911
1217
|
];
|
|
912
|
-
lowerer.liftedFns.push({
|
|
1218
|
+
lowerer.liftedFns.push(withFastCallback({
|
|
913
1219
|
name,
|
|
914
1220
|
params: arrayCallbackParams(arrT, fnT),
|
|
915
1221
|
returnType: fnRet,
|
|
@@ -923,7 +1229,7 @@ function flatMapHelper(lowerer, elem, fnRet, arity, loc) {
|
|
|
923
1229
|
],
|
|
924
1230
|
body,
|
|
925
1231
|
loc,
|
|
926
|
-
});
|
|
1232
|
+
}, fastT, elem));
|
|
927
1233
|
return name;
|
|
928
1234
|
}
|
|
929
1235
|
/** `a.reduce(f)` / `a.reduce(f, init)` and reduceRight — both declared
|
|
@@ -944,10 +1250,15 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
|
|
|
944
1250
|
if (accT.kind === "void" || accT.kind === "func")
|
|
945
1251
|
lowerer.badType(call, lowerer.typeOf(call));
|
|
946
1252
|
const { fnArg, arity } = lowerArrayCallback(lowerer, argNode, [accT, arrayValueType(lowerer, elem)], arrT, false, accT);
|
|
947
|
-
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);
|
|
948
1255
|
const args = [receiver, fnArg];
|
|
949
1256
|
if (hasInit)
|
|
950
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);
|
|
951
1262
|
return { kind: "call", callee: helper, args, type: accT, loc };
|
|
952
1263
|
}
|
|
953
1264
|
/** The reduce/reduceRight loops, from existing IR nodes:
|
|
@@ -960,8 +1271,8 @@ export function lowerArrayReduceCall(lowerer, call, access, method, elem) {
|
|
|
960
1271
|
* reduce walks 0→n-1, reduceRight n-1→0; the seed without an initial
|
|
961
1272
|
* value is a[0] / a[n-1] and the loop starts one past it. The empty-array
|
|
962
1273
|
* TypeError message is Node's, byte for byte. */
|
|
963
|
-
function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
|
|
964
|
-
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" : ""}`;
|
|
965
1276
|
const existing = lowerer.arrHofHelpers.get(key);
|
|
966
1277
|
if (existing)
|
|
967
1278
|
return existing;
|
|
@@ -1101,7 +1412,7 @@ function reduceHelper(lowerer, method, elem, accT, fnRet, arity, hasInit, loc) {
|
|
|
1101
1412
|
loop,
|
|
1102
1413
|
{ kind: "return", value: varRef("acc.0", accT, loc), loc },
|
|
1103
1414
|
];
|
|
1104
|
-
lowerer.liftedFns.push({ name, params, returnType: accT, locals, body, loc });
|
|
1415
|
+
lowerer.liftedFns.push(withFastCallback({ name, params, returnType: accT, locals, body, loc }, fastT, elem));
|
|
1105
1416
|
return name;
|
|
1106
1417
|
}
|
|
1107
1418
|
/** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic
|
|
@@ -1196,13 +1507,16 @@ export function lowerArraySortCall(lowerer, call, access, elem, arrT) {
|
|
|
1196
1507
|
lowerer.badType(argNode, lowerer.typeOf(argNode));
|
|
1197
1508
|
}
|
|
1198
1509
|
const arity = fnArg.type.params.length;
|
|
1199
|
-
|
|
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" : ""}`;
|
|
1200
1514
|
let helper = lowerer.arrHofHelpers.get(key);
|
|
1201
1515
|
if (!helper) {
|
|
1202
1516
|
helper = `%arr.${method}.${lowerer.arrHofHelpers.size}`;
|
|
1203
1517
|
lowerer.arrHofHelpers.set(key, helper);
|
|
1204
1518
|
const undefinedTag = elem.kind === "union" ? lowerer.armTag(elem.unionId, UNDEFINED_T) : -1;
|
|
1205
|
-
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));
|
|
1206
1520
|
}
|
|
1207
1521
|
return { kind: "call", callee: helper, args: [receiver, fnArg], type: arrT, loc };
|
|
1208
1522
|
}
|