@scriptc/compiler 0.0.35 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ambient/scriptc-node-fallback.d.ts +14 -11
- package/ambient/scriptc-overrides.d.ts +0 -7
- package/ambient/scriptc.d.ts +1 -1
- package/dist/backend/build-cache.d.ts +44 -0
- package/dist/backend/build-cache.js +241 -0
- package/dist/backend/build-cache.js.map +1 -0
- package/dist/backend/{emission/emit-async.d.ts → c/async.d.ts} +21 -30
- package/dist/backend/{emission/emit-async.js → c/async.js} +270 -286
- package/dist/backend/c/async.js.map +1 -0
- package/dist/backend/{emission/emitter.d.ts → c/c-emitter.d.ts} +6 -23
- package/dist/backend/{emission/emitter.js → c/c-emitter.js} +53 -107
- package/dist/backend/c/c-emitter.js.map +1 -0
- package/dist/backend/c/exprs.d.ts +8 -0
- package/dist/backend/c/exprs.js +7937 -0
- package/dist/backend/c/exprs.js.map +1 -0
- package/dist/backend/{emission/emit-island.d.ts → c/island.d.ts} +5 -5
- package/dist/backend/{emission/emit-island.js → c/island.js} +24 -22
- package/dist/backend/c/island.js.map +1 -0
- package/dist/backend/{emission → c}/may-throw.d.ts +1 -1
- package/dist/backend/{emission → c}/may-throw.js +4 -1
- package/dist/backend/c/may-throw.js.map +1 -0
- package/dist/backend/{emission/emit-shapes.d.ts → c/shapes.d.ts} +19 -19
- package/dist/backend/{emission/emit-shapes.js → c/shapes.js} +78 -87
- package/dist/backend/c/shapes.js.map +1 -0
- package/dist/backend/{emission/emit-stmts.d.ts → c/stmts.d.ts} +12 -12
- package/dist/backend/{emission/emit-stmts.js → c/stmts.js} +395 -343
- package/dist/backend/c/stmts.js.map +1 -0
- package/dist/backend/{emission/emit-types.d.ts → c/types.d.ts} +1 -1
- package/dist/backend/{emission/emit-types.js → c/types.js} +42 -286
- package/dist/backend/c/types.js.map +1 -0
- package/dist/backend/c/types.test.js +25 -0
- package/dist/backend/c/types.test.js.map +1 -0
- package/dist/backend/{emission/emit-walkers.d.ts → c/walkers.d.ts} +19 -41
- package/dist/backend/{emission/emit-walkers.js → c/walkers.js} +242 -304
- package/dist/backend/c/walkers.js.map +1 -0
- package/dist/backend/external-c.d.ts +33 -0
- package/dist/backend/external-c.js +51 -0
- package/dist/backend/external-c.js.map +1 -0
- package/dist/backend/ffi-callbacks.d.ts +1 -1
- package/dist/backend/ffi-callbacks.js +4 -3
- package/dist/backend/ffi-callbacks.js.map +1 -1
- package/dist/backend/{library-identity.d.ts → library-identity-markers.d.ts} +0 -4
- package/dist/backend/{library-identity.js → library-identity-markers.js} +10 -9
- package/dist/backend/library-identity-markers.js.map +1 -0
- package/dist/backend/link-plan.d.ts +37 -0
- package/dist/backend/link-plan.js +26 -0
- package/dist/backend/link-plan.js.map +1 -0
- package/dist/backend/linker.d.ts +22 -0
- package/dist/backend/linker.js +236 -0
- package/dist/backend/linker.js.map +1 -0
- package/dist/backend/llvm/blocks.d.ts +4 -0
- package/dist/backend/llvm/blocks.js +29 -0
- package/dist/backend/llvm/blocks.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +2 -19
- package/dist/backend/llvm/classes.js +20 -52
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +4 -0
- package/dist/backend/llvm/common.js +27 -0
- package/dist/backend/llvm/common.js.map +1 -0
- package/dist/backend/llvm/dyn.d.ts +3 -8
- package/dist/backend/llvm/dyn.js +159 -224
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +4 -1
- package/dist/backend/llvm/emitter.js +548 -9988
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.d.ts +4 -0
- package/dist/backend/llvm/expr-async.js +726 -0
- package/dist/backend/llvm/expr-async.js.map +1 -0
- package/dist/backend/llvm/expr-bytes.d.ts +13 -0
- package/dist/backend/llvm/expr-bytes.js +456 -0
- package/dist/backend/llvm/expr-bytes.js.map +1 -0
- package/dist/backend/llvm/expr-callbacks.d.ts +22 -0
- package/dist/backend/llvm/expr-callbacks.js +520 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -0
- package/dist/backend/llvm/expr-calls.d.ts +2 -0
- package/dist/backend/llvm/expr-calls.js +618 -0
- package/dist/backend/llvm/expr-calls.js.map +1 -0
- package/dist/backend/llvm/expr-containers.d.ts +25 -0
- package/dist/backend/llvm/expr-containers.js +637 -0
- package/dist/backend/llvm/expr-containers.js.map +1 -0
- package/dist/backend/llvm/expr-context.d.ts +255 -0
- package/dist/backend/llvm/expr-context.js +2 -0
- package/dist/backend/llvm/expr-context.js.map +1 -0
- package/dist/backend/llvm/expr-control.d.ts +2 -0
- package/dist/backend/llvm/expr-control.js +473 -0
- package/dist/backend/llvm/expr-control.js.map +1 -0
- package/dist/backend/llvm/expr-dispatch.d.ts +4 -0
- package/dist/backend/llvm/expr-dispatch.js +153 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -0
- package/dist/backend/llvm/expr-dynamic.d.ts +2 -0
- package/dist/backend/llvm/expr-dynamic.js +810 -0
- package/dist/backend/llvm/expr-dynamic.js.map +1 -0
- package/dist/backend/llvm/expr-island.d.ts +15 -0
- package/dist/backend/llvm/expr-island.js +690 -0
- package/dist/backend/llvm/expr-island.js.map +1 -0
- package/dist/backend/llvm/expr-primitives.d.ts +6 -0
- package/dist/backend/llvm/expr-primitives.js +642 -0
- package/dist/backend/llvm/expr-primitives.js.map +1 -0
- package/dist/backend/llvm/expr-records.d.ts +9 -0
- package/dist/backend/llvm/expr-records.js +299 -0
- package/dist/backend/llvm/expr-records.js.map +1 -0
- package/dist/backend/llvm/expr-stream-bridges.d.ts +13 -0
- package/dist/backend/llvm/expr-stream-bridges.js +420 -0
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -0
- package/dist/backend/llvm/expr-stream-callbacks.d.ts +12 -0
- package/dist/backend/llvm/expr-stream-callbacks.js +360 -0
- package/dist/backend/llvm/expr-stream-callbacks.js.map +1 -0
- package/dist/backend/llvm/lib-dispatch.d.ts +5 -0
- package/dist/backend/llvm/lib-dispatch.js +267 -0
- package/dist/backend/llvm/lib-dispatch.js.map +1 -0
- package/dist/backend/llvm/lib-filesystem.d.ts +6 -0
- package/dist/backend/llvm/lib-filesystem.js +594 -0
- package/dist/backend/llvm/lib-filesystem.js.map +1 -0
- package/dist/backend/llvm/lib-network.d.ts +2 -0
- package/dist/backend/llvm/lib-network.js +429 -0
- package/dist/backend/llvm/lib-network.js.map +1 -0
- package/dist/backend/llvm/lib-process.d.ts +5 -0
- package/dist/backend/llvm/lib-process.js +585 -0
- package/dist/backend/llvm/lib-process.js.map +1 -0
- package/dist/backend/llvm/lib-shared.d.ts +6 -0
- package/dist/backend/llvm/lib-shared.js +687 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -0
- package/dist/backend/llvm/lib-stream.d.ts +2 -0
- package/dist/backend/llvm/lib-stream.js +470 -0
- package/dist/backend/llvm/lib-stream.js.map +1 -0
- package/dist/backend/llvm/shapes.d.ts +12 -2
- package/dist/backend/llvm/shapes.js +66 -307
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +52 -0
- package/dist/backend/llvm/shapes.test.js.map +1 -0
- package/dist/backend/llvm/unsupported.d.ts +1 -1
- package/dist/backend/llvm/walkers.d.ts +2 -3
- package/dist/backend/llvm/walkers.js +195 -222
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +45 -0
- package/dist/backend/native-codegen.js +275 -0
- package/dist/backend/native-codegen.js.map +1 -0
- package/dist/backend/native-codegen.test.js +226 -0
- package/dist/backend/native-codegen.test.js.map +1 -0
- package/dist/backend/native-link-info.d.ts +96 -0
- package/dist/backend/native-link-info.js +243 -0
- package/dist/backend/native-link-info.js.map +1 -0
- package/dist/backend/native-link-info.test.d.ts +1 -0
- package/dist/backend/native-link-info.test.js +134 -0
- package/dist/backend/native-link-info.test.js.map +1 -0
- package/dist/backend/{cc.d.ts → native-toolchain.d.ts} +54 -34
- package/dist/backend/{cc.js → native-toolchain.js} +231 -810
- package/dist/backend/native-toolchain.js.map +1 -0
- package/dist/backend/native-toolchain.test.d.ts +1 -0
- package/dist/backend/{cc-cache.test.js → native-toolchain.test.js} +219 -7
- package/dist/backend/native-toolchain.test.js.map +1 -0
- package/dist/backend/object-localize.js +1 -1
- package/dist/backend/runtime-abi.d.ts +10 -0
- package/dist/backend/runtime-abi.js +11 -0
- package/dist/backend/runtime-abi.js.map +1 -0
- package/dist/backend/runtime-pack-targets.test.d.ts +1 -0
- package/dist/backend/runtime-pack-targets.test.js +54 -0
- package/dist/backend/runtime-pack-targets.test.js.map +1 -0
- package/dist/backend/runtime-pack.d.ts +112 -0
- package/dist/backend/runtime-pack.js +305 -0
- package/dist/backend/runtime-pack.js.map +1 -0
- package/dist/backend/runtime-pack.test.d.ts +1 -0
- package/dist/backend/runtime-pack.test.js +473 -0
- package/dist/backend/runtime-pack.test.js.map +1 -0
- package/dist/backend/targets.d.ts +76 -0
- package/dist/backend/targets.js +262 -0
- package/dist/backend/targets.js.map +1 -0
- package/dist/backend/targets.test.d.ts +1 -0
- package/dist/backend/targets.test.js +41 -0
- package/dist/backend/targets.test.js.map +1 -0
- package/dist/backend/vendor-archives.d.ts +41 -0
- package/dist/backend/vendor-archives.js +462 -0
- package/dist/backend/vendor-archives.js.map +1 -0
- package/dist/compat/fetch-profile.d.ts +0 -1
- package/dist/compat/fetch-profile.js +0 -1
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/coverage/report.js +3 -3
- package/dist/coverage/report.js.map +1 -1
- package/dist/coverage/surface-manifest.js +35 -33
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +11 -12
- package/dist/diagnostics/diagnostic.js +19 -17
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/diagnostics/render.d.ts +1 -1
- package/dist/diagnostics/render.js +1 -1
- package/dist/diagnostics/render.js.map +1 -1
- package/dist/errors.d.ts +5 -0
- package/dist/errors.js +9 -0
- package/dist/errors.js.map +1 -0
- package/dist/executable/{early-cache.d.ts → executable-cache.d.ts} +2 -2
- package/dist/executable/{early-cache.js → executable-cache.js} +36 -98
- package/dist/executable/executable-cache.js.map +1 -0
- package/dist/executable/executable-cache.test.d.ts +1 -0
- package/dist/executable/{early-cache.test.js → executable-cache.test.js} +3 -3
- package/dist/executable/executable-cache.test.js.map +1 -0
- package/dist/ffi/{profile.js → ffi-manifest.js} +1 -1
- package/dist/ffi/ffi-manifest.js.map +1 -0
- package/dist/frontend/builtin-modules.d.ts +21 -0
- package/dist/frontend/builtin-modules.js +82 -0
- package/dist/frontend/builtin-modules.js.map +1 -0
- package/dist/frontend/cjs-lexer.d.ts +7 -0
- package/dist/frontend/cjs-lexer.js +15 -17
- package/dist/frontend/cjs-lexer.js.map +1 -1
- package/dist/frontend/dts-paths.d.ts +26 -0
- package/dist/frontend/dts-paths.js +41 -0
- package/dist/frontend/dts-paths.js.map +1 -0
- package/dist/frontend/input-tracker.d.ts +0 -2
- package/dist/frontend/input-tracker.js +1 -4
- package/dist/frontend/input-tracker.js.map +1 -1
- package/dist/frontend/lib-contract.d.ts +1 -5
- package/dist/frontend/lib-contract.js +1 -1
- package/dist/frontend/lib-contract.js.map +1 -1
- package/dist/frontend/lib-exports.d.ts +1 -1
- package/dist/frontend/lowering/array-values.d.ts +8 -0
- package/dist/frontend/lowering/array-values.js +60 -0
- package/dist/frontend/lowering/array-values.js.map +1 -0
- package/dist/frontend/lowering/call-position.d.ts +4 -0
- package/dist/frontend/lowering/call-position.js +7 -0
- package/dist/frontend/lowering/call-position.js.map +1 -0
- package/dist/frontend/lowering/callback-arg.d.ts +20 -0
- package/dist/frontend/lowering/callback-arg.js +44 -0
- package/dist/frontend/lowering/callback-arg.js.map +1 -0
- package/dist/frontend/lowering/lib-boundary.d.ts +1 -1
- package/dist/frontend/lowering/lib-boundary.js +34 -34
- package/dist/frontend/lowering/lib-boundary.js.map +1 -1
- package/dist/frontend/lowering/lower-array-sort.d.ts +22 -0
- package/dist/frontend/lowering/lower-array-sort.js +619 -0
- package/dist/frontend/lowering/lower-array-sort.js.map +1 -0
- package/dist/frontend/lowering/lower-assert.d.ts +3 -3
- package/dist/frontend/lowering/lower-assert.js +214 -241
- package/dist/frontend/lowering/lower-assert.js.map +1 -1
- package/dist/frontend/lowering/lower-builtins.d.ts +74 -146
- package/dist/frontend/lowering/lower-builtins.js +1285 -1233
- package/dist/frontend/lowering/lower-builtins.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.d.ts +59 -192
- package/dist/frontend/lowering/lower-calls.js +1644 -1506
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.d.ts +62 -125
- package/dist/frontend/lowering/lower-classes.js +832 -866
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-comptime.d.ts +5 -12
- package/dist/frontend/lowering/lower-comptime.js +32 -31
- package/dist/frontend/lowering/lower-comptime.js.map +1 -1
- package/dist/frontend/lowering/lower-containers.d.ts +35 -135
- package/dist/frontend/lowering/lower-containers.js +1984 -2227
- package/dist/frontend/lowering/lower-containers.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.d.ts +3 -7
- package/dist/frontend/lowering/lower-dgram.js +97 -111
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-enums.d.ts +4 -4
- package/dist/frontend/lowering/lower-enums.js +30 -30
- package/dist/frontend/lowering/lower-enums.js.map +1 -1
- package/dist/frontend/lowering/{lower-emitter.d.ts → lower-event-emitter.d.ts} +7 -18
- package/dist/frontend/lowering/{lower-emitter.js → lower-event-emitter.js} +172 -174
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -0
- package/dist/frontend/lowering/lower-expando.d.ts +5 -5
- package/dist/frontend/lowering/lower-expando.js +40 -40
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +60 -264
- package/dist/frontend/lowering/lower-exprs.js +2361 -1765
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-generators.d.ts +6 -6
- package/dist/frontend/lowering/lower-generators.js +73 -72
- package/dist/frontend/lowering/lower-generators.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.d.ts +5 -17
- package/dist/frontend/lowering/lower-inspect.js +273 -261
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-island.d.ts +39 -49
- package/dist/frontend/lowering/lower-island.js +447 -513
- package/dist/frontend/lowering/lower-island.js.map +1 -1
- package/dist/frontend/lowering/lower-mixins.d.ts +7 -10
- package/dist/frontend/lowering/lower-mixins.js +85 -85
- package/dist/frontend/lowering/lower-mixins.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.d.ts +12 -18
- package/dist/frontend/lowering/lower-modules.js +284 -283
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-namespaces.d.ts +23 -49
- package/dist/frontend/lowering/lower-namespaces.js +123 -115
- package/dist/frontend/lowering/lower-namespaces.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +18 -25
- package/dist/frontend/lowering/lower-server.js +909 -899
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +30 -149
- package/dist/frontend/lowering/lower-stmts.js +1463 -1285
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +12 -12
- package/dist/frontend/lowering/lower-stream.js +300 -301
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.d.ts +5 -5
- package/dist/frontend/lowering/lower-test.js +82 -82
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +134 -22
- package/dist/frontend/lowering/lowerer.js +1277 -126
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/pairs-snapshot.d.ts +11 -0
- package/dist/frontend/lowering/pairs-snapshot.js +85 -0
- package/dist/frontend/lowering/pairs-snapshot.js.map +1 -0
- package/dist/frontend/lowering/static-this.d.ts +6 -0
- package/dist/frontend/lowering/static-this.js +24 -0
- package/dist/frontend/lowering/static-this.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +24 -35
- package/dist/frontend/lowering/surfaces.js +78 -66
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/npm-static-rewrite.js +6 -28
- package/dist/frontend/npm-static-rewrite.js.map +1 -1
- package/dist/frontend/npm-static.d.ts +0 -10
- package/dist/frontend/npm-static.js +4 -7
- package/dist/frontend/npm-static.js.map +1 -1
- package/dist/frontend/npm.d.ts +0 -24
- package/dist/frontend/npm.js +11 -85
- package/dist/frontend/npm.js.map +1 -1
- package/dist/frontend/program.d.ts +3 -1
- package/dist/frontend/program.js +9 -4
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/provenance-registry.d.ts +0 -2
- package/dist/frontend/provenance-registry.js +0 -10
- package/dist/frontend/provenance-registry.js.map +1 -1
- package/dist/frontend/provenance.js +4 -7
- package/dist/frontend/provenance.js.map +1 -1
- package/dist/frontend/resolve.d.ts +7 -2
- package/dist/frontend/resolve.js +12 -17
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/resolve.test.d.ts +1 -0
- package/dist/frontend/resolve.test.js +29 -0
- package/dist/frontend/resolve.test.js.map +1 -0
- package/dist/frontend/ts7/adapter.d.ts +2 -2
- package/dist/frontend/ts7/adapter.js +1 -1
- package/dist/frontend/ts7/adapter.js.map +1 -1
- package/dist/frontend/ts7/checker.js +2 -36
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/enums.js +2 -1
- package/dist/frontend/ts7/enums.js.map +1 -1
- package/dist/frontend/ts7/{program.js → program-adapter.js} +7 -6
- package/dist/frontend/ts7/program-adapter.js.map +1 -0
- package/dist/frontend/ts7/world-check.d.ts +1 -3
- package/dist/frontend/ts7/world-check.js +3 -1
- package/dist/frontend/ts7/world-check.js.map +1 -1
- package/dist/frontend/tsc-codes.d.ts +8 -0
- package/dist/frontend/tsc-codes.js +109 -0
- package/dist/frontend/tsc-codes.js.map +1 -0
- package/dist/frontend/{types.d.ts → type-mapper.d.ts} +2 -25
- package/dist/frontend/{types.js → type-mapper.js} +12 -11
- package/dist/frontend/type-mapper.js.map +1 -0
- package/dist/frontend/workspace-registry.d.ts +26 -0
- package/dist/frontend/workspace-registry.js +71 -0
- package/dist/frontend/workspace-registry.js.map +1 -0
- package/dist/index.d.ts +113 -31
- package/dist/index.js +536 -128
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +37 -0
- package/dist/ir/analysis.js +118 -0
- package/dist/ir/analysis.js.map +1 -0
- package/dist/ir/analysis.test.d.ts +1 -0
- package/dist/ir/analysis.test.js +21 -0
- package/dist/ir/analysis.test.js.map +1 -0
- package/dist/ir/build.d.ts +9 -0
- package/dist/ir/build.js +33 -0
- package/dist/ir/build.js.map +1 -0
- package/dist/ir/integer-loops.d.ts +1 -1
- package/dist/ir/{nodes.d.ts → ir.d.ts} +119 -37
- package/dist/ir/{nodes.js → ir.js} +170 -166
- package/dist/ir/ir.js.map +1 -0
- package/dist/ir/ir.test.d.ts +1 -0
- package/dist/ir/ir.test.js +17 -0
- package/dist/ir/ir.test.js.map +1 -0
- package/dist/ir/serialize.d.ts +2 -2
- package/dist/ir/serialize.js +3 -2
- package/dist/ir/serialize.js.map +1 -1
- package/dist/ir/validate.d.ts +1 -1
- package/dist/ir/validate.js +93 -41
- package/dist/ir/validate.js.map +1 -1
- package/dist/library/cache-primitives.d.ts +24 -0
- package/dist/library/cache-primitives.js +83 -0
- package/dist/library/cache-primitives.js.map +1 -0
- package/dist/library/cache-reset.test.d.ts +1 -0
- package/dist/library/cache-reset.test.js +47 -0
- package/dist/library/cache-reset.test.js.map +1 -0
- package/dist/library/{implementation-identity.js → compiler-self-identity.js} +1 -1
- package/dist/library/compiler-self-identity.js.map +1 -0
- package/dist/library/fence-eval.d.ts +3 -1
- package/dist/library/fence-eval.js +8 -2
- package/dist/library/fence-eval.js.map +1 -1
- package/dist/library/int-infer.d.ts +1 -36
- package/dist/library/int-infer.js +29 -18
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/int-infer.test.js +4 -4
- package/dist/library/{early-cache.d.ts → library-cache.d.ts} +1 -1
- package/dist/library/{early-cache.js → library-cache.js} +34 -89
- package/dist/library/library-cache.js.map +1 -0
- package/dist/library/library-cache.test.d.ts +1 -0
- package/dist/library/{early-cache.test.js → library-cache.test.js} +7 -7
- package/dist/library/library-cache.test.js.map +1 -0
- package/dist/library/{profile.d.ts → library-profile.d.ts} +4 -7
- package/dist/library/{profile.js → library-profile.js} +18 -11
- package/dist/library/library-profile.js.map +1 -0
- package/dist/library/semantic-source.js +2 -1
- package/dist/library/semantic-source.js.map +1 -1
- package/dist/library/sidecar.d.ts +5 -2
- package/dist/library/sidecar.js +11 -5
- package/dist/library/sidecar.js.map +1 -1
- package/dist/startup-cache.d.ts +11 -3
- package/dist/startup-cache.js +17 -2
- package/dist/startup-cache.js.map +1 -1
- package/package.json +19 -2
- package/surface-manifest.json +5 -5
- package/dist/backend/cc-cache.test.js.map +0 -1
- package/dist/backend/cc.js.map +0 -1
- package/dist/backend/emission/emit-async.js.map +0 -1
- package/dist/backend/emission/emit-exprs.d.ts +0 -13
- package/dist/backend/emission/emit-exprs.js +0 -7407
- package/dist/backend/emission/emit-exprs.js.map +0 -1
- package/dist/backend/emission/emit-island.js.map +0 -1
- package/dist/backend/emission/emit-shapes.js.map +0 -1
- package/dist/backend/emission/emit-stmts.js.map +0 -1
- package/dist/backend/emission/emit-types.js.map +0 -1
- package/dist/backend/emission/emit-walkers.js.map +0 -1
- package/dist/backend/emission/emitter.js.map +0 -1
- package/dist/backend/emission/may-throw.js.map +0 -1
- package/dist/backend/library-identity.js.map +0 -1
- package/dist/executable/early-cache.js.map +0 -1
- package/dist/executable/early-cache.test.js.map +0 -1
- package/dist/ffi/profile.js.map +0 -1
- package/dist/frontend/lowering/lower-emitter.js.map +0 -1
- package/dist/frontend/shared.d.ts +0 -82
- package/dist/frontend/shared.js +0 -308
- package/dist/frontend/shared.js.map +0 -1
- package/dist/frontend/ts7/program.js.map +0 -1
- package/dist/frontend/types.js.map +0 -1
- package/dist/ir/nodes.js.map +0 -1
- package/dist/library/early-cache.js.map +0 -1
- package/dist/library/early-cache.test.js.map +0 -1
- package/dist/library/implementation-identity.js.map +0 -1
- package/dist/library/profile.js.map +0 -1
- /package/dist/backend/{cc-cache.test.d.ts → c/types.test.d.ts} +0 -0
- /package/dist/{executable/early-cache.test.d.ts → backend/llvm/shapes.test.d.ts} +0 -0
- /package/dist/{library/early-cache.test.d.ts → backend/native-codegen.test.d.ts} +0 -0
- /package/dist/ffi/{profile.d.ts → ffi-manifest.d.ts} +0 -0
- /package/dist/frontend/ts7/{program.d.ts → program-adapter.d.ts} +0 -0
- /package/dist/library/{implementation-identity.d.ts → compiler-self-identity.d.ts} +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { InternalCompilerError } from "../../errors.js";
|
|
1
2
|
/* AST + checker → IR.
|
|
2
3
|
*
|
|
3
4
|
* Invariants:
|
|
@@ -13,13 +14,14 @@
|
|
|
13
14
|
* ("x.0", "x.1" for shadowing); the IR is scope-flat.
|
|
14
15
|
*/
|
|
15
16
|
import { resolve } from "node:path";
|
|
16
|
-
import {
|
|
17
|
+
import { tsgoPath } from "../dts-paths.js";
|
|
18
|
+
import { isRelativeSpecifier } from "../workspace-registry.js";
|
|
17
19
|
import * as ts from "../ts7/adapter.js";
|
|
18
20
|
import { anyOpRequiresDynamicDiag, blockedBindingUseDiag, checkerPanicDiag, componentTypeDiag, isCheckerPanic, genericSignatureTypeDiag, indexSignatureTypeDiag, intersectionTypeDiag, noLoweringDiag, overloadedSignatureTypeDiag, recordShapeMismatchDiag, requiresDynamicApiDiag, requiresDynamicPackageDiag, requiresDynamicTypeDiag, unionMismatchDiag, unsupportedDiag, unsupportedTypeDiag, } from "../../diagnostics/diagnostic.js";
|
|
19
|
-
import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, F64, isJsonSafeType, isUndefinedArmedUnion, isUnitType, JSVAL, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/
|
|
21
|
+
import { arrayOf, BOOL, canAdaptDynFuncTo, canConvertToDyn, canCrossIslandBoundary, canExitIslandToType, canMarshalTypedFuncIntoIsland, DYN, F64, isJsonSafeType, isJsonStringifySafeType, isUndefinedArmedUnion, isUnitType, JSVAL, RUNTIME_ERROR_CLASSES, STRING, typeEquals, UNDEFINED_T, VOID } from "../../ir/ir.js";
|
|
20
22
|
import { provenanceActive } from "../provenance-registry.js";
|
|
21
23
|
import { ambientDtsPath, canonicalBuiltinModule, cjsExportAssignmentOf, cjsExportDiscardReason, fallbackDtsPath, isCjsExportTableLiteral, isJsSourceFile, isNodeEsmFile, isNodeTypesPath, locOf, orderedImportsOf, overridesDtsPath, npmStaticDepSf7, requireSpecOf, resolveImport, workspacePackageOfPath, } from "../program.js";
|
|
22
|
-
import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../
|
|
24
|
+
import { containsRecord, containsUnion, describeComponentBlocker, describeRecordMemberBlocker, formatIrType, ISLAND_AMBIENT_TYPES, isUnitOnlyTsType, mapType, ShapeRegistry, typeKey, UnionRegistry, withUndefinedArm as withUndefinedArmCanonical, } from "../type-mapper.js";
|
|
23
25
|
import { boundaryIntoIslandMsg, boundaryOutOfIslandMsg, builtinConstLit, builtinModuleConstOf, builtinModulesArrayLit, builtinFenceHintOf, builtinModuleFnOf, stdlibMemberFence, isStdlibMember, isStdlibSymbol, isStdlibGlobal, stdlibGlobalMember, nodeTypesOnlySymbol } from "./surfaces.js";
|
|
24
26
|
import { splitFiles, collectProgram, collectNpmImports, collectJsonImports, moduleArtifacts, collectGlobals, declSymbolOf, defaultExportSymbolOf, lowerFileInit, lowerDefaultExport, buildMain, appendDynamicImportModules } from "./lower-modules.js";
|
|
25
27
|
import { registerBuiltinErrorClasses, registerBuiltinEmitterClass, registerBuiltinStreamClasses, builtinErrorInfoOf, builtinEmitterInfoOf, builtinStreamInfoOf, analyzeClassDecoration, classIteratorDrainCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, classIteratorRestDrainCall, classMemberNameOf, classValueRef, collectClassShape, exactClassOfReceiver, collectClassShapeInner, ctorAbiEquals, findMethodOn, findStaticOn, findGenericMethodOn, findGenericStaticOn, genericClassInstanceType, isSubclassOf, inHierarchy, overrideBelow, staticShadowBelow, upcastTo, lowerClassMembers, lowerClassCtor, lowerClassExpression, lowerClassExpressionInfo, lowerClassMethodMember, lowerClassValueProperty, lowerStaticMethod, throwingSetterFn, fieldInitStmts, lowerStaticFieldInits, lowerStaticFieldRead, lowerDerivedCtorBody, superCallStmt, lowerSuperMethodCall, superThisRef, lowerSuperAccessorRead, lowerSuperAccessorWrite, inheritsBuiltinErrorCtor, inheritsBuiltinEmitterCtor, errorMessageArg, lowerNew, accessorCall } from "./lower-classes.js";
|
|
@@ -27,7 +29,7 @@ import { mixinCallClassInfoOf, mixinIntersectionInstanceType } from "./lower-mix
|
|
|
27
29
|
import { bindingNeverReassigned, bodyReadsArguments, implicitMonoFile, isThisParameter, paramShape, paramShapes, checkDefaultParamBodyType, completeArgs, wrappedUndefined, undefinedArgFor, requireExactArityValue, bodyReturnType, declaredReturnType, collectSignature, collectSignatureInner, collectGenericSignature, genericFnOf, lowerGenericCall, lowerGenericFnValue, inferTypeParamBindings, lowerGenericInstance, lowerCall, lowerFfiCall, lowerTimersMemberCall, lowerPromiseMethodCall, lowerFilterNarrowCall, isTopLevelFnSymbol, lowerNestedFunctionDecl, lambdaSignature, lowerLambda, lowerFunction, validateFfiImports } from "./lower-calls.js";
|
|
28
30
|
import { lowerArrayMethodCall, lowerBufferStaticCall, lowerBytesMethodCall, lowerBytesNew, lowerMapMethodCall, lowerMapForEachCall, buildMapForEachFn, lowerRecordOvfCaptureHelper, lowerEnvToPairsHelper, lowerSetMethodCall, lowerSetForEachCall, buildSetForEachFn, lowerRegexMethodCall, lowerStringMethodCall } from "./lower-containers.js";
|
|
29
31
|
import { lowerStreamModuleCall } from "./lower-stream.js";
|
|
30
|
-
import { lowerEmitOverrideSpec } from "./lower-emitter.js";
|
|
32
|
+
import { lowerEmitOverrideSpec } from "./lower-event-emitter.js";
|
|
31
33
|
import { builtinImportOf, createRequireBindingDecl, createRequireNamespaceDecl, createRequireSpecOf, stripTypeCasts, lowerBuiltinModuleCall, lowerFsToUnixTimestampCall, lowerFsLadderCall, lowerChildArgsArg, lowerSpawnSyncCall, lowerSpawnCall, lowerExecSyncCall, recordToEnvPairs, lowerJsonMethodCall, fencedBuiltinImportOf, lowerCryptoComposedCall, lowerUrlMethodCall, lowerSearchParamsMethodCall, lowerStatsMethodCall, lowerChildMethodCall, lowerAtomicsCall, lowerBuiltinExtraProperty, promisifiedExecFileDecl, lowerExecFileAsyncCall, execFileAsyncHelper, lowerStringDecoderMethodCall, strdecHelper, lowerReadlineMethodCall, lowerDcChannelMethodCall, lowerDcChannelProperty, lowerAlsMethodCall, lowerDcTracingChannelMethodCall, lowerDcTracingChannelProperty, lowerJsonProperty, lowerErrorCodeProperty, lowerProcessProperty, isProcessEnv, envValueType, lowerProcessEnvGet, lowerProcessMethodCall, lowerProcessOptionalMethodCall, lowerTimeoutMethodCall, envSnapshotHelper, isConsoleLog, consoleCallMember, lowerNumberStaticCall, lowerNumberStaticProperty, lowerDateCall, lowerTextCodecCall, lowerCryptoModuleCall, lowerFsConstantsProperty, lowerBuiltinConstantsProperty, builtinConstantBindingOf, builtinConstantsDestructureDecl, lowerProcessStreamProperty, lowerStringStaticCall, lowerStringLastIndexOfCall, lowerPromiseStaticCall, textCodecBindingClassOf } from "./lower-builtins.js";
|
|
32
34
|
import { fenceFetchObjectAssignment, fenceFetchObjectBinding, fenceStaticAbortControllerMemberRead, fenceStaticHeadersIteration, fenceStaticHeadersMember, fenceStaticReadableStreamMember, fenceStaticResponseMember, fenceUnsupportedFetchConstructorMember, isIslandExpr, islandFuncValueFence, islandRegexpOf, jsvalIn, requireDynamicApi, islandGlobalFnOf, lowerAbortControllerNew, lowerDynamicHeadersIteratorCall, lowerDynamicHeadersSpread, lowerDynamicImportCall, lowerFetchCall, lowerFetchElementMethodCall, lowerResponseNew, lowerStaticFetchCompanionCall, lowerStaticAbortControllerCall, lowerStaticAbortSignalListenerCall, lowerStaticReadableStreamCancelCall, lowerStaticReadableStreamControllerCall, lowerStaticReadableStreamNew, lowerStaticReadableStreamReaderCall, lowerStaticResponseCall, lowerIslandMethodCall, lowerMathProperty, npmPackageOf, npmMemberFence, npmPackageOfSymbol } from "./lower-island.js";
|
|
33
35
|
import { lowerHttpHeadersElement, lowerNetModuleCall, lowerServerMethodCall, lowerServerProperty, lowerTlsRootCertificates } from "./lower-server.js";
|
|
@@ -40,6 +42,7 @@ import { lowerStmts, noteBlockedBindings, isBlockedBinding, lowerScopedBlock, pr
|
|
|
40
42
|
import { lowerDynObjectLiteral, lowerExpr, maybeNarrow, lowerUnitComparison, lowerNullishCoalesce, lowerOptionalChain, finishOptionalChain, lowerCondition, ensureBool, requireTruthyUnion, eqComparableUnion, lowerIntrinsicProperty, lowerArrayLiteral, lowerObjectLiteral, lowerShorthandValue, rejectThisInObjectMethod, lowerElementAccess, lowerElementWrite, lowerRecordKeyRead, ensureString, lowerTemplate, lowerAsExpression, lowerPrefixUnary, lowerBinary, lowerCaughtTypeofTest, caughtRead, caughtLocalOf, caughtToString, lowerInstanceOf, lowerRegexLiteral, lowerFieldRead, lowerUnionProperty, fieldTarget, fieldGetExpr, fieldSetStmt, lowerFieldCompound, uniqueSymbolKeyOf, foldedStringKeyOf } from "./lower-exprs.js";
|
|
41
43
|
import { lowerRecordFieldCall, lowerObjectMethodCall } from "./lower-calls.js";
|
|
42
44
|
import { fenceCrossBlockNsRef, nsPathPrefix } from "./lower-namespaces.js";
|
|
45
|
+
import { numLit, varRef } from "../../ir/build.js";
|
|
43
46
|
/** Entry function name. '%' cannot appear in a TS identifier, so a user
|
|
44
47
|
* function can never collide with it (mangling is injective per prefix). */
|
|
45
48
|
export const ENTRY_NAME = "%main";
|
|
@@ -56,7 +59,7 @@ export function own(table, key) {
|
|
|
56
59
|
/** Sentinel binding key for `this` (which has no ts.Symbol): a stable
|
|
57
60
|
* object identity used in the same scope/capture maps as real symbols, so
|
|
58
61
|
* arrows capturing `this` ride the ordinary capture machinery. */
|
|
59
|
-
|
|
62
|
+
const THIS_BINDING = { escapedName: "%this" };
|
|
60
63
|
export function newFnCtx(lifted, selfSymbol, selfType, returnType) {
|
|
61
64
|
return {
|
|
62
65
|
locals: [],
|
|
@@ -76,9 +79,9 @@ export function newFnCtx(lifted, selfSymbol, selfType, returnType) {
|
|
|
76
79
|
* visit; descending would attribute a nested island statement to every
|
|
77
80
|
* enclosing construct too). The top-level statement object itself is
|
|
78
81
|
* always visited. */
|
|
79
|
-
|
|
82
|
+
const IR_STMT_KINDS = new Set([
|
|
80
83
|
"varDecl", "assign", "exprStmt", "if", "while", "doWhile", "switch",
|
|
81
|
-
"arraySet", "forOf", "return", "fieldSet", "recordSet", "break",
|
|
84
|
+
"arraySet", "arraySetLength", "arraySetUndefined", "arrayDelete", "forOf", "return", "fieldSet", "recordSet", "break",
|
|
82
85
|
"continue", "block", "tryCatch", "throw", "rethrow", "runtimeFence",
|
|
83
86
|
]);
|
|
84
87
|
/** True when a lowered statement's OWN expressions contain island
|
|
@@ -308,8 +311,8 @@ export function importCallHandleType(expr) {
|
|
|
308
311
|
* Ambient (.d.ts) declarations never reach this: they have no compiled
|
|
309
312
|
* implementation, so their calls lower through the island/builtin paths
|
|
310
313
|
* whose validated exits keep the checker-trust trap. */
|
|
311
|
-
export function uncheckedOverloadHandleCall(
|
|
312
|
-
if (!
|
|
314
|
+
export function uncheckedOverloadHandleCall(lowerer, expr) {
|
|
315
|
+
if (!lowerer.dynamic || !expr)
|
|
313
316
|
return false;
|
|
314
317
|
let e = expr;
|
|
315
318
|
while (ts.isParenthesizedExpression(e))
|
|
@@ -319,25 +322,25 @@ export function uncheckedOverloadHandleCall(L, expr) {
|
|
|
319
322
|
// overload of an any-returning implementation stores the handle.
|
|
320
323
|
if (!ts.isCallExpression(e) && !ts.isTaggedTemplateExpression(e))
|
|
321
324
|
return false;
|
|
322
|
-
const rsig =
|
|
323
|
-
const rdecl = rsig ?
|
|
325
|
+
const rsig = lowerer.checker.getResolvedSignature(e);
|
|
326
|
+
const rdecl = rsig ? lowerer.checker.signatureDeclaration(rsig) : undefined;
|
|
324
327
|
if (!rsig || !rdecl)
|
|
325
328
|
return false;
|
|
326
329
|
if (!(ts.isFunctionDeclaration(rdecl) || ts.isMethodDeclaration(rdecl)) || rdecl.body)
|
|
327
330
|
return false;
|
|
328
331
|
const name = rdecl.name;
|
|
329
|
-
const symbol = name ?
|
|
332
|
+
const symbol = name ? lowerer.checker.getSymbolAtLocation(name) : undefined;
|
|
330
333
|
if (!symbol)
|
|
331
334
|
return false;
|
|
332
|
-
const impl =
|
|
335
|
+
const impl = lowerer.checker
|
|
333
336
|
.declarationsOf(symbol)
|
|
334
337
|
.find((d) => (ts.isFunctionDeclaration(d) || ts.isMethodDeclaration(d)) && d.body !== undefined);
|
|
335
338
|
if (!impl)
|
|
336
339
|
return false;
|
|
337
|
-
const implSig =
|
|
340
|
+
const implSig = lowerer.checker.getSignatureFromDeclaration(impl);
|
|
338
341
|
if (!implSig)
|
|
339
342
|
return false;
|
|
340
|
-
return
|
|
343
|
+
return lowerer.mapTypeOf(lowerer.checker.getReturnTypeOfSignature(implSig))?.kind === "jsval";
|
|
341
344
|
}
|
|
342
345
|
/** The JavaScript declaration fallback for unmappable binding types (see
|
|
343
346
|
* irTypeOf): `any` and every other inference residue is the checked-
|
|
@@ -356,7 +359,7 @@ export function uncheckedOverloadHandleCall(L, expr) {
|
|
|
356
359
|
* checked-dynamic fallbacks apply, the pre-never-mapping behavior. Bare
|
|
357
360
|
* `never` at the ROOT stays out (`for (const v of [])`'s loop var — the
|
|
358
361
|
* dead read the f64 mapping is FOR). */
|
|
359
|
-
export function neverTaintedJsType(
|
|
362
|
+
export function neverTaintedJsType(lowerer, node, t) {
|
|
360
363
|
if (!isJsSourceFile(node.getSourceFile()))
|
|
361
364
|
return false;
|
|
362
365
|
const walk = (x, depth) => {
|
|
@@ -364,8 +367,8 @@ export function neverTaintedJsType(L, node, t) {
|
|
|
364
367
|
return false;
|
|
365
368
|
if (x.isUnionType())
|
|
366
369
|
return ts.constituentTypes(x).some((a) => walk(a, depth - 1));
|
|
367
|
-
if (
|
|
368
|
-
return
|
|
370
|
+
if (lowerer.checker.isArrayType(x) || lowerer.checker.isTupleType(x)) {
|
|
371
|
+
return lowerer.checker
|
|
369
372
|
.getTypeArguments(x)
|
|
370
373
|
.some((a) => (a.flags & ts.TypeFlags.Never) !== 0 || walk(a, depth - 1));
|
|
371
374
|
}
|
|
@@ -414,10 +417,10 @@ export function nodeThrowExpr(kind, code, message, type, loc) {
|
|
|
414
417
|
* (scr_throw_lowering_fence). The diagnostic joins the runtime-fence
|
|
415
418
|
* ledger exactly like a deferred statement fence — nothing silently
|
|
416
419
|
* drops off the coverage report. */
|
|
417
|
-
export function ladderFenceExpr(
|
|
420
|
+
export function ladderFenceExpr(lowerer, surface, node, hint) {
|
|
418
421
|
const loc = locOf(node);
|
|
419
422
|
const d = noLoweringDiag(surface, loc, hint);
|
|
420
|
-
|
|
423
|
+
lowerer.runtimeFences.push(d);
|
|
421
424
|
const sf = node.getSourceFile();
|
|
422
425
|
const pos = ts.getLineAndCharacterOfPosition(sf, loc.start);
|
|
423
426
|
return {
|
|
@@ -450,7 +453,7 @@ export function ladderFenceExpr(L, surface, node, hint) {
|
|
|
450
453
|
* this fallback for `any` (mapType answers jsval first).
|
|
451
454
|
*
|
|
452
455
|
* Null for void (no value exists to represent). */
|
|
453
|
-
export function dynFallbackType(
|
|
456
|
+
export function dynFallbackType(lowerer, node, t) {
|
|
454
457
|
if (t.flags & ts.TypeFlags.Void)
|
|
455
458
|
return null;
|
|
456
459
|
if (!isJsSourceFile(node.getSourceFile())) {
|
|
@@ -459,13 +462,13 @@ export function dynFallbackType(L, node, t) {
|
|
|
459
462
|
// TS single-call-signature function types: per-piece fallback, but
|
|
460
463
|
// ONLY `any` pieces fall to dyn — any other unmappable piece keeps
|
|
461
464
|
// the whole type's own fence.
|
|
462
|
-
return anyPiecedFuncType(
|
|
465
|
+
return anyPiecedFuncType(lowerer, node, t);
|
|
463
466
|
}
|
|
464
|
-
if (
|
|
465
|
-
const elem =
|
|
467
|
+
if (lowerer.checker.isArrayType(t)) {
|
|
468
|
+
const elem = lowerer.checker.getTypeArguments(t)[0];
|
|
466
469
|
const elemTainted = elem !== undefined &&
|
|
467
|
-
((elem.flags & ts.TypeFlags.Never) !== 0 || neverTaintedJsType(
|
|
468
|
-
const mappedElem = elem !== undefined && !elemTainted ?
|
|
470
|
+
((elem.flags & ts.TypeFlags.Never) !== 0 || neverTaintedJsType(lowerer, node, elem));
|
|
471
|
+
const mappedElem = elem !== undefined && !elemTainted ? lowerer.mapTypeOf(elem) : null;
|
|
469
472
|
// A mappable element keeps the static array; an unmappable one makes
|
|
470
473
|
// the WHOLE value dyn (the checked-dynamic tree has real arrays — length/index/push
|
|
471
474
|
// read through the keyed-dyn paths; dyn-element STATIC arrays have no
|
|
@@ -482,14 +485,14 @@ export function dynFallbackType(L, node, t) {
|
|
|
482
485
|
// construct signatures, overloads, and function-with-properties shapes
|
|
483
486
|
// stay out (the whole value falls to dyn below, where every reached
|
|
484
487
|
// use meets its own fence or boxes as-is).
|
|
485
|
-
const sig = pureSingleCallSignatureOf(
|
|
488
|
+
const sig = pureSingleCallSignatureOf(lowerer, t);
|
|
486
489
|
if (sig) {
|
|
487
490
|
const params = sig.getParameters().map((p) => {
|
|
488
|
-
const pt =
|
|
489
|
-
return
|
|
491
|
+
const pt = lowerer.checker.getTypeOfSymbolAtLocation(p, node);
|
|
492
|
+
return lowerer.mapTypeOf(pt) ?? DYN;
|
|
490
493
|
});
|
|
491
|
-
const retT =
|
|
492
|
-
const ret = retT.flags & ts.TypeFlags.Void ? VOID :
|
|
494
|
+
const retT = lowerer.checker.getReturnTypeOfSignature(sig);
|
|
495
|
+
const ret = retT.flags & ts.TypeFlags.Void ? VOID : lowerer.mapTypeOf(retT) ?? DYN;
|
|
493
496
|
return { kind: "func", params, ret };
|
|
494
497
|
}
|
|
495
498
|
return DYN;
|
|
@@ -498,23 +501,23 @@ export function dynFallbackType(L, node, t) {
|
|
|
498
501
|
* properties, no construct signatures, no type parameters, no rest params
|
|
499
502
|
* (declared or synthesized from an `arguments` read). Null for every
|
|
500
503
|
* other shape. The structural gate both dynFallbackType arms share. */
|
|
501
|
-
function pureSingleCallSignatureOf(
|
|
504
|
+
function pureSingleCallSignatureOf(lowerer, t) {
|
|
502
505
|
if (!(t.flags & ts.TypeFlags.Object))
|
|
503
506
|
return null;
|
|
504
|
-
const sigs =
|
|
507
|
+
const sigs = lowerer.checker.getCallSignatures(t);
|
|
505
508
|
if (sigs.length === 1 &&
|
|
506
|
-
|
|
507
|
-
|
|
509
|
+
lowerer.checker.getPropertiesOfType(t).length === 0 &&
|
|
510
|
+
lowerer.checker.getConstructSignatures(t).length === 0 &&
|
|
508
511
|
sigs[0].getTypeParameters().length === 0 &&
|
|
509
512
|
sigs[0].getParameters().every((p) => {
|
|
510
|
-
const pDecl =
|
|
513
|
+
const pDecl = lowerer.checker.valueDeclarationOf(p);
|
|
511
514
|
return !pDecl || !ts.isParameter(pDecl) || pDecl.dotDotDotToken === undefined;
|
|
512
515
|
}) &&
|
|
513
516
|
// A SYNTHESIZED rest param (tsc's `arguments` inference — no
|
|
514
517
|
// valueDeclaration to carry the dotDotDot): param-count mismatch
|
|
515
518
|
// against the signature's declaration; the whole value stays dyn.
|
|
516
519
|
(() => {
|
|
517
|
-
const sigDecl =
|
|
520
|
+
const sigDecl = lowerer.checker.signatureDeclaration(sigs[0]);
|
|
518
521
|
const declParams = sigDecl !== undefined && ts.isFunctionLike(sigDecl) ? sigDecl.parameters : undefined;
|
|
519
522
|
if (declParams !== undefined && declParams.length !== sigs[0].getParameters().length)
|
|
520
523
|
return false;
|
|
@@ -534,21 +537,21 @@ function pureSingleCallSignatureOf(L, t) {
|
|
|
534
537
|
* irTypeOf fallback, so the binding type and the closure type agree).
|
|
535
538
|
* A piece that fails to map for any other reason answers null — the
|
|
536
539
|
* whole type keeps its own diagnostic. */
|
|
537
|
-
function anyPiecedFuncType(
|
|
538
|
-
const sig = pureSingleCallSignatureOf(
|
|
540
|
+
function anyPiecedFuncType(lowerer, node, t) {
|
|
541
|
+
const sig = pureSingleCallSignatureOf(lowerer, t);
|
|
539
542
|
if (!sig)
|
|
540
543
|
return null;
|
|
541
544
|
const params = [];
|
|
542
545
|
for (const p of sig.getParameters()) {
|
|
543
|
-
const pt =
|
|
544
|
-
const mapped =
|
|
546
|
+
const pt = lowerer.checker.getTypeOfSymbolAtLocation(p, node);
|
|
547
|
+
const mapped = lowerer.mapTypeOf(pt) ?? (pt.flags & ts.TypeFlags.Any ? DYN : null);
|
|
545
548
|
if (!mapped || mapped.kind === "void")
|
|
546
549
|
return null;
|
|
547
550
|
params.push(mapped);
|
|
548
551
|
}
|
|
549
|
-
const retT =
|
|
552
|
+
const retT = lowerer.checker.getReturnTypeOfSignature(sig);
|
|
550
553
|
const ret = retT.flags & (ts.TypeFlags.Void | ts.TypeFlags.Never) ? VOID
|
|
551
|
-
:
|
|
554
|
+
: lowerer.mapTypeOf(retT) ?? (retT.flags & ts.TypeFlags.Any ? DYN : null);
|
|
552
555
|
if (!ret)
|
|
553
556
|
return null;
|
|
554
557
|
return { kind: "func", params, ret };
|
|
@@ -818,12 +821,233 @@ export class Lowerer {
|
|
|
818
821
|
/** All storage slots widened for runtime absence, including slots whose
|
|
819
822
|
* current control-flow branch has temporarily narrowed the value. */
|
|
820
823
|
runtimeOptionalStorageLocals = new Set();
|
|
824
|
+
/** Globals whose checker-bare type was widened because an indexed read can
|
|
825
|
+
* carry undefined at runtime. Identifier reads keep the union tag so
|
|
826
|
+
* typeof and later boundaries observe the real value. */
|
|
827
|
+
runtimeOptionalGlobals = new Set();
|
|
828
|
+
/** Bindings whose unchecked string arithmetic can produce either a number
|
|
829
|
+
* (NaN for an absent read) or a string. Preserve that result union at bare
|
|
830
|
+
* reads instead of applying the checker-bare string narrowing adapter. */
|
|
831
|
+
runtimeOptionalArithmeticLocals = new Set();
|
|
832
|
+
runtimeOptionalArithmeticGlobals = new Set();
|
|
833
|
+
/** Binding symbols whose IR storage type was widened by the indexed-read
|
|
834
|
+
* prepass. This includes explicit annotations: unchecked TS annotations do
|
|
835
|
+
* not prove that an array property read produced a value. */
|
|
836
|
+
runtimeOptionalBindingTypes = new Map();
|
|
837
|
+
/** Concise callback/lambda returns promoted by the HOF callback prepass;
|
|
838
|
+
* arrows have no declaration symbol to key in fnSigsBySymbol. */
|
|
839
|
+
runtimeOptionalFunctionReturns = new WeakMap();
|
|
840
|
+
/** Arithmetic over an unchecked string read can answer either NaN or a
|
|
841
|
+
* string. Bindings and returns use this marker to retain that result union
|
|
842
|
+
* through checker-bare string annotations. */
|
|
843
|
+
runtimeOptionalArithmeticTypes = new WeakMap();
|
|
844
|
+
/** Record fields promoted to an undefined-armed union by an indexed-read
|
|
845
|
+
* value. The key is the concrete emitted shape and field name. */
|
|
846
|
+
runtimeOptionalFields = new Set();
|
|
847
|
+
/** Callback pattern parameters carry an optional source without making
|
|
848
|
+
* every name destructured from a present source optional. */
|
|
849
|
+
runtimeOptionalPatternTypes = new WeakMap();
|
|
850
|
+
runtimeOptionalReduceTypes = new WeakMap();
|
|
821
851
|
/** Capture entries and their origin share one mutable box. Normalize each
|
|
822
852
|
* entry to the origin so writes and flow proofs stay synchronized. */
|
|
823
853
|
runtimeOptionalRoots = new Map();
|
|
824
854
|
runtimeOptionalRootOf(local) {
|
|
825
855
|
return this.runtimeOptionalRoots.get(local) ?? local;
|
|
826
856
|
}
|
|
857
|
+
runtimeOptionalBindingType(node, fallback) {
|
|
858
|
+
const patternType = this.runtimeOptionalPatternTypes.get(node);
|
|
859
|
+
if (patternType)
|
|
860
|
+
return patternType;
|
|
861
|
+
const symbol = ts.isIdentifier(node) ? this.resolveValueSymbol(node) : this.checker.getSymbolAtLocation(node);
|
|
862
|
+
if (!symbol)
|
|
863
|
+
return fallback ?? null;
|
|
864
|
+
const known = this.runtimeOptionalBindingTypes.get(symbol);
|
|
865
|
+
if (known)
|
|
866
|
+
return known;
|
|
867
|
+
// A module-scope function alias is collected as a global before the
|
|
868
|
+
// optional-read fixed point settles. Derive its promoted function ABI
|
|
869
|
+
// directly from the aliased declaration as a final read-side hook, so
|
|
870
|
+
// the initializer cannot fall back to a narrowing adapter.
|
|
871
|
+
if (ts.isIdentifier(node) && fallback?.kind === "func") {
|
|
872
|
+
const decl = this.checker.valueDeclarationOf(symbol);
|
|
873
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer) {
|
|
874
|
+
let init = decl.initializer;
|
|
875
|
+
while (ts.isParenthesizedExpression(init))
|
|
876
|
+
init = init.expression;
|
|
877
|
+
if (ts.isIdentifier(init)) {
|
|
878
|
+
const source = this.resolveValueSymbol(init);
|
|
879
|
+
const sig = source ? this.fnSigsBySymbol.get(source) : undefined;
|
|
880
|
+
if (sig) {
|
|
881
|
+
return {
|
|
882
|
+
...fallback,
|
|
883
|
+
params: sig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
|
|
884
|
+
ret: sig.returnType,
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return fallback ?? null;
|
|
891
|
+
}
|
|
892
|
+
runtimeOptionalIdentifierValue(node) {
|
|
893
|
+
if (!ts.isIdentifier(node) || this.chainRecvByNode.has(node))
|
|
894
|
+
return null;
|
|
895
|
+
const local = this.resolveLocal(node);
|
|
896
|
+
const symbol = this.resolveValueSymbol(node);
|
|
897
|
+
const storage = local ?? (symbol ? this.globalsBySymbol.get(symbol) : undefined);
|
|
898
|
+
if (!storage || storage.type.kind !== "union" || this.armTag(storage.type.unionId, UNDEFINED_T) < 0)
|
|
899
|
+
return null;
|
|
900
|
+
const present = this.stripUndefinedArm(storage.type);
|
|
901
|
+
if (isUnitType(present))
|
|
902
|
+
return null;
|
|
903
|
+
return { value: varRef(storage.id, storage.type, locOf(node)), present, unionId: storage.type.unionId };
|
|
904
|
+
}
|
|
905
|
+
/** Recover the original optional union when a checked single-arm helper
|
|
906
|
+
* was installed before a strict property consumer could name its member.
|
|
907
|
+
* Recovery is limited to array element reads and storage roots marked by
|
|
908
|
+
* the optional-read analysis, so ordinary assertions keep their generic
|
|
909
|
+
* checked-narrow behavior. */
|
|
910
|
+
runtimeOptionalSourceValue(node, value) {
|
|
911
|
+
let origin = node;
|
|
912
|
+
while (ts.isParenthesizedExpression(origin))
|
|
913
|
+
origin = origin.expression;
|
|
914
|
+
let optionalOrigin = ts.isElementAccessExpression(origin);
|
|
915
|
+
if (ts.isIdentifier(origin)) {
|
|
916
|
+
const local = this.resolveLocal(origin);
|
|
917
|
+
const root = local ? this.runtimeOptionalRootOf(local) : null;
|
|
918
|
+
const global = this.globalOf(origin);
|
|
919
|
+
optionalOrigin =
|
|
920
|
+
(!!root && this.runtimeOptionalStorageLocals.has(root)) ||
|
|
921
|
+
(!!global && (this.isRuntimeOptionalGlobal(global) ||
|
|
922
|
+
(global.type.kind === "union" && this.armTag(global.type.unionId, UNDEFINED_T) >= 0)));
|
|
923
|
+
}
|
|
924
|
+
if (!optionalOrigin)
|
|
925
|
+
return null;
|
|
926
|
+
let source = value;
|
|
927
|
+
if (value.kind === "call" &&
|
|
928
|
+
this.checkedNarrowHelpers.has(value.callee) &&
|
|
929
|
+
value.args.length === 1 &&
|
|
930
|
+
value.args[0]?.type.kind === "union") {
|
|
931
|
+
source = value.args[0];
|
|
932
|
+
}
|
|
933
|
+
return source.type.kind === "union" && this.armTag(source.type.unionId, UNDEFINED_T) >= 0
|
|
934
|
+
? source
|
|
935
|
+
: null;
|
|
936
|
+
}
|
|
937
|
+
/** A strict property or method receiver over an array-derived optional
|
|
938
|
+
* value. Stabilize the receiver once, throw Node's member-read TypeError
|
|
939
|
+
* for a unit arm, and extract the expected present arm otherwise. */
|
|
940
|
+
runtimeOptionalPropertyReceiver(node, value, expected, member) {
|
|
941
|
+
const source = this.runtimeOptionalSourceValue(node, value);
|
|
942
|
+
if (source?.type.kind !== "union")
|
|
943
|
+
return null;
|
|
944
|
+
const def = this.unions.get(source.type.unionId);
|
|
945
|
+
const valueTag = this.armTag(source.type.unionId, expected);
|
|
946
|
+
if (!def ||
|
|
947
|
+
valueTag < 0 ||
|
|
948
|
+
!def.arms.every((arm) => typeEquals(arm, expected) || isUnitType(arm)))
|
|
949
|
+
return null;
|
|
950
|
+
const loc = locOf(node);
|
|
951
|
+
const stable = this.declareHiddenLocal("%propertyRecv", source.type);
|
|
952
|
+
const stableRef = () => varRef(stable.id, source.type, loc);
|
|
953
|
+
let result = {
|
|
954
|
+
kind: "unionNarrow",
|
|
955
|
+
unionId: source.type.unionId,
|
|
956
|
+
tag: valueTag,
|
|
957
|
+
value: stableRef(),
|
|
958
|
+
type: expected,
|
|
959
|
+
loc,
|
|
960
|
+
};
|
|
961
|
+
for (let i = def.arms.length - 1; i >= 0; i--) {
|
|
962
|
+
const arm = def.arms[i];
|
|
963
|
+
if (!arm || !isUnitType(arm))
|
|
964
|
+
continue;
|
|
965
|
+
const unit = arm.kind === "nullT" ? "null" : "undefined";
|
|
966
|
+
result = {
|
|
967
|
+
kind: "ternary",
|
|
968
|
+
cond: {
|
|
969
|
+
kind: "unionIsTag",
|
|
970
|
+
unionId: source.type.unionId,
|
|
971
|
+
tag: i,
|
|
972
|
+
negated: false,
|
|
973
|
+
value: stableRef(),
|
|
974
|
+
type: BOOL,
|
|
975
|
+
loc,
|
|
976
|
+
},
|
|
977
|
+
then: nodeThrowExpr(1, "", `Cannot read properties of ${unit} (reading '${member}')`, expected, loc),
|
|
978
|
+
else_: result,
|
|
979
|
+
type: expected,
|
|
980
|
+
loc,
|
|
981
|
+
};
|
|
982
|
+
}
|
|
983
|
+
return {
|
|
984
|
+
kind: "seqExpr",
|
|
985
|
+
stmts: [{ kind: "varDecl", localId: stable.id, init: source, loc }],
|
|
986
|
+
result,
|
|
987
|
+
type: expected,
|
|
988
|
+
loc,
|
|
989
|
+
};
|
|
990
|
+
}
|
|
991
|
+
runtimeOptionalFieldKey(shapeId, field) {
|
|
992
|
+
return `${shapeId}:${field}`;
|
|
993
|
+
}
|
|
994
|
+
isRuntimeOptionalField(shapeId, field) {
|
|
995
|
+
return this.runtimeOptionalFields.has(this.runtimeOptionalFieldKey(shapeId, field));
|
|
996
|
+
}
|
|
997
|
+
isRuntimeOptionalGlobal(global) {
|
|
998
|
+
return this.runtimeOptionalGlobals.has(global);
|
|
999
|
+
}
|
|
1000
|
+
isRuntimeOptionalArithmeticGlobal(global) {
|
|
1001
|
+
return this.runtimeOptionalArithmeticGlobals.has(global);
|
|
1002
|
+
}
|
|
1003
|
+
/** The union produced when an unchecked array read reaches a typed slot
|
|
1004
|
+
* whose checker type is the corresponding bare arm. */
|
|
1005
|
+
runtimeOptionalWidening(actual, expected) {
|
|
1006
|
+
if (actual.kind !== "union" || this.armTag(actual.unionId, UNDEFINED_T) < 0)
|
|
1007
|
+
return null;
|
|
1008
|
+
return typeEquals(this.stripUndefinedArm(actual), expected) ? actual : null;
|
|
1009
|
+
}
|
|
1010
|
+
runtimeOptionalType(t) {
|
|
1011
|
+
if (t.kind === "union")
|
|
1012
|
+
return this.armTag(t.unionId, UNDEFINED_T) >= 0 ? t : this.withUndefinedArmOf(t) ?? t;
|
|
1013
|
+
if (t.kind === "void" || t.kind === "dyn" || t.kind === "jsval" || t.kind === "generator")
|
|
1014
|
+
return t;
|
|
1015
|
+
return this.withUndefinedArm(t);
|
|
1016
|
+
}
|
|
1017
|
+
promoteRuntimeOptionalParameter(node, type) {
|
|
1018
|
+
const widened = this.runtimeOptionalType(type);
|
|
1019
|
+
const symbol = this.checker.getSymbolAtLocation(node);
|
|
1020
|
+
if (symbol)
|
|
1021
|
+
this.runtimeOptionalBindingTypes.set(symbol, widened);
|
|
1022
|
+
return widened;
|
|
1023
|
+
}
|
|
1024
|
+
promoteRuntimeOptionalFunctionReturn(node, type) {
|
|
1025
|
+
const widened = this.runtimeOptionalType(type);
|
|
1026
|
+
this.runtimeOptionalFunctionReturns.set(node, widened);
|
|
1027
|
+
return widened;
|
|
1028
|
+
}
|
|
1029
|
+
runtimeOptionalFunctionReturnType(node, fallback) {
|
|
1030
|
+
return this.runtimeOptionalFunctionReturns.get(node) ?? fallback;
|
|
1031
|
+
}
|
|
1032
|
+
/** Promote one field of a record storage shape to the value's runtime
|
|
1033
|
+
* type. Shapes are immutable by identity, so this interns a sibling shape
|
|
1034
|
+
* and records the field as runtime-optional for property-read narrowing. */
|
|
1035
|
+
runtimeOptionalRecordField(type, field, fieldType) {
|
|
1036
|
+
if (type.kind !== "record")
|
|
1037
|
+
return type;
|
|
1038
|
+
const shape = this.shapes.get(type.shapeId);
|
|
1039
|
+
if (!shape)
|
|
1040
|
+
return type;
|
|
1041
|
+
const existing = shape.fields.find((f) => f.name === field);
|
|
1042
|
+
if (!existing || typeEquals(existing.type, fieldType)) {
|
|
1043
|
+
if (existing)
|
|
1044
|
+
this.runtimeOptionalFields.add(this.runtimeOptionalFieldKey(type.shapeId, field));
|
|
1045
|
+
return type;
|
|
1046
|
+
}
|
|
1047
|
+
const shapeId = this.shapes.intern(shape.fields.map((f) => ({ name: f.name, type: f.name === field ? fieldType : f.type })), shape.tuple === true, shape.indexValue, shape.declaredOrder);
|
|
1048
|
+
this.runtimeOptionalFields.add(this.runtimeOptionalFieldKey(shapeId, field));
|
|
1049
|
+
return { kind: "record", shapeId };
|
|
1050
|
+
}
|
|
827
1051
|
/** Runs `fn` with the given aliased-typeof narrows applied (and restored
|
|
828
1052
|
* after) — the branch-scoping primitive. */
|
|
829
1053
|
narrowingAliases(narrows, fn) {
|
|
@@ -863,7 +1087,7 @@ export class Lowerer {
|
|
|
863
1087
|
* Reachability lowers inits before the declarations they discover, so
|
|
864
1088
|
* these rebuild after the worklist restores historical shape metadata. */
|
|
865
1089
|
shapeOrderHelperFinalizers = [];
|
|
866
|
-
/** Emit-override specializations (`%C.emit:<event>` — lower-emitter.ts's
|
|
1090
|
+
/** Emit-override specializations (`%C.emit:<event>` — lower-event-emitter.ts's
|
|
867
1091
|
* emit-overrides block): interned names, the drive-loop queue, and the
|
|
868
1092
|
* currently-lowering specialization's context (the super-forward
|
|
869
1093
|
* interception reads it). */
|
|
@@ -917,6 +1141,10 @@ export class Lowerer {
|
|
|
917
1141
|
* declaration: member reads call the getter (lower-exprs). */
|
|
918
1142
|
cjsAccessorFns = new Map();
|
|
919
1143
|
narrowHelpers = new Map();
|
|
1144
|
+
/** Exact members of narrowHelpers produced by narrowedArmHelper. This
|
|
1145
|
+
* lets property consumers recognize an earlier checked extraction by
|
|
1146
|
+
* provenance instead of relying on its generated-name prefix. */
|
|
1147
|
+
checkedNarrowHelpers = new Set();
|
|
920
1148
|
/** Interned `%iter.drain.<n>` helpers (classIteratorDrainCall): one per
|
|
921
1149
|
* receiver class — the eager drain of a class iterable's protocol into
|
|
922
1150
|
* a fresh element array, behind array/call spreads. */
|
|
@@ -1130,7 +1358,7 @@ export class Lowerer {
|
|
|
1130
1358
|
get ctx() {
|
|
1131
1359
|
const top = this.fnStack[this.fnStack.length - 1];
|
|
1132
1360
|
if (!top)
|
|
1133
|
-
throw new
|
|
1361
|
+
throw new InternalCompilerError("lowerer bug: no active function context");
|
|
1134
1362
|
return top;
|
|
1135
1363
|
}
|
|
1136
1364
|
get scopes() {
|
|
@@ -1377,6 +1605,31 @@ export class Lowerer {
|
|
|
1377
1605
|
this.flushDeferred(symbol);
|
|
1378
1606
|
return symbol;
|
|
1379
1607
|
}
|
|
1608
|
+
/** Whether this exact direct call belongs to a manifest-validated native
|
|
1609
|
+
* binding. Declaration classification uses this as a probe before normal
|
|
1610
|
+
* expression lowering: resolving must not flush deferred diagnostics or
|
|
1611
|
+
* trigger the merged-namespace fence just because it is asking ownership.
|
|
1612
|
+
* Call lowering remains the authority for every ABI and call-shape
|
|
1613
|
+
* diagnostic once this answers true. */
|
|
1614
|
+
ownsFfiCall(expr) {
|
|
1615
|
+
if (!ts.isIdentifier(expr.expression))
|
|
1616
|
+
return false;
|
|
1617
|
+
const binding = this.ffiImportsByName.get(expr.expression.text);
|
|
1618
|
+
if (binding === undefined || this.ffiBindingSymbols === null)
|
|
1619
|
+
return false;
|
|
1620
|
+
const validSymbols = this.ffiBindingSymbols.get(binding.name);
|
|
1621
|
+
if (validSymbols === undefined)
|
|
1622
|
+
return false;
|
|
1623
|
+
const wasCollecting = this.collecting;
|
|
1624
|
+
this.collecting = true;
|
|
1625
|
+
try {
|
|
1626
|
+
const symbol = this.resolveValueSymbol(expr.expression);
|
|
1627
|
+
return symbol !== null && validSymbols.has(symbol);
|
|
1628
|
+
}
|
|
1629
|
+
finally {
|
|
1630
|
+
this.collecting = wasCollecting;
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1380
1633
|
/** The configured external host module owning an expression's runtime
|
|
1381
1634
|
* value, or null. Alias chains are followed to their declaration file so
|
|
1382
1635
|
* direct imports and local re-export facades classify identically. Type
|
|
@@ -1983,6 +2236,720 @@ export class Lowerer {
|
|
|
1983
2236
|
collectJsonImports(parts) {
|
|
1984
2237
|
return collectJsonImports(this, parts);
|
|
1985
2238
|
}
|
|
2239
|
+
/** Discover the unchecked-array values that cross static ABI/storage
|
|
2240
|
+
* boundaries before any function body or module initializer is emitted.
|
|
2241
|
+
* TypeScript's default indexed-access type is a useful source annotation,
|
|
2242
|
+
* but it is not a runtime proof; promoting only the affected slots keeps
|
|
2243
|
+
* the rest of the dense ABI unchanged. */
|
|
2244
|
+
analyzeRuntimeOptionalArrayReads(parts) {
|
|
2245
|
+
const optionalSymbols = new Set();
|
|
2246
|
+
const optionalReturns = new Set();
|
|
2247
|
+
const arithmeticReturns = new Map();
|
|
2248
|
+
const optionalParams = new Map();
|
|
2249
|
+
const optionalFields = new Map();
|
|
2250
|
+
const dynamicObjectEntryRows = new Set();
|
|
2251
|
+
const sourceFiles = parts.map((p) => p.sf);
|
|
2252
|
+
const fnDecls = parts.flatMap((p) => p.fnDecls);
|
|
2253
|
+
// This fixed-point scan intentionally sees deferred bodies before
|
|
2254
|
+
// reachability is known. Batch their binding queries through the
|
|
2255
|
+
// facade's panic fence, then keep lookup free of lowering side effects:
|
|
2256
|
+
// resolveValueSymbol also flushes deferred diagnostics and applies
|
|
2257
|
+
// merged-namespace fences, whose authority remains ordinary lowering.
|
|
2258
|
+
this.checker.prefetchSymbolRoots(sourceFiles);
|
|
2259
|
+
const symbolOf = (node) => {
|
|
2260
|
+
const s = this.checker.getSymbolAtLocation(node);
|
|
2261
|
+
if (!s)
|
|
2262
|
+
return null;
|
|
2263
|
+
return s.flags & ts.SymbolFlags.Alias ? this.checker.getAliasedSymbol(s) : s;
|
|
2264
|
+
};
|
|
2265
|
+
const functionDeclBySymbol = new Map();
|
|
2266
|
+
const signatureBySymbol = new Map();
|
|
2267
|
+
for (const [symbol, sig] of this.fnSigsBySymbol)
|
|
2268
|
+
signatureBySymbol.set(symbol, { params: sig.params, returnType: sig.returnType, top: sig });
|
|
2269
|
+
for (const decl of fnDecls) {
|
|
2270
|
+
const symbol = declSymbolOf(this, decl);
|
|
2271
|
+
if (symbol)
|
|
2272
|
+
functionDeclBySymbol.set(symbol, decl);
|
|
2273
|
+
}
|
|
2274
|
+
for (const sf of sourceFiles) {
|
|
2275
|
+
ts.walkPreorder(sf, (node) => {
|
|
2276
|
+
if ((ts.isMethodDeclaration(node) || ts.isGetAccessorDeclaration(node) || ts.isSetAccessorDeclaration(node)) &&
|
|
2277
|
+
node.body && node.name && (ts.isIdentifier(node.name) || ts.isStringLiteral(node.name))) {
|
|
2278
|
+
const symbol = symbolOf(node.name);
|
|
2279
|
+
if (symbol)
|
|
2280
|
+
functionDeclBySymbol.set(symbol, node);
|
|
2281
|
+
}
|
|
2282
|
+
});
|
|
2283
|
+
}
|
|
2284
|
+
for (const info of this.classes.values()) {
|
|
2285
|
+
for (const { mName, member } of this.classMethodMembers(info)) {
|
|
2286
|
+
if (!member.name || !(ts.isIdentifier(member.name) || ts.isStringLiteral(member.name)))
|
|
2287
|
+
continue;
|
|
2288
|
+
const symbol = symbolOf(member.name);
|
|
2289
|
+
const sig = info.methods.get(mName);
|
|
2290
|
+
if (symbol && sig)
|
|
2291
|
+
signatureBySymbol.set(symbol, { params: sig.params, returnType: sig.ret, method: sig });
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
const peel = (node) => {
|
|
2295
|
+
let e = node;
|
|
2296
|
+
while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isTypeAssertion(e) || ts.isNonNullExpression(e)) {
|
|
2297
|
+
e = e.expression;
|
|
2298
|
+
}
|
|
2299
|
+
return e;
|
|
2300
|
+
};
|
|
2301
|
+
const explicitlyNonNull = (node) => {
|
|
2302
|
+
let e = node;
|
|
2303
|
+
while (ts.isParenthesizedExpression(e) || ts.isAsExpression(e) || ts.isTypeAssertion(e) || ts.isNonNullExpression(e)) {
|
|
2304
|
+
if (ts.isNonNullExpression(e))
|
|
2305
|
+
return true;
|
|
2306
|
+
e = e.expression;
|
|
2307
|
+
}
|
|
2308
|
+
return false;
|
|
2309
|
+
};
|
|
2310
|
+
const isArrayRead = (node) => {
|
|
2311
|
+
const e = peel(node);
|
|
2312
|
+
if (!ts.isElementAccessExpression(e))
|
|
2313
|
+
return false;
|
|
2314
|
+
return this.mapTypeOf(this.typeOf(e.expression))?.kind === "array";
|
|
2315
|
+
};
|
|
2316
|
+
const isDynamicObjectEntryRead = (node) => {
|
|
2317
|
+
const read = peel(node);
|
|
2318
|
+
if (!ts.isElementAccessExpression(read) || !ts.isIdentifier(read.expression))
|
|
2319
|
+
return false;
|
|
2320
|
+
const source = symbolOf(read.expression);
|
|
2321
|
+
const declaration = source ? this.checker.valueDeclarationOf(source) : undefined;
|
|
2322
|
+
if (!declaration || !ts.isVariableDeclaration(declaration) || !declaration.initializer)
|
|
2323
|
+
return false;
|
|
2324
|
+
const init = peel(declaration.initializer);
|
|
2325
|
+
if (!ts.isCallExpression(init) || !ts.isPropertyAccessExpression(init.expression))
|
|
2326
|
+
return false;
|
|
2327
|
+
if (init.expression.name.text !== "entries" || !this.isStdlibGlobal(init.expression.expression, "Object"))
|
|
2328
|
+
return false;
|
|
2329
|
+
const object = init.arguments[0];
|
|
2330
|
+
const objectType = object ? this.mapTypeOf(this.typeOf(object)) : null;
|
|
2331
|
+
return objectType?.kind === "dyn" || objectType?.kind === "jsval";
|
|
2332
|
+
};
|
|
2333
|
+
const addUndefined = (t) => {
|
|
2334
|
+
if (t.kind === "union")
|
|
2335
|
+
return this.armTag(t.unionId, UNDEFINED_T) >= 0 ? t : this.withUndefinedArmOf(t) ?? t;
|
|
2336
|
+
if (t.kind === "void" || t.kind === "dyn" || t.kind === "jsval" || t.kind === "generator")
|
|
2337
|
+
return t;
|
|
2338
|
+
return this.withUndefinedArm(t);
|
|
2339
|
+
};
|
|
2340
|
+
const fieldName = (node) => node.name.text;
|
|
2341
|
+
const mayBeOptional = (node) => {
|
|
2342
|
+
// `xs[i]!` is the explicit proven-present form. Its array read keeps
|
|
2343
|
+
// the established dense bounds trap and must not promote the enclosing
|
|
2344
|
+
// function/global ABI to `T | undefined`.
|
|
2345
|
+
if (explicitlyNonNull(node))
|
|
2346
|
+
return false;
|
|
2347
|
+
const e = peel(node);
|
|
2348
|
+
if (isArrayRead(e))
|
|
2349
|
+
return true;
|
|
2350
|
+
if (ts.isCallExpression(e) && this.runtimeOptionalReduceTypes.has(e))
|
|
2351
|
+
return true;
|
|
2352
|
+
if (ts.isCallExpression(e) &&
|
|
2353
|
+
ts.isPropertyAccessExpression(e.expression) &&
|
|
2354
|
+
(e.expression.name.text === "pop" || e.expression.name.text === "shift") &&
|
|
2355
|
+
this.mapTypeOf(this.typeOf(e))?.kind === "union" &&
|
|
2356
|
+
this.armTag(this.mapTypeOf(this.typeOf(e)).unionId, UNDEFINED_T) >= 0)
|
|
2357
|
+
return true;
|
|
2358
|
+
if (ts.isIdentifier(e))
|
|
2359
|
+
return optionalSymbols.has(symbolOf(e) ?? {});
|
|
2360
|
+
if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) {
|
|
2361
|
+
return optionalReturns.has(symbolOf(e.expression) ?? {});
|
|
2362
|
+
}
|
|
2363
|
+
if (ts.isCallExpression(e) && ts.isPropertyAccessExpression(e.expression)) {
|
|
2364
|
+
return optionalReturns.has(symbolOf(e.expression.name) ?? {});
|
|
2365
|
+
}
|
|
2366
|
+
if (ts.isConditionalExpression(e)) {
|
|
2367
|
+
return mayBeOptional(e.whenTrue) || mayBeOptional(e.whenFalse);
|
|
2368
|
+
}
|
|
2369
|
+
if (ts.isBinaryExpression(e)) {
|
|
2370
|
+
const op = e.operatorToken.kind;
|
|
2371
|
+
if (op === ts.SyntaxKind.AmpersandAmpersandToken ||
|
|
2372
|
+
op === ts.SyntaxKind.BarBarToken ||
|
|
2373
|
+
op === ts.SyntaxKind.QuestionQuestionToken)
|
|
2374
|
+
return mayBeOptional(e.left) || mayBeOptional(e.right);
|
|
2375
|
+
}
|
|
2376
|
+
if (ts.isPropertyAccessExpression(e) && ts.isIdentifier(e.expression)) {
|
|
2377
|
+
const fields = optionalFields.get(symbolOf(e.expression) ?? {});
|
|
2378
|
+
return fields?.has(fieldName(e)) ?? false;
|
|
2379
|
+
}
|
|
2380
|
+
return false;
|
|
2381
|
+
};
|
|
2382
|
+
const optionalStringArithmeticType = (node) => {
|
|
2383
|
+
const e = peel(node);
|
|
2384
|
+
if (!ts.isBinaryExpression(e) || e.operatorToken.kind !== ts.SyntaxKind.PlusToken)
|
|
2385
|
+
return null;
|
|
2386
|
+
const stringArrayRead = (part) => {
|
|
2387
|
+
const t = this.mapTypeOf(this.typeOf(part));
|
|
2388
|
+
const p = peel(part);
|
|
2389
|
+
if (t?.kind !== "string" || !ts.isElementAccessExpression(p))
|
|
2390
|
+
return false;
|
|
2391
|
+
const recv = this.mapTypeOf(this.typeOf(p.expression));
|
|
2392
|
+
return recv?.kind === "array" && recv.elem.kind === "string";
|
|
2393
|
+
};
|
|
2394
|
+
const primitive = (part) => {
|
|
2395
|
+
const t = this.mapTypeOf(this.typeOf(part));
|
|
2396
|
+
return t?.kind === "f64" || t?.kind === "string";
|
|
2397
|
+
};
|
|
2398
|
+
if (!stringArrayRead(e.left) && !stringArrayRead(e.right))
|
|
2399
|
+
return null;
|
|
2400
|
+
if (!(primitive(e.left) || stringArrayRead(e.left)) || !(primitive(e.right) || stringArrayRead(e.right)))
|
|
2401
|
+
return null;
|
|
2402
|
+
return { kind: "union", unionId: this.unions.intern([F64, STRING]) };
|
|
2403
|
+
};
|
|
2404
|
+
const noteField = (decl, name) => {
|
|
2405
|
+
if (!ts.isIdentifier(decl.name))
|
|
2406
|
+
return false;
|
|
2407
|
+
const symbol = symbolOf(decl.name);
|
|
2408
|
+
if (!symbol)
|
|
2409
|
+
return false;
|
|
2410
|
+
return noteFieldSymbol(symbol, name);
|
|
2411
|
+
};
|
|
2412
|
+
const noteFieldSymbol = (symbol, name) => {
|
|
2413
|
+
const set = optionalFields.get(symbol) ?? new Set();
|
|
2414
|
+
const before = set.size;
|
|
2415
|
+
set.add(name);
|
|
2416
|
+
optionalFields.set(symbol, set);
|
|
2417
|
+
return set.size !== before;
|
|
2418
|
+
};
|
|
2419
|
+
const scanPattern = (name, init) => {
|
|
2420
|
+
if (!ts.isArrayBindingPattern(name))
|
|
2421
|
+
return false;
|
|
2422
|
+
const sourceType = this.mapTypeOf(this.typeOf(init));
|
|
2423
|
+
if (sourceType?.kind !== "array")
|
|
2424
|
+
return false;
|
|
2425
|
+
let changed = false;
|
|
2426
|
+
name.elements.forEach((el) => {
|
|
2427
|
+
if (ts.isOmittedExpression(el) || el.name === undefined || el.dotDotDotToken)
|
|
2428
|
+
return;
|
|
2429
|
+
if (ts.isIdentifier(el.name)) {
|
|
2430
|
+
const symbol = symbolOf(el.name);
|
|
2431
|
+
if (symbol && !el.initializer && !optionalSymbols.has(symbol)) {
|
|
2432
|
+
optionalSymbols.add(symbol);
|
|
2433
|
+
// Indexed flow facts can survive a mutating method call in the
|
|
2434
|
+
// checker. The array's element ABI describes every value a
|
|
2435
|
+
// position may hold after that call, so bind from that type.
|
|
2436
|
+
const mapped = sourceType.elem;
|
|
2437
|
+
if (mapped && mapped.kind !== "void" && mapped.kind !== "dyn" && mapped.kind !== "jsval") {
|
|
2438
|
+
const widened = mapped.kind === "union" ? this.withUndefinedArmOf(mapped) : this.withUndefinedArm(mapped);
|
|
2439
|
+
if (widened) {
|
|
2440
|
+
this.runtimeOptionalBindingTypes.set(symbol, widened);
|
|
2441
|
+
const global = this.globalsBySymbol.get(symbol);
|
|
2442
|
+
if (global) {
|
|
2443
|
+
global.type = widened;
|
|
2444
|
+
this.runtimeOptionalGlobals.add(global);
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
}
|
|
2448
|
+
changed = true;
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
});
|
|
2452
|
+
return changed;
|
|
2453
|
+
};
|
|
2454
|
+
const hofCallbackIndices = (name, hasInitialValue) => {
|
|
2455
|
+
if (name === "reduce" || name === "reduceRight")
|
|
2456
|
+
return hasInitialValue ? [1] : [0, 1];
|
|
2457
|
+
if (name === "map" || name === "filter" || name === "forEach" ||
|
|
2458
|
+
name === "find" || name === "findIndex" || name === "findLast" ||
|
|
2459
|
+
name === "findLastIndex" || name === "some" || name === "every" ||
|
|
2460
|
+
name === "flatMap")
|
|
2461
|
+
return [0];
|
|
2462
|
+
return null;
|
|
2463
|
+
};
|
|
2464
|
+
const bodyReturnsOptional = (fn) => {
|
|
2465
|
+
if (!fn.body)
|
|
2466
|
+
return false;
|
|
2467
|
+
if (!ts.isBlock(fn.body))
|
|
2468
|
+
return mayBeOptional(fn.body);
|
|
2469
|
+
let found = false;
|
|
2470
|
+
ts.walkPreorder(fn.body, (node) => {
|
|
2471
|
+
if (node !== fn.body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)))
|
|
2472
|
+
return "skip";
|
|
2473
|
+
if (ts.isReturnStatement(node) && node.expression && mayBeOptional(node.expression))
|
|
2474
|
+
found = true;
|
|
2475
|
+
return undefined;
|
|
2476
|
+
});
|
|
2477
|
+
return found;
|
|
2478
|
+
};
|
|
2479
|
+
const promoteHofCallback = (callback, parameterIndices, seen = new Set()) => {
|
|
2480
|
+
let changed = false;
|
|
2481
|
+
const checkerTypeContainsTypeParameter = (type) => {
|
|
2482
|
+
if ((type.flags & ts.TypeFlags.TypeParameter) !== 0)
|
|
2483
|
+
return true;
|
|
2484
|
+
return type.isUnionType() && ts.constituentTypes(type).some(checkerTypeContainsTypeParameter);
|
|
2485
|
+
};
|
|
2486
|
+
const promoteNode = (fn) => {
|
|
2487
|
+
for (const parameterIndex of parameterIndices) {
|
|
2488
|
+
const parameter = fn.parameters[parameterIndex];
|
|
2489
|
+
if (!parameter)
|
|
2490
|
+
continue;
|
|
2491
|
+
const symbol = ts.isIdentifier(parameter.name) ? symbolOf(parameter.name) : null;
|
|
2492
|
+
const checkerType = this.typeOf(parameter.name);
|
|
2493
|
+
const mapped = this.mapTypeOf(checkerType);
|
|
2494
|
+
// Generic callbacks are monomorphized by their call-site binder.
|
|
2495
|
+
// During this prepass the type parameter has no static ABI yet;
|
|
2496
|
+
// asking irTypeOf to invent one poisons otherwise valid generic
|
|
2497
|
+
// value/HOF programs. Leave that parameter at its generic
|
|
2498
|
+
// signature and let the normal instantiation path specialize it.
|
|
2499
|
+
const current = mapped ??
|
|
2500
|
+
(checkerTypeContainsTypeParameter(checkerType) ? null : this.irTypeOf(parameter.name));
|
|
2501
|
+
if (!current)
|
|
2502
|
+
continue;
|
|
2503
|
+
if (!ts.isIdentifier(parameter.name)) {
|
|
2504
|
+
const widened = this.runtimeOptionalType(current);
|
|
2505
|
+
const previous = this.runtimeOptionalPatternTypes.get(parameter.name);
|
|
2506
|
+
this.runtimeOptionalPatternTypes.set(parameter.name, widened);
|
|
2507
|
+
if (!previous || !typeEquals(previous, widened))
|
|
2508
|
+
changed = true;
|
|
2509
|
+
}
|
|
2510
|
+
if (symbol) {
|
|
2511
|
+
const widened = this.runtimeOptionalType(current);
|
|
2512
|
+
const previous = this.runtimeOptionalBindingTypes.get(symbol);
|
|
2513
|
+
this.runtimeOptionalBindingTypes.set(symbol, widened);
|
|
2514
|
+
if (!previous || !typeEquals(previous, widened))
|
|
2515
|
+
changed = true;
|
|
2516
|
+
if (!optionalSymbols.has(symbol)) {
|
|
2517
|
+
optionalSymbols.add(symbol);
|
|
2518
|
+
changed = true;
|
|
2519
|
+
}
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
const fnType = this.mapTypeOf(this.typeOf(fn));
|
|
2523
|
+
if (fnType?.kind === "func" && bodyReturnsOptional(fn)) {
|
|
2524
|
+
const widenedReturn = this.runtimeOptionalType(fnType.ret);
|
|
2525
|
+
const previousReturn = this.runtimeOptionalFunctionReturnType(fn, fnType.ret);
|
|
2526
|
+
this.runtimeOptionalFunctionReturns.set(fn, widenedReturn);
|
|
2527
|
+
if (!typeEquals(previousReturn, widenedReturn))
|
|
2528
|
+
changed = true;
|
|
2529
|
+
}
|
|
2530
|
+
};
|
|
2531
|
+
if (ts.isArrowFunction(callback) || ts.isFunctionExpression(callback) || ts.isFunctionDeclaration(callback) || ts.isMethodDeclaration(callback)) {
|
|
2532
|
+
promoteNode(callback);
|
|
2533
|
+
return changed;
|
|
2534
|
+
}
|
|
2535
|
+
const callbackName = ts.isIdentifier(callback)
|
|
2536
|
+
? callback
|
|
2537
|
+
: ts.isPropertyAccessExpression(callback)
|
|
2538
|
+
? callback.name
|
|
2539
|
+
: null;
|
|
2540
|
+
if (!callbackName)
|
|
2541
|
+
return false;
|
|
2542
|
+
const symbol = symbolOf(callbackName);
|
|
2543
|
+
if (!symbol || seen.has(symbol))
|
|
2544
|
+
return false;
|
|
2545
|
+
// Generic function values are pinned and monomorphized by the normal
|
|
2546
|
+
// contextual-value path when the HOF lowers its callback. Promoting
|
|
2547
|
+
// their type-parameter body here either asks for an impossible
|
|
2548
|
+
// monomorphic ABI or poisons valid generic value programs.
|
|
2549
|
+
if (this.genericFnsBySymbol.has(symbol))
|
|
2550
|
+
return false;
|
|
2551
|
+
seen.add(symbol);
|
|
2552
|
+
const declaration = this.checker.valueDeclarationOf(symbol);
|
|
2553
|
+
if (declaration && ts.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
2554
|
+
if (promoteHofCallback(peel(declaration.initializer), parameterIndices, seen))
|
|
2555
|
+
changed = true;
|
|
2556
|
+
}
|
|
2557
|
+
const sig = signatureBySymbol.get(symbol);
|
|
2558
|
+
if (sig) {
|
|
2559
|
+
for (const parameterIndex of parameterIndices) {
|
|
2560
|
+
if (!sig.params[parameterIndex])
|
|
2561
|
+
continue;
|
|
2562
|
+
const before = sig.params[parameterIndex].type;
|
|
2563
|
+
sig.params[parameterIndex].type = this.runtimeOptionalType(before);
|
|
2564
|
+
if (!typeEquals(before, sig.params[parameterIndex].type))
|
|
2565
|
+
changed = true;
|
|
2566
|
+
}
|
|
2567
|
+
}
|
|
2568
|
+
const fn = functionDeclBySymbol.get(symbol);
|
|
2569
|
+
if (fn)
|
|
2570
|
+
promoteNode(fn);
|
|
2571
|
+
const valueType = this.runtimeOptionalBindingTypes.get(symbol) ?? this.mapTypeOf(this.typeOf(callback));
|
|
2572
|
+
if (valueType?.kind === "func") {
|
|
2573
|
+
const params = valueType.params.slice();
|
|
2574
|
+
for (const parameterIndex of parameterIndices) {
|
|
2575
|
+
if (params[parameterIndex])
|
|
2576
|
+
params[parameterIndex] = this.runtimeOptionalType(params[parameterIndex]);
|
|
2577
|
+
}
|
|
2578
|
+
const promoted = { ...valueType, params };
|
|
2579
|
+
const previous = this.runtimeOptionalBindingTypes.get(symbol);
|
|
2580
|
+
this.runtimeOptionalBindingTypes.set(symbol, promoted);
|
|
2581
|
+
if (!previous || !typeEquals(previous, promoted))
|
|
2582
|
+
changed = true;
|
|
2583
|
+
const global = this.globalsBySymbol.get(symbol);
|
|
2584
|
+
if (global)
|
|
2585
|
+
global.type = promoted;
|
|
2586
|
+
// A callback-typed parameter used by a native array HOF changes
|
|
2587
|
+
// the containing function's own call ABI. Record that edge in the
|
|
2588
|
+
// already-collected signature as well as on the body binding, so a
|
|
2589
|
+
// caller can promote the concrete callback value it supplies on a
|
|
2590
|
+
// later fixed-point pass (`wrapper(xs, predicate)` ->
|
|
2591
|
+
// `xs.some(predicate)`).
|
|
2592
|
+
if (declaration && ts.isParameter(declaration)) {
|
|
2593
|
+
const owner = declaration.parent;
|
|
2594
|
+
let ownerSymbol = null;
|
|
2595
|
+
if (ts.isFunctionDeclaration(owner))
|
|
2596
|
+
ownerSymbol = declSymbolOf(this, owner) ?? null;
|
|
2597
|
+
else if ((ts.isMethodDeclaration(owner) || ts.isGetAccessorDeclaration(owner) || ts.isSetAccessorDeclaration(owner)) &&
|
|
2598
|
+
owner.name)
|
|
2599
|
+
ownerSymbol = symbolOf(owner.name);
|
|
2600
|
+
const ownerSig = ownerSymbol ? signatureBySymbol.get(ownerSymbol) : undefined;
|
|
2601
|
+
const ownerIndex = ts.isFunctionLike(owner) ? owner.parameters.indexOf(declaration) : -1;
|
|
2602
|
+
const slot = ownerIndex >= 0 ? ownerSig?.params[ownerIndex] : undefined;
|
|
2603
|
+
if (slot && !typeEquals(slot.type, promoted)) {
|
|
2604
|
+
slot.type = promoted;
|
|
2605
|
+
changed = true;
|
|
2606
|
+
}
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2609
|
+
return changed;
|
|
2610
|
+
};
|
|
2611
|
+
const callbackReturnsOptional = (callback, seen = new Set()) => {
|
|
2612
|
+
const node = peel(callback);
|
|
2613
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
|
|
2614
|
+
return bodyReturnsOptional(node);
|
|
2615
|
+
const symbol = symbolOf(ts.isPropertyAccessExpression(node) ? node.name : node);
|
|
2616
|
+
if (!symbol || seen.has(symbol))
|
|
2617
|
+
return false;
|
|
2618
|
+
seen.add(symbol);
|
|
2619
|
+
const fn = functionDeclBySymbol.get(symbol);
|
|
2620
|
+
if (fn)
|
|
2621
|
+
return bodyReturnsOptional(fn);
|
|
2622
|
+
const decl = this.checker.valueDeclarationOf(symbol);
|
|
2623
|
+
return !!decl && ts.isVariableDeclaration(decl) && !!decl.initializer && callbackReturnsOptional(decl.initializer, seen);
|
|
2624
|
+
};
|
|
2625
|
+
const scanFile = (sf) => {
|
|
2626
|
+
let changed = false;
|
|
2627
|
+
ts.walkPreorder(sf, (node) => {
|
|
2628
|
+
if (ts.isVariableDeclaration(node)) {
|
|
2629
|
+
if (node.initializer) {
|
|
2630
|
+
if (ts.isIdentifier(node.name) && isDynamicObjectEntryRead(node.initializer)) {
|
|
2631
|
+
const symbol = symbolOf(node.name);
|
|
2632
|
+
if (symbol && !dynamicObjectEntryRows.has(symbol)) {
|
|
2633
|
+
dynamicObjectEntryRows.add(symbol);
|
|
2634
|
+
changed = true;
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
else if (ts.isIdentifier(node.name) && mayBeOptional(node.initializer)) {
|
|
2638
|
+
const symbol = symbolOf(node.name);
|
|
2639
|
+
if (symbol && !optionalSymbols.has(symbol)) {
|
|
2640
|
+
optionalSymbols.add(symbol);
|
|
2641
|
+
changed = true;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
if (ts.isIdentifier(node.name)) {
|
|
2645
|
+
const valueSymbol = ts.isIdentifier(peel(node.initializer))
|
|
2646
|
+
? symbolOf(peel(node.initializer))
|
|
2647
|
+
: ts.isPropertyAccessExpression(peel(node.initializer))
|
|
2648
|
+
? symbolOf(peel(node.initializer).name)
|
|
2649
|
+
: null;
|
|
2650
|
+
const symbol = symbolOf(node.name);
|
|
2651
|
+
const sourceSig = valueSymbol ? signatureBySymbol.get(valueSymbol) : undefined;
|
|
2652
|
+
const sourceOptional = !!sourceSig &&
|
|
2653
|
+
(optionalReturns.has(valueSymbol) ||
|
|
2654
|
+
(sourceSig.returnType.kind === "union" && this.armTag(sourceSig.returnType.unionId, UNDEFINED_T) >= 0) ||
|
|
2655
|
+
sourceSig.params.some((p) => p.type.kind === "union" && this.armTag(p.type.unionId, UNDEFINED_T) >= 0));
|
|
2656
|
+
if (symbol && valueSymbol && sourceOptional) {
|
|
2657
|
+
const aliasNew = !optionalReturns.has(symbol);
|
|
2658
|
+
if (aliasNew)
|
|
2659
|
+
optionalReturns.add(symbol);
|
|
2660
|
+
if (aliasNew)
|
|
2661
|
+
changed = true;
|
|
2662
|
+
const valueType = this.mapTypeOf(this.typeOf(node.name));
|
|
2663
|
+
if (valueType?.kind === "func" && sourceSig) {
|
|
2664
|
+
const promotedFn = {
|
|
2665
|
+
...valueType,
|
|
2666
|
+
params: sourceSig.params.map((p) => p.type),
|
|
2667
|
+
ret: sourceSig.returnType,
|
|
2668
|
+
};
|
|
2669
|
+
const previous = this.runtimeOptionalBindingTypes.get(symbol);
|
|
2670
|
+
if (!previous || !typeEquals(previous, promotedFn)) {
|
|
2671
|
+
this.runtimeOptionalBindingTypes.set(symbol, promotedFn);
|
|
2672
|
+
const global = this.globalsBySymbol.get(symbol);
|
|
2673
|
+
if (global)
|
|
2674
|
+
global.type = promotedFn;
|
|
2675
|
+
changed = true;
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
if (scanPattern(node.name, node.initializer))
|
|
2681
|
+
changed = true;
|
|
2682
|
+
if (ts.isIdentifier(node.name) && ts.isObjectLiteralExpression(peel(node.initializer))) {
|
|
2683
|
+
const object = peel(node.initializer);
|
|
2684
|
+
for (const prop of object.properties) {
|
|
2685
|
+
if (!ts.isPropertyAssignment(prop) && !ts.isShorthandPropertyAssignment(prop))
|
|
2686
|
+
continue;
|
|
2687
|
+
const name = prop.name;
|
|
2688
|
+
if (!name || !(ts.isIdentifier(name) || ts.isStringLiteral(name) || ts.isNumericLiteral(name)))
|
|
2689
|
+
continue;
|
|
2690
|
+
const value = ts.isPropertyAssignment(prop) ? prop.initializer : prop.name;
|
|
2691
|
+
if (mayBeOptional(value) && noteField(node, name.text))
|
|
2692
|
+
changed = true;
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
2697
|
+
if (ts.isBinaryExpression(node) &&
|
|
2698
|
+
(node.operatorToken.kind === ts.SyntaxKind.EqualsToken ||
|
|
2699
|
+
node.operatorToken.kind === ts.SyntaxKind.QuestionQuestionEqualsToken ||
|
|
2700
|
+
node.operatorToken.kind === ts.SyntaxKind.BarBarEqualsToken ||
|
|
2701
|
+
node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandEqualsToken) &&
|
|
2702
|
+
mayBeOptional(node.right)) {
|
|
2703
|
+
if (ts.isIdentifier(node.left)) {
|
|
2704
|
+
const symbol = symbolOf(node.left);
|
|
2705
|
+
if (symbol && !optionalSymbols.has(symbol)) {
|
|
2706
|
+
optionalSymbols.add(symbol);
|
|
2707
|
+
changed = true;
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
else if (ts.isPropertyAccessExpression(node.left) && ts.isIdentifier(node.left.expression)) {
|
|
2711
|
+
const symbol = symbolOf(node.left.expression);
|
|
2712
|
+
if (symbol && noteFieldSymbol(symbol, node.left.name.text))
|
|
2713
|
+
changed = true;
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
if (ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression)) {
|
|
2717
|
+
const callbackIndices = hofCallbackIndices(node.expression.name.text, node.arguments.length >= 2);
|
|
2718
|
+
const receiverNode = node.expression.expression;
|
|
2719
|
+
const receiver = this.mapTypeOf(this.typeOf(receiverNode));
|
|
2720
|
+
const callback = callbackIndices === null ? undefined : node.arguments[0];
|
|
2721
|
+
const tuple = receiver?.kind === "record" && this.shapes.get(receiver.shapeId)?.tuple === true;
|
|
2722
|
+
// A JS/evolving-any array may have acquired a precise FLOW type
|
|
2723
|
+
// at this call while its actual binding remains a checked-dynamic
|
|
2724
|
+
// array. Its callback consumes DYN values through runtime method
|
|
2725
|
+
// dispatch, so widening that callback to the native array value
|
|
2726
|
+
// ABI makes it impossible to box back into DYN. Judge a simple
|
|
2727
|
+
// binding by its declaration type, the same storage fact local
|
|
2728
|
+
// declaration lowering uses.
|
|
2729
|
+
let nativeArrayReceiver = receiver?.kind === "array" || tuple;
|
|
2730
|
+
if (nativeArrayReceiver && ts.isIdentifier(receiverNode)) {
|
|
2731
|
+
const receiverSymbol = symbolOf(receiverNode);
|
|
2732
|
+
const declaration = receiverSymbol ? this.checker.valueDeclarationOf(receiverSymbol) : undefined;
|
|
2733
|
+
if (declaration && ts.isVariableDeclaration(declaration)) {
|
|
2734
|
+
const declared = this.mapTypeOf(this.typeOf(declaration.name));
|
|
2735
|
+
if (declared?.kind !== "array" && !(declared?.kind === "record" && this.shapes.get(declared.shapeId)?.tuple === true)) {
|
|
2736
|
+
nativeArrayReceiver = false;
|
|
2737
|
+
}
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
if (nativeArrayReceiver && callback && !ts.isSpreadElement(callback)) {
|
|
2741
|
+
if (promoteHofCallback(callback, callbackIndices))
|
|
2742
|
+
changed = true;
|
|
2743
|
+
const method = node.expression.name.text;
|
|
2744
|
+
if ((method === "reduce" || method === "reduceRight") &&
|
|
2745
|
+
(node.arguments.length < 2 || callbackReturnsOptional(callback))) {
|
|
2746
|
+
if (promoteHofCallback(callback, [0, 1]))
|
|
2747
|
+
changed = true;
|
|
2748
|
+
const result = this.runtimeOptionalType(this.irTypeOf(node));
|
|
2749
|
+
const previous = this.runtimeOptionalReduceTypes.get(node);
|
|
2750
|
+
if (!previous || !typeEquals(previous, result)) {
|
|
2751
|
+
this.runtimeOptionalReduceTypes.set(node, result);
|
|
2752
|
+
changed = true;
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
if (ts.isCallExpression(node) &&
|
|
2758
|
+
(ts.isIdentifier(node.expression) || ts.isPropertyAccessExpression(node.expression))) {
|
|
2759
|
+
const calleeNode = ts.isIdentifier(node.expression) ? node.expression : node.expression.name;
|
|
2760
|
+
const symbol = symbolOf(calleeNode);
|
|
2761
|
+
if (!symbol)
|
|
2762
|
+
return;
|
|
2763
|
+
const sig = signatureBySymbol.get(symbol);
|
|
2764
|
+
if (!sig) {
|
|
2765
|
+
const decl = this.checker.valueDeclarationOf(symbol);
|
|
2766
|
+
if (decl && ts.isVariableDeclaration(decl) && decl.initializer && ts.isIdentifier(decl.initializer)) {
|
|
2767
|
+
const source = symbolOf(decl.initializer);
|
|
2768
|
+
const sourceSig = source ? signatureBySymbol.get(source) : undefined;
|
|
2769
|
+
if (sourceSig) {
|
|
2770
|
+
node.arguments.forEach((arg, i) => {
|
|
2771
|
+
if (ts.isSpreadElement(arg) || !mayBeOptional(arg) || !sourceSig.params[i])
|
|
2772
|
+
return;
|
|
2773
|
+
const before = sourceSig.params[i].type;
|
|
2774
|
+
sourceSig.params[i].type = this.runtimeOptionalType(before);
|
|
2775
|
+
if (!typeEquals(before, sourceSig.params[i].type)) {
|
|
2776
|
+
changed = true;
|
|
2777
|
+
const sourceFn = functionDeclBySymbol.get(source);
|
|
2778
|
+
const parameter = sourceFn?.parameters[i];
|
|
2779
|
+
if (parameter) {
|
|
2780
|
+
for (const bound of boundIdentifiersOf(parameter.name)) {
|
|
2781
|
+
const boundSymbol = symbolOf(bound);
|
|
2782
|
+
if (boundSymbol && !optionalSymbols.has(boundSymbol)) {
|
|
2783
|
+
optionalSymbols.add(boundSymbol);
|
|
2784
|
+
changed = true;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
});
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
return;
|
|
2793
|
+
}
|
|
2794
|
+
node.arguments.forEach((arg, i) => {
|
|
2795
|
+
const callbackSlot = sig.params[i]?.type;
|
|
2796
|
+
if (callbackSlot?.kind === "func" && !ts.isSpreadElement(arg)) {
|
|
2797
|
+
const optionalCallbackParams = callbackSlot.params.flatMap((type, index) => type.kind === "union" && this.armTag(type.unionId, UNDEFINED_T) >= 0 ? [index] : []);
|
|
2798
|
+
if (optionalCallbackParams.length > 0 && promoteHofCallback(arg, optionalCallbackParams)) {
|
|
2799
|
+
changed = true;
|
|
2800
|
+
}
|
|
2801
|
+
}
|
|
2802
|
+
if (ts.isSpreadElement(arg) || !mayBeOptional(arg) || !sig.params[i])
|
|
2803
|
+
return;
|
|
2804
|
+
const set = optionalParams.get(symbol) ?? new Set();
|
|
2805
|
+
const before = set.size;
|
|
2806
|
+
set.add(i);
|
|
2807
|
+
optionalParams.set(symbol, set);
|
|
2808
|
+
if (set.size !== before) {
|
|
2809
|
+
changed = true;
|
|
2810
|
+
const callee = functionDeclBySymbol.get(symbol);
|
|
2811
|
+
const parameter = callee?.parameters[i];
|
|
2812
|
+
if (parameter) {
|
|
2813
|
+
for (const bound of boundIdentifiersOf(parameter.name)) {
|
|
2814
|
+
const boundSymbol = symbolOf(bound);
|
|
2815
|
+
if (boundSymbol && !optionalSymbols.has(boundSymbol)) {
|
|
2816
|
+
optionalSymbols.add(boundSymbol);
|
|
2817
|
+
changed = true;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
});
|
|
2823
|
+
}
|
|
2824
|
+
});
|
|
2825
|
+
return changed;
|
|
2826
|
+
};
|
|
2827
|
+
const scanReturns = (symbol, decl) => {
|
|
2828
|
+
if (!decl.body)
|
|
2829
|
+
return false;
|
|
2830
|
+
let changed = false;
|
|
2831
|
+
if (!ts.isBlock(decl.body) && mayBeOptional(decl.body) && !optionalReturns.has(symbol)) {
|
|
2832
|
+
optionalReturns.add(symbol);
|
|
2833
|
+
changed = true;
|
|
2834
|
+
}
|
|
2835
|
+
if (!ts.isBlock(decl.body)) {
|
|
2836
|
+
const arithmetic = optionalStringArithmeticType(decl.body);
|
|
2837
|
+
if (arithmetic && !arithmeticReturns.has(symbol)) {
|
|
2838
|
+
arithmeticReturns.set(symbol, arithmetic);
|
|
2839
|
+
changed = true;
|
|
2840
|
+
}
|
|
2841
|
+
}
|
|
2842
|
+
ts.walkPreorder(decl.body, (node) => {
|
|
2843
|
+
if (node !== decl.body && (ts.isFunctionDeclaration(node) || ts.isFunctionExpression(node) || ts.isArrowFunction(node) || ts.isMethodDeclaration(node)))
|
|
2844
|
+
return "skip";
|
|
2845
|
+
if (ts.isReturnStatement(node) && node.expression && mayBeOptional(node.expression) && !optionalReturns.has(symbol)) {
|
|
2846
|
+
optionalReturns.add(symbol);
|
|
2847
|
+
changed = true;
|
|
2848
|
+
}
|
|
2849
|
+
if (ts.isReturnStatement(node) && node.expression) {
|
|
2850
|
+
const arithmetic = optionalStringArithmeticType(node.expression);
|
|
2851
|
+
if (arithmetic && !arithmeticReturns.has(symbol)) {
|
|
2852
|
+
arithmeticReturns.set(symbol, arithmetic);
|
|
2853
|
+
changed = true;
|
|
2854
|
+
}
|
|
2855
|
+
}
|
|
2856
|
+
return undefined;
|
|
2857
|
+
});
|
|
2858
|
+
return changed;
|
|
2859
|
+
};
|
|
2860
|
+
let changed = true;
|
|
2861
|
+
while (changed) {
|
|
2862
|
+
changed = false;
|
|
2863
|
+
for (const sf of sourceFiles)
|
|
2864
|
+
if (scanFile(sf))
|
|
2865
|
+
changed = true;
|
|
2866
|
+
for (const [symbol, decl] of functionDeclBySymbol)
|
|
2867
|
+
if (scanReturns(symbol, decl))
|
|
2868
|
+
changed = true;
|
|
2869
|
+
}
|
|
2870
|
+
for (const [symbol, sig] of signatureBySymbol) {
|
|
2871
|
+
const params = optionalParams.get(symbol);
|
|
2872
|
+
if (params) {
|
|
2873
|
+
for (const i of params) {
|
|
2874
|
+
const shape = sig.params[i];
|
|
2875
|
+
if (shape)
|
|
2876
|
+
shape.type = addUndefined(shape.type);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
if (optionalReturns.has(symbol)) {
|
|
2880
|
+
const next = sig.returnType.kind === "promise"
|
|
2881
|
+
? { kind: "promise", inner: addUndefined(sig.returnType.inner) }
|
|
2882
|
+
: addUndefined(sig.returnType);
|
|
2883
|
+
sig.returnType = next;
|
|
2884
|
+
if (sig.top)
|
|
2885
|
+
sig.top.returnType = next;
|
|
2886
|
+
if (sig.method)
|
|
2887
|
+
sig.method.ret = next;
|
|
2888
|
+
}
|
|
2889
|
+
const arithmetic = arithmeticReturns.get(symbol);
|
|
2890
|
+
if (arithmetic && sig.returnType.kind !== "promise") {
|
|
2891
|
+
sig.returnType = arithmetic;
|
|
2892
|
+
if (sig.top)
|
|
2893
|
+
sig.top.returnType = arithmetic;
|
|
2894
|
+
if (sig.method)
|
|
2895
|
+
sig.method.ret = arithmetic;
|
|
2896
|
+
const decl = functionDeclBySymbol.get(symbol);
|
|
2897
|
+
if (decl)
|
|
2898
|
+
this.runtimeOptionalFunctionReturns.set(decl, arithmetic);
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
for (const sf of sourceFiles) {
|
|
2902
|
+
ts.walkPreorder(sf, (node) => {
|
|
2903
|
+
if (!ts.isVariableDeclaration(node) || !ts.isIdentifier(node.name))
|
|
2904
|
+
return;
|
|
2905
|
+
const symbol = symbolOf(node.name);
|
|
2906
|
+
if (!symbol)
|
|
2907
|
+
return;
|
|
2908
|
+
const fields = optionalFields.get(symbol);
|
|
2909
|
+
if (!dynamicObjectEntryRows.has(symbol) && !optionalSymbols.has(symbol) && !fields)
|
|
2910
|
+
return;
|
|
2911
|
+
const current = this.mapTypeOf(this.typeOf(node.name));
|
|
2912
|
+
if (!current)
|
|
2913
|
+
return;
|
|
2914
|
+
let promoted = dynamicObjectEntryRows.has(symbol) ? DYN : current;
|
|
2915
|
+
if (!dynamicObjectEntryRows.has(symbol) && optionalSymbols.has(symbol))
|
|
2916
|
+
promoted = addUndefined(promoted);
|
|
2917
|
+
if (promoted.kind === "func" && node.initializer && ts.isIdentifier(node.initializer)) {
|
|
2918
|
+
const sourceSig = this.fnSigOf(node.initializer);
|
|
2919
|
+
if (sourceSig) {
|
|
2920
|
+
promoted = {
|
|
2921
|
+
...promoted,
|
|
2922
|
+
params: sourceSig.params.filter((p) => p.mode !== "dynRest").map((p) => p.type),
|
|
2923
|
+
ret: sourceSig.returnType,
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
if (fields && promoted.kind === "record") {
|
|
2928
|
+
for (const field of fields) {
|
|
2929
|
+
const source = promoted.kind === "record"
|
|
2930
|
+
? this.shapes.get(promoted.shapeId)?.fields.find((f) => f.name === field)
|
|
2931
|
+
: undefined;
|
|
2932
|
+
if (!source)
|
|
2933
|
+
continue;
|
|
2934
|
+
promoted = this.runtimeOptionalRecordField(promoted, field, addUndefined(source.type));
|
|
2935
|
+
}
|
|
2936
|
+
}
|
|
2937
|
+
if (!typeEquals(promoted, current)) {
|
|
2938
|
+
this.runtimeOptionalBindingTypes.set(symbol, promoted);
|
|
2939
|
+
const global = ts.isIdentifier(node.name) ? this.globalOf(node.name) : this.globalsBySymbol.get(symbol);
|
|
2940
|
+
if (global) {
|
|
2941
|
+
global.type = promoted;
|
|
2942
|
+
this.runtimeOptionalGlobals.add(global);
|
|
2943
|
+
}
|
|
2944
|
+
}
|
|
2945
|
+
else if (promoted.kind === "union" && this.armTag(promoted.unionId, UNDEFINED_T) >= 0) {
|
|
2946
|
+
const global = ts.isIdentifier(node.name) ? this.globalOf(node.name) : this.globalsBySymbol.get(symbol);
|
|
2947
|
+
if (global)
|
|
2948
|
+
this.runtimeOptionalGlobals.add(global);
|
|
2949
|
+
}
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
}
|
|
1986
2953
|
run() {
|
|
1987
2954
|
const parts = this.splitFiles();
|
|
1988
2955
|
// The coverage remainder deliberately visits every body that reachable
|
|
@@ -1996,6 +2963,7 @@ export class Lowerer {
|
|
|
1996
2963
|
this.checker.prefetchSourceFile(fp.sf);
|
|
1997
2964
|
}
|
|
1998
2965
|
this.collectProgram(parts);
|
|
2966
|
+
this.analyzeRuntimeOptionalArrayReads(parts);
|
|
1999
2967
|
// Decorated classes analyze AFTER the whole collection pass: a
|
|
2000
2968
|
// decorator's return type may name a subclass declared below the
|
|
2001
2969
|
// class, and reference lowering needs each class's rebindability
|
|
@@ -2224,7 +3192,7 @@ export class Lowerer {
|
|
|
2224
3192
|
const module = this.diags.length > 0
|
|
2225
3193
|
? null
|
|
2226
3194
|
: {
|
|
2227
|
-
irVersion:
|
|
3195
|
+
irVersion: 8,
|
|
2228
3196
|
sourceFile: this.entry.fileName,
|
|
2229
3197
|
functions,
|
|
2230
3198
|
classes: artifacts.classes,
|
|
@@ -2367,6 +3335,7 @@ export class Lowerer {
|
|
|
2367
3335
|
// will reuse the same answers later.
|
|
2368
3336
|
this.prefetchClassCollection(parts.flatMap((fp) => fp.classDecls));
|
|
2369
3337
|
this.collectProgram(parts);
|
|
3338
|
+
this.analyzeRuntimeOptionalArrayReads(parts);
|
|
2370
3339
|
// Decorated classes analyze post-collection here too: the %init seeds
|
|
2371
3340
|
// lower the decoration calls, whose edges (decorator bodies, construct
|
|
2372
3341
|
// thunks) reachable emit must see.
|
|
@@ -2710,7 +3679,61 @@ export class Lowerer {
|
|
|
2710
3679
|
moduleArtifacts(functions) {
|
|
2711
3680
|
return moduleArtifacts(this, functions);
|
|
2712
3681
|
}
|
|
2713
|
-
|
|
3682
|
+
deferToRuntimeFence(diagsBefore, node, target) {
|
|
3683
|
+
if ((this.diagSink !== null && target.allowDiagSink !== true) ||
|
|
3684
|
+
(this.diags.length <= diagsBefore && target.fallback === undefined)) {
|
|
3685
|
+
return null;
|
|
3686
|
+
}
|
|
3687
|
+
const captured = this.diags.splice(diagsBefore);
|
|
3688
|
+
if (captured.some((d) => d.code === "SC9001")) {
|
|
3689
|
+
this.diags.push(...captured);
|
|
3690
|
+
return null;
|
|
3691
|
+
}
|
|
3692
|
+
this.runtimeFences.push(...captured);
|
|
3693
|
+
const first = captured[0];
|
|
3694
|
+
const loc = locOf(node);
|
|
3695
|
+
const code = first?.code ?? target.fallback.code;
|
|
3696
|
+
const baseMessage = first?.message ?? target.fallback.message;
|
|
3697
|
+
const messageLoc = first?.loc ?? loc;
|
|
3698
|
+
const source = first
|
|
3699
|
+
? this.program.getSourceFile(messageLoc.file) ?? node.getSourceFile()
|
|
3700
|
+
: node.getSourceFile();
|
|
3701
|
+
const pos = ts.getLineAndCharacterOfPosition(source, messageLoc.start);
|
|
3702
|
+
const fence = {
|
|
3703
|
+
kind: "runtimeFence",
|
|
3704
|
+
code,
|
|
3705
|
+
message: target.bareMessage
|
|
3706
|
+
? baseMessage
|
|
3707
|
+
: `${baseMessage} [${code} at ${messageLoc.file}:${pos.line + 1}]`,
|
|
3708
|
+
loc,
|
|
3709
|
+
};
|
|
3710
|
+
if (target.kind === "statement")
|
|
3711
|
+
return fence;
|
|
3712
|
+
const params = target.params ?? [];
|
|
3713
|
+
const name = typeof target.name === "function" ? target.name() : target.name;
|
|
3714
|
+
const fn = {
|
|
3715
|
+
name,
|
|
3716
|
+
params,
|
|
3717
|
+
returnType: target.returnType,
|
|
3718
|
+
locals: params.map((p) => ({
|
|
3719
|
+
id: p.localId,
|
|
3720
|
+
name: p.name,
|
|
3721
|
+
type: p.type,
|
|
3722
|
+
mutable: target.paramsMutable ?? false,
|
|
3723
|
+
})),
|
|
3724
|
+
body: [fence],
|
|
3725
|
+
loc,
|
|
3726
|
+
};
|
|
3727
|
+
if (target.async)
|
|
3728
|
+
fn.async = true;
|
|
3729
|
+
if (target.generator)
|
|
3730
|
+
fn.generator = target.generator;
|
|
3731
|
+
if (target.kind === "function")
|
|
3732
|
+
return fn;
|
|
3733
|
+
fn.captures = [];
|
|
3734
|
+
this.liftedFns.push(fn);
|
|
3735
|
+
return { kind: "closure", fnName: fn.name, captures: [], type: target.type, loc };
|
|
3736
|
+
}
|
|
2714
3737
|
/** All diagnostics land here; while a generic instance body is lowering,
|
|
2715
3738
|
* the instantiation context is appended so the user knows which concrete
|
|
2716
3739
|
* types made the (source-anchored) construct fail. */
|
|
@@ -3112,11 +4135,14 @@ export class Lowerer {
|
|
|
3112
4135
|
const def = this.unions.get(unionId);
|
|
3113
4136
|
return def ? def.arms.flatMap((arm, tag) => (this.isArrayValueType(arm) ? [tag] : [])) : [];
|
|
3114
4137
|
}
|
|
3115
|
-
/**
|
|
3116
|
-
*
|
|
4138
|
+
/** Checked JSON conversion excludes undefined array slots because JSON
|
|
4139
|
+
* text cannot preserve that distinction. */
|
|
3117
4140
|
jsonSafe(t) {
|
|
3118
4141
|
return isJsonSafeType(t, (id) => this.shapes.get(id), (id) => this.unions.get(id));
|
|
3119
4142
|
}
|
|
4143
|
+
jsonStringifySafe(t) {
|
|
4144
|
+
return isJsonStringifySafeType(t, (id) => this.shapes.get(id), (id) => this.unions.get(id));
|
|
4145
|
+
}
|
|
3120
4146
|
/** True when a type is a BARE undefined-armed union — the one JSON-unsafe
|
|
3121
4147
|
* shape whose rejections deserve their own wording: Node's stringify of
|
|
3122
4148
|
* bare undefined is not a string at all and JSON text never matches the
|
|
@@ -3316,7 +4342,7 @@ export class Lowerer {
|
|
|
3316
4342
|
/** Unwraps a HYBRID (function-with-properties) record to its callable:
|
|
3317
4343
|
* a record whose shape carries the reserved `%call` func field reads
|
|
3318
4344
|
* that field; anything else returns unchanged. The consumer half of
|
|
3319
|
-
*
|
|
4345
|
+
* type-mapper.ts's chalk-shape mapping — call paths and func-slot coercions
|
|
3320
4346
|
* share it. */
|
|
3321
4347
|
hybridCallUnwrap(expr) {
|
|
3322
4348
|
if (expr.type.kind !== "record")
|
|
@@ -3499,7 +4525,7 @@ export class Lowerer {
|
|
|
3499
4525
|
}
|
|
3500
4526
|
// A HYBRID (function-with-properties) record flowing into a plain
|
|
3501
4527
|
// func slot extracts its reserved %call field — the chalk shape's
|
|
3502
|
-
// "the value IS callable" half (
|
|
4528
|
+
// "the value IS callable" half (type-mapper.ts's hybrid mapping).
|
|
3503
4529
|
if (expected.kind === "func" && expr.type.kind === "record") {
|
|
3504
4530
|
const un = this.hybridCallUnwrap(expr);
|
|
3505
4531
|
if (un !== expr && typeEquals(un.type, expected))
|
|
@@ -3954,102 +4980,102 @@ export class Lowerer {
|
|
|
3954
4980
|
return value;
|
|
3955
4981
|
case "wrap": {
|
|
3956
4982
|
if (dst.kind !== "union")
|
|
3957
|
-
throw new
|
|
4983
|
+
throw new InternalCompilerError("lowerer bug: wrap lift against a non-union");
|
|
3958
4984
|
return { kind: "unionWrap", unionId: dst.unionId, tag: lift.tag, value, type: dst, loc };
|
|
3959
4985
|
}
|
|
3960
4986
|
case "retag": {
|
|
3961
4987
|
if (dst.kind !== "union" || value.type.kind !== "union")
|
|
3962
|
-
throw new
|
|
4988
|
+
throw new InternalCompilerError("lowerer bug: retag lift shape");
|
|
3963
4989
|
const retag = this.unionRetagHelper(value.type.unionId, dst.unionId, loc);
|
|
3964
4990
|
if (!retag)
|
|
3965
|
-
throw new
|
|
4991
|
+
throw new InternalCompilerError("lowerer bug: planned retag lift failed to intern");
|
|
3966
4992
|
return { kind: "call", callee: retag, args: [value], type: dst, loc };
|
|
3967
4993
|
}
|
|
3968
4994
|
case "liftWrap": {
|
|
3969
4995
|
if (dst.kind !== "union")
|
|
3970
|
-
throw new
|
|
4996
|
+
throw new InternalCompilerError("lowerer bug: liftWrap lift against a non-union");
|
|
3971
4997
|
const inner = this.widthLiftPlan(value.type, lift.arm);
|
|
3972
4998
|
if (!inner)
|
|
3973
|
-
throw new
|
|
4999
|
+
throw new InternalCompilerError("lowerer bug: planned liftWrap arm stopped lifting");
|
|
3974
5000
|
const lifted = this.applyWidthLift(inner, value, lift.arm, loc);
|
|
3975
5001
|
return { kind: "unionWrap", unionId: dst.unionId, tag: lift.tag, value: lifted, type: dst, loc };
|
|
3976
5002
|
}
|
|
3977
5003
|
case "width": {
|
|
3978
5004
|
if (dst.kind !== "record" || value.type.kind !== "record")
|
|
3979
|
-
throw new
|
|
5005
|
+
throw new InternalCompilerError("lowerer bug: width lift shape");
|
|
3980
5006
|
const helper = this.recordWidthHelper(value.type.shapeId, dst.shapeId, loc);
|
|
3981
5007
|
if (!helper)
|
|
3982
|
-
throw new
|
|
5008
|
+
throw new InternalCompilerError("lowerer bug: planned width lift failed to intern");
|
|
3983
5009
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
3984
5010
|
}
|
|
3985
5011
|
case "arr": {
|
|
3986
5012
|
if (dst.kind !== "array" || value.type.kind !== "array")
|
|
3987
|
-
throw new
|
|
5013
|
+
throw new InternalCompilerError("lowerer bug: arr lift shape");
|
|
3988
5014
|
const helper = this.arrayWidthHelper(value.type, dst, loc);
|
|
3989
5015
|
if (!helper)
|
|
3990
|
-
throw new
|
|
5016
|
+
throw new InternalCompilerError("lowerer bug: planned arr lift failed to intern");
|
|
3991
5017
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
3992
5018
|
}
|
|
3993
5019
|
case "tupleArr": {
|
|
3994
5020
|
if (dst.kind !== "array" || value.type.kind !== "record")
|
|
3995
|
-
throw new
|
|
5021
|
+
throw new InternalCompilerError("lowerer bug: tupleArr lift shape");
|
|
3996
5022
|
const helper = this.tupleArrayWidthHelper(value.type.shapeId, dst, loc);
|
|
3997
5023
|
if (!helper)
|
|
3998
|
-
throw new
|
|
5024
|
+
throw new InternalCompilerError("lowerer bug: planned tupleArr lift failed to intern");
|
|
3999
5025
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
4000
5026
|
}
|
|
4001
5027
|
case "emptyArr": {
|
|
4002
5028
|
if (dst.kind !== "array" || value.type.kind !== "array")
|
|
4003
|
-
throw new
|
|
5029
|
+
throw new InternalCompilerError("lowerer bug: emptyArr lift shape");
|
|
4004
5030
|
const helper = this.emptyArrayLiftHelper(value.type, dst, loc);
|
|
4005
5031
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
4006
5032
|
}
|
|
4007
5033
|
case "objWidth": {
|
|
4008
5034
|
if (dst.kind !== "record" || value.type.kind !== "object")
|
|
4009
|
-
throw new
|
|
5035
|
+
throw new InternalCompilerError("lowerer bug: objWidth lift shape");
|
|
4010
5036
|
const helper = this.objRecordWidthHelper(value.type.className, dst.shapeId, loc);
|
|
4011
5037
|
if (!helper)
|
|
4012
|
-
throw new
|
|
5038
|
+
throw new InternalCompilerError("lowerer bug: planned objWidth lift failed to intern");
|
|
4013
5039
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
4014
5040
|
}
|
|
4015
5041
|
case "clsWidth": {
|
|
4016
5042
|
if (dst.kind !== "object" || value.type.kind !== "record")
|
|
4017
|
-
throw new
|
|
5043
|
+
throw new InternalCompilerError("lowerer bug: clsWidth lift shape");
|
|
4018
5044
|
const helper = this.recordClassWidthHelper(value.type.shapeId, dst.className, loc);
|
|
4019
5045
|
if (!helper)
|
|
4020
|
-
throw new
|
|
5046
|
+
throw new InternalCompilerError("lowerer bug: planned clsWidth lift failed to intern");
|
|
4021
5047
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
4022
5048
|
}
|
|
4023
5049
|
case "narrow": {
|
|
4024
5050
|
if (value.type.kind !== "union")
|
|
4025
|
-
throw new
|
|
5051
|
+
throw new InternalCompilerError("lowerer bug: narrow lift on a non-union");
|
|
4026
5052
|
const helper = this.narrowedArmHelper(value.type.unionId, dst, loc);
|
|
4027
5053
|
if (!helper)
|
|
4028
|
-
throw new
|
|
5054
|
+
throw new InternalCompilerError("lowerer bug: planned narrow lift failed to intern");
|
|
4029
5055
|
return { kind: "call", callee: helper, args: [value], type: dst, loc };
|
|
4030
5056
|
}
|
|
4031
5057
|
case "dynIn": {
|
|
4032
5058
|
if (dst.kind !== "dyn")
|
|
4033
|
-
throw new
|
|
5059
|
+
throw new InternalCompilerError("lowerer bug: dynIn lift against a non-dyn slot");
|
|
4034
5060
|
return { kind: "dynFrom", value, type: DYN, loc };
|
|
4035
5061
|
}
|
|
4036
5062
|
case "upcast": {
|
|
4037
5063
|
if (dst.kind !== "object" || value.type.kind !== "object")
|
|
4038
|
-
throw new
|
|
5064
|
+
throw new InternalCompilerError("lowerer bug: upcast lift shape");
|
|
4039
5065
|
return this.upcastTo(value, dst.className);
|
|
4040
5066
|
}
|
|
4041
5067
|
case "funcAdapt": {
|
|
4042
5068
|
if (dst.kind !== "func" || value.type.kind !== "func")
|
|
4043
|
-
throw new
|
|
5069
|
+
throw new InternalCompilerError("lowerer bug: funcAdapt lift shape");
|
|
4044
5070
|
const adapter = this.funcCoerceAdapter(value.type, dst, loc);
|
|
4045
5071
|
if (!adapter)
|
|
4046
|
-
throw new
|
|
5072
|
+
throw new InternalCompilerError("lowerer bug: planned funcAdapt lift failed to intern");
|
|
4047
5073
|
return { kind: "call", callee: adapter, args: [value], type: dst, loc };
|
|
4048
5074
|
}
|
|
4049
5075
|
default: {
|
|
4050
5076
|
const _exhaustive = lift;
|
|
4051
5077
|
void _exhaustive;
|
|
4052
|
-
throw new
|
|
5078
|
+
throw new InternalCompilerError("unreachable");
|
|
4053
5079
|
}
|
|
4054
5080
|
}
|
|
4055
5081
|
}
|
|
@@ -4264,7 +5290,7 @@ export class Lowerer {
|
|
|
4264
5290
|
}
|
|
4265
5291
|
if ("absent" in lift) {
|
|
4266
5292
|
if (f.type.kind !== "union")
|
|
4267
|
-
throw new
|
|
5293
|
+
throw new InternalCompilerError("lowerer bug: absent lift against a non-union field");
|
|
4268
5294
|
// The unset optional field: build the undefined arm.
|
|
4269
5295
|
return {
|
|
4270
5296
|
name: f.name,
|
|
@@ -4406,8 +5432,6 @@ export class Lowerer {
|
|
|
4406
5432
|
this.widthHelpers.set(key, name);
|
|
4407
5433
|
const arrT = { kind: "array", elem: fromElem };
|
|
4408
5434
|
const outT = { kind: "array", elem: toElem };
|
|
4409
|
-
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
4410
|
-
const num = (value) => ({ kind: "numLit", value, type: { kind: "f64" }, loc });
|
|
4411
5435
|
const f64 = { kind: "f64" };
|
|
4412
5436
|
this.liftedFns.push({
|
|
4413
5437
|
name,
|
|
@@ -4424,17 +5448,17 @@ export class Lowerer {
|
|
|
4424
5448
|
{
|
|
4425
5449
|
kind: "varDecl",
|
|
4426
5450
|
localId: "n.0",
|
|
4427
|
-
init: { kind: "arrIntrinsic", method: "length", receiver:
|
|
5451
|
+
init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
|
|
4428
5452
|
loc,
|
|
4429
5453
|
},
|
|
4430
5454
|
{
|
|
4431
5455
|
kind: "for",
|
|
4432
|
-
init: { kind: "varDecl", localId: "i.0", init:
|
|
4433
|
-
cond: { kind: "bin", op: "<", left:
|
|
5456
|
+
init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
|
|
5457
|
+
cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
|
|
4434
5458
|
update: {
|
|
4435
5459
|
kind: "assign",
|
|
4436
5460
|
localId: "i.0",
|
|
4437
|
-
value: { kind: "bin", op: "+", left:
|
|
5461
|
+
value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
|
|
4438
5462
|
loc,
|
|
4439
5463
|
},
|
|
4440
5464
|
body: [
|
|
@@ -4443,9 +5467,9 @@ export class Lowerer {
|
|
|
4443
5467
|
expr: {
|
|
4444
5468
|
kind: "arrIntrinsic",
|
|
4445
5469
|
method: "push",
|
|
4446
|
-
receiver:
|
|
5470
|
+
receiver: varRef("out.0", outT, loc),
|
|
4447
5471
|
args: [
|
|
4448
|
-
this.applyWidthLift(elemLift, { kind: "arrayGet", arr:
|
|
5472
|
+
this.applyWidthLift(elemLift, { kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: fromElem, loc }, toElem, loc),
|
|
4449
5473
|
],
|
|
4450
5474
|
type: f64,
|
|
4451
5475
|
loc,
|
|
@@ -4455,7 +5479,7 @@ export class Lowerer {
|
|
|
4455
5479
|
],
|
|
4456
5480
|
loc,
|
|
4457
5481
|
},
|
|
4458
|
-
{ kind: "return", value:
|
|
5482
|
+
{ kind: "return", value: varRef("out.0", outT, loc), loc },
|
|
4459
5483
|
],
|
|
4460
5484
|
loc,
|
|
4461
5485
|
});
|
|
@@ -4554,7 +5578,7 @@ export class Lowerer {
|
|
|
4554
5578
|
const lift = plan.get(f.name);
|
|
4555
5579
|
if ("absent" in lift) {
|
|
4556
5580
|
if (f.type.kind !== "union")
|
|
4557
|
-
throw new
|
|
5581
|
+
throw new InternalCompilerError("lowerer bug: absent lift against a non-union field");
|
|
4558
5582
|
return {
|
|
4559
5583
|
name: f.name,
|
|
4560
5584
|
value: {
|
|
@@ -4683,7 +5707,7 @@ export class Lowerer {
|
|
|
4683
5707
|
if ("absent" in entry) {
|
|
4684
5708
|
const u = this.wrappedUndefined(shape.type, loc);
|
|
4685
5709
|
if (!u)
|
|
4686
|
-
throw new
|
|
5710
|
+
throw new InternalCompilerError("lowerer bug: planned absent ctor arg has no undefined arm");
|
|
4687
5711
|
return u;
|
|
4688
5712
|
}
|
|
4689
5713
|
const get = { kind: "recordGet", obj: r, shapeId: fromId, field: entry.field, type: entry.src, loc };
|
|
@@ -4986,7 +6010,7 @@ export class Lowerer {
|
|
|
4986
6010
|
const aRef = { kind: "varRef", localId: `a.${i}`, type: toT.params[i], loc };
|
|
4987
6011
|
const converted = this.coerceToExpected(aRef, pt);
|
|
4988
6012
|
if (!typeEquals(converted.type, pt))
|
|
4989
|
-
throw new
|
|
6013
|
+
throw new InternalCompilerError("lowerer bug: probed fn-adapter param stopped coercing");
|
|
4990
6014
|
return converted;
|
|
4991
6015
|
});
|
|
4992
6016
|
const call = {
|
|
@@ -5029,7 +6053,7 @@ export class Lowerer {
|
|
|
5029
6053
|
else {
|
|
5030
6054
|
const result = this.coerceToExpected(call, toT.ret);
|
|
5031
6055
|
if (!typeEquals(result.type, toT.ret))
|
|
5032
|
-
throw new
|
|
6056
|
+
throw new InternalCompilerError("lowerer bug: probed fn-adapter return stopped coercing");
|
|
5033
6057
|
body = [{ kind: "return", value: result, loc }];
|
|
5034
6058
|
}
|
|
5035
6059
|
}
|
|
@@ -5519,10 +6543,13 @@ export class Lowerer {
|
|
|
5519
6543
|
return null;
|
|
5520
6544
|
const key = `${fromId}:${tag}`;
|
|
5521
6545
|
const existing = this.narrowHelpers.get(key);
|
|
5522
|
-
if (existing)
|
|
6546
|
+
if (existing) {
|
|
6547
|
+
this.checkedNarrowHelpers.add(existing);
|
|
5523
6548
|
return existing;
|
|
6549
|
+
}
|
|
5524
6550
|
const name = `%union.narrow.${this.narrowHelpers.size}`;
|
|
5525
6551
|
this.narrowHelpers.set(key, name);
|
|
6552
|
+
this.checkedNarrowHelpers.add(name);
|
|
5526
6553
|
const fromT = { kind: "union", unionId: fromId };
|
|
5527
6554
|
const u = { kind: "varRef", localId: "u.0", type: fromT, loc };
|
|
5528
6555
|
const body = [];
|
|
@@ -5720,7 +6747,7 @@ export class Lowerer {
|
|
|
5720
6747
|
if (e.type.kind === "dyn" || e.type.kind === "func") {
|
|
5721
6748
|
return { kind: "jsMarshal", value: e, type: JSVAL, loc };
|
|
5722
6749
|
}
|
|
5723
|
-
throw new
|
|
6750
|
+
throw new InternalCompilerError(`lowerer bug: jsvalLiftExpr of unliftable ${e.type.kind}`);
|
|
5724
6751
|
}
|
|
5725
6752
|
/** Interned `%jsin.union.<n>(u)` — the runtime tag switch marshaling a
|
|
5726
6753
|
* union value INTO the island: unit arms become the engine's own
|
|
@@ -5737,7 +6764,7 @@ export class Lowerer {
|
|
|
5737
6764
|
return existing;
|
|
5738
6765
|
const def = this.unions.get(unionId);
|
|
5739
6766
|
if (!def)
|
|
5740
|
-
throw new
|
|
6767
|
+
throw new InternalCompilerError(`lowerer bug: jsval lift of unknown union ${unionId}`);
|
|
5741
6768
|
const name = `%jsin.union.${this.jsinHelpers.size}`;
|
|
5742
6769
|
this.jsinHelpers.set(key, name);
|
|
5743
6770
|
const fromT = { kind: "union", unionId };
|
|
@@ -5779,7 +6806,7 @@ export class Lowerer {
|
|
|
5779
6806
|
return existing;
|
|
5780
6807
|
const shape = this.shapes.get(shapeId);
|
|
5781
6808
|
if (!shape)
|
|
5782
|
-
throw new
|
|
6809
|
+
throw new InternalCompilerError(`lowerer bug: jsval lift of unknown shape ${shapeId}`);
|
|
5783
6810
|
const name = `%jsin.rec.${this.jsinHelpers.size}`;
|
|
5784
6811
|
this.jsinHelpers.set(key, name);
|
|
5785
6812
|
const recT = { kind: "record", shapeId };
|
|
@@ -5812,9 +6839,7 @@ export class Lowerer {
|
|
|
5812
6839
|
const iv = shape.indexValue;
|
|
5813
6840
|
const f64 = { kind: "f64" };
|
|
5814
6841
|
const ksT = arrayOf(STRING);
|
|
5815
|
-
const
|
|
5816
|
-
const num = (value) => ({ kind: "numLit", value, type: f64, loc });
|
|
5817
|
-
const kRef = ref("k.0", STRING);
|
|
6842
|
+
const kRef = varRef("k.0", STRING, loc);
|
|
5818
6843
|
this.liftedFns.push({
|
|
5819
6844
|
name,
|
|
5820
6845
|
params: [{ localId: "r.0", name: "r", type: recT }],
|
|
@@ -5831,25 +6856,25 @@ export class Lowerer {
|
|
|
5831
6856
|
{ kind: "varDecl", localId: "ks.0", init: { kind: "recordOvfKeys", obj: r, shapeId, type: ksT, loc }, loc },
|
|
5832
6857
|
{
|
|
5833
6858
|
kind: "for",
|
|
5834
|
-
init: { kind: "varDecl", localId: "i.0", init:
|
|
6859
|
+
init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
|
|
5835
6860
|
cond: {
|
|
5836
6861
|
kind: "bin",
|
|
5837
6862
|
op: "<",
|
|
5838
|
-
left:
|
|
5839
|
-
right: { kind: "arrIntrinsic", method: "length", receiver:
|
|
6863
|
+
left: varRef("i.0", f64, loc),
|
|
6864
|
+
right: { kind: "arrIntrinsic", method: "length", receiver: varRef("ks.0", ksT, loc), args: [], type: f64, loc },
|
|
5840
6865
|
type: BOOL,
|
|
5841
6866
|
loc,
|
|
5842
6867
|
},
|
|
5843
|
-
update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left:
|
|
6868
|
+
update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc }, loc },
|
|
5844
6869
|
body: [
|
|
5845
|
-
{ kind: "varDecl", localId: "k.0", init: { kind: "arrayGet", arr:
|
|
6870
|
+
{ kind: "varDecl", localId: "k.0", init: { kind: "arrayGet", arr: varRef("ks.0", ksT, loc), index: varRef("i.0", f64, loc), type: STRING, loc }, loc },
|
|
5846
6871
|
{
|
|
5847
6872
|
kind: "exprStmt",
|
|
5848
6873
|
expr: {
|
|
5849
6874
|
kind: "jsOp",
|
|
5850
6875
|
op: "setIdx",
|
|
5851
6876
|
args: [
|
|
5852
|
-
|
|
6877
|
+
varRef("out.0", JSVAL, loc),
|
|
5853
6878
|
{ kind: "jsMarshal", value: kRef, type: JSVAL, loc },
|
|
5854
6879
|
this.jsvalLiftExpr({ kind: "recordKeyGet", obj: r, shapeId, key: kRef, overflowOnly: true, type: iv, loc }, loc),
|
|
5855
6880
|
],
|
|
@@ -5861,7 +6886,7 @@ export class Lowerer {
|
|
|
5861
6886
|
],
|
|
5862
6887
|
loc,
|
|
5863
6888
|
},
|
|
5864
|
-
{ kind: "return", value:
|
|
6889
|
+
{ kind: "return", value: varRef("out.0", JSVAL, loc), loc },
|
|
5865
6890
|
],
|
|
5866
6891
|
loc,
|
|
5867
6892
|
});
|
|
@@ -5880,8 +6905,6 @@ export class Lowerer {
|
|
|
5880
6905
|
this.jsinHelpers.set(key, name);
|
|
5881
6906
|
const arrT = { kind: "array", elem };
|
|
5882
6907
|
const f64 = { kind: "f64" };
|
|
5883
|
-
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
5884
|
-
const num = (value) => ({ kind: "numLit", value, type: f64, loc });
|
|
5885
6908
|
this.liftedFns.push({
|
|
5886
6909
|
name,
|
|
5887
6910
|
params: [{ localId: "a.0", name: "a", type: arrT }],
|
|
@@ -5897,17 +6920,17 @@ export class Lowerer {
|
|
|
5897
6920
|
{
|
|
5898
6921
|
kind: "varDecl",
|
|
5899
6922
|
localId: "n.0",
|
|
5900
|
-
init: { kind: "arrIntrinsic", method: "length", receiver:
|
|
6923
|
+
init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
|
|
5901
6924
|
loc,
|
|
5902
6925
|
},
|
|
5903
6926
|
{
|
|
5904
6927
|
kind: "for",
|
|
5905
|
-
init: { kind: "varDecl", localId: "i.0", init:
|
|
5906
|
-
cond: { kind: "bin", op: "<", left:
|
|
6928
|
+
init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
|
|
6929
|
+
cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
|
|
5907
6930
|
update: {
|
|
5908
6931
|
kind: "assign",
|
|
5909
6932
|
localId: "i.0",
|
|
5910
|
-
value: { kind: "bin", op: "+", left:
|
|
6933
|
+
value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
|
|
5911
6934
|
loc,
|
|
5912
6935
|
},
|
|
5913
6936
|
body: [
|
|
@@ -5917,9 +6940,9 @@ export class Lowerer {
|
|
|
5917
6940
|
kind: "jsOp",
|
|
5918
6941
|
op: "setIdx",
|
|
5919
6942
|
args: [
|
|
5920
|
-
|
|
5921
|
-
{ kind: "jsMarshal", value:
|
|
5922
|
-
this.jsvalLiftExpr({ kind: "arrayGet", arr:
|
|
6943
|
+
varRef("out.0", JSVAL, loc),
|
|
6944
|
+
{ kind: "jsMarshal", value: varRef("i.0", f64, loc), type: JSVAL, loc },
|
|
6945
|
+
this.jsvalLiftExpr({ kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: elem, loc }, loc),
|
|
5923
6946
|
],
|
|
5924
6947
|
type: { kind: "void" },
|
|
5925
6948
|
loc,
|
|
@@ -5929,7 +6952,7 @@ export class Lowerer {
|
|
|
5929
6952
|
],
|
|
5930
6953
|
loc,
|
|
5931
6954
|
},
|
|
5932
|
-
{ kind: "return", value:
|
|
6955
|
+
{ kind: "return", value: varRef("out.0", JSVAL, loc), loc },
|
|
5933
6956
|
],
|
|
5934
6957
|
loc,
|
|
5935
6958
|
});
|
|
@@ -5951,8 +6974,6 @@ export class Lowerer {
|
|
|
5951
6974
|
const arrT = { kind: "array", elem: fromElem };
|
|
5952
6975
|
const outT = { kind: "array", elem: JSVAL };
|
|
5953
6976
|
const f64 = { kind: "f64" };
|
|
5954
|
-
const ref = (localId, type) => ({ kind: "varRef", localId, type, loc });
|
|
5955
|
-
const num = (value) => ({ kind: "numLit", value, type: f64, loc });
|
|
5956
6977
|
this.liftedFns.push({
|
|
5957
6978
|
name,
|
|
5958
6979
|
params: [{ localId: "a.0", name: "a", type: arrT }],
|
|
@@ -5968,17 +6989,17 @@ export class Lowerer {
|
|
|
5968
6989
|
{
|
|
5969
6990
|
kind: "varDecl",
|
|
5970
6991
|
localId: "n.0",
|
|
5971
|
-
init: { kind: "arrIntrinsic", method: "length", receiver:
|
|
6992
|
+
init: { kind: "arrIntrinsic", method: "length", receiver: varRef("a.0", arrT, loc), args: [], type: f64, loc },
|
|
5972
6993
|
loc,
|
|
5973
6994
|
},
|
|
5974
6995
|
{
|
|
5975
6996
|
kind: "for",
|
|
5976
|
-
init: { kind: "varDecl", localId: "i.0", init:
|
|
5977
|
-
cond: { kind: "bin", op: "<", left:
|
|
6997
|
+
init: { kind: "varDecl", localId: "i.0", init: numLit(0, loc), loc },
|
|
6998
|
+
cond: { kind: "bin", op: "<", left: varRef("i.0", f64, loc), right: varRef("n.0", f64, loc), type: BOOL, loc },
|
|
5978
6999
|
update: {
|
|
5979
7000
|
kind: "assign",
|
|
5980
7001
|
localId: "i.0",
|
|
5981
|
-
value: { kind: "bin", op: "+", left:
|
|
7002
|
+
value: { kind: "bin", op: "+", left: varRef("i.0", f64, loc), right: numLit(1, loc), type: f64, loc },
|
|
5982
7003
|
loc,
|
|
5983
7004
|
},
|
|
5984
7005
|
body: [
|
|
@@ -5987,9 +7008,9 @@ export class Lowerer {
|
|
|
5987
7008
|
expr: {
|
|
5988
7009
|
kind: "arrIntrinsic",
|
|
5989
7010
|
method: "push",
|
|
5990
|
-
receiver:
|
|
7011
|
+
receiver: varRef("out.0", outT, loc),
|
|
5991
7012
|
args: [
|
|
5992
|
-
this.jsvalLiftExpr({ kind: "arrayGet", arr:
|
|
7013
|
+
this.jsvalLiftExpr({ kind: "arrayGet", arr: varRef("a.0", arrT, loc), index: varRef("i.0", f64, loc), type: fromElem, loc }, loc),
|
|
5993
7014
|
],
|
|
5994
7015
|
type: f64,
|
|
5995
7016
|
loc,
|
|
@@ -5999,7 +7020,7 @@ export class Lowerer {
|
|
|
5999
7020
|
],
|
|
6000
7021
|
loc,
|
|
6001
7022
|
},
|
|
6002
|
-
{ kind: "return", value:
|
|
7023
|
+
{ kind: "return", value: varRef("out.0", outT, loc), loc },
|
|
6003
7024
|
],
|
|
6004
7025
|
loc,
|
|
6005
7026
|
});
|
|
@@ -6998,6 +8019,14 @@ export class Lowerer {
|
|
|
6998
8019
|
}
|
|
6999
8020
|
const local = this.declareLocal(decl.name, name, shape.type, true);
|
|
7000
8021
|
params.push({ localId: local.id, name, type: local.type });
|
|
8022
|
+
if (shape.mode === "required" &&
|
|
8023
|
+
shape.type.kind === "union" &&
|
|
8024
|
+
this.armTag(shape.type.unionId, UNDEFINED_T) >= 0 &&
|
|
8025
|
+
typeEquals(this.stripUndefinedArm(shape.type), this.mapTypeOf(this.typeOf(decl.name)) ?? VOID)) {
|
|
8026
|
+
const root = this.runtimeOptionalRootOf(local);
|
|
8027
|
+
this.runtimeOptionalLocals.add(root);
|
|
8028
|
+
this.runtimeOptionalStorageLocals.add(root);
|
|
8029
|
+
}
|
|
7001
8030
|
});
|
|
7002
8031
|
return { params, prologue };
|
|
7003
8032
|
}
|
|
@@ -7466,7 +8495,13 @@ export class Lowerer {
|
|
|
7466
8495
|
return lowerExprStatement(this, expr);
|
|
7467
8496
|
}
|
|
7468
8497
|
lowerForOf(stmt) {
|
|
7469
|
-
|
|
8498
|
+
const optional = this.runtimeOptionalIdentifierValue(stmt.expression);
|
|
8499
|
+
if (optional?.present.kind !== "string")
|
|
8500
|
+
return lowerForOf(this, stmt);
|
|
8501
|
+
const helper = this.narrowedArmHelper(optional.unionId, optional.present, locOf(stmt.expression));
|
|
8502
|
+
if (!helper)
|
|
8503
|
+
return lowerForOf(this, stmt);
|
|
8504
|
+
return this.withExpressionOverride(stmt.expression, { kind: "call", callee: helper, args: [optional.value], type: optional.present, loc: locOf(stmt.expression) }, () => lowerForOf(this, stmt));
|
|
7470
8505
|
}
|
|
7471
8506
|
lowerForStatement(stmt) {
|
|
7472
8507
|
return lowerForStatement(this, stmt);
|
|
@@ -7513,7 +8548,7 @@ export class Lowerer {
|
|
|
7513
8548
|
* node_modules but NOT the standard library (typescript's own lib files
|
|
7514
8549
|
* live under node_modules too), or inside a registered workspace-linked
|
|
7515
8550
|
* package (a node_modules symlink whose realpath'd files carry no
|
|
7516
|
-
* node_modules segment —
|
|
8551
|
+
* node_modules segment — workspace-registry.ts). The provenance half of the npm
|
|
7517
8552
|
* typing rule (package types are island handles) and of the per-package
|
|
7518
8553
|
* requires-dynamic attribution. */
|
|
7519
8554
|
isNpmFile = (sf) => sf.isDeclarationFile &&
|
|
@@ -7553,7 +8588,38 @@ export class Lowerer {
|
|
|
7553
8588
|
return rejectThisInObjectMethod(this, node);
|
|
7554
8589
|
}
|
|
7555
8590
|
lowerElementAccess(expr) {
|
|
7556
|
-
|
|
8591
|
+
const receiver = this.runtimeOptionalIdentifierValue(expr.expression);
|
|
8592
|
+
const receiverValue = receiver && (receiver.present.kind === "array" || receiver.present.kind === "record")
|
|
8593
|
+
? (() => {
|
|
8594
|
+
const helper = this.narrowedArmHelper(receiver.unionId, receiver.present, locOf(expr.expression));
|
|
8595
|
+
return helper ? { kind: "call", callee: helper, args: [receiver.value], type: receiver.present, loc: locOf(expr.expression) } : null;
|
|
8596
|
+
})()
|
|
8597
|
+
: null;
|
|
8598
|
+
if (receiverValue && receiver?.present.kind === "record" && ts.isNumericLiteral(expr.argumentExpression)) {
|
|
8599
|
+
const shape = this.shapes.get(receiver.present.shapeId);
|
|
8600
|
+
const index = expr.argumentExpression.text;
|
|
8601
|
+
const field = shape?.tuple ? shape.fields.find((candidate) => candidate.name === String(Number(index))) : undefined;
|
|
8602
|
+
if (field) {
|
|
8603
|
+
const read = {
|
|
8604
|
+
kind: "recordGet",
|
|
8605
|
+
obj: receiverValue,
|
|
8606
|
+
shapeId: receiver.present.shapeId,
|
|
8607
|
+
field: field.name,
|
|
8608
|
+
type: field.type,
|
|
8609
|
+
loc: locOf(expr),
|
|
8610
|
+
};
|
|
8611
|
+
if (expr.parent && ts.isTypeOfExpression(expr.parent) &&
|
|
8612
|
+
(field.type.kind === "f64" || field.type.kind === "bool" || field.type.kind === "string")) {
|
|
8613
|
+
return { kind: "dynFrom", value: read, type: DYN, loc: locOf(expr) };
|
|
8614
|
+
}
|
|
8615
|
+
return read;
|
|
8616
|
+
}
|
|
8617
|
+
}
|
|
8618
|
+
const key = this.runtimeOptionalIdentifierValue(expr.argumentExpression);
|
|
8619
|
+
const keyValue = key?.present.kind === "string" ? this.ensureString(key.value, expr.argumentExpression) : null;
|
|
8620
|
+
const lower = () => lowerElementAccess(this, expr);
|
|
8621
|
+
const withKey = () => keyValue ? this.withExpressionOverride(expr.argumentExpression, keyValue, lower) : lower();
|
|
8622
|
+
return receiverValue ? this.withExpressionOverride(expr.expression, receiverValue, withKey) : withKey();
|
|
7557
8623
|
}
|
|
7558
8624
|
lowerRecordKeyRead(expr, shapeId, shape, includeUndefined = false) {
|
|
7559
8625
|
return lowerRecordKeyRead(this, expr, shapeId, shape, includeUndefined);
|
|
@@ -7620,7 +8686,84 @@ export class Lowerer {
|
|
|
7620
8686
|
return caughtToString(this, node);
|
|
7621
8687
|
}
|
|
7622
8688
|
lowerInstanceOf(expr, loc) {
|
|
7623
|
-
|
|
8689
|
+
const lower = () => this.withRuntimeOptionalClassValue(expr.right, () => lowerInstanceOf(this, expr, loc));
|
|
8690
|
+
if (!ts.isIdentifier(expr.right) || this.mapTypeOf(this.typeOf(expr.right))?.kind !== "classval") {
|
|
8691
|
+
return lower();
|
|
8692
|
+
}
|
|
8693
|
+
const optionalLeft = this.runtimeOptionalIdentifierValue(expr.left);
|
|
8694
|
+
const left = optionalLeft?.value ?? (ts.isElementAccessExpression(expr.left) ? this.lowerExpr(expr.left) : null);
|
|
8695
|
+
if (!left)
|
|
8696
|
+
return lower();
|
|
8697
|
+
if (left.type.kind !== "union" || this.armTag(left.type.unionId, UNDEFINED_T) < 0)
|
|
8698
|
+
return lower();
|
|
8699
|
+
const present = this.stripUndefinedArm(left.type);
|
|
8700
|
+
if (present.kind !== "object")
|
|
8701
|
+
return lower();
|
|
8702
|
+
const undefinedTag = this.armTag(left.type.unionId, UNDEFINED_T);
|
|
8703
|
+
const valueTag = this.armTag(left.type.unionId, present);
|
|
8704
|
+
if (undefinedTag < 0 || valueTag < 0)
|
|
8705
|
+
return lower();
|
|
8706
|
+
const stable = this.declareHiddenLocal("%instanceofLeft", left.type);
|
|
8707
|
+
const value = varRef(stable.id, left.type, locOf(expr.left));
|
|
8708
|
+
const optionalRight = this.runtimeOptionalIdentifierValue(expr.right);
|
|
8709
|
+
let right;
|
|
8710
|
+
if (optionalRight?.present.kind === "classval") {
|
|
8711
|
+
const helper = this.narrowedArmHelper(optionalRight.unionId, optionalRight.present, locOf(expr.right));
|
|
8712
|
+
if (!helper)
|
|
8713
|
+
return lower();
|
|
8714
|
+
right = { kind: "call", callee: helper, args: [optionalRight.value], type: optionalRight.present, loc: locOf(expr.right) };
|
|
8715
|
+
}
|
|
8716
|
+
else {
|
|
8717
|
+
right = this.lowerExpr(expr.right);
|
|
8718
|
+
}
|
|
8719
|
+
if (right.type.kind !== "classval")
|
|
8720
|
+
return lower();
|
|
8721
|
+
const stableRight = this.declareHiddenLocal("%instanceofRight", right.type);
|
|
8722
|
+
const rightValue = varRef(stableRight.id, right.type, locOf(expr.right));
|
|
8723
|
+
const body = this.withExpressionOverride(expr.left, {
|
|
8724
|
+
kind: "unionNarrow", unionId: left.type.unionId, tag: valueTag, value, type: present, loc: locOf(expr.left),
|
|
8725
|
+
}, () => this.withExpressionOverride(expr.right, rightValue, () => lowerInstanceOf(this, expr, loc)));
|
|
8726
|
+
return {
|
|
8727
|
+
kind: "seqExpr",
|
|
8728
|
+
stmts: [
|
|
8729
|
+
{ kind: "varDecl", localId: stable.id, init: left, loc: locOf(expr.left) },
|
|
8730
|
+
{ kind: "varDecl", localId: stableRight.id, init: right, loc: locOf(expr.right) },
|
|
8731
|
+
],
|
|
8732
|
+
result: {
|
|
8733
|
+
kind: "ternary",
|
|
8734
|
+
cond: { kind: "unionIsTag", unionId: left.type.unionId, tag: undefinedTag, negated: false, value, type: BOOL, loc },
|
|
8735
|
+
then: { kind: "boolLit", value: false, type: BOOL, loc },
|
|
8736
|
+
else_: body,
|
|
8737
|
+
type: BOOL,
|
|
8738
|
+
loc,
|
|
8739
|
+
},
|
|
8740
|
+
type: BOOL,
|
|
8741
|
+
loc,
|
|
8742
|
+
};
|
|
8743
|
+
}
|
|
8744
|
+
withRuntimeOptionalClassValue(node, lower) {
|
|
8745
|
+
if (this.mapTypeOf(this.typeOf(node))?.kind !== "classval")
|
|
8746
|
+
return lower();
|
|
8747
|
+
const optional = this.runtimeOptionalIdentifierValue(node);
|
|
8748
|
+
if (optional?.present.kind !== "classval")
|
|
8749
|
+
return lower();
|
|
8750
|
+
const helper = this.narrowedArmHelper(optional.unionId, optional.present, locOf(node));
|
|
8751
|
+
if (!helper)
|
|
8752
|
+
return lower();
|
|
8753
|
+
return this.withExpressionOverride(node, { kind: "call", callee: helper, args: [optional.value], type: optional.present, loc: locOf(node) }, lower);
|
|
8754
|
+
}
|
|
8755
|
+
withExpressionOverride(node, value, lower) {
|
|
8756
|
+
const previous = this.chainRecvByNode.get(node);
|
|
8757
|
+
this.chainRecvByNode.set(node, value);
|
|
8758
|
+
try {
|
|
8759
|
+
return lower();
|
|
8760
|
+
}
|
|
8761
|
+
finally {
|
|
8762
|
+
if (previous)
|
|
8763
|
+
this.chainRecvByNode.set(node, previous);
|
|
8764
|
+
else
|
|
8765
|
+
this.chainRecvByNode.delete(node);
|
|
8766
|
+
}
|
|
7624
8767
|
}
|
|
7625
8768
|
lowerCall(expr) {
|
|
7626
8769
|
// Ambient fetch (native in static builds, island-backed under
|
|
@@ -7760,7 +8903,8 @@ export class Lowerer {
|
|
|
7760
8903
|
const arg = this.lowerExpr(expr.arguments[0]);
|
|
7761
8904
|
return { kind: "jsOp", op: "construct", args: [ctor, arg], type: JSVAL, loc };
|
|
7762
8905
|
}
|
|
7763
|
-
|
|
8906
|
+
const builtin = lowerAbortControllerNew(this, expr) ?? lowerResponseNew(this, expr) ?? lowerStaticReadableStreamNew(this, expr);
|
|
8907
|
+
return builtin ?? this.withRuntimeOptionalClassValue(expr.expression, () => lowerNew(this, expr));
|
|
7764
8908
|
}
|
|
7765
8909
|
lowerFieldRead(expr) {
|
|
7766
8910
|
// `C.x` static reads first (the receiver is a CLASS, not an instance
|
|
@@ -8249,6 +9393,13 @@ export class Lowerer {
|
|
|
8249
9393
|
return lowerStringLastIndexOfCall(this, call, access);
|
|
8250
9394
|
}
|
|
8251
9395
|
lowerFilterNarrowCall(call, access) {
|
|
9396
|
+
// Native array filters use the state-aware HOF helper: its callback
|
|
9397
|
+
// receives present undefined values and skips holes before a narrowed
|
|
9398
|
+
// survivor is extracted. The older narrowing helper reads the payload
|
|
9399
|
+
// directly and therefore cannot represent that three-state contract.
|
|
9400
|
+
if (this.mapTypeOf(this.typeOf(access.expression))?.kind === "array" && this.isStdlibMember(access)) {
|
|
9401
|
+
return null;
|
|
9402
|
+
}
|
|
8252
9403
|
return lowerFilterNarrowCall(this, call, access);
|
|
8253
9404
|
}
|
|
8254
9405
|
lowerPromiseMethodCall(call, access) {
|