@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
|
/* The node:assert lowering (a spoke module like lower-dgram.ts): the
|
|
2
3
|
* callable module form (`assert(x)` through a default import or a CJS
|
|
3
4
|
* require binding), ok, the strict/deep equality quartet, fail, throws,
|
|
@@ -22,10 +23,12 @@
|
|
|
22
23
|
* signature records, dyn/unknown) fences at the call site instead of
|
|
23
24
|
* miscomparing. */
|
|
24
25
|
import * as ts from "../ts7/adapter.js";
|
|
26
|
+
import { resultIsDiscarded } from "./call-position.js";
|
|
25
27
|
import { jsFuncNameOf, own } from "./lowerer.js";
|
|
26
28
|
import { NARROW_FIRST } from "./surfaces.js";
|
|
27
29
|
import { typeReachesItself } from "./lower-inspect.js";
|
|
28
|
-
import { BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, REGEX, RUNTIME_ERROR_CLASSES, STRING, VOID, isUnitType, typeEquals, typeKey } from "../../ir/
|
|
30
|
+
import { BOOL, CAUGHT, DYN, DYN_HANDLE_KINDS, F64, REGEX, RUNTIME_ERROR_CLASSES, STRING, VOID, isUnitType, typeEquals, typeKey } from "../../ir/ir.js";
|
|
31
|
+
import { boolLit, countedFor, numLit, strLit, varRef } from "../../ir/build.js";
|
|
29
32
|
/** node:assert/strict binds the loose NAMES to the strict comparisons —
|
|
30
33
|
* Node's own aliasing (`strict.equal === assert.strictEqual`). */
|
|
31
34
|
const STRICT_ALIASES = {
|
|
@@ -43,59 +46,58 @@ function canonicalAssertMember(module, member) {
|
|
|
43
46
|
}
|
|
44
47
|
/** VOID/never results are usable as statements and concise arrow bodies
|
|
45
48
|
* only (the lower-dgram stance): nothing downstream can consume them. */
|
|
46
|
-
function requireStatementPosition(
|
|
47
|
-
if (
|
|
49
|
+
function requireStatementPosition(lowerer, call, what) {
|
|
50
|
+
if (resultIsDiscarded(call))
|
|
48
51
|
return;
|
|
49
|
-
|
|
52
|
+
lowerer.noLowering(`using the result of ${what}`, call, "the result is void — call it as its own statement");
|
|
50
53
|
}
|
|
51
54
|
/** The optional trailing message argument: Node accepts a string or an
|
|
52
55
|
* Error (throwing the Error itself) — the STRING form lowers; a literal
|
|
53
56
|
* `undefined` counts as omitted (Node's `message == null` test). Returns
|
|
54
57
|
* the libCall's (msg, hasMsg) pair — a "" dummy when omitted, so the
|
|
55
58
|
* runtime can distinguish an omitted message from an empty one. */
|
|
56
|
-
function lowerMessageArg(
|
|
57
|
-
const flag = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
59
|
+
function lowerMessageArg(lowerer, node, loc) {
|
|
58
60
|
if (!node || (ts.isIdentifier(node) && node.text === "undefined")) {
|
|
59
|
-
return { msg: { kind: "strLit", value: "", type: STRING, loc }, hasMsg:
|
|
61
|
+
return { msg: { kind: "strLit", value: "", type: STRING, loc }, hasMsg: boolLit(false, loc) };
|
|
60
62
|
}
|
|
61
|
-
const msg =
|
|
63
|
+
const msg = lowerer.lowerExpr(node);
|
|
62
64
|
if (msg.type.kind !== "string") {
|
|
63
|
-
|
|
65
|
+
lowerer.noLowering(`assert messages of type '${lowerer.fmt(msg.type)}'`, node, "only string messages lower (Node also accepts an Error to throw — construct and throw it directly)");
|
|
64
66
|
}
|
|
65
|
-
return { msg, hasMsg:
|
|
67
|
+
return { msg, hasMsg: boolLit(true, loc) };
|
|
66
68
|
}
|
|
67
69
|
/** The module-function dispatch — the spoke's entry, called from both the
|
|
68
70
|
* named-import and namespace/default-import call paths. Null for other
|
|
69
71
|
* modules and for members with no lowering (the module tables' fence
|
|
70
72
|
* takes over, module-qualified with the surfaces.ts hints). */
|
|
71
|
-
export function lowerAssertModuleCall(
|
|
73
|
+
export function lowerAssertModuleCall(lowerer, expr, bi, loc) {
|
|
72
74
|
if (bi.module !== "assert" && bi.module !== "assert/strict")
|
|
73
75
|
return null;
|
|
74
76
|
switch (canonicalAssertMember(bi.module, bi.member)) {
|
|
75
77
|
case "ok":
|
|
76
|
-
return lowerAssertOk(
|
|
78
|
+
return lowerAssertOk(lowerer, expr, loc);
|
|
77
79
|
case "strictEqual":
|
|
78
|
-
return lowerAssertEqual(
|
|
80
|
+
return lowerAssertEqual(lowerer, expr, loc, false, false);
|
|
79
81
|
case "notStrictEqual":
|
|
80
|
-
return lowerAssertEqual(
|
|
82
|
+
return lowerAssertEqual(lowerer, expr, loc, true, false);
|
|
81
83
|
case "deepStrictEqual":
|
|
82
|
-
return lowerAssertEqual(
|
|
84
|
+
return lowerAssertEqual(lowerer, expr, loc, false, true);
|
|
83
85
|
case "notDeepStrictEqual":
|
|
84
|
-
return lowerAssertEqual(
|
|
86
|
+
return lowerAssertEqual(lowerer, expr, loc, true, true);
|
|
85
87
|
case "fail":
|
|
86
|
-
return lowerAssertFail(
|
|
88
|
+
return lowerAssertFail(lowerer, expr, loc);
|
|
87
89
|
case "match":
|
|
88
|
-
return lowerAssertMatch(
|
|
90
|
+
return lowerAssertMatch(lowerer, expr, loc, false);
|
|
89
91
|
case "doesNotMatch":
|
|
90
|
-
return lowerAssertMatch(
|
|
92
|
+
return lowerAssertMatch(lowerer, expr, loc, true);
|
|
91
93
|
case "throws":
|
|
92
|
-
return lowerAssertThrows(
|
|
94
|
+
return lowerAssertThrows(lowerer, expr, loc);
|
|
93
95
|
case "rejects":
|
|
94
|
-
return lowerAssertRejects(
|
|
96
|
+
return lowerAssertRejects(lowerer, expr, loc, false);
|
|
95
97
|
case "doesNotReject":
|
|
96
|
-
return lowerAssertRejects(
|
|
98
|
+
return lowerAssertRejects(lowerer, expr, loc, true);
|
|
97
99
|
case "ifError":
|
|
98
|
-
return lowerAssertIfError(
|
|
100
|
+
return lowerAssertIfError(lowerer, expr, loc);
|
|
99
101
|
default:
|
|
100
102
|
return null;
|
|
101
103
|
}
|
|
@@ -106,32 +108,32 @@ export function lowerAssertModuleCall(L, expr, bi, loc) {
|
|
|
106
108
|
* module object is assert.ok itself. A NAMESPACE import binding is not
|
|
107
109
|
* callable in Node (ES namespace objects throw TypeError), so that form
|
|
108
110
|
* fences instead of compiling a crash. Null for non-assert callees. */
|
|
109
|
-
export function lowerAssertDirectCall(
|
|
111
|
+
export function lowerAssertDirectCall(lowerer, expr, loc) {
|
|
110
112
|
const callee = expr.expression;
|
|
111
113
|
if (!ts.isIdentifier(callee))
|
|
112
114
|
return null;
|
|
113
|
-
const module =
|
|
115
|
+
const module = lowerer.builtinNamespaceModuleOf(callee);
|
|
114
116
|
if (module !== "assert" && module !== "assert/strict")
|
|
115
117
|
return null;
|
|
116
|
-
const calleeSym =
|
|
117
|
-
const decl = calleeSym ?
|
|
118
|
+
const calleeSym = lowerer.checker.getSymbolAtLocation(callee);
|
|
119
|
+
const decl = calleeSym ? lowerer.checker.declarationsOf(calleeSym)[0] : undefined;
|
|
118
120
|
if (decl && ts.isNamespaceImport(decl)) {
|
|
119
|
-
|
|
121
|
+
lowerer.unsupported("SC1013", expr, "calling a module namespace object (Node throws TypeError there — " +
|
|
120
122
|
'use the default import: import assert from "node:assert")');
|
|
121
123
|
}
|
|
122
|
-
return lowerAssertOk(
|
|
124
|
+
return lowerAssertOk(lowerer, expr, loc);
|
|
123
125
|
}
|
|
124
126
|
/** assert(value[, message]) / assert.ok(value[, message]): the truthiness
|
|
125
127
|
* test over any condition-testable type; the generated message carries the
|
|
126
128
|
* call's SOURCE TEXT (Node re-reads the file at runtime — the frontend has
|
|
127
129
|
* the same bytes at compile time). */
|
|
128
|
-
function lowerAssertOk(
|
|
129
|
-
requireStatementPosition(
|
|
130
|
+
function lowerAssertOk(lowerer, expr, loc) {
|
|
131
|
+
requireStatementPosition(lowerer, expr, expr.expression.getText());
|
|
130
132
|
if (expr.arguments.length < 1 || expr.arguments.length > 2) {
|
|
131
|
-
|
|
133
|
+
lowerer.noLowering(`${expr.expression.getText()} with ${expr.arguments.length} arguments`, expr, "the supported forms are assert(value) and assert(value, message)");
|
|
132
134
|
}
|
|
133
135
|
const valueNode = expr.arguments[0];
|
|
134
|
-
const pass =
|
|
136
|
+
const pass = lowerer.ensureBool(lowerer.lowerExpr(valueNode), valueNode);
|
|
135
137
|
const msgNode = expr.arguments[1];
|
|
136
138
|
if (!msgNode || (ts.isIdentifier(msgNode) && msgNode.text === "undefined")) {
|
|
137
139
|
// Node reads the CALLSITE LINE and slices the expression out of it
|
|
@@ -142,16 +144,16 @@ function lowerAssertOk(L, expr, loc) {
|
|
|
142
144
|
const msg = { kind: "strLit", value: generated, type: STRING, loc };
|
|
143
145
|
return { kind: "libCall", fn: "assert.ok", args: [pass, msg], type: VOID, loc };
|
|
144
146
|
}
|
|
145
|
-
const { msg } = lowerMessageArg(
|
|
147
|
+
const { msg } = lowerMessageArg(lowerer, msgNode, loc);
|
|
146
148
|
return { kind: "libCall", fn: "assert.ok", args: [pass, msg], type: VOID, loc };
|
|
147
149
|
}
|
|
148
150
|
/** assert.fail([message]): an unconditional AssertionError — "Failed"
|
|
149
151
|
* when the message is omitted (Node's internal default). Lowers as
|
|
150
152
|
* assert.ok over a false literal. */
|
|
151
|
-
function lowerAssertFail(
|
|
152
|
-
requireStatementPosition(
|
|
153
|
+
function lowerAssertFail(lowerer, expr, loc) {
|
|
154
|
+
requireStatementPosition(lowerer, expr, "assert.fail");
|
|
153
155
|
if (expr.arguments.length > 1) {
|
|
154
|
-
|
|
156
|
+
lowerer.noLowering(`assert.fail with ${expr.arguments.length} arguments`, expr, "the supported form is fail(message?) — the deprecated fail(actual, expected, ...) has no lowering");
|
|
155
157
|
}
|
|
156
158
|
let msg;
|
|
157
159
|
const msgNode = expr.arguments[0];
|
|
@@ -159,7 +161,7 @@ function lowerAssertFail(L, expr, loc) {
|
|
|
159
161
|
msg = { kind: "strLit", value: "Failed", type: STRING, loc };
|
|
160
162
|
}
|
|
161
163
|
else {
|
|
162
|
-
msg = lowerMessageArg(
|
|
164
|
+
msg = lowerMessageArg(lowerer, msgNode, loc).msg;
|
|
163
165
|
}
|
|
164
166
|
const falseLit = { kind: "boolLit", value: false, type: BOOL, loc };
|
|
165
167
|
return { kind: "libCall", fn: "assert.ok", args: [falseLit, msg], type: VOID, loc };
|
|
@@ -170,11 +172,11 @@ function lowerAssertFail(L, expr, loc) {
|
|
|
170
172
|
* deepStrictEqual synthesizes the per-type structural comparison. Objects
|
|
171
173
|
* under strictEqual (reference equality), mixed static types, and unions
|
|
172
174
|
* fence — honestly, never a miscompare. */
|
|
173
|
-
function lowerAssertEqual(
|
|
175
|
+
function lowerAssertEqual(lowerer, expr, loc, negated, deep) {
|
|
174
176
|
const surface = `assert.${deep ? (negated ? "notDeepStrictEqual" : "deepStrictEqual") : negated ? "notStrictEqual" : "strictEqual"}`;
|
|
175
|
-
requireStatementPosition(
|
|
177
|
+
requireStatementPosition(lowerer, expr, surface);
|
|
176
178
|
if (expr.arguments.length < 2 || expr.arguments.length > 3) {
|
|
177
|
-
|
|
179
|
+
lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr);
|
|
178
180
|
}
|
|
179
181
|
// A context-free EMPTY array literal on either side has no element type
|
|
180
182
|
// of its own (`deepStrictEqual(ee.listeners('x'), [])` — the checker
|
|
@@ -190,15 +192,14 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
190
192
|
let a;
|
|
191
193
|
let b;
|
|
192
194
|
if (emptyArrayLit(aNode) && !emptyArrayLit(bNode)) {
|
|
193
|
-
b =
|
|
194
|
-
a = adoptedEmpty(b.type) ??
|
|
195
|
+
b = lowerer.lowerExpr(bNode);
|
|
196
|
+
a = adoptedEmpty(b.type) ?? lowerer.lowerExpr(aNode);
|
|
195
197
|
}
|
|
196
198
|
else {
|
|
197
|
-
a =
|
|
198
|
-
b = emptyArrayLit(bNode) ? (adoptedEmpty(a.type) ??
|
|
199
|
+
a = lowerer.lowerExpr(aNode);
|
|
200
|
+
b = emptyArrayLit(bNode) ? (adoptedEmpty(a.type) ?? lowerer.lowerExpr(bNode)) : lowerer.lowerExpr(bNode);
|
|
199
201
|
}
|
|
200
|
-
const { msg, hasMsg } = lowerMessageArg(
|
|
201
|
-
const flag = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
202
|
+
const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
|
|
202
203
|
// CHECKED-DYNAMIC operands (dyn-vs-dyn, dyn-vs-static): both sides
|
|
203
204
|
// cross into the checked-dynamic tree and one runtime entry answers the whole quartet —
|
|
204
205
|
// SameValue for the strict pair (boxed-closure identity for
|
|
@@ -224,7 +225,7 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
224
225
|
k === "f64" ||
|
|
225
226
|
k === "string" ||
|
|
226
227
|
k === "bool" ||
|
|
227
|
-
(k === "func" &&
|
|
228
|
+
(k === "func" && lowerer.dynConvertible(e.type)) ||
|
|
228
229
|
// Runtime handles cross by REFERENCE (identity preserved), so the
|
|
229
230
|
// strict compare is honest: assert.strictEqual(this, server) —
|
|
230
231
|
// the ambient-receiver suite shape. The runtime's deep arm
|
|
@@ -240,14 +241,14 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
240
241
|
// code — Node's deepStrictEqual over Errors. Island round trips
|
|
241
242
|
// re-encode and lose the identity (SEMANTICS.md).
|
|
242
243
|
(k === "object" && e.type.kind === "object" && e.type.className === "%Error") ||
|
|
243
|
-
(deep && k !== "bytes" && k !== "object" &&
|
|
244
|
+
(deep && k !== "bytes" && k !== "object" && lowerer.dynConvertible(e.type));
|
|
244
245
|
if (!ok) {
|
|
245
246
|
const hint = !deep && (k === "record" || k === "array" || k === "map" || k === "set" || k === "union")
|
|
246
247
|
? "strictEqual on objects is reference equality, which does not survive the unknown boundary (values copy when they cross) — deepStrictEqual compares structure, or narrow the unknown side first"
|
|
247
248
|
: k === "bytes"
|
|
248
249
|
? "the unknown boundary cannot carry the Buffer-vs-Uint8Array brand Node compares — narrow the unknown side to a typed array and compare those"
|
|
249
250
|
: "the static side must convert into the checked-dynamic tree (numbers, strings, booleans, null/undefined, boxable functions, or JSON-safe structures under the deep forms) — narrow the unknown side instead";
|
|
250
|
-
|
|
251
|
+
lowerer.noLowering(`${surface} of 'unknown' and '${lowerer.fmt(e.type)}' values`, node, hint);
|
|
251
252
|
}
|
|
252
253
|
// A boxed closure takes its best-effort JS name from the source
|
|
253
254
|
// node (the coerceInto convention) — the failure message renders
|
|
@@ -258,7 +259,7 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
258
259
|
return {
|
|
259
260
|
kind: "libCall",
|
|
260
261
|
fn: "assert.eqDyn",
|
|
261
|
-
args: [box(a, aNode), box(b, bNode),
|
|
262
|
+
args: [box(a, aNode), box(b, bNode), boolLit(negated, loc), boolLit(deep, loc), msg, hasMsg],
|
|
262
263
|
type: VOID,
|
|
263
264
|
loc,
|
|
264
265
|
};
|
|
@@ -281,7 +282,7 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
281
282
|
return {
|
|
282
283
|
kind: "libCall",
|
|
283
284
|
fn: scalarFn,
|
|
284
|
-
args: [a, b,
|
|
285
|
+
args: [a, b, boolLit(negated, loc), boolLit(deep, loc), msg, hasMsg],
|
|
285
286
|
type: VOID,
|
|
286
287
|
loc,
|
|
287
288
|
};
|
|
@@ -297,35 +298,35 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
297
298
|
// the call through a binding whose DECLARED constructor differs from the
|
|
298
299
|
// value's runtime one compares by the declared brand (SEMANTICS.md).
|
|
299
300
|
if (a.type.kind === "bytes" && typeEquals(a.type, b.type)) {
|
|
300
|
-
const brandA = bytesBrandOf(
|
|
301
|
-
const brandB = bytesBrandOf(
|
|
301
|
+
const brandA = bytesBrandOf(lowerer, expr.arguments[0]);
|
|
302
|
+
const brandB = bytesBrandOf(lowerer, expr.arguments[1]);
|
|
302
303
|
if (!deep) {
|
|
303
304
|
// Brands shape only the failure HEADER (same-structure vs
|
|
304
305
|
// reference-equal expectation); an unclassifiable side defers to the
|
|
305
306
|
// content probe.
|
|
306
|
-
const brandsEq =
|
|
307
|
+
const brandsEq = boolLit(brandA === null || brandB === null || brandA === brandB, loc);
|
|
307
308
|
return {
|
|
308
309
|
kind: "libCall",
|
|
309
310
|
fn: "assert.refEqBytes",
|
|
310
|
-
args: [a, b,
|
|
311
|
+
args: [a, b, boolLit(negated, loc), brandsEq, msg, hasMsg],
|
|
311
312
|
type: VOID,
|
|
312
313
|
loc,
|
|
313
314
|
};
|
|
314
315
|
}
|
|
315
316
|
if (brandA === null || brandB === null) {
|
|
316
|
-
|
|
317
|
+
lowerer.noLowering(`${surface} of typed-array values whose constructor is not in the static type`, brandA === null ? expr.arguments[0] : expr.arguments[1], "Node's deep equality compares prototypes (a Buffer is never deep-equal to a plain Uint8Array) — annotate the value so its constructor is visible");
|
|
317
318
|
}
|
|
318
319
|
const verdict = {
|
|
319
320
|
kind: "libCall",
|
|
320
321
|
fn: "assert.bytesDeepEq",
|
|
321
|
-
args: [a, b,
|
|
322
|
+
args: [a, b, boolLit(brandA === brandB, loc)],
|
|
322
323
|
type: BOOL,
|
|
323
324
|
loc,
|
|
324
325
|
};
|
|
325
326
|
return {
|
|
326
327
|
kind: "libCall",
|
|
327
328
|
fn: "assert.deepResult",
|
|
328
|
-
args: [verdict,
|
|
329
|
+
args: [verdict, boolLit(negated, loc), msg, hasMsg],
|
|
329
330
|
type: VOID,
|
|
330
331
|
loc,
|
|
331
332
|
};
|
|
@@ -340,7 +341,7 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
340
341
|
return {
|
|
341
342
|
kind: "libCall",
|
|
342
343
|
fn: "assert.refEqFn",
|
|
343
|
-
args: [a, b,
|
|
344
|
+
args: [a, b, boolLit(negated, loc), msg, hasMsg],
|
|
344
345
|
type: VOID,
|
|
345
346
|
loc,
|
|
346
347
|
};
|
|
@@ -351,32 +352,32 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
351
352
|
: a.type.kind !== b.type.kind
|
|
352
353
|
? "both sides must share one static scalar type (number, string, or boolean)"
|
|
353
354
|
: "strictEqual on objects is reference equality — deepStrictEqual compares structure";
|
|
354
|
-
|
|
355
|
+
lowerer.noLowering(`${surface} of '${lowerer.fmt(a.type)}' and '${lowerer.fmt(b.type)}' values`, expr, hint);
|
|
355
356
|
}
|
|
356
357
|
// Deep equality: identical static types, structurally comparable.
|
|
357
358
|
if (!typeEquals(a.type, b.type)) {
|
|
358
|
-
|
|
359
|
+
lowerer.noLowering(`${surface} of '${lowerer.fmt(a.type)}' and '${lowerer.fmt(b.type)}' values`, expr, "deep equality lowers when both sides have the SAME static type — annotate or narrow one side");
|
|
359
360
|
}
|
|
360
361
|
if (isUnitType(a.type)) {
|
|
361
362
|
// undefined vs undefined / null vs null: trivially deep-equal.
|
|
362
363
|
return {
|
|
363
364
|
kind: "libCall",
|
|
364
365
|
fn: "assert.deepResult",
|
|
365
|
-
args: [
|
|
366
|
+
args: [boolLit(true, loc), boolLit(negated, loc), msg, hasMsg],
|
|
366
367
|
type: VOID,
|
|
367
368
|
loc,
|
|
368
369
|
};
|
|
369
370
|
}
|
|
370
|
-
const unsupported = deepUnsupportedReason(
|
|
371
|
+
const unsupported = deepUnsupportedReason(lowerer, a.type, new Set());
|
|
371
372
|
if (unsupported !== null) {
|
|
372
|
-
|
|
373
|
+
lowerer.noLowering(`${surface} of '${lowerer.fmt(a.type)}' values`, expr, unsupported);
|
|
373
374
|
}
|
|
374
|
-
const helper = deepEqHelper(
|
|
375
|
+
const helper = deepEqHelper(lowerer, a.type, loc);
|
|
375
376
|
const verdict = { kind: "call", callee: helper, args: [a, b], type: BOOL, loc };
|
|
376
377
|
return {
|
|
377
378
|
kind: "libCall",
|
|
378
379
|
fn: "assert.deepResult",
|
|
379
|
-
args: [verdict,
|
|
380
|
+
args: [verdict, boolLit(negated, loc), msg, hasMsg],
|
|
380
381
|
type: VOID,
|
|
381
382
|
loc,
|
|
382
383
|
};
|
|
@@ -384,18 +385,18 @@ function lowerAssertEqual(L, expr, loc, negated, deep) {
|
|
|
384
385
|
/** assert.match / assert.doesNotMatch: the regex test with Node's
|
|
385
386
|
* generated message (regex source + getter-ordered flags, the inspected
|
|
386
387
|
* input). */
|
|
387
|
-
function lowerAssertMatch(
|
|
388
|
+
function lowerAssertMatch(lowerer, expr, loc, negated) {
|
|
388
389
|
const surface = negated ? "assert.doesNotMatch" : "assert.match";
|
|
389
|
-
requireStatementPosition(
|
|
390
|
+
requireStatementPosition(lowerer, expr, surface);
|
|
390
391
|
if (expr.arguments.length < 2 || expr.arguments.length > 3) {
|
|
391
|
-
|
|
392
|
+
lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr);
|
|
392
393
|
}
|
|
393
|
-
const s =
|
|
394
|
-
const re =
|
|
394
|
+
const s = lowerer.lowerExprExpecting(expr.arguments[0], STRING);
|
|
395
|
+
const re = lowerer.lowerExpr(expr.arguments[1]);
|
|
395
396
|
if (re.type.kind !== "regex") {
|
|
396
|
-
|
|
397
|
+
lowerer.noLowering(`${surface} with a non-regex pattern`, expr.arguments[1], "the second argument must be a regular expression");
|
|
397
398
|
}
|
|
398
|
-
const { msg, hasMsg } = lowerMessageArg(
|
|
399
|
+
const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
|
|
399
400
|
const neg = { kind: "boolLit", value: negated, type: BOOL, loc };
|
|
400
401
|
return { kind: "libCall", fn: "assert.match", args: [s, re, neg, msg, hasMsg], type: VOID, loc };
|
|
401
402
|
}
|
|
@@ -407,10 +408,10 @@ function regexFlagsGetterOrder(flags) {
|
|
|
407
408
|
}
|
|
408
409
|
/** Is `className` the runtime %Error root or a class inside its
|
|
409
410
|
* hierarchy (builtin kinds and user subclasses alike)? */
|
|
410
|
-
function inErrorHierarchy(
|
|
411
|
+
function inErrorHierarchy(lowerer, className) {
|
|
411
412
|
if (className === "%Error" || RUNTIME_ERROR_CLASSES.has(className))
|
|
412
413
|
return true;
|
|
413
|
-
for (let c =
|
|
414
|
+
for (let c = lowerer.classes.get(className)?.base ?? null; c; c = c.base) {
|
|
414
415
|
if (c.def.name === "%Error")
|
|
415
416
|
return true;
|
|
416
417
|
}
|
|
@@ -420,23 +421,23 @@ function inErrorHierarchy(L, className) {
|
|
|
420
421
|
* regex test over String(error), an error-class identifier → instanceof,
|
|
421
422
|
* an object LITERAL over name/message/code (string or regex values) →
|
|
422
423
|
* the per-key shape comparison. Anything else fences honestly. */
|
|
423
|
-
function classifyThrowsExpected(
|
|
424
|
-
const expectedT =
|
|
424
|
+
function classifyThrowsExpected(lowerer, surface, node, loc) {
|
|
425
|
+
const expectedT = lowerer.mapTypeOf(lowerer.typeOf(node));
|
|
425
426
|
if (expectedT?.kind === "string") {
|
|
426
|
-
const m = lowerMessageArg(
|
|
427
|
+
const m = lowerMessageArg(lowerer, node, loc);
|
|
427
428
|
return { form: "message", msg: m.msg, hasMsg: m.hasMsg };
|
|
428
429
|
}
|
|
429
430
|
if (expectedT?.kind === "regex") {
|
|
430
|
-
return { form: "regex", value:
|
|
431
|
+
return { form: "regex", value: lowerer.lowerExpr(node) };
|
|
431
432
|
}
|
|
432
|
-
const sym = ts.isIdentifier(node) ?
|
|
433
|
-
const info = (sym &&
|
|
433
|
+
const sym = ts.isIdentifier(node) ? lowerer.resolveValueSymbol(node) : null;
|
|
434
|
+
const info = (sym && lowerer.builtinErrorInfoOf(sym)) ?? (sym && lowerer.classBySymbol.get(sym)) ?? null;
|
|
434
435
|
// A rebindable decorated name: the runtime expectation is the decoration
|
|
435
436
|
// result's interval, not the declaration's — no static class check.
|
|
436
437
|
if (info?.classDecorators?.valueGlobalId !== undefined) {
|
|
437
|
-
|
|
438
|
+
lowerer.unsupported("SC1090", node, "assert.throws/rejects against a decorated class whose decorators may replace it");
|
|
438
439
|
}
|
|
439
|
-
if (info &&
|
|
440
|
+
if (info && lowerer.inHierarchy(info)) {
|
|
440
441
|
const rec = RUNTIME_ERROR_CLASSES.get(info.def.name);
|
|
441
442
|
return {
|
|
442
443
|
form: "class",
|
|
@@ -449,7 +450,7 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
449
450
|
obj = obj.expression;
|
|
450
451
|
if (ts.isObjectLiteralExpression(obj)) {
|
|
451
452
|
if (obj.properties.length === 0) {
|
|
452
|
-
|
|
453
|
+
lowerer.noLowering(`${surface} with an empty expected object`, obj, "Node rejects this (the error 'may not be an empty object') — name at least one of name/message/code");
|
|
453
454
|
}
|
|
454
455
|
// Duplicate keys keep the LAST value (JS object-literal semantics);
|
|
455
456
|
// property order is preserved for argument evaluation.
|
|
@@ -457,15 +458,15 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
457
458
|
for (const prop of obj.properties) {
|
|
458
459
|
const named = ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop) ? prop : null;
|
|
459
460
|
if (!named || !(ts.isIdentifier(named.name) || ts.isStringLiteral(named.name))) {
|
|
460
|
-
|
|
461
|
+
lowerer.noLowering(`${surface} with this expected-object property form`, prop, "plain `key: value` properties are the lowered form");
|
|
461
462
|
}
|
|
462
463
|
const keyName = named.name.text;
|
|
463
464
|
const id = own(SHAPE_KEY_IDS, keyName);
|
|
464
465
|
if (id === undefined) {
|
|
465
|
-
|
|
466
|
+
lowerer.noLowering(`${surface} comparing the '${keyName}' property of the thrown error`, prop, "the static error surface carries name, message, and code — compare other properties in a catch block");
|
|
466
467
|
}
|
|
467
468
|
const valueNode = ts.isPropertyAssignment(named) ? named.initializer : named.name;
|
|
468
|
-
const value =
|
|
469
|
+
const value = lowerer.lowerExpr(valueNode);
|
|
469
470
|
if (value.type.kind === "string") {
|
|
470
471
|
byId.set(id, { id, kind: "str", value, enameBake: null });
|
|
471
472
|
}
|
|
@@ -479,7 +480,7 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
479
480
|
byId.set(id, { id, kind: "re", value, enameBake: bake });
|
|
480
481
|
}
|
|
481
482
|
else {
|
|
482
|
-
|
|
483
|
+
lowerer.noLowering(`${surface} expected-object values of type '${lowerer.fmt(value.type)}'`, valueNode, "string and regular-expression values are the lowered comparisons");
|
|
483
484
|
}
|
|
484
485
|
}
|
|
485
486
|
return { form: "shape", keys: [...byId.values()] };
|
|
@@ -489,12 +490,12 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
489
490
|
// the runtime compares per Node's expectsError key walk. A
|
|
490
491
|
// checked-dynamic expected rides directly; a static %Error boxes.
|
|
491
492
|
if (expectedT?.kind === "dyn") {
|
|
492
|
-
const value =
|
|
493
|
+
const value = lowerer.lowerExpr(node);
|
|
493
494
|
if (value.type.kind === "dyn")
|
|
494
495
|
return { form: "errValue", value };
|
|
495
496
|
}
|
|
496
497
|
if (expectedT?.kind === "object" && expectedT.className === "%Error") {
|
|
497
|
-
const value =
|
|
498
|
+
const value = lowerer.lowerExpr(node);
|
|
498
499
|
if (value.type.kind === "object") {
|
|
499
500
|
return { form: "errValue", value: { kind: "dynFrom", value, type: DYN, loc } };
|
|
500
501
|
}
|
|
@@ -505,8 +506,8 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
505
506
|
// the expected's own keys only, so a convertible record crosses as its
|
|
506
507
|
// dyn object. Records carrying regex members are not convertible and
|
|
507
508
|
// keep the fence (the runtime walk would deep-compare, not test).
|
|
508
|
-
if (expectedT?.kind === "record" &&
|
|
509
|
-
const value =
|
|
509
|
+
if (expectedT?.kind === "record" && lowerer.dynConvertible(expectedT)) {
|
|
510
|
+
const value = lowerer.lowerExpr(node);
|
|
510
511
|
// JS-lane locals holding object literals lower to dyn already; a
|
|
511
512
|
// typed record crosses through dynFrom.
|
|
512
513
|
if (value.type.kind === "dyn")
|
|
@@ -515,7 +516,7 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
515
516
|
return { form: "errValue", value: { kind: "dynFrom", value, type: DYN, loc } };
|
|
516
517
|
}
|
|
517
518
|
}
|
|
518
|
-
|
|
519
|
+
lowerer.noLowering(`${surface} with this expected-error shape`, node, "an error CLASS (Error/TypeError/... or a class extending them), an error instance, a message string, " +
|
|
519
520
|
"a regular expression, or an object literal over name/message/code are the lowered forms");
|
|
520
521
|
}
|
|
521
522
|
/** assert.throws(fn[, expected][, message]): the zero-parameter callback
|
|
@@ -529,17 +530,17 @@ function classifyThrowsExpected(L, surface, node, loc) {
|
|
|
529
530
|
* non-Error thrown value under any expectation propagates
|
|
530
531
|
* (SEMANTICS.md 104 — Node builds an AssertionError from its
|
|
531
532
|
* inspection). */
|
|
532
|
-
function lowerAssertThrows(
|
|
533
|
-
requireStatementPosition(
|
|
533
|
+
function lowerAssertThrows(lowerer, expr, loc) {
|
|
534
|
+
requireStatementPosition(lowerer, expr, "assert.throws");
|
|
534
535
|
if (expr.arguments.length < 1 || expr.arguments.length > 3) {
|
|
535
|
-
|
|
536
|
+
lowerer.noLowering(`assert.throws with ${expr.arguments.length} arguments`, expr, "the supported forms are throws(fn), throws(fn, expected), and throws(fn, expected, message)");
|
|
536
537
|
}
|
|
537
|
-
const fn =
|
|
538
|
+
const fn = lowerer.lowerExpr(expr.arguments[0]);
|
|
538
539
|
if (fn.type.kind !== "func" || fn.type.params.length !== 0) {
|
|
539
|
-
|
|
540
|
+
lowerer.noLowering("assert.throws with this callback shape", expr.arguments[0], "the callback must be a zero-parameter function");
|
|
540
541
|
}
|
|
541
|
-
const { expected, msg, hasMsg } = throwsArguments(
|
|
542
|
-
const helper = assertThrowsHelper(
|
|
542
|
+
const { expected, msg, hasMsg } = throwsArguments(lowerer, "assert.throws", expr, loc);
|
|
543
|
+
const helper = assertThrowsHelper(lowerer, "throws", fn.type, false, expected, loc);
|
|
543
544
|
return { kind: "call", callee: helper, args: [fn, msg, hasMsg, ...expectedArgs(expected)], type: VOID, loc };
|
|
544
545
|
}
|
|
545
546
|
/** assert.rejects / assert.doesNotReject: the async twins. The first
|
|
@@ -552,26 +553,26 @@ function lowerAssertThrows(L, expr, loc) {
|
|
|
552
553
|
* doesNotReject rethrows a NON-matching rejection and throws Node's
|
|
553
554
|
* "Got unwanted rejection" AssertionError on a match (regex
|
|
554
555
|
* expectations fence — the runtime predicate is throw-shaped). */
|
|
555
|
-
function lowerAssertRejects(
|
|
556
|
+
function lowerAssertRejects(lowerer, expr, loc, doesNot) {
|
|
556
557
|
const surface = doesNot ? "assert.doesNotReject" : "assert.rejects";
|
|
557
558
|
if (expr.arguments.length < 1 || expr.arguments.length > 3) {
|
|
558
|
-
|
|
559
|
+
lowerer.noLowering(`${surface} with ${expr.arguments.length} arguments`, expr, `the supported forms are ${doesNot ? "doesNotReject" : "rejects"}(fn), (fn, expected), and (fn, expected, message)`);
|
|
559
560
|
}
|
|
560
|
-
const recv =
|
|
561
|
+
const recv = lowerer.lowerExpr(expr.arguments[0]);
|
|
561
562
|
const recvIsPromise = recv.type.kind === "promise";
|
|
562
563
|
if (!recvIsPromise &&
|
|
563
564
|
(recv.type.kind !== "func" || recv.type.params.length !== 0 || recv.type.ret.kind !== "promise")) {
|
|
564
|
-
|
|
565
|
+
lowerer.noLowering(`${surface} with this first argument`, expr.arguments[0], "an async (promise-returning) zero-parameter function or a promise are the lowered forms " +
|
|
565
566
|
"(a bare thenable — an object with a then method — has no lowering: wrap it, e.g. Promise.resolve().then(() => thenable))");
|
|
566
567
|
}
|
|
567
|
-
const { expected, msg, hasMsg } = throwsArguments(
|
|
568
|
+
const { expected, msg, hasMsg } = throwsArguments(lowerer, surface, expr, loc);
|
|
568
569
|
if (doesNot && (expected.form === "shape" || expected.form === "errValue")) {
|
|
569
570
|
// Node itself rejects this form (ERR_INVALID_ARG_TYPE: "expected"
|
|
570
571
|
// must be a function or RegExp) — the fence is the compile-time
|
|
571
572
|
// statement of the same rule.
|
|
572
|
-
|
|
573
|
+
lowerer.noLowering(`${surface} with an object-shape expectation`, expr.arguments[1], "Node rejects this form (doesNotReject takes a class or RegExp) — use a class, a regex, or a bare call");
|
|
573
574
|
}
|
|
574
|
-
const helper = assertThrowsHelper(
|
|
575
|
+
const helper = assertThrowsHelper(lowerer, doesNot ? "dnr" : "rejects", recv.type, recvIsPromise, expected, loc);
|
|
575
576
|
return {
|
|
576
577
|
kind: "call",
|
|
577
578
|
callee: helper,
|
|
@@ -583,20 +584,20 @@ function lowerAssertRejects(L, expr, loc, doesNot) {
|
|
|
583
584
|
/** The shared expected/message argument split (arguments 2 and 3): a
|
|
584
585
|
* string expected IS the message and excludes a third argument (Node
|
|
585
586
|
* throws ERR_INVALID_ARG_TYPE there). */
|
|
586
|
-
function throwsArguments(
|
|
587
|
+
function throwsArguments(lowerer, surface, expr, loc) {
|
|
587
588
|
const expectedNode = expr.arguments[1];
|
|
588
589
|
// A literal `undefined` expected counts as omitted (Node reads the
|
|
589
590
|
// message from the THIRD argument in that spelling).
|
|
590
591
|
const expected = expectedNode && !(ts.isIdentifier(expectedNode) && expectedNode.text === "undefined")
|
|
591
|
-
? classifyThrowsExpected(
|
|
592
|
+
? classifyThrowsExpected(lowerer, surface, expectedNode, loc)
|
|
592
593
|
: { form: "bare" };
|
|
593
594
|
if (expected.form === "message") {
|
|
594
595
|
if (expr.arguments.length === 3) {
|
|
595
|
-
|
|
596
|
+
lowerer.noLowering(`${surface} with a string expected argument AND a message`, expr.arguments[2], "Node rejects this form (the string IS the message) — use an expected shape second");
|
|
596
597
|
}
|
|
597
598
|
return { expected, msg: expected.msg, hasMsg: expected.hasMsg };
|
|
598
599
|
}
|
|
599
|
-
const { msg, hasMsg } = lowerMessageArg(
|
|
600
|
+
const { msg, hasMsg } = lowerMessageArg(lowerer, expr.arguments[2], loc);
|
|
600
601
|
return { expected, msg, hasMsg };
|
|
601
602
|
}
|
|
602
603
|
/** The extra call-site arguments a form carries into its helper, in the
|
|
@@ -634,7 +635,7 @@ function expectedArgs(expected) {
|
|
|
634
635
|
* return. doesNotReject inverts: a MATCHING Error throws "Got unwanted
|
|
635
636
|
* rejection", everything else rethrows the original reason. A non-Error
|
|
636
637
|
* thrown value under any expectation propagates (SEMANTICS.md 104). */
|
|
637
|
-
function assertThrowsHelper(
|
|
638
|
+
function assertThrowsHelper(lowerer, mode, recvType, recvIsPromise, expected, loc) {
|
|
638
639
|
const sig = expected.form === "class"
|
|
639
640
|
? `class:${expected.className}`
|
|
640
641
|
: expected.form === "regex"
|
|
@@ -645,16 +646,12 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
645
646
|
? "errval"
|
|
646
647
|
: "bare";
|
|
647
648
|
const key = `assert.${mode}:${recvIsPromise ? "p" : "f"}:${typeKey(recvType)}:${sig}`;
|
|
648
|
-
const existing =
|
|
649
|
+
const existing = lowerer.assertHelpers.get(key);
|
|
649
650
|
if (existing)
|
|
650
651
|
return existing;
|
|
651
|
-
const name = `%assert.${mode}.${
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
const flag = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
655
|
-
const str = (value) => ({ kind: "strLit", value, type: STRING, loc });
|
|
656
|
-
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
657
|
-
const caughtRef = () => ref("e.0", CAUGHT);
|
|
652
|
+
const name = `%assert.${mode}.${lowerer.assertHelpers.size}`;
|
|
653
|
+
lowerer.assertHelpers.set(key, name);
|
|
654
|
+
const caughtRef = () => varRef("e.0", CAUGHT, loc);
|
|
658
655
|
const errT = { kind: "object", className: "%Error" };
|
|
659
656
|
const narrowed = () => ({ kind: "caughtNarrow", value: caughtRef(), type: errT, loc });
|
|
660
657
|
const isInstance = (className) => ({
|
|
@@ -665,8 +662,8 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
665
662
|
expr: { kind: "libCall", fn, args, type: VOID, loc },
|
|
666
663
|
loc,
|
|
667
664
|
});
|
|
668
|
-
const m = () =>
|
|
669
|
-
const hm = () =>
|
|
665
|
+
const m = () => varRef("m.0", STRING, loc);
|
|
666
|
+
const hm = () => varRef("hm.0", BOOL, loc);
|
|
670
667
|
const doReturn = { kind: "return", value: null, loc };
|
|
671
668
|
const rethrow = { kind: "rethrow", localId: "e.0", loc };
|
|
672
669
|
const ifStmt = (cond, then) => ({ kind: "if", cond, then, else_: null, loc });
|
|
@@ -697,8 +694,8 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
697
694
|
const stmts = [lib("assert.shapeBegin", [narrowed()])];
|
|
698
695
|
expected.keys.forEach((k, i) => {
|
|
699
696
|
stmts.push(lib(k.kind === "str" ? "assert.shapeStr" : "assert.shapeRe", [
|
|
700
|
-
|
|
701
|
-
|
|
697
|
+
numLit(k.id, loc),
|
|
698
|
+
varRef(shapeParamIds[i], k.kind === "str" ? STRING : REGEX, loc),
|
|
702
699
|
]));
|
|
703
700
|
});
|
|
704
701
|
return stmts;
|
|
@@ -709,18 +706,18 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
709
706
|
// name drops the detail (a documented sliver).
|
|
710
707
|
const ename = (() => {
|
|
711
708
|
if (expected.form === "class")
|
|
712
|
-
return { e:
|
|
709
|
+
return { e: strLit(expected.displayName, loc), has: true };
|
|
713
710
|
if (expected.form === "shape") {
|
|
714
711
|
const i = expected.keys.findIndex((k) => k.id === 2);
|
|
715
712
|
if (i >= 0) {
|
|
716
713
|
const k = expected.keys[i];
|
|
717
714
|
if (k.kind === "str")
|
|
718
|
-
return { e:
|
|
715
|
+
return { e: varRef(shapeParamIds[i], STRING, loc), has: true };
|
|
719
716
|
if (k.enameBake !== null)
|
|
720
|
-
return { e:
|
|
717
|
+
return { e: strLit(k.enameBake, loc), has: true };
|
|
721
718
|
}
|
|
722
719
|
}
|
|
723
|
-
return { e:
|
|
720
|
+
return { e: strLit("", loc), has: false };
|
|
724
721
|
})();
|
|
725
722
|
let catchBody;
|
|
726
723
|
if (mode === "dnr") {
|
|
@@ -746,7 +743,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
746
743
|
ifStmt({
|
|
747
744
|
kind: "libCall",
|
|
748
745
|
fn: "assert.regexErrTest",
|
|
749
|
-
args: [
|
|
746
|
+
args: [varRef("re.0", REGEX, loc), narrowed()],
|
|
750
747
|
type: BOOL,
|
|
751
748
|
loc,
|
|
752
749
|
}, [lib("assert.unwantedRejection", [narrowed(), m(), hm()])]),
|
|
@@ -757,7 +754,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
757
754
|
default:
|
|
758
755
|
// Node itself rejects shape expectations here (ERR_INVALID_ARG_TYPE)
|
|
759
756
|
// — the call site fences before reaching this helper.
|
|
760
|
-
throw new
|
|
757
|
+
throw new InternalCompilerError("assert helper: doesNotReject shape forms fence at the call site");
|
|
761
758
|
}
|
|
762
759
|
}
|
|
763
760
|
else {
|
|
@@ -770,7 +767,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
770
767
|
catchBody = [
|
|
771
768
|
ifStmt(isInstance(expected.className), [doReturn]),
|
|
772
769
|
ifStmt(isInstance("%Error"), [
|
|
773
|
-
lib("assert.throwsMismatch", [
|
|
770
|
+
lib("assert.throwsMismatch", [strLit(expected.displayName, loc), narrowed(), m(), hm()]),
|
|
774
771
|
]),
|
|
775
772
|
// A non-Error thrown value: propagate (SEMANTICS.md 104; the
|
|
776
773
|
// mismatch throw above never falls through — its pending
|
|
@@ -781,7 +778,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
781
778
|
case "regex":
|
|
782
779
|
catchBody = [
|
|
783
780
|
ifStmt(isInstance("%Error"), [
|
|
784
|
-
lib("assert.throwsRegex", [
|
|
781
|
+
lib("assert.throwsRegex", [varRef("re.0", REGEX, loc), narrowed(), m(), hm()]),
|
|
785
782
|
doReturn,
|
|
786
783
|
]),
|
|
787
784
|
rethrow,
|
|
@@ -805,7 +802,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
805
802
|
catchBody = [
|
|
806
803
|
lib("assert.expectsErrDyn", [
|
|
807
804
|
{ kind: "caughtToDyn", value: caughtRef(), type: DYN, loc },
|
|
808
|
-
|
|
805
|
+
varRef("ev.0", DYN, loc),
|
|
809
806
|
m(),
|
|
810
807
|
hm(),
|
|
811
808
|
]),
|
|
@@ -821,7 +818,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
821
818
|
tryBody = [
|
|
822
819
|
{
|
|
823
820
|
kind: "exprStmt",
|
|
824
|
-
expr: { kind: "callValue", callee:
|
|
821
|
+
expr: { kind: "callValue", callee: varRef("f.0", fnT, loc), args: [], type: fnT.ret, loc },
|
|
825
822
|
loc,
|
|
826
823
|
},
|
|
827
824
|
];
|
|
@@ -829,7 +826,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
829
826
|
else {
|
|
830
827
|
let awaited;
|
|
831
828
|
if (recvIsPromise) {
|
|
832
|
-
awaited =
|
|
829
|
+
awaited = varRef("f.0", recvType, loc);
|
|
833
830
|
}
|
|
834
831
|
else {
|
|
835
832
|
const fnT = recvType;
|
|
@@ -838,10 +835,10 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
838
835
|
body.push({
|
|
839
836
|
kind: "varDecl",
|
|
840
837
|
localId: "pr.0",
|
|
841
|
-
init: { kind: "callValue", callee:
|
|
838
|
+
init: { kind: "callValue", callee: varRef("f.0", fnT, loc), args: [], type: promT, loc },
|
|
842
839
|
loc,
|
|
843
840
|
});
|
|
844
|
-
awaited =
|
|
841
|
+
awaited = varRef("pr.0", promT, loc);
|
|
845
842
|
}
|
|
846
843
|
const inner = awaited.type.inner;
|
|
847
844
|
tryBody = [
|
|
@@ -850,10 +847,10 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
850
847
|
}
|
|
851
848
|
body.push({ kind: "tryCatch", tryBody, catchBody, catchLocalId: "e.0", finallyBody: null, loc });
|
|
852
849
|
if (mode !== "dnr") {
|
|
853
|
-
body.push(lib("assert.throwsNone", [
|
|
850
|
+
body.push(lib("assert.throwsNone", [boolLit(mode === "rejects", loc), ename.e, boolLit(ename.has, loc), m(), hm()]));
|
|
854
851
|
}
|
|
855
852
|
body.push(doReturn);
|
|
856
|
-
|
|
853
|
+
lowerer.liftedFns.push({
|
|
857
854
|
name,
|
|
858
855
|
params,
|
|
859
856
|
returnType: VOID,
|
|
@@ -869,7 +866,7 @@ function assertThrowsHelper(L, mode, recvType, recvIsPromise, expected, loc) {
|
|
|
869
866
|
* "unit" for null/undefined (can never throw — the evaluated expression
|
|
870
867
|
* alone suffices), a libCall name for scalars and %Error-hierarchy
|
|
871
868
|
* objects, null for everything else (the caller fences). */
|
|
872
|
-
function ifErrorLibFn(
|
|
869
|
+
function ifErrorLibFn(lowerer, t) {
|
|
873
870
|
switch (t.kind) {
|
|
874
871
|
case "undefinedT":
|
|
875
872
|
case "nullT":
|
|
@@ -881,7 +878,7 @@ function ifErrorLibFn(L, t) {
|
|
|
881
878
|
case "bool":
|
|
882
879
|
return "assert.ifErrorBool";
|
|
883
880
|
case "object":
|
|
884
|
-
return inErrorHierarchy(
|
|
881
|
+
return inErrorHierarchy(lowerer, t.className) ? "assert.ifErrorErr" : null;
|
|
885
882
|
default:
|
|
886
883
|
return null;
|
|
887
884
|
}
|
|
@@ -893,13 +890,13 @@ function ifErrorLibFn(L, t) {
|
|
|
893
890
|
* evaluated expression alone; scalars and %Error-hierarchy objects
|
|
894
891
|
* throw through the typed runtime entries; unions dispatch per arm in
|
|
895
892
|
* an interned helper. Anything else fences. */
|
|
896
|
-
function lowerAssertIfError(
|
|
897
|
-
requireStatementPosition(
|
|
893
|
+
function lowerAssertIfError(lowerer, expr, loc) {
|
|
894
|
+
requireStatementPosition(lowerer, expr, "assert.ifError");
|
|
898
895
|
if (expr.arguments.length !== 1) {
|
|
899
|
-
|
|
896
|
+
lowerer.noLowering(`assert.ifError with ${expr.arguments.length} arguments`, expr, "the supported form is ifError(value)");
|
|
900
897
|
}
|
|
901
898
|
const argNode = expr.arguments[0];
|
|
902
|
-
const argT =
|
|
899
|
+
const argT = lowerer.mapTypeOf(lowerer.typeOf(argNode));
|
|
903
900
|
if (argT && isUnitType(argT)) {
|
|
904
901
|
// null/undefined can never throw, and a unit-typed expression has no
|
|
905
902
|
// standalone runtime value to evaluate — a passing assert.ok is the
|
|
@@ -915,9 +912,9 @@ function lowerAssertIfError(L, expr, loc) {
|
|
|
915
912
|
loc,
|
|
916
913
|
};
|
|
917
914
|
}
|
|
918
|
-
const v =
|
|
919
|
-
const fence = (t) =>
|
|
920
|
-
const direct = ifErrorLibFn(
|
|
915
|
+
const v = lowerer.lowerExpr(argNode);
|
|
916
|
+
const fence = (t) => lowerer.noLowering(`assert.ifError over '${lowerer.fmt(t)}' values`, argNode, "numbers, strings, booleans, Errors, null/undefined, and unions of those are the lowered forms");
|
|
917
|
+
const direct = ifErrorLibFn(lowerer, v.type);
|
|
921
918
|
if (direct === "unit") {
|
|
922
919
|
// A unit-typed value that mapped through some other checker spelling:
|
|
923
920
|
// the same no-op (unreachable in practice — the mapTypeOf branch
|
|
@@ -945,36 +942,36 @@ function lowerAssertIfError(L, expr, loc) {
|
|
|
945
942
|
if (v.type.kind !== "union")
|
|
946
943
|
fence(v.type);
|
|
947
944
|
const unionT = v.type;
|
|
948
|
-
const def =
|
|
945
|
+
const def = lowerer.unions.get(unionT.unionId);
|
|
949
946
|
if (!def)
|
|
950
947
|
fence(v.type);
|
|
951
948
|
for (const arm of def.arms) {
|
|
952
|
-
if (ifErrorLibFn(
|
|
949
|
+
if (ifErrorLibFn(lowerer, arm) === null)
|
|
953
950
|
fence(arm);
|
|
954
951
|
}
|
|
955
|
-
const helper = ifErrorHelper(
|
|
952
|
+
const helper = ifErrorHelper(lowerer, unionT, loc);
|
|
956
953
|
return { kind: "call", callee: helper, args: [v], type: VOID, loc };
|
|
957
954
|
}
|
|
958
955
|
/** The interned per-union ifError helper `%assert.iferr.<n>(v): void` —
|
|
959
956
|
* one tag test per arm: unit arms return quietly, every other arm
|
|
960
957
|
* narrows and throws through its typed runtime entry. */
|
|
961
|
-
function ifErrorHelper(
|
|
958
|
+
function ifErrorHelper(lowerer, t, loc) {
|
|
962
959
|
const key = `assert.iferr:${typeKey(t)}`;
|
|
963
|
-
const existing =
|
|
960
|
+
const existing = lowerer.assertHelpers.get(key);
|
|
964
961
|
if (existing)
|
|
965
962
|
return existing;
|
|
966
|
-
const name = `%assert.iferr.${
|
|
967
|
-
|
|
968
|
-
const def =
|
|
963
|
+
const name = `%assert.iferr.${lowerer.assertHelpers.size}`;
|
|
964
|
+
lowerer.assertHelpers.set(key, name);
|
|
965
|
+
const def = lowerer.unions.get(t.unionId);
|
|
969
966
|
if (!def)
|
|
970
|
-
throw new
|
|
967
|
+
throw new InternalCompilerError(`assert.ifError over unknown union ${t.unionId}`);
|
|
971
968
|
const v = () => ({ kind: "varRef", localId: "v.0", type: t, loc });
|
|
972
969
|
const doReturn = { kind: "return", value: null, loc };
|
|
973
970
|
const body = [];
|
|
974
971
|
def.arms.forEach((arm, tag) => {
|
|
975
|
-
const fn = ifErrorLibFn(
|
|
972
|
+
const fn = ifErrorLibFn(lowerer, arm);
|
|
976
973
|
if (fn === null)
|
|
977
|
-
throw new
|
|
974
|
+
throw new InternalCompilerError("assert.ifError helper over an unfenced arm");
|
|
978
975
|
const then = fn === "unit"
|
|
979
976
|
? [doReturn]
|
|
980
977
|
: [
|
|
@@ -1000,7 +997,7 @@ function ifErrorHelper(L, t, loc) {
|
|
|
1000
997
|
});
|
|
1001
998
|
});
|
|
1002
999
|
body.push(doReturn); // unreachable: some arm always matches
|
|
1003
|
-
|
|
1000
|
+
lowerer.liftedFns.push({
|
|
1004
1001
|
name,
|
|
1005
1002
|
params: [{ localId: "v.0", name: "v", type: t }],
|
|
1006
1003
|
returnType: VOID,
|
|
@@ -1021,8 +1018,8 @@ const BYTES_BRANDS = new Set([
|
|
|
1021
1018
|
"Int8Array", "Int16Array", "Int32Array", "Float32Array", "Float64Array",
|
|
1022
1019
|
"BigInt64Array", "BigUint64Array", "DataView",
|
|
1023
1020
|
]);
|
|
1024
|
-
function bytesBrandOf(
|
|
1025
|
-
const tname =
|
|
1021
|
+
function bytesBrandOf(lowerer, node) {
|
|
1022
|
+
const tname = lowerer.checker.typeToString(lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(node)));
|
|
1026
1023
|
const head = /^[A-Za-z_$][A-Za-z0-9_$]*/.exec(tname)?.[0] ?? "";
|
|
1027
1024
|
if (head === "Buffer" || head === "NonSharedBuffer")
|
|
1028
1025
|
return "Buffer";
|
|
@@ -1033,7 +1030,7 @@ function bytesBrandOf(L, node) {
|
|
|
1033
1030
|
* fence names the FIRST unsupported constituent — never a silent
|
|
1034
1031
|
* miscompare. Recursive record shapes terminate through `visiting`
|
|
1035
1032
|
* (a shape being checked is assumed fine; its own walk decides). */
|
|
1036
|
-
function deepUnsupportedReason(
|
|
1033
|
+
function deepUnsupportedReason(lowerer, t, visiting) {
|
|
1037
1034
|
switch (t.kind) {
|
|
1038
1035
|
case "f64":
|
|
1039
1036
|
case "string":
|
|
@@ -1042,40 +1039,40 @@ function deepUnsupportedReason(L, t, visiting) {
|
|
|
1042
1039
|
case "nullT":
|
|
1043
1040
|
return null;
|
|
1044
1041
|
case "array":
|
|
1045
|
-
return deepUnsupportedReason(
|
|
1042
|
+
return deepUnsupportedReason(lowerer, t.elem, visiting);
|
|
1046
1043
|
case "record": {
|
|
1047
1044
|
if (visiting.has(t.shapeId))
|
|
1048
1045
|
return null;
|
|
1049
1046
|
visiting.add(t.shapeId);
|
|
1050
|
-
const shape =
|
|
1047
|
+
const shape = lowerer.shapes.get(t.shapeId);
|
|
1051
1048
|
if (!shape)
|
|
1052
1049
|
return "this record shape has no deep comparison";
|
|
1053
1050
|
if (shape.indexValue !== undefined) {
|
|
1054
1051
|
return "index-signature records have no deep comparison (their key sets are dynamic)";
|
|
1055
1052
|
}
|
|
1056
1053
|
for (const f of shape.fields) {
|
|
1057
|
-
const why = deepUnsupportedReason(
|
|
1054
|
+
const why = deepUnsupportedReason(lowerer, f.type, visiting);
|
|
1058
1055
|
if (why !== null)
|
|
1059
1056
|
return why;
|
|
1060
1057
|
}
|
|
1061
1058
|
return null;
|
|
1062
1059
|
}
|
|
1063
1060
|
case "map": {
|
|
1064
|
-
const keyWhy = deepUnsupportedReason(
|
|
1061
|
+
const keyWhy = deepUnsupportedReason(lowerer, t.key, visiting);
|
|
1065
1062
|
if (keyWhy !== null)
|
|
1066
1063
|
return keyWhy;
|
|
1067
|
-
return deepUnsupportedReason(
|
|
1064
|
+
return deepUnsupportedReason(lowerer, t.value, visiting);
|
|
1068
1065
|
}
|
|
1069
1066
|
case "set":
|
|
1070
1067
|
return t.elem.kind === "f64" || t.elem.kind === "string" || t.elem.kind === "bool"
|
|
1071
1068
|
? null
|
|
1072
1069
|
: "Sets of non-scalar elements have no deep comparison (Node matches object members structurally)";
|
|
1073
1070
|
case "union": {
|
|
1074
|
-
const def =
|
|
1071
|
+
const def = lowerer.unions.get(t.unionId);
|
|
1075
1072
|
if (!def)
|
|
1076
1073
|
return "this union has no deep comparison";
|
|
1077
1074
|
for (const arm of def.arms) {
|
|
1078
|
-
const why = deepUnsupportedReason(
|
|
1075
|
+
const why = deepUnsupportedReason(lowerer, arm, visiting);
|
|
1079
1076
|
if (why !== null)
|
|
1080
1077
|
return why;
|
|
1081
1078
|
}
|
|
@@ -1098,7 +1095,7 @@ function deepUnsupportedReason(L, t, visiting) {
|
|
|
1098
1095
|
case "object":
|
|
1099
1096
|
return "class instances have no deep comparison (Node compares prototypes and own properties)";
|
|
1100
1097
|
default:
|
|
1101
|
-
return `'${
|
|
1098
|
+
return `'${lowerer.fmt(t)}' values have no deep comparison`;
|
|
1102
1099
|
}
|
|
1103
1100
|
}
|
|
1104
1101
|
/** The interned per-type deep-equality helper `%assert.deq.<n>(a, b):
|
|
@@ -1107,28 +1104,25 @@ function deepUnsupportedReason(L, t, visiting) {
|
|
|
1107
1104
|
* tag+payload unions, SameValueZero-keyed Maps with deep values, scalar
|
|
1108
1105
|
* Sets by membership. Registered in the cache BEFORE the body builds, so
|
|
1109
1106
|
* recursive record shapes call themselves by name. */
|
|
1110
|
-
function deepEqHelper(
|
|
1107
|
+
function deepEqHelper(lowerer, t, loc) {
|
|
1111
1108
|
const key = `assert.deq:${typeKey(t)}`;
|
|
1112
|
-
const existing =
|
|
1109
|
+
const existing = lowerer.assertHelpers.get(key);
|
|
1113
1110
|
if (existing)
|
|
1114
1111
|
return existing;
|
|
1115
|
-
const name = `%assert.deq.${
|
|
1116
|
-
|
|
1117
|
-
const
|
|
1118
|
-
const
|
|
1119
|
-
const b = () => ref("b.0", t);
|
|
1120
|
-
const num = (value) => ({ kind: "numLit", value, type: F64, loc });
|
|
1121
|
-
const boolLit = (value) => ({ kind: "boolLit", value, type: BOOL, loc });
|
|
1112
|
+
const name = `%assert.deq.${lowerer.assertHelpers.size}`;
|
|
1113
|
+
lowerer.assertHelpers.set(key, name);
|
|
1114
|
+
const a = () => varRef("a.0", t, loc);
|
|
1115
|
+
const b = () => varRef("b.0", t, loc);
|
|
1122
1116
|
const ret = (value) => ({ kind: "return", value, loc });
|
|
1123
|
-
const retFalse = ret(boolLit(false));
|
|
1117
|
+
const retFalse = ret(boolLit(false, loc));
|
|
1124
1118
|
const not = (operand) => ({ kind: "unary", op: "!", operand, type: BOOL, loc });
|
|
1125
1119
|
const neq = (left, right) => ({ kind: "bin", op: "!==", left, right, type: BOOL, loc });
|
|
1126
1120
|
/** if (cond) return false; */
|
|
1127
1121
|
const bailIf = (cond) => ({ kind: "if", cond, then: [retFalse], else_: null, loc });
|
|
1128
1122
|
/** Deep-compare two same-typed exprs through the per-type helper. */
|
|
1129
1123
|
const deq = (elemT, x, y) => isUnitType(elemT)
|
|
1130
|
-
? boolLit(true)
|
|
1131
|
-
: { kind: "call", callee: deepEqHelper(
|
|
1124
|
+
? boolLit(true, loc)
|
|
1125
|
+
: { kind: "call", callee: deepEqHelper(lowerer, elemT, loc), args: [x, y], type: BOOL, loc };
|
|
1132
1126
|
let locals = [
|
|
1133
1127
|
{ id: "a.0", name: "a", type: t, mutable: false },
|
|
1134
1128
|
{ id: "b.0", name: "b", type: t, mutable: false },
|
|
@@ -1156,22 +1150,15 @@ function deepEqHelper(L, t, loc) {
|
|
|
1156
1150
|
locals.push({ id: "i.0", name: "i", type: F64, mutable: true });
|
|
1157
1151
|
body = [
|
|
1158
1152
|
bailIf(neq(len(a()), len(b()))),
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
init: { kind: "varDecl", localId: "i.0", init: num(0), loc },
|
|
1162
|
-
cond: { kind: "bin", op: "<", left: ref("i.0", F64), right: len(a()), type: BOOL, loc },
|
|
1163
|
-
update: { kind: "assign", localId: "i.0", value: { kind: "bin", op: "+", left: ref("i.0", F64), right: num(1), type: F64, loc }, loc },
|
|
1164
|
-
body: [bailIf(not(deq(t.elem, at(a(), ref("i.0", F64)), at(b(), ref("i.0", F64)))))],
|
|
1165
|
-
loc,
|
|
1166
|
-
},
|
|
1167
|
-
ret(boolLit(true)),
|
|
1153
|
+
countedFor(loc, len(a()), (i) => [bailIf(not(deq(t.elem, at(a(), i), at(b(), i))))]),
|
|
1154
|
+
ret(boolLit(true, loc)),
|
|
1168
1155
|
];
|
|
1169
1156
|
break;
|
|
1170
1157
|
}
|
|
1171
1158
|
case "record": {
|
|
1172
|
-
const shape =
|
|
1159
|
+
const shape = lowerer.shapes.get(t.shapeId);
|
|
1173
1160
|
if (!shape)
|
|
1174
|
-
throw new
|
|
1161
|
+
throw new InternalCompilerError(`assert deep-equal of unknown shape ${t.shapeId}`);
|
|
1175
1162
|
const get = (obj, field, type) => ({ kind: "recordGet", obj, shapeId: t.shapeId, field, type, loc });
|
|
1176
1163
|
body = [];
|
|
1177
1164
|
for (const f of shape.fields) {
|
|
@@ -1179,13 +1166,13 @@ function deepEqHelper(L, t, loc) {
|
|
|
1179
1166
|
continue; // a unit field is equal by type
|
|
1180
1167
|
body.push(bailIf(not(deq(f.type, get(a(), f.name, f.type), get(b(), f.name, f.type)))));
|
|
1181
1168
|
}
|
|
1182
|
-
body.push(ret(boolLit(true)));
|
|
1169
|
+
body.push(ret(boolLit(true, loc)));
|
|
1183
1170
|
break;
|
|
1184
1171
|
}
|
|
1185
1172
|
case "union": {
|
|
1186
|
-
const def =
|
|
1173
|
+
const def = lowerer.unions.get(t.unionId);
|
|
1187
1174
|
if (!def)
|
|
1188
|
-
throw new
|
|
1175
|
+
throw new InternalCompilerError(`assert deep-equal of unknown union ${t.unionId}`);
|
|
1189
1176
|
const isTag = (v, tag, negated) => ({ kind: "unionIsTag", unionId: t.unionId, tag, negated, value: v, type: BOOL, loc });
|
|
1190
1177
|
const narrow = (v, tag, armT) => ({ kind: "unionNarrow", unionId: t.unionId, tag, value: v, type: armT, loc });
|
|
1191
1178
|
body = [];
|
|
@@ -1208,67 +1195,53 @@ function deepEqHelper(L, t, loc) {
|
|
|
1208
1195
|
const mi = (method, receiver, args, type) => ({ kind: "mapIntrinsic", method, receiver, args, type, loc });
|
|
1209
1196
|
const valueT = t.value;
|
|
1210
1197
|
const hasUndefArm = valueT.kind === "union" &&
|
|
1211
|
-
(
|
|
1212
|
-
const getT = hasUndefArm ? valueT :
|
|
1198
|
+
(lowerer.unions.get(valueT.unionId)?.arms.some((arm) => arm.kind === "undefinedT") ?? false);
|
|
1199
|
+
const getT = hasUndefArm ? valueT : lowerer.withUndefinedArm(valueT);
|
|
1213
1200
|
locals.push({ id: "i.0", name: "i", type: F64, mutable: true }, { id: "k.0", name: "k", type: t.key, mutable: false }, { id: "av.0", name: "av", type: valueT, mutable: false }, { id: "bv.0", name: "bv", type: getT, mutable: false });
|
|
1214
|
-
const i = () =>
|
|
1215
|
-
const k = () =>
|
|
1201
|
+
const i = () => varRef("i.0", F64, loc);
|
|
1202
|
+
const k = () => varRef("k.0", t.key, loc);
|
|
1216
1203
|
// The b-side value: get() answers `V | undefined`; has() already
|
|
1217
1204
|
// proved presence, so a plain V narrows through the value arm.
|
|
1218
1205
|
const bValue = getT === valueT
|
|
1219
|
-
?
|
|
1206
|
+
? varRef("bv.0", getT, loc)
|
|
1220
1207
|
: {
|
|
1221
1208
|
kind: "unionNarrow",
|
|
1222
1209
|
unionId: getT.unionId,
|
|
1223
|
-
tag:
|
|
1224
|
-
value:
|
|
1210
|
+
tag: lowerer.armTag(getT.unionId, valueT),
|
|
1211
|
+
value: varRef("bv.0", getT, loc),
|
|
1225
1212
|
type: valueT,
|
|
1226
1213
|
loc,
|
|
1227
1214
|
};
|
|
1228
1215
|
body = [
|
|
1229
1216
|
bailIf(neq(mi("size", a(), [], F64), mi("size", b(), [], F64))),
|
|
1230
|
-
|
|
1231
|
-
kind: "
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
{ kind: "varDecl", localId: "av.0", init: mi("iterValue", a(), [i()], valueT), loc },
|
|
1240
|
-
{ kind: "varDecl", localId: "bv.0", init: mi("get", b(), [k()], getT), loc },
|
|
1241
|
-
bailIf(not(deq(valueT, ref("av.0", valueT), bValue))),
|
|
1242
|
-
],
|
|
1243
|
-
loc,
|
|
1244
|
-
},
|
|
1245
|
-
ret(boolLit(true)),
|
|
1217
|
+
countedFor(loc, mi("iterCount", a(), [], F64), () => [
|
|
1218
|
+
{ kind: "if", cond: not(mi("iterLive", a(), [i()], BOOL)), then: [{ kind: "continue", loc }], else_: null, loc },
|
|
1219
|
+
{ kind: "varDecl", localId: "k.0", init: mi("iterKey", a(), [i()], t.key), loc },
|
|
1220
|
+
bailIf(not(mi("has", b(), [k()], BOOL))),
|
|
1221
|
+
{ kind: "varDecl", localId: "av.0", init: mi("iterValue", a(), [i()], valueT), loc },
|
|
1222
|
+
{ kind: "varDecl", localId: "bv.0", init: mi("get", b(), [k()], getT), loc },
|
|
1223
|
+
bailIf(not(deq(valueT, varRef("av.0", valueT, loc), bValue))),
|
|
1224
|
+
]),
|
|
1225
|
+
ret(boolLit(true, loc)),
|
|
1246
1226
|
];
|
|
1247
1227
|
break;
|
|
1248
1228
|
}
|
|
1249
1229
|
case "set": {
|
|
1250
1230
|
const si = (method, receiver, args, type) => ({ kind: "setIntrinsic", method, receiver, args, type, loc });
|
|
1251
1231
|
locals.push({ id: "i.0", name: "i", type: F64, mutable: true });
|
|
1252
|
-
const i = () =>
|
|
1232
|
+
const i = () => varRef("i.0", F64, loc);
|
|
1253
1233
|
body = [
|
|
1254
1234
|
bailIf(neq(si("size", a(), [], F64), si("size", b(), [], F64))),
|
|
1255
|
-
|
|
1256
|
-
kind: "
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
body: [
|
|
1261
|
-
{ kind: "if", cond: not(si("iterLive", a(), [i()], BOOL)), then: [{ kind: "continue", loc }], else_: null, loc },
|
|
1262
|
-
bailIf(not(si("has", b(), [si("iterKey", a(), [i()], t.elem)], BOOL))),
|
|
1263
|
-
],
|
|
1264
|
-
loc,
|
|
1265
|
-
},
|
|
1266
|
-
ret(boolLit(true)),
|
|
1235
|
+
countedFor(loc, si("iterCount", a(), [], F64), () => [
|
|
1236
|
+
{ kind: "if", cond: not(si("iterLive", a(), [i()], BOOL)), then: [{ kind: "continue", loc }], else_: null, loc },
|
|
1237
|
+
bailIf(not(si("has", b(), [si("iterKey", a(), [i()], t.elem)], BOOL))),
|
|
1238
|
+
]),
|
|
1239
|
+
ret(boolLit(true, loc)),
|
|
1267
1240
|
];
|
|
1268
1241
|
break;
|
|
1269
1242
|
}
|
|
1270
1243
|
default:
|
|
1271
|
-
throw new
|
|
1244
|
+
throw new InternalCompilerError(`assert deep-equal helper over unexpected type ${typeKey(t)}`);
|
|
1272
1245
|
}
|
|
1273
1246
|
// CYCLE-CAPABLE containers (recursive record types and their arrays/
|
|
1274
1247
|
// maps) wrap the structural walk in the runtime PAIR MEMO: identical
|
|
@@ -1277,9 +1250,9 @@ function deepEqHelper(L, t, loc) {
|
|
|
1277
1250
|
// structures compare true instead of recursing forever. The walk moves
|
|
1278
1251
|
// into a sibling function; `name` becomes the memo wrapper every caller
|
|
1279
1252
|
// (recursion included) enters through.
|
|
1280
|
-
if ((t.kind === "record" || t.kind === "array" || t.kind === "map") && typeReachesItself(
|
|
1253
|
+
if ((t.kind === "record" || t.kind === "array" || t.kind === "map") && typeReachesItself(lowerer, t)) {
|
|
1281
1254
|
const walkName = `${name}.walk`;
|
|
1282
|
-
|
|
1255
|
+
lowerer.liftedFns.push({
|
|
1283
1256
|
name: walkName,
|
|
1284
1257
|
params: [
|
|
1285
1258
|
{ localId: "a.0", name: "a", type: t },
|
|
@@ -1296,20 +1269,20 @@ function deepEqHelper(L, t, loc) {
|
|
|
1296
1269
|
{ id: "eq.0", name: "eq", type: BOOL, mutable: false },
|
|
1297
1270
|
];
|
|
1298
1271
|
body = [
|
|
1299
|
-
{ kind: "if", cond: { kind: "bin", op: "===", left: a(), right: b(), type: BOOL, loc }, then: [ret(boolLit(true))], else_: null, loc },
|
|
1272
|
+
{ kind: "if", cond: { kind: "bin", op: "===", left: a(), right: b(), type: BOOL, loc }, then: [ret(boolLit(true, loc))], else_: null, loc },
|
|
1300
1273
|
{
|
|
1301
1274
|
kind: "if",
|
|
1302
1275
|
cond: { kind: "libCall", fn: "assert.deqEnter", args: [a(), b()], type: BOOL, loc },
|
|
1303
|
-
then: [ret(boolLit(true))],
|
|
1276
|
+
then: [ret(boolLit(true, loc))],
|
|
1304
1277
|
else_: null,
|
|
1305
1278
|
loc,
|
|
1306
1279
|
},
|
|
1307
1280
|
{ kind: "varDecl", localId: "eq.0", init: { kind: "call", callee: walkName, args: [a(), b()], type: BOOL, loc }, loc },
|
|
1308
1281
|
{ kind: "exprStmt", expr: { kind: "libCall", fn: "assert.deqLeave", args: [], type: VOID, loc }, loc },
|
|
1309
|
-
ret(
|
|
1282
|
+
ret(varRef("eq.0", BOOL, loc)),
|
|
1310
1283
|
];
|
|
1311
1284
|
}
|
|
1312
|
-
|
|
1285
|
+
lowerer.liftedFns.push({
|
|
1313
1286
|
name,
|
|
1314
1287
|
params: [
|
|
1315
1288
|
{ localId: "a.0", name: "a", type: t },
|