@scriptc/compiler 0.4.8 → 0.4.9
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/node-fallback/buffer.d.ts +2 -0
- package/ambient/node-fallback/child_process.d.ts +9 -3
- package/ambient/node-fallback/dns-promises.d.ts +25 -0
- package/ambient/node-fallback/dns.d.ts +29 -0
- package/ambient/node-fallback/test.d.ts +7 -0
- package/ambient/scriptc-node-fallback.d.ts +145 -2
- package/ambient/scriptc-overrides.d.ts +22 -13
- package/dist/backend/build-cache.d.ts +1 -1
- package/dist/backend/build-cache.js +1 -1
- package/dist/backend/build-cache.js.map +1 -1
- package/dist/backend/cache-root.d.ts +7 -0
- package/dist/backend/cache-root.js +27 -0
- package/dist/backend/cache-root.js.map +1 -1
- package/dist/backend/executable-features.js +5 -1
- package/dist/backend/executable-features.js.map +1 -1
- package/dist/backend/link-plan.js +7 -1
- package/dist/backend/link-plan.js.map +1 -1
- package/dist/backend/llvm/bytes-loop-versions.d.ts +12 -1
- package/dist/backend/llvm/bytes-loop-versions.js +107 -30
- package/dist/backend/llvm/bytes-loop-versions.js.map +1 -1
- package/dist/backend/llvm/bytes-loop-versions.test.js +96 -0
- package/dist/backend/llvm/bytes-loop-versions.test.js.map +1 -1
- package/dist/backend/llvm/checked-value-lifetimes.js +1 -0
- package/dist/backend/llvm/checked-value-lifetimes.js.map +1 -1
- package/dist/backend/llvm/classes.d.ts +16 -5
- package/dist/backend/llvm/classes.js +34 -6
- package/dist/backend/llvm/classes.js.map +1 -1
- package/dist/backend/llvm/classes.test.js +21 -2
- package/dist/backend/llvm/classes.test.js.map +1 -1
- package/dist/backend/llvm/common.d.ts +9 -0
- package/dist/backend/llvm/common.js +9 -0
- package/dist/backend/llvm/common.js.map +1 -1
- package/dist/backend/llvm/cpu-dispatch.d.ts +36 -2
- package/dist/backend/llvm/cpu-dispatch.js +96 -2
- package/dist/backend/llvm/cpu-dispatch.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +5 -2
- package/dist/backend/llvm/dense-array-access.js +16 -12
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.test.js +3 -1
- package/dist/backend/llvm/dense-array-access.test.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +24 -0
- package/dist/backend/llvm/dyn.js +117 -3
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emit-function.js +6 -0
- package/dist/backend/llvm/emit-function.js.map +1 -1
- package/dist/backend/llvm/emit-journal.d.ts +1 -0
- package/dist/backend/llvm/emit-journal.js.map +1 -1
- package/dist/backend/llvm/emit-module.js +48 -5
- package/dist/backend/llvm/emit-module.js.map +1 -1
- package/dist/backend/llvm/emit-module.test.js +41 -0
- package/dist/backend/llvm/emit-module.test.js.map +1 -1
- package/dist/backend/llvm/emit-statements.js +11 -0
- package/dist/backend/llvm/emit-statements.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +87 -7
- package/dist/backend/llvm/emitter.js +136 -15
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +28 -6
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +19 -5
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +29 -1
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.js +104 -6
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-records.js +15 -1
- package/dist/backend/llvm/expr-records.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +53 -5
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/inline-arrays.js +1 -1
- package/dist/backend/llvm/inline-arrays.js.map +1 -1
- package/dist/backend/llvm/js-ic.js +126 -2
- package/dist/backend/llvm/js-ic.js.map +1 -1
- package/dist/backend/llvm/lanes.d.ts +38 -0
- package/dist/backend/llvm/lanes.js +778 -0
- package/dist/backend/llvm/lanes.js.map +1 -0
- package/dist/backend/llvm/lanes.test.d.ts +1 -0
- package/dist/backend/llvm/lanes.test.js +402 -0
- package/dist/backend/llvm/lanes.test.js.map +1 -0
- package/dist/backend/llvm/lib-dispatch.js +9 -4
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +20 -0
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +27 -0
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +11 -0
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +2 -2
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.js +8 -2
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/nullable-unions.js +5 -2
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +3 -0
- package/dist/backend/llvm/publish.js +2 -2
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/reference-writes.js +1 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/region-groups.js +43 -4
- package/dist/backend/llvm/region-groups.js.map +1 -1
- package/dist/backend/llvm/region-groups.test.js +79 -0
- package/dist/backend/llvm/region-groups.test.js.map +1 -1
- package/dist/backend/llvm/runtime-registries.test.js +32 -1
- package/dist/backend/llvm/runtime-registries.test.js.map +1 -1
- package/dist/backend/llvm/shapes.js +10 -1
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/string-reads.d.ts +1 -1
- package/dist/backend/llvm/string-reads.js +1 -1
- package/dist/backend/llvm/string-reads.js.map +1 -1
- package/dist/backend/llvm/unwind-abi.js +24 -2
- package/dist/backend/llvm/unwind-abi.js.map +1 -1
- package/dist/backend/llvm/unwind-abi.test.js +38 -0
- package/dist/backend/llvm/unwind-abi.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +3 -0
- package/dist/backend/llvm/walkers.js +20 -2
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +15 -3
- package/dist/backend/native/executable.js +19 -5
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native-codegen-core.d.ts +20 -0
- package/dist/backend/native-codegen-core.js +15 -0
- package/dist/backend/native-codegen-core.js.map +1 -1
- package/dist/backend/native-codegen.d.ts +5 -0
- package/dist/backend/native-codegen.js +62 -8
- package/dist/backend/native-codegen.js.map +1 -1
- package/dist/backend/native-codegen.test.js +48 -8
- package/dist/backend/native-codegen.test.js.map +1 -1
- package/dist/backend/native-link-info-core.d.ts +27 -3
- package/dist/backend/native-link-info-core.js.map +1 -1
- package/dist/backend/native-link-info.test.js +17 -1
- package/dist/backend/native-link-info.test.js.map +1 -1
- package/dist/backend/native-toolchain.d.ts +1 -1
- package/dist/backend/native-toolchain.js +1 -1
- package/dist/backend/native-toolchain.js.map +1 -1
- package/dist/backend/native-toolchain.test.js +14 -1
- package/dist/backend/native-toolchain.test.js.map +1 -1
- package/dist/backend/runtime-pack-core.d.ts +9 -3
- package/dist/backend/runtime-pack-core.js +6 -1
- package/dist/backend/runtime-pack-core.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +32 -1
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/backend/targets.d.ts +9 -1
- package/dist/backend/targets.js +11 -2
- package/dist/backend/targets.js.map +1 -1
- package/dist/backend/targets.test.js +6 -0
- package/dist/backend/targets.test.js.map +1 -1
- package/dist/cli/command.js +15 -1
- package/dist/cli/command.js.map +1 -1
- package/dist/cli/host.d.ts +6 -0
- package/dist/cli/mcp.d.ts +72 -0
- package/dist/cli/mcp.js +601 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/mcp.test.d.ts +1 -0
- package/dist/cli/mcp.test.js +380 -0
- package/dist/cli/mcp.test.js.map +1 -0
- package/dist/cli/output-options.d.ts +1 -0
- package/dist/cli/output-options.js +3 -0
- package/dist/cli/output-options.js.map +1 -1
- package/dist/cli/usage.d.ts +51 -1
- package/dist/cli/usage.js +709 -186
- package/dist/cli/usage.js.map +1 -1
- package/dist/compat/fetch-profile.js +9 -4
- package/dist/compat/fetch-profile.js.map +1 -1
- package/dist/compile-types.d.ts +17 -0
- package/dist/coverage/report.d.ts +5 -9
- package/dist/coverage/report.js.map +1 -1
- package/dist/executable/executable-cache.d.ts +17 -3
- package/dist/executable/executable-cache.js +17 -3
- package/dist/executable/executable-cache.js.map +1 -1
- package/dist/executable/prepare.js +87 -10
- package/dist/executable/prepare.js.map +1 -1
- package/dist/frontend/analysis.js +3 -2
- package/dist/frontend/analysis.js.map +1 -1
- package/dist/frontend/canon-map.js +13 -8
- package/dist/frontend/canon-map.js.map +1 -1
- package/dist/frontend/decl-projection.d.ts +18 -0
- package/dist/frontend/decl-projection.js +90 -22
- package/dist/frontend/decl-projection.js.map +1 -1
- package/dist/frontend/decl-projection.test.js +47 -1
- package/dist/frontend/decl-projection.test.js.map +1 -1
- package/dist/frontend/default-library.d.ts +10 -0
- package/dist/frontend/default-library.js +43 -0
- package/dist/frontend/default-library.js.map +1 -0
- package/dist/frontend/fork-target.js +54 -9
- package/dist/frontend/fork-target.js.map +1 -1
- package/dist/frontend/fork-target.test.js +82 -0
- package/dist/frontend/fork-target.test.js.map +1 -1
- package/dist/frontend/inferred-js-diagnostics.test.js +73 -0
- package/dist/frontend/inferred-js-diagnostics.test.js.map +1 -1
- package/dist/frontend/lowering/abstract-equality.d.ts +2 -1
- package/dist/frontend/lowering/abstract-equality.js +7 -1
- package/dist/frontend/lowering/abstract-equality.js.map +1 -1
- package/dist/frontend/lowering/array-values.js +2 -2
- package/dist/frontend/lowering/array-values.js.map +1 -1
- package/dist/frontend/lowering/assertion-members.js +52 -2
- package/dist/frontend/lowering/assertion-members.js.map +1 -1
- package/dist/frontend/lowering/builtin-namespaces.d.ts +5 -0
- package/dist/frontend/lowering/builtin-namespaces.js +19 -12
- package/dist/frontend/lowering/builtin-namespaces.js.map +1 -1
- package/dist/frontend/lowering/builtins/callable-aliases.js +42 -6
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process.d.ts +12 -11
- package/dist/frontend/lowering/builtins/child-process.js +235 -38
- package/dist/frontend/lowering/builtins/child-process.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +6 -1
- package/dist/frontend/lowering/builtins/compression.js +3 -3
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/constants.js +2 -2
- package/dist/frontend/lowering/builtins/constants.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.d.ts +3 -1
- package/dist/frontend/lowering/builtins/crypto.js +9 -1
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/dates.js +26 -6
- package/dist/frontend/lowering/builtins/dates.js.map +1 -1
- package/dist/frontend/lowering/builtins/environment.d.ts +13 -1
- package/dist/frontend/lowering/builtins/environment.js +15 -4
- package/dist/frontend/lowering/builtins/environment.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-bindings.d.ts +33 -0
- package/dist/frontend/lowering/builtins/module-bindings.js +213 -11
- package/dist/frontend/lowering/builtins/module-bindings.js.map +1 -1
- package/dist/frontend/lowering/builtins/module-resolution.d.ts +9 -2
- package/dist/frontend/lowering/builtins/module-resolution.js +187 -19
- package/dist/frontend/lowering/builtins/module-resolution.js.map +1 -1
- package/dist/frontend/lowering/builtins/performance.js +1 -1
- package/dist/frontend/lowering/builtins/performance.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +40 -2
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/promises.js +33 -0
- package/dist/frontend/lowering/builtins/promises.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +9 -5
- package/dist/frontend/lowering/builtins/readline.js +184 -75
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/url.d.ts +4 -0
- package/dist/frontend/lowering/builtins/url.js +6 -0
- package/dist/frontend/lowering/builtins/url.js.map +1 -1
- package/dist/frontend/lowering/call-arguments.js +15 -0
- package/dist/frontend/lowering/call-arguments.js.map +1 -1
- package/dist/frontend/lowering/callable-properties.d.ts +34 -0
- package/dist/frontend/lowering/callable-properties.js +210 -0
- package/dist/frontend/lowering/callable-properties.js.map +1 -0
- package/dist/frontend/lowering/cjs-inline-require.d.ts +16 -0
- package/dist/frontend/lowering/cjs-inline-require.js +105 -0
- package/dist/frontend/lowering/cjs-inline-require.js.map +1 -1
- package/dist/frontend/lowering/cjs-inline-require.test.d.ts +1 -0
- package/dist/frontend/lowering/cjs-inline-require.test.js +61 -0
- package/dist/frontend/lowering/cjs-inline-require.test.js.map +1 -0
- package/dist/frontend/lowering/class-dynamic-dispatch.js +82 -2
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +57 -4
- package/dist/frontend/lowering/class-protocols.js +597 -30
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/class-unions.js +2 -2
- package/dist/frontend/lowering/class-unions.js.map +1 -1
- package/dist/frontend/lowering/coercions/function-adapters.d.ts +12 -0
- package/dist/frontend/lowering/coercions/function-adapters.js +62 -0
- package/dist/frontend/lowering/coercions/function-adapters.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural-plans.js +56 -1
- package/dist/frontend/lowering/coercions/structural-plans.js.map +1 -1
- package/dist/frontend/lowering/coercions/structural.js +9 -4
- package/dist/frontend/lowering/coercions/structural.js.map +1 -1
- package/dist/frontend/lowering/collection-ingestion.d.ts +9 -0
- package/dist/frontend/lowering/collection-ingestion.js +115 -41
- package/dist/frontend/lowering/collection-ingestion.js.map +1 -1
- package/dist/frontend/lowering/containers/array-callbacks.js +16 -0
- package/dist/frontend/lowering/containers/array-callbacks.js.map +1 -1
- package/dist/frontend/lowering/containers/bytes.js +66 -10
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +61 -5
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/containers/filter-predicates.js +11 -0
- package/dist/frontend/lowering/containers/filter-predicates.js.map +1 -1
- package/dist/frontend/lowering/containers/indexed-objects.d.ts +15 -0
- package/dist/frontend/lowering/containers/indexed-objects.js +213 -30
- package/dist/frontend/lowering/containers/indexed-objects.js.map +1 -1
- package/dist/frontend/lowering/error-name-order.d.ts +16 -0
- package/dist/frontend/lowering/error-name-order.js +61 -0
- package/dist/frontend/lowering/error-name-order.js.map +1 -1
- package/dist/frontend/lowering/expressions/asserted-receiver.d.ts +17 -0
- package/dist/frontend/lowering/expressions/asserted-receiver.js +123 -1
- package/dist/frontend/lowering/expressions/asserted-receiver.js.map +1 -1
- package/dist/frontend/lowering/expressions/binary.js +147 -20
- package/dist/frontend/lowering/expressions/binary.js.map +1 -1
- package/dist/frontend/lowering/expressions/element-access.js +63 -14
- package/dist/frontend/lowering/expressions/element-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/erased-delete.d.ts +59 -0
- package/dist/frontend/lowering/expressions/erased-delete.js +247 -0
- package/dist/frontend/lowering/expressions/erased-delete.js.map +1 -0
- package/dist/frontend/lowering/expressions/hosted-narrowing.d.ts +10 -0
- package/dist/frontend/lowering/expressions/hosted-narrowing.js +48 -1
- package/dist/frontend/lowering/expressions/hosted-narrowing.js.map +1 -1
- package/dist/frontend/lowering/expressions/identifiers.js +20 -0
- package/dist/frontend/lowering/expressions/identifiers.js.map +1 -1
- package/dist/frontend/lowering/expressions/narrowing.d.ts +7 -2
- package/dist/frontend/lowering/expressions/narrowing.js +77 -45
- package/dist/frontend/lowering/expressions/narrowing.js.map +1 -1
- package/dist/frontend/lowering/expressions/object-literals.js +62 -19
- package/dist/frontend/lowering/expressions/object-literals.js.map +1 -1
- package/dist/frontend/lowering/expressions/optional-chains.js +19 -0
- package/dist/frontend/lowering/expressions/optional-chains.js.map +1 -1
- package/dist/frontend/lowering/expressions/property-access.d.ts +7 -7
- package/dist/frontend/lowering/expressions/property-access.js +247 -48
- package/dist/frontend/lowering/expressions/property-access.js.map +1 -1
- package/dist/frontend/lowering/expressions/relational.d.ts +1 -0
- package/dist/frontend/lowering/expressions/relational.js +18 -8
- package/dist/frontend/lowering/expressions/relational.js.map +1 -1
- package/dist/frontend/lowering/expressions/union-fields.js +11 -5
- package/dist/frontend/lowering/expressions/union-fields.js.map +1 -1
- package/dist/frontend/lowering/expressions/updates.js +121 -11
- package/dist/frontend/lowering/expressions/updates.js.map +1 -1
- package/dist/frontend/lowering/function-context.d.ts +10 -0
- package/dist/frontend/lowering/function-context.js +36 -0
- package/dist/frontend/lowering/function-context.js.map +1 -1
- package/dist/frontend/lowering/function-returns.js +8 -8
- package/dist/frontend/lowering/function-returns.js.map +1 -1
- package/dist/frontend/lowering/handle-properties.d.ts +62 -3
- package/dist/frontend/lowering/handle-properties.js +674 -26
- package/dist/frontend/lowering/handle-properties.js.map +1 -1
- package/dist/frontend/lowering/handle-properties.test.js +95 -2
- package/dist/frontend/lowering/handle-properties.test.js.map +1 -1
- package/dist/frontend/lowering/lower-builtin-values.d.ts +12 -0
- package/dist/frontend/lowering/lower-builtin-values.js +44 -0
- package/dist/frontend/lowering/lower-builtin-values.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +328 -136
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +82 -17
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.js +113 -9
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-expando.d.ts +13 -21
- package/dist/frontend/lowering/lower-expando.js +90 -126
- package/dist/frontend/lowering/lower-expando.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.js +2 -2
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-functions.js +65 -0
- package/dist/frontend/lowering/lower-functions.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +471 -0
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +36 -10
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-node-island.js +28 -0
- package/dist/frontend/lowering/lower-node-island.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +53 -7
- package/dist/frontend/lowering/lower-server.js +213 -42
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stdlib.js +50 -7
- package/dist/frontend/lowering/lower-stdlib.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.d.ts +24 -0
- package/dist/frontend/lowering/lower-stmts.js +463 -220
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.js +2 -2
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +71 -2
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +81 -10
- package/dist/frontend/lowering/lowerer.js +319 -72
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/new-target.js +10 -2
- package/dist/frontend/lowering/new-target.js.map +1 -1
- package/dist/frontend/lowering/nullish-empty-pattern.js +3 -3
- package/dist/frontend/lowering/nullish-empty-pattern.js.map +1 -1
- package/dist/frontend/lowering/partial-assertions.js +30 -5
- package/dist/frontend/lowering/partial-assertions.js.map +1 -1
- package/dist/frontend/lowering/primitive-throws.js +91 -1
- package/dist/frontend/lowering/primitive-throws.js.map +1 -1
- package/dist/frontend/lowering/primitive-wrappers.d.ts +9 -0
- package/dist/frontend/lowering/primitive-wrappers.js +2 -2
- package/dist/frontend/lowering/primitive-wrappers.js.map +1 -1
- package/dist/frontend/lowering/promise-executor-adapter.js +5 -2
- package/dist/frontend/lowering/promise-executor-adapter.js.map +1 -1
- package/dist/frontend/lowering/record-links.js +7 -2
- package/dist/frontend/lowering/record-links.js.map +1 -1
- package/dist/frontend/lowering/surfaces.d.ts +4 -0
- package/dist/frontend/lowering/surfaces.js +118 -2
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/lowering/surfaces.test.d.ts +1 -0
- package/dist/frontend/lowering/surfaces.test.js +31 -0
- package/dist/frontend/lowering/surfaces.test.js.map +1 -0
- package/dist/frontend/mock-shapes.js +3 -3
- package/dist/frontend/mock-shapes.js.map +1 -1
- package/dist/frontend/npm-static-ladder.d.ts +21 -0
- package/dist/frontend/npm-static-ladder.js +2 -0
- package/dist/frontend/npm-static-ladder.js.map +1 -0
- package/dist/frontend/npm-static-ladder.test.d.ts +1 -0
- package/dist/frontend/npm-static-ladder.test.js +138 -0
- package/dist/frontend/npm-static-ladder.test.js.map +1 -0
- package/dist/frontend/npm-static-status.d.ts +15 -0
- package/dist/frontend/npm-static-status.js +2 -0
- package/dist/frontend/npm-static-status.js.map +1 -0
- package/dist/frontend/package-shims.js +1 -1
- package/dist/frontend/package-shims.js.map +1 -1
- package/dist/frontend/pipeline.d.ts +1 -1
- package/dist/frontend/pipeline.js +222 -25
- package/dist/frontend/pipeline.js.map +1 -1
- package/dist/frontend/program-analysis.d.ts +4 -0
- package/dist/frontend/program-analysis.js +6 -0
- package/dist/frontend/program-analysis.js.map +1 -1
- package/dist/frontend/program.js +258 -32
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/program.test.js +30 -0
- package/dist/frontend/program.test.js.map +1 -1
- package/dist/frontend/resolve.js +29 -5
- package/dist/frontend/resolve.js.map +1 -1
- package/dist/frontend/resolve.test.js +40 -0
- package/dist/frontend/resolve.test.js.map +1 -1
- package/dist/frontend/services.d.ts +8 -0
- package/dist/frontend/services.js +7 -0
- package/dist/frontend/services.js.map +1 -1
- package/dist/frontend/ts7/checker.d.ts +7 -0
- package/dist/frontend/ts7/checker.js +12 -0
- package/dist/frontend/ts7/checker.js.map +1 -1
- package/dist/frontend/ts7/checker.test.js +1 -0
- package/dist/frontend/ts7/checker.test.js.map +1 -1
- package/dist/frontend/ts7/program-host.d.ts +39 -2
- package/dist/frontend/ts7/program-host.js +62 -8
- package/dist/frontend/ts7/program-host.js.map +1 -1
- package/dist/frontend/ts7/program-host.test.js +33 -0
- package/dist/frontend/ts7/program-host.test.js.map +1 -1
- package/dist/frontend/ts7/session-cache.d.ts +5 -1
- package/dist/frontend/ts7/session-cache.js +7 -1
- package/dist/frontend/ts7/session-cache.js.map +1 -1
- package/dist/frontend/ts7/session-cache.test.js +37 -0
- package/dist/frontend/ts7/session-cache.test.js.map +1 -1
- package/dist/frontend/ts7/session.js +19 -1
- package/dist/frontend/ts7/session.js.map +1 -1
- package/dist/frontend/ts7/source-parser.d.ts +17 -2
- package/dist/frontend/ts7/source-parser.js +61 -2
- package/dist/frontend/ts7/source-parser.js.map +1 -1
- package/dist/frontend/ts7/source-parser.test.js +55 -2
- package/dist/frontend/ts7/source-parser.test.js.map +1 -1
- package/dist/frontend/tsc-codes.d.ts +3 -2
- package/dist/frontend/tsc-codes.js +129 -22
- package/dist/frontend/tsc-codes.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +5 -11
- package/dist/frontend/type-mapper.js +380 -70
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +67 -7
- package/dist/index.js.map +1 -1
- package/dist/ir/builtin-effects.js +29 -0
- package/dist/ir/builtin-effects.js.map +1 -1
- package/dist/ir/builtin-signatures.d.ts +1 -1
- package/dist/ir/builtin-signatures.js +72 -6
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/codec.generated.d.ts +1 -1
- package/dist/ir/codec.generated.js +321 -263
- package/dist/ir/codec.generated.js.map +1 -1
- package/dist/ir/constant-length-clones.d.ts +26 -0
- package/dist/ir/constant-length-clones.js +589 -0
- package/dist/ir/constant-length-clones.js.map +1 -0
- package/dist/ir/constant-length-clones.test.d.ts +1 -0
- package/dist/ir/constant-length-clones.test.js +292 -0
- package/dist/ir/constant-length-clones.test.js.map +1 -0
- package/dist/ir/constant-tables.d.ts +10 -5
- package/dist/ir/constant-tables.js +83 -17
- package/dist/ir/constant-tables.js.map +1 -1
- package/dist/ir/constant-tables.test.js +58 -1
- package/dist/ir/constant-tables.test.js.map +1 -1
- package/dist/ir/fields.generated.js +5 -2
- package/dist/ir/fields.generated.js.map +1 -1
- package/dist/ir/function-references.js +2 -0
- package/dist/ir/function-references.js.map +1 -1
- package/dist/ir/function-references.test.js +13 -0
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/integer-loops.js +1 -0
- package/dist/ir/integer-loops.js.map +1 -1
- package/dist/ir/integer-loops.test.js +16 -0
- package/dist/ir/integer-loops.test.js.map +1 -1
- package/dist/ir/ir.d.ts +50 -6
- package/dist/ir/ir.js +44 -2
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/ir.test.js +83 -1
- package/dist/ir/ir.test.js.map +1 -1
- package/dist/ir/js-groups.js +5 -1
- package/dist/ir/js-groups.js.map +1 -1
- package/dist/ir/js-ic.d.ts +20 -0
- package/dist/ir/js-ic.js +81 -4
- package/dist/ir/js-ic.js.map +1 -1
- package/dist/ir/js-ic.test.js +8 -1
- package/dist/ir/js-ic.test.js.map +1 -1
- package/dist/ir/lane-plans.d.ts +86 -0
- package/dist/ir/lane-plans.js +589 -0
- package/dist/ir/lane-plans.js.map +1 -0
- package/dist/ir/lane-plans.test.d.ts +1 -0
- package/dist/ir/lane-plans.test.js +549 -0
- package/dist/ir/lane-plans.test.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +68 -10
- package/dist/ir/runtime-features.js +285 -17
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +190 -1
- package/dist/ir/runtime-features.test.js.map +1 -1
- package/dist/ir/validate.js +61 -24
- package/dist/ir/validate.js.map +1 -1
- package/dist/native/cache.d.ts +5 -0
- package/dist/native/cache.js +23 -1
- package/dist/native/cache.js.map +1 -1
- package/dist/native/cache.test.js +29 -1
- package/dist/native/cache.test.js.map +1 -1
- package/dist/native/cli.js +4 -2
- package/dist/native/cli.js.map +1 -1
- package/dist/native/compiler.d.ts +11 -3
- package/dist/native/compiler.js +102 -16
- package/dist/native/compiler.js.map +1 -1
- package/dist/native/compiler.test.js +244 -2
- package/dist/native/compiler.test.js.map +1 -1
- package/dist/native/prepare.d.ts +14 -1
- package/dist/native/prepare.js +79 -29
- package/dist/native/prepare.js.map +1 -1
- package/dist/native/sanitizer.test.js +3 -0
- package/dist/native/sanitizer.test.js.map +1 -1
- package/dist/native/unchanged.d.ts +80 -0
- package/dist/native/unchanged.js +301 -0
- package/dist/native/unchanged.js.map +1 -0
- package/dist/native/unchanged.test.d.ts +1 -0
- package/dist/native/unchanged.test.js +249 -0
- package/dist/native/unchanged.test.js.map +1 -0
- package/dist/node-islands/boundary.d.ts +16 -0
- package/dist/node-islands/boundary.js +70 -7
- package/dist/node-islands/boundary.js.map +1 -1
- package/dist/node-islands/boundary.test.js +59 -14
- package/dist/node-islands/boundary.test.js.map +1 -1
- package/dist/node-islands/detect.js +203 -47
- package/dist/node-islands/detect.js.map +1 -1
- package/dist/node-islands/detect.test.js +45 -0
- package/dist/node-islands/detect.test.js.map +1 -1
- package/dist/node-islands/growth.js +4 -16
- package/dist/node-islands/growth.js.map +1 -1
- package/dist/node-islands/modules.d.ts +3 -0
- package/dist/node-islands/modules.js +143 -12
- package/dist/node-islands/modules.js.map +1 -1
- package/dist/node-islands/modules.test.js +125 -0
- package/dist/node-islands/modules.test.js.map +1 -1
- package/dist/node-islands/report.d.ts +1 -1
- package/dist/node-islands/report.js +2 -1
- package/dist/node-islands/report.js.map +1 -1
- package/package.json +20 -20
- package/shims/undici/core/request.ts +7 -1
- package/surface-manifest.json +380 -2
|
@@ -9,6 +9,8 @@ export class ClassProtocols {
|
|
|
9
9
|
answers = new Map();
|
|
10
10
|
/** The program classes each Pick or Omit view accepts (classesAcceptedBy). */
|
|
11
11
|
accepted = new Map();
|
|
12
|
+
/** copiedArgument's answers, per call and argument position. */
|
|
13
|
+
copiedArguments = new Map();
|
|
12
14
|
/** What markIdentityFlows learned about the program, while it runs. */
|
|
13
15
|
facts = null;
|
|
14
16
|
/** The value types of the string-keyed dictionaries that keep checked
|
|
@@ -19,6 +21,9 @@ export class ClassProtocols {
|
|
|
19
21
|
* without protocol dispatch: their members are invoked on the collection
|
|
20
22
|
* itself, not read from a property bag. */
|
|
21
23
|
collectionViews = new Set();
|
|
24
|
+
/** The mapped views a receiver-dependent literal is used as, whose source
|
|
25
|
+
* cannot carry the marking (see index). */
|
|
26
|
+
literalViews = new Set();
|
|
22
27
|
constructor(checker, sources) {
|
|
23
28
|
this.checker = checker;
|
|
24
29
|
this.sources = sources;
|
|
@@ -29,6 +34,23 @@ export class ClassProtocols {
|
|
|
29
34
|
const protocols = new Set();
|
|
30
35
|
this.implemented = protocols;
|
|
31
36
|
const add = (type) => {
|
|
37
|
+
// A homomorphic mapped view's own symbol is the shared mapped
|
|
38
|
+
// `__type` that every mapped type in the program uses: marking it
|
|
39
|
+
// would make every Pick, Omit, Partial and Readonly a view. Mark the
|
|
40
|
+
// type the view maps instead when that is a structural type. A source
|
|
41
|
+
// that cannot carry the marking keeps its own representation: a class
|
|
42
|
+
// instance would make every instance a view, and an intersection has
|
|
43
|
+
// no symbol. The VIEW type itself is recorded for those, so a
|
|
44
|
+
// receiver-dependent literal typed as it still keeps checked identity
|
|
45
|
+
// and protocol answers it through that record.
|
|
46
|
+
const mapped = this.mappedViewSource(type);
|
|
47
|
+
if (mapped !== null) {
|
|
48
|
+
if (!this.isStructuralTarget(mapped)) {
|
|
49
|
+
this.literalViews.add(type);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
type = mapped;
|
|
53
|
+
}
|
|
32
54
|
const symbol = type.getSymbol();
|
|
33
55
|
if (!symbol || protocols.has(symbol))
|
|
34
56
|
return;
|
|
@@ -106,10 +128,11 @@ export class ClassProtocols {
|
|
|
106
128
|
* checked-dynamic view, where the accessor stays live, `Object.keys`
|
|
107
129
|
* lists it, and `JSON.stringify` calls it — Node's own model.
|
|
108
130
|
*
|
|
109
|
-
* Only the TARGET is marked
|
|
110
|
-
* literal
|
|
111
|
-
*
|
|
112
|
-
*
|
|
131
|
+
* Only the TARGET is marked (for an intersection or union, its object
|
|
132
|
+
* constituents): the literal then takes the checked-dynamic literal path
|
|
133
|
+
* (`lowerDynObjectLiteral`), which defines an accessor member as a live
|
|
134
|
+
* get/set property and a data member as a plain property, so both
|
|
135
|
+
* directions construct live objects. */
|
|
113
136
|
markMemberKindViews(literal, accessorNames, add) {
|
|
114
137
|
const members = [];
|
|
115
138
|
for (const property of literal.properties.nodes) {
|
|
@@ -134,29 +157,127 @@ export class ClassProtocols {
|
|
|
134
157
|
const contextual = attempt(() => this.checker.getContextualType(literal));
|
|
135
158
|
if (contextual === undefined)
|
|
136
159
|
return;
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
//
|
|
160
|
+
// The literal converts into an object PART of its contextual type, so
|
|
161
|
+
// both composites are resolved part by part. An intersection needs the
|
|
162
|
+
// views of every constituent that declares a disagreeing member. A
|
|
163
|
+
// union keeps checked identity only as a whole (usesCheckedIdentity
|
|
164
|
+
// answers it when every present arm does), so it becomes a view only
|
|
165
|
+
// when NO present arm can hold the literal natively: every present arm
|
|
166
|
+
// declares a disagreeing member. An arm that agrees is the arm the
|
|
167
|
+
// literal is, and marking the union anyway would make a program whose
|
|
168
|
+
// literals already match their arms dynamic for nothing. Nullish arms
|
|
169
|
+
// are ignored, so `Counter | undefined` still names Counter.
|
|
142
170
|
const present = contextual.isUnionType()
|
|
143
171
|
? ts
|
|
144
172
|
.constituentTypes(contextual)
|
|
145
173
|
.filter((part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Null)) === 0)
|
|
146
174
|
: [contextual];
|
|
147
|
-
|
|
148
|
-
if (target === undefined || target.isIntersectionType())
|
|
149
|
-
return;
|
|
150
|
-
if ((target.flags & ts.TypeFlags.TypeParameter) !== 0)
|
|
175
|
+
if (present.length === 0)
|
|
151
176
|
return;
|
|
152
|
-
|
|
177
|
+
const union = present.length > 1;
|
|
178
|
+
if (union && !present.every((part) => this.memberKindDisagrees(part, members)))
|
|
153
179
|
return;
|
|
154
|
-
const
|
|
180
|
+
const targets = [];
|
|
181
|
+
for (const arm of present) {
|
|
182
|
+
const found = this.viewTargets(arm, members, union);
|
|
183
|
+
// An arm that cannot become a view leaves the union native; marking
|
|
184
|
+
// the other arms alone would not give it checked identity.
|
|
185
|
+
if (found === null)
|
|
186
|
+
return;
|
|
187
|
+
targets.push(...found);
|
|
188
|
+
}
|
|
189
|
+
for (const target of targets)
|
|
190
|
+
add(target);
|
|
191
|
+
}
|
|
192
|
+
/** The view targets `target` needs for a literal with these member kinds,
|
|
193
|
+
* or null when `target` cannot become a view. An intersection needs the
|
|
194
|
+
* targets of every constituent. A homomorphic mapped view (Partial, Pick,
|
|
195
|
+
* Omit, Readonly) has no symbol of its own — its symbol is the shared
|
|
196
|
+
* mapped `__type`, which every mapped type in the program uses — so the
|
|
197
|
+
* type it maps is the target instead, and `protocol` answers the view
|
|
198
|
+
* through that marking. `force` targets a union arm that must keep
|
|
199
|
+
* checked identity even when it agrees with the literal by itself. */
|
|
200
|
+
viewTargets(target, members, force) {
|
|
201
|
+
if (target.isIntersectionType()) {
|
|
202
|
+
const targets = [];
|
|
203
|
+
for (const part of ts.constituentTypes(target)) {
|
|
204
|
+
const found = this.viewTargets(part, members, force);
|
|
205
|
+
if (found === null)
|
|
206
|
+
return null;
|
|
207
|
+
targets.push(...found);
|
|
208
|
+
}
|
|
209
|
+
return targets;
|
|
210
|
+
}
|
|
211
|
+
if ((target.flags & ts.TypeFlags.TypeParameter) !== 0)
|
|
212
|
+
return null;
|
|
213
|
+
const source = this.mappedViewSource(target) ?? target;
|
|
214
|
+
if (!this.isStructuralTarget(source))
|
|
215
|
+
return null;
|
|
216
|
+
if (!force && !this.memberKindDisagrees(target, members))
|
|
217
|
+
return [];
|
|
218
|
+
return [source];
|
|
219
|
+
}
|
|
220
|
+
/** Whether any of the literal's member kinds disagrees with the member
|
|
221
|
+
* `target` declares under that name (a missing member never disagrees). */
|
|
222
|
+
memberKindDisagrees(target, members) {
|
|
223
|
+
return members.some((member) => {
|
|
155
224
|
const kind = attempt(() => this.memberKind(target, member.name));
|
|
156
225
|
return kind == null ? false : (kind === "accessor") !== member.accessor;
|
|
157
226
|
});
|
|
158
|
-
|
|
159
|
-
|
|
227
|
+
}
|
|
228
|
+
/** The structural type a homomorphic mapped VIEW maps — Partial, Pick,
|
|
229
|
+
* Omit or Readonly over a program type. Mapped types share one `__type`
|
|
230
|
+
* symbol, so a view is identified through the alias it is spelled with;
|
|
231
|
+
* program aliases of views (`type A = B`, `type B = Partial<X>`) are
|
|
232
|
+
* followed through their declarations, and nested views
|
|
233
|
+
* (`Partial<Omit<X, K>>`) resolve to the type carrying the members.
|
|
234
|
+
* Null for everything else. */
|
|
235
|
+
mappedViewSource(type, depth = 0) {
|
|
236
|
+
if (depth > 8)
|
|
237
|
+
return null;
|
|
238
|
+
const alias = type.getAliasSymbol();
|
|
239
|
+
if (alias === undefined)
|
|
240
|
+
return null;
|
|
241
|
+
if (this.isHomomorphicMappedAlias(alias)) {
|
|
242
|
+
const [source] = type.getAliasTypeArguments();
|
|
243
|
+
if (source === undefined)
|
|
244
|
+
return null;
|
|
245
|
+
return this.mappedViewSource(source, depth + 1) ?? source;
|
|
246
|
+
}
|
|
247
|
+
const declaration = this.programTypeAlias(alias);
|
|
248
|
+
return declaration === null ? null : this.mappedViewSourceNode(declaration.type, depth + 1);
|
|
249
|
+
}
|
|
250
|
+
/** mappedViewSource for a view spelled as a type node (a program alias's
|
|
251
|
+
* declaration, whose resolved type is the alias itself). */
|
|
252
|
+
mappedViewSourceNode(node, depth) {
|
|
253
|
+
if (depth > 8)
|
|
254
|
+
return null;
|
|
255
|
+
while (ts.isParenthesizedTypeNode(node))
|
|
256
|
+
node = node.type;
|
|
257
|
+
if (!ts.isTypeReferenceNode(node))
|
|
258
|
+
return null;
|
|
259
|
+
const symbol = attempt(() => this.checker.getSymbolAtLocation(node.typeName));
|
|
260
|
+
if (symbol === undefined)
|
|
261
|
+
return null;
|
|
262
|
+
if (this.isHomomorphicMappedAlias(symbol)) {
|
|
263
|
+
const sourceNode = node.typeArguments?.nodes[0];
|
|
264
|
+
if (sourceNode === undefined)
|
|
265
|
+
return null;
|
|
266
|
+
const source = attempt(() => this.checker.getTypeFromTypeNode(sourceNode));
|
|
267
|
+
if (source === undefined)
|
|
268
|
+
return null;
|
|
269
|
+
return this.mappedViewSource(source, depth + 1) ?? source;
|
|
270
|
+
}
|
|
271
|
+
const declaration = this.programTypeAlias(symbol);
|
|
272
|
+
return declaration === null ? null : this.mappedViewSourceNode(declaration.type, depth + 1);
|
|
273
|
+
}
|
|
274
|
+
/** The lib's homomorphic mapped utility types. */
|
|
275
|
+
isHomomorphicMappedAlias(symbol) {
|
|
276
|
+
const name = ts.symbolName(symbol);
|
|
277
|
+
if (name !== "Pick" && name !== "Omit" && name !== "Partial" && name !== "Readonly")
|
|
278
|
+
return false;
|
|
279
|
+
return (symbol.declarations.length > 0 &&
|
|
280
|
+
symbol.declarations.every((declaration) => declaration.getSourceFile().isDeclarationFile));
|
|
160
281
|
}
|
|
161
282
|
/** The member kind `type` declares at `name` — an accessor (get/set pair)
|
|
162
283
|
* or a data property — or null when it declares no member by that name. */
|
|
@@ -207,9 +328,9 @@ export class ClassProtocols {
|
|
|
207
328
|
* signature's parameter) flows into the declared parameter type. */
|
|
208
329
|
const callbackParams = [];
|
|
209
330
|
const contextual = (expr) => () => this.checker.getContextualType(expr);
|
|
210
|
-
const flow = (expr) => {
|
|
331
|
+
const flow = (expr, call) => {
|
|
211
332
|
if (expr !== undefined)
|
|
212
|
-
sites.push({ source: expr, target: contextual(expr), contextual: expr });
|
|
333
|
+
sites.push({ source: expr, target: contextual(expr), contextual: expr, call });
|
|
213
334
|
};
|
|
214
335
|
const write = (target) => {
|
|
215
336
|
while (ts.isParenthesizedExpression(target) || ts.isNonNullExpression(target))
|
|
@@ -303,7 +424,7 @@ export class ClassProtocols {
|
|
|
303
424
|
const visit = (node) => {
|
|
304
425
|
observe(node);
|
|
305
426
|
if (ts.isCallExpression(node) || ts.isNewExpression(node))
|
|
306
|
-
node.arguments?.nodes.forEach(flow);
|
|
427
|
+
node.arguments?.nodes.forEach((argument, index) => flow(argument, { node, index }));
|
|
307
428
|
else if (ts.isVariableDeclaration(node) && node.type !== undefined)
|
|
308
429
|
flow(node.initializer);
|
|
309
430
|
else if (ts.isPropertyDeclaration(node) && node.type !== undefined)
|
|
@@ -330,7 +451,11 @@ export class ClassProtocols {
|
|
|
330
451
|
!ts.isObjectLiteralExpression(node.left) &&
|
|
331
452
|
!ts.isArrayLiteralExpression(node.left)) {
|
|
332
453
|
const left = node.left;
|
|
333
|
-
sites.push({
|
|
454
|
+
sites.push({
|
|
455
|
+
source: node.right,
|
|
456
|
+
target: () => this.checker.getTypeAtLocation(left),
|
|
457
|
+
call: undefined,
|
|
458
|
+
});
|
|
334
459
|
}
|
|
335
460
|
else if ((ts.isAsExpression(node) || ts.isTypeAssertion(node)) && !accessedInPlace(node)) {
|
|
336
461
|
const typeNode = node.type;
|
|
@@ -338,6 +463,7 @@ export class ClassProtocols {
|
|
|
338
463
|
source: node.expression,
|
|
339
464
|
target: () => this.checker.getTypeFromTypeNode(typeNode),
|
|
340
465
|
assertion: true,
|
|
466
|
+
call: undefined,
|
|
341
467
|
});
|
|
342
468
|
}
|
|
343
469
|
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
|
|
@@ -377,6 +503,8 @@ export class ClassProtocols {
|
|
|
377
503
|
origins: new Map(),
|
|
378
504
|
targets: new Map(),
|
|
379
505
|
flows: new Map(),
|
|
506
|
+
callSites: new Map(),
|
|
507
|
+
otherSites: new Set(),
|
|
380
508
|
genericObservers: new Set(),
|
|
381
509
|
};
|
|
382
510
|
const typeOf = (node) => attempt(() => this.checker.getTypeAtLocation(node));
|
|
@@ -449,7 +577,7 @@ export class ClassProtocols {
|
|
|
449
577
|
const target = attempt(site.target);
|
|
450
578
|
if (target !== undefined)
|
|
451
579
|
for (const { classType, view } of attempt(() => this.methodViewSources(target)) ?? []) {
|
|
452
|
-
pending.push({ sourceType: classType, target: () => view });
|
|
580
|
+
pending.push({ sourceType: classType, target: () => view, call: undefined });
|
|
453
581
|
const symbol = view.getSymbol();
|
|
454
582
|
if (symbol !== undefined)
|
|
455
583
|
methodViews.add(symbol);
|
|
@@ -457,8 +585,8 @@ export class ClassProtocols {
|
|
|
457
585
|
continue;
|
|
458
586
|
}
|
|
459
587
|
pending.push(site.contextual === undefined
|
|
460
|
-
? { sourceType, target: site.target }
|
|
461
|
-
: { sourceType, target: site.target, contextual: site.contextual });
|
|
588
|
+
? { sourceType, target: site.target, call: site.call }
|
|
589
|
+
: { sourceType, target: site.target, contextual: site.contextual, call: site.call });
|
|
462
590
|
}
|
|
463
591
|
for (const { fn, index, name } of callbackParams) {
|
|
464
592
|
attempt(() => {
|
|
@@ -478,6 +606,7 @@ export class ClassProtocols {
|
|
|
478
606
|
pending.push({
|
|
479
607
|
sourceType: this.checker.getTypeOfSymbol(parameter),
|
|
480
608
|
target: () => declared,
|
|
609
|
+
call: undefined,
|
|
481
610
|
});
|
|
482
611
|
}
|
|
483
612
|
});
|
|
@@ -504,7 +633,7 @@ export class ClassProtocols {
|
|
|
504
633
|
targets.set(i, attempt(entry.target));
|
|
505
634
|
const target = targets.get(i);
|
|
506
635
|
if (target !== undefined &&
|
|
507
|
-
attempt(() => this.markTarget(entry.sourceType, target, marked)) === true)
|
|
636
|
+
attempt(() => this.markTarget(entry.sourceType, target, marked, entry.call ?? null, true)) === true)
|
|
508
637
|
changed = true;
|
|
509
638
|
}
|
|
510
639
|
}
|
|
@@ -709,7 +838,11 @@ export class ClassProtocols {
|
|
|
709
838
|
const writesNames = (written) => written === "all" || [...written].some((name) => names.has(name));
|
|
710
839
|
for (const origin of origins) {
|
|
711
840
|
const written = facts.written.get(origin);
|
|
712
|
-
|
|
841
|
+
// A field written after construction would be stale in a copy — unless
|
|
842
|
+
// every value of the view arrives as a call argument the callee reads
|
|
843
|
+
// and nothing else, where the copy answers the same reads the instance
|
|
844
|
+
// would (copiedAtEverySite).
|
|
845
|
+
if (written !== undefined && writesNames(written) && !this.copiedAtEverySite(symbol, facts))
|
|
713
846
|
return true;
|
|
714
847
|
// An accessor runs on every read of the instance: a copy would keep
|
|
715
848
|
// the value of one call.
|
|
@@ -740,6 +873,191 @@ export class ClassProtocols {
|
|
|
740
873
|
(declaration.parent !== undefined && facts.genericObservers.has(declaration.parent))));
|
|
741
874
|
}) === true);
|
|
742
875
|
}
|
|
876
|
+
/** Whether every value of the view arrives as a call argument whose
|
|
877
|
+
* callee only reads it: then the record copy the boundary builds answers
|
|
878
|
+
* the same reads the instance itself would, and later writes to the
|
|
879
|
+
* instance cannot be observed through the view. */
|
|
880
|
+
copiedAtEverySite(symbol, facts) {
|
|
881
|
+
if (facts.otherSites.has(symbol))
|
|
882
|
+
return false;
|
|
883
|
+
const sites = facts.callSites.get(symbol);
|
|
884
|
+
if (sites === undefined || sites.length === 0)
|
|
885
|
+
return false;
|
|
886
|
+
return sites.every((site) => this.isProgramClassInstance(site.source) && this.copiedArgument(site.node, site.index));
|
|
887
|
+
}
|
|
888
|
+
/** Whether argument `index` of `call` can be copied into the parameter's
|
|
889
|
+
* record: the callee is a program function whose body reads the instance
|
|
890
|
+
* only through declared fields of primitive type, keeps no reference to
|
|
891
|
+
* it, and runs no code that could write to it (assignments only to its
|
|
892
|
+
* own locals, no await or yield, and every call a numeric builtin). */
|
|
893
|
+
copiedArgument(call, index) {
|
|
894
|
+
let byIndex = this.copiedArguments.get(call);
|
|
895
|
+
if (byIndex === undefined) {
|
|
896
|
+
byIndex = [];
|
|
897
|
+
this.copiedArguments.set(call, byIndex);
|
|
898
|
+
}
|
|
899
|
+
const cached = byIndex[index];
|
|
900
|
+
if (cached !== undefined)
|
|
901
|
+
return cached;
|
|
902
|
+
const answer = attempt(() => this.copiedArgumentNow(call, index)) === true;
|
|
903
|
+
byIndex[index] = answer;
|
|
904
|
+
return answer;
|
|
905
|
+
}
|
|
906
|
+
copiedArgumentNow(call, index) {
|
|
907
|
+
const args = call.arguments?.nodes ?? [];
|
|
908
|
+
if (index >= args.length || args.some((argument) => ts.isSpreadElement(argument)))
|
|
909
|
+
return false;
|
|
910
|
+
const signature = this.checker.getResolvedSignature(call);
|
|
911
|
+
const declaration = signature?.declaration;
|
|
912
|
+
if (declaration === undefined)
|
|
913
|
+
return false;
|
|
914
|
+
if (!ts.isFunctionDeclaration(declaration) &&
|
|
915
|
+
!ts.isFunctionExpression(declaration) &&
|
|
916
|
+
!ts.isArrowFunction(declaration))
|
|
917
|
+
return false;
|
|
918
|
+
if (declaration.body === undefined)
|
|
919
|
+
return false;
|
|
920
|
+
if (!this.fixedCallee(declaration, call))
|
|
921
|
+
return false;
|
|
922
|
+
if (declaration.asteriskToken !== undefined)
|
|
923
|
+
return false;
|
|
924
|
+
if (declaration.modifiers?.nodes.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) === true)
|
|
925
|
+
return false;
|
|
926
|
+
// Defaults run in the callee's frame, after the arguments, and may write
|
|
927
|
+
// the instance; a parameter pattern reads members the same way.
|
|
928
|
+
if (declaration.parameters.nodes.some((parameter) => !ts.isIdentifier(parameter.name) || parameter.initializer !== undefined))
|
|
929
|
+
return false;
|
|
930
|
+
const parameter = declaration.parameters.nodes[index];
|
|
931
|
+
if (parameter === undefined || !ts.isIdentifier(parameter.name))
|
|
932
|
+
return false;
|
|
933
|
+
if (parameter.dotDotDotToken !== undefined || parameter.questionToken !== undefined)
|
|
934
|
+
return false;
|
|
935
|
+
// Arguments evaluated after this one run while the copy stands: code in
|
|
936
|
+
// them may write the instance before the callee reads the copy.
|
|
937
|
+
for (let position = index + 1; position < args.length; position++) {
|
|
938
|
+
const argument = args[position];
|
|
939
|
+
if (argument !== undefined && containsProgramCode(argument, this.checker))
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
942
|
+
return this.readsParameterOnlyFields(declaration, parameter.name.text);
|
|
943
|
+
}
|
|
944
|
+
/** Whether the function whose body is inspected is the one this call runs:
|
|
945
|
+
* the callee is the function itself, the identifier of the function
|
|
946
|
+
* declaration, or the identifier of the `const` binding that holds it.
|
|
947
|
+
* A `let` binding, a property, or another binding of the same signature
|
|
948
|
+
* could run a body this analysis never saw. */
|
|
949
|
+
fixedCallee(fn, call) {
|
|
950
|
+
const callee = unwrapExpression(call.expression);
|
|
951
|
+
if (callee === fn)
|
|
952
|
+
return true;
|
|
953
|
+
if (!ts.isIdentifier(callee))
|
|
954
|
+
return false;
|
|
955
|
+
const symbol = attempt(() => this.checker.getSymbolAtLocation(callee));
|
|
956
|
+
if (ts.isFunctionDeclaration(fn))
|
|
957
|
+
return symbol?.declarations?.some((declaration) => declaration === fn) === true;
|
|
958
|
+
const parent = fn.parent;
|
|
959
|
+
const list = parent?.parent;
|
|
960
|
+
if (!ts.isVariableDeclaration(parent) ||
|
|
961
|
+
parent.initializer !== fn ||
|
|
962
|
+
list === undefined ||
|
|
963
|
+
(list.flags & ts.NodeFlags.Const) === 0)
|
|
964
|
+
return false;
|
|
965
|
+
return symbol?.declarations?.some((declaration) => declaration === parent) === true;
|
|
966
|
+
}
|
|
967
|
+
/** The body of `declaration` mentions `name` only as the receiver of a
|
|
968
|
+
* property read whose value is a primitive, and never stores, returns,
|
|
969
|
+
* passes on or compares the value itself. */
|
|
970
|
+
readsParameterOnlyFields(declaration, name) {
|
|
971
|
+
const body = declaration.body;
|
|
972
|
+
if (body === undefined)
|
|
973
|
+
return false;
|
|
974
|
+
const locals = new Set();
|
|
975
|
+
for (const parameter of declaration.parameters.nodes)
|
|
976
|
+
if (ts.isIdentifier(parameter.name))
|
|
977
|
+
locals.add(parameter.name.text);
|
|
978
|
+
ts.walkPreorder(body, (node) => {
|
|
979
|
+
if (ts.isFunctionLike(node))
|
|
980
|
+
return "skip";
|
|
981
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name))
|
|
982
|
+
locals.add(node.name.text);
|
|
983
|
+
return undefined;
|
|
984
|
+
});
|
|
985
|
+
let ok = true;
|
|
986
|
+
ts.walkPreorder(body, (node) => {
|
|
987
|
+
if (!ok)
|
|
988
|
+
return "stop";
|
|
989
|
+
if (ts.isTypeNode(node))
|
|
990
|
+
return "skip";
|
|
991
|
+
if (ts.isFunctionLike(node)) {
|
|
992
|
+
// A nested function that mentions the parameter captures the value,
|
|
993
|
+
// so the copy would be told apart from the instance.
|
|
994
|
+
if (mentionsBinding(node, name))
|
|
995
|
+
ok = false;
|
|
996
|
+
return "skip";
|
|
997
|
+
}
|
|
998
|
+
if (ts.isBinaryExpression(node) &&
|
|
999
|
+
node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
|
|
1000
|
+
node.operatorToken.kind <= ts.SyntaxKind.LastAssignment) {
|
|
1001
|
+
// Only the body's own locals may be written: a write through any
|
|
1002
|
+
// other value could reach the instance. A compound assignment also
|
|
1003
|
+
// coerces both sides, and a non-primitive operand runs its value
|
|
1004
|
+
// hook.
|
|
1005
|
+
const left = unwrapExpression(node.left);
|
|
1006
|
+
if (!ts.isIdentifier(left) || !locals.has(left.text)) {
|
|
1007
|
+
ok = false;
|
|
1008
|
+
return "stop";
|
|
1009
|
+
}
|
|
1010
|
+
if (node.operatorToken.kind !== ts.SyntaxKind.EqualsToken &&
|
|
1011
|
+
!primitiveOperands(left, node.right, this.checker)) {
|
|
1012
|
+
ok = false;
|
|
1013
|
+
return "stop";
|
|
1014
|
+
}
|
|
1015
|
+
return undefined;
|
|
1016
|
+
}
|
|
1017
|
+
if ((ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) &&
|
|
1018
|
+
(node.operator === ts.SyntaxKind.PlusPlusToken ||
|
|
1019
|
+
node.operator === ts.SyntaxKind.MinusMinusToken)) {
|
|
1020
|
+
const operand = unwrapExpression(node.operand);
|
|
1021
|
+
if (!ts.isIdentifier(operand) ||
|
|
1022
|
+
!locals.has(operand.text) ||
|
|
1023
|
+
!primitiveNode(operand, this.checker)) {
|
|
1024
|
+
ok = false;
|
|
1025
|
+
return "stop";
|
|
1026
|
+
}
|
|
1027
|
+
return undefined;
|
|
1028
|
+
}
|
|
1029
|
+
// Calls, await and yield, element access, accessors, dynamic member
|
|
1030
|
+
// access, iteration and value coercion can all run program code while
|
|
1031
|
+
// the copy is the callee's parameter.
|
|
1032
|
+
if (expressionRunsCode(node, this.checker)) {
|
|
1033
|
+
ok = false;
|
|
1034
|
+
return "stop";
|
|
1035
|
+
}
|
|
1036
|
+
if (ts.isIdentifier(node) && node.text === name) {
|
|
1037
|
+
if (isMemberName(node))
|
|
1038
|
+
return "skip";
|
|
1039
|
+
const receiver = unwrapExpression(node);
|
|
1040
|
+
const access = receiver.parent;
|
|
1041
|
+
if (access === undefined ||
|
|
1042
|
+
!ts.isPropertyAccessExpression(access) ||
|
|
1043
|
+
access.expression !== receiver) {
|
|
1044
|
+
ok = false;
|
|
1045
|
+
return "stop";
|
|
1046
|
+
}
|
|
1047
|
+
if (!primitiveValue(this.checker.getTypeAtLocation(access))) {
|
|
1048
|
+
ok = false;
|
|
1049
|
+
return "stop";
|
|
1050
|
+
}
|
|
1051
|
+
if (isWrittenAccess(access)) {
|
|
1052
|
+
ok = false;
|
|
1053
|
+
return "stop";
|
|
1054
|
+
}
|
|
1055
|
+
return "skip";
|
|
1056
|
+
}
|
|
1057
|
+
return undefined;
|
|
1058
|
+
});
|
|
1059
|
+
return ok;
|
|
1060
|
+
}
|
|
743
1061
|
/** Whether one of `names` is a member the collection type itself
|
|
744
1062
|
* declares (`has`, `get`, `size`, `keys`, ...). */
|
|
745
1063
|
exposesCollectionMember(collection, names) {
|
|
@@ -1109,6 +1427,9 @@ export class ClassProtocols {
|
|
|
1109
1427
|
// A live Pick or Omit view of a program class holds the instance itself.
|
|
1110
1428
|
if (this.pickOfProgramClass(type) && this.usesCheckedIdentity(type))
|
|
1111
1429
|
return true;
|
|
1430
|
+
// A homomorphic mapped view of a marked type is the live view itself.
|
|
1431
|
+
if (this.mappedViewSource(type) !== null && this.protocol(type))
|
|
1432
|
+
return true;
|
|
1112
1433
|
const symbol = type.getSymbol();
|
|
1113
1434
|
if (symbol === undefined)
|
|
1114
1435
|
return false;
|
|
@@ -1141,11 +1462,12 @@ export class ClassProtocols {
|
|
|
1141
1462
|
}
|
|
1142
1463
|
/** Marks the structural parts of `target` that the identity-carrying
|
|
1143
1464
|
* parts of `source` flow into. Answers whether anything new was marked. */
|
|
1144
|
-
markTarget(source, target, marked) {
|
|
1465
|
+
markTarget(source, target, marked, site, record) {
|
|
1145
1466
|
if (source.isUnionType()) {
|
|
1146
1467
|
let changed = false;
|
|
1147
1468
|
for (const part of ts.constituentTypes(source))
|
|
1148
|
-
if (this.carriesIdentity(part, marked) &&
|
|
1469
|
+
if (this.carriesIdentity(part, marked) &&
|
|
1470
|
+
this.markTarget(part, target, marked, site, false))
|
|
1149
1471
|
changed = true;
|
|
1150
1472
|
return changed;
|
|
1151
1473
|
}
|
|
@@ -1167,14 +1489,14 @@ export class ClassProtocols {
|
|
|
1167
1489
|
}
|
|
1168
1490
|
let changed = false;
|
|
1169
1491
|
for (const part of accepting)
|
|
1170
|
-
if (this.markTarget(source, part, marked))
|
|
1492
|
+
if (this.markTarget(source, part, marked, site, false))
|
|
1171
1493
|
changed = true;
|
|
1172
1494
|
return changed;
|
|
1173
1495
|
}
|
|
1174
1496
|
if (this.checker.isArrayType(source) && this.checker.isArrayType(target)) {
|
|
1175
1497
|
const [from] = this.checker.getTypeArguments(source);
|
|
1176
1498
|
const [to] = this.checker.getTypeArguments(target);
|
|
1177
|
-
return from !== undefined && to !== undefined && this.markTarget(from, to, marked);
|
|
1499
|
+
return (from !== undefined && to !== undefined && this.markTarget(from, to, marked, site, false));
|
|
1178
1500
|
}
|
|
1179
1501
|
if (!this.isStructuralTarget(target))
|
|
1180
1502
|
return false;
|
|
@@ -1214,6 +1536,19 @@ export class ClassProtocols {
|
|
|
1214
1536
|
facts.flows.set(from, flows);
|
|
1215
1537
|
}
|
|
1216
1538
|
}
|
|
1539
|
+
if (facts !== null) {
|
|
1540
|
+
// Every top-level site that reaches this view is remembered: a view
|
|
1541
|
+
// whose values only ever arrive as a call argument the callee reads can
|
|
1542
|
+
// keep the record shape its type declares (copiedAtEverySite).
|
|
1543
|
+
if (site === null || !record)
|
|
1544
|
+
facts.otherSites.add(symbol);
|
|
1545
|
+
else {
|
|
1546
|
+
const recorded = facts.callSites.get(symbol) ?? [];
|
|
1547
|
+
if (!recorded.some((entry) => entry.node === site.node && entry.index === site.index))
|
|
1548
|
+
recorded.push({ node: site.node, index: site.index, source });
|
|
1549
|
+
facts.callSites.set(symbol, recorded);
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1217
1552
|
// A view marked earlier that becomes a collection view still changes
|
|
1218
1553
|
// the fixpoint: the views its values flow into are asked again.
|
|
1219
1554
|
if (marked.has(symbol))
|
|
@@ -1267,6 +1602,17 @@ export class ClassProtocols {
|
|
|
1267
1602
|
const properties = this.checker.getPropertiesOfType(type);
|
|
1268
1603
|
if (symbol && protocols.has(symbol))
|
|
1269
1604
|
return true;
|
|
1605
|
+
// A mapped view whose source cannot carry the marking was recorded
|
|
1606
|
+
// itself (index): the receiver-dependent literal typed as it needs the
|
|
1607
|
+
// live object, and no other view of that source does.
|
|
1608
|
+
if (this.literalViews.has(type))
|
|
1609
|
+
return true;
|
|
1610
|
+
// A homomorphic mapped view (Partial, Pick, Omit, Readonly) has no
|
|
1611
|
+
// symbol of its own to mark, so it is a view exactly when the type it
|
|
1612
|
+
// maps is one.
|
|
1613
|
+
const mapped = this.mappedViewSource(type);
|
|
1614
|
+
if (mapped !== null && this.protocol(mapped))
|
|
1615
|
+
return true;
|
|
1270
1616
|
if (!this.pickOfProgramClass(type) &&
|
|
1271
1617
|
(!symbol ||
|
|
1272
1618
|
!symbol.declarations.some((declaration) => ts.isInterfaceDeclaration(declaration) &&
|
|
@@ -1436,6 +1782,227 @@ function attempt(query) {
|
|
|
1436
1782
|
return undefined;
|
|
1437
1783
|
}
|
|
1438
1784
|
}
|
|
1785
|
+
/** Ground numeric calls: they cannot run program code, so a callee that
|
|
1786
|
+
* only uses them cannot observe a write to an instance it was handed. */
|
|
1787
|
+
const PURE_CALLS = new Set(["parseInt", "parseFloat", "isNaN", "isFinite"]);
|
|
1788
|
+
/** The identifier names a member (`o.value`), not the binding `o`. */
|
|
1789
|
+
function isMemberName(node) {
|
|
1790
|
+
const parent = node.parent;
|
|
1791
|
+
if (parent === undefined || ts.isShorthandPropertyAssignment(parent))
|
|
1792
|
+
return false;
|
|
1793
|
+
if (parent.name === node)
|
|
1794
|
+
return true;
|
|
1795
|
+
return ts.isBindingElement(parent) && parent.propertyName === node;
|
|
1796
|
+
}
|
|
1797
|
+
/** The node with parentheses, non-null assertions and type assertions
|
|
1798
|
+
* peeled off. */
|
|
1799
|
+
function unwrapExpression(node) {
|
|
1800
|
+
let outer = node;
|
|
1801
|
+
for (;;) {
|
|
1802
|
+
const parent = outer.parent;
|
|
1803
|
+
if (parent === undefined)
|
|
1804
|
+
return outer;
|
|
1805
|
+
if (!ts.isParenthesizedExpression(parent) &&
|
|
1806
|
+
!ts.isNonNullExpression(parent) &&
|
|
1807
|
+
!ts.isAssertionExpression(parent))
|
|
1808
|
+
return outer;
|
|
1809
|
+
outer = parent;
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
/** A number, string, boolean, bigint, null or undefined (or a union of
|
|
1813
|
+
* them): a value a record copy carries by value. */
|
|
1814
|
+
function primitiveValue(type) {
|
|
1815
|
+
if (type.isUnionType())
|
|
1816
|
+
return ts.constituentTypes(type).every(primitiveValue);
|
|
1817
|
+
return ((type.flags &
|
|
1818
|
+
(ts.TypeFlags.Number |
|
|
1819
|
+
ts.TypeFlags.NumberLiteral |
|
|
1820
|
+
ts.TypeFlags.String |
|
|
1821
|
+
ts.TypeFlags.StringLiteral |
|
|
1822
|
+
ts.TypeFlags.Boolean |
|
|
1823
|
+
ts.TypeFlags.BooleanLiteral |
|
|
1824
|
+
ts.TypeFlags.BigInt |
|
|
1825
|
+
ts.TypeFlags.BigIntLiteral |
|
|
1826
|
+
ts.TypeFlags.Null |
|
|
1827
|
+
ts.TypeFlags.Undefined)) !==
|
|
1828
|
+
0);
|
|
1829
|
+
}
|
|
1830
|
+
/** Whether the property read `access` is assigned, updated or deleted. */
|
|
1831
|
+
function isWrittenAccess(access) {
|
|
1832
|
+
let outer = access;
|
|
1833
|
+
for (;;) {
|
|
1834
|
+
const parent = outer.parent;
|
|
1835
|
+
if (parent !== undefined &&
|
|
1836
|
+
(ts.isParenthesizedExpression(parent) || ts.isNonNullExpression(parent))) {
|
|
1837
|
+
outer = parent;
|
|
1838
|
+
continue;
|
|
1839
|
+
}
|
|
1840
|
+
if (parent === undefined)
|
|
1841
|
+
return false;
|
|
1842
|
+
if (ts.isBinaryExpression(parent))
|
|
1843
|
+
return (parent.left === outer &&
|
|
1844
|
+
parent.operatorToken.kind >= ts.SyntaxKind.FirstAssignment &&
|
|
1845
|
+
parent.operatorToken.kind <= ts.SyntaxKind.LastAssignment);
|
|
1846
|
+
if (ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent))
|
|
1847
|
+
return parent.operand === outer;
|
|
1848
|
+
return ts.isDeleteExpression(parent);
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
/** Whether `call` is one of the calls a copying callee may make: a numeric
|
|
1852
|
+
* builtin or console printer the program does not shadow, over values of
|
|
1853
|
+
* primitive type only (a coercion runs no hook on them). */
|
|
1854
|
+
function pureCall(call, checker) {
|
|
1855
|
+
const callee = call.expression;
|
|
1856
|
+
const global = (node) => libSymbol(attempt(() => checker.getSymbolAtLocation(node)));
|
|
1857
|
+
if (ts.isIdentifier(callee)) {
|
|
1858
|
+
if (!PURE_CALLS.has(callee.text) || !global(callee))
|
|
1859
|
+
return false;
|
|
1860
|
+
}
|
|
1861
|
+
else if (ts.isPropertyAccessExpression(callee) && ts.isIdentifier(callee.expression)) {
|
|
1862
|
+
const owner = callee.expression.text;
|
|
1863
|
+
if (owner !== "Math" && owner !== "Number" && owner !== "console")
|
|
1864
|
+
return false;
|
|
1865
|
+
if (!global(callee.expression) || !global(callee.name))
|
|
1866
|
+
return false;
|
|
1867
|
+
}
|
|
1868
|
+
else
|
|
1869
|
+
return false;
|
|
1870
|
+
const args = call.arguments?.nodes ?? [];
|
|
1871
|
+
return args.every((argument) => {
|
|
1872
|
+
if (ts.isSpreadElement(argument))
|
|
1873
|
+
return false;
|
|
1874
|
+
const type = attempt(() => checker.getTypeAtLocation(argument));
|
|
1875
|
+
return type !== undefined && primitiveValue(type);
|
|
1876
|
+
});
|
|
1877
|
+
}
|
|
1878
|
+
/** Whether every declaration of `symbol` is in a declaration file: the
|
|
1879
|
+
* binding is the library's own, not one the program shadows it with. */
|
|
1880
|
+
function libSymbol(symbol) {
|
|
1881
|
+
const declarations = symbol?.declarations;
|
|
1882
|
+
return (declarations !== undefined &&
|
|
1883
|
+
declarations.length > 0 &&
|
|
1884
|
+
declarations.every((declaration) => declaration.getSourceFile().isDeclarationFile));
|
|
1885
|
+
}
|
|
1886
|
+
/** Whether evaluating `node` can run program code — a call, a constructor, a
|
|
1887
|
+
* getter or a dynamic member read, an iterator, a coercion hook — and so
|
|
1888
|
+
* write an instance a copy was made of. */
|
|
1889
|
+
function expressionRunsCode(node, checker) {
|
|
1890
|
+
if (ts.isCallExpression(node))
|
|
1891
|
+
return !pureCall(node, checker);
|
|
1892
|
+
if (ts.isNewExpression(node))
|
|
1893
|
+
return true;
|
|
1894
|
+
if (ts.isElementAccessExpression(node))
|
|
1895
|
+
return true;
|
|
1896
|
+
if (ts.isPropertyAccessExpression(node))
|
|
1897
|
+
return accessRunsCode(node, checker);
|
|
1898
|
+
if (ts.isTemplateExpression(node)) {
|
|
1899
|
+
for (const span of node.templateSpans.nodes)
|
|
1900
|
+
if (!primitiveNode(span.expression, checker))
|
|
1901
|
+
return true;
|
|
1902
|
+
return false;
|
|
1903
|
+
}
|
|
1904
|
+
if (ts.isBinaryExpression(node)) {
|
|
1905
|
+
const operator = node.operatorToken.kind;
|
|
1906
|
+
if (operator === ts.SyntaxKind.InstanceOfKeyword)
|
|
1907
|
+
return true;
|
|
1908
|
+
if (operator >= ts.SyntaxKind.FirstAssignment && operator <= ts.SyntaxKind.LastAssignment)
|
|
1909
|
+
return true;
|
|
1910
|
+
return !primitiveOperands(node.left, node.right, checker);
|
|
1911
|
+
}
|
|
1912
|
+
if (ts.isPrefixUnaryExpression(node)) {
|
|
1913
|
+
const operator = node.operator;
|
|
1914
|
+
if (operator === ts.SyntaxKind.PlusPlusToken || operator === ts.SyntaxKind.MinusMinusToken)
|
|
1915
|
+
return true;
|
|
1916
|
+
if (operator !== ts.SyntaxKind.PlusToken &&
|
|
1917
|
+
operator !== ts.SyntaxKind.MinusToken &&
|
|
1918
|
+
operator !== ts.SyntaxKind.TildeToken)
|
|
1919
|
+
return false;
|
|
1920
|
+
return !primitiveNode(node.operand, checker);
|
|
1921
|
+
}
|
|
1922
|
+
if (ts.isPostfixUnaryExpression(node))
|
|
1923
|
+
return true;
|
|
1924
|
+
if (ts.isDeleteExpression(node) || ts.isAwaitExpression(node) || ts.isYieldExpression(node))
|
|
1925
|
+
return true;
|
|
1926
|
+
if (ts.isTaggedTemplateExpression(node))
|
|
1927
|
+
return true;
|
|
1928
|
+
if (ts.isForOfStatement(node))
|
|
1929
|
+
return true;
|
|
1930
|
+
if (ts.isSpreadElement(node) || ts.isSpreadAssignment(node))
|
|
1931
|
+
return true;
|
|
1932
|
+
return false;
|
|
1933
|
+
}
|
|
1934
|
+
/** Whether reading `access` can run program code: a getter, or a member of
|
|
1935
|
+
* a value the analysis knows nothing static about. */
|
|
1936
|
+
function accessRunsCode(access, checker) {
|
|
1937
|
+
const symbol = attempt(() => checker.getSymbolAtLocation(access.name));
|
|
1938
|
+
if (symbol === undefined)
|
|
1939
|
+
return true;
|
|
1940
|
+
if ((symbol.flags & (ts.SymbolFlags.GetAccessor | ts.SymbolFlags.SetAccessor)) !== 0)
|
|
1941
|
+
return true;
|
|
1942
|
+
const receiver = valueType(access.expression, checker);
|
|
1943
|
+
if (receiver === undefined)
|
|
1944
|
+
return true;
|
|
1945
|
+
return ((receiver.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.TypeParameter)) !== 0);
|
|
1946
|
+
}
|
|
1947
|
+
/** Whether both operand types are primitive, so an operator between them
|
|
1948
|
+
* runs no value coercion. */
|
|
1949
|
+
function primitiveOperands(left, right, checker) {
|
|
1950
|
+
return primitiveNode(left, checker) && primitiveNode(right, checker);
|
|
1951
|
+
}
|
|
1952
|
+
/** The type of `node`'s value, ignoring parentheses, non-null assertions and
|
|
1953
|
+
* type assertions: a cast does not change what the value is at run time. */
|
|
1954
|
+
function valueType(node, checker) {
|
|
1955
|
+
let current = node;
|
|
1956
|
+
while (ts.isParenthesizedExpression(current) ||
|
|
1957
|
+
ts.isNonNullExpression(current) ||
|
|
1958
|
+
ts.isAssertionExpression(current))
|
|
1959
|
+
current = current.expression;
|
|
1960
|
+
return attempt(() => checker.getTypeAtLocation(current));
|
|
1961
|
+
}
|
|
1962
|
+
/** Whether the value of `node` has a primitive type, so coercing it runs no
|
|
1963
|
+
* value hook. */
|
|
1964
|
+
function primitiveNode(node, checker) {
|
|
1965
|
+
const type = valueType(node, checker);
|
|
1966
|
+
return type !== undefined && primitiveValue(type);
|
|
1967
|
+
}
|
|
1968
|
+
/** Whether `root` contains an expression that runs program code. */
|
|
1969
|
+
function containsProgramCode(root, checker) {
|
|
1970
|
+
let runs = false;
|
|
1971
|
+
ts.walkPreorder(root, (node) => {
|
|
1972
|
+
if (runs)
|
|
1973
|
+
return "stop";
|
|
1974
|
+
if (ts.isTypeNode(node))
|
|
1975
|
+
return "skip";
|
|
1976
|
+
if (ts.isFunctionLike(node))
|
|
1977
|
+
return "skip";
|
|
1978
|
+
// A class body's computed keys and static fields run when the class is
|
|
1979
|
+
// evaluated.
|
|
1980
|
+
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
|
|
1981
|
+
runs = true;
|
|
1982
|
+
return "stop";
|
|
1983
|
+
}
|
|
1984
|
+
if (expressionRunsCode(node, checker)) {
|
|
1985
|
+
runs = true;
|
|
1986
|
+
return "stop";
|
|
1987
|
+
}
|
|
1988
|
+
return undefined;
|
|
1989
|
+
});
|
|
1990
|
+
return runs;
|
|
1991
|
+
}
|
|
1992
|
+
/** Whether `node` mentions the binding `name`. */
|
|
1993
|
+
function mentionsBinding(node, name) {
|
|
1994
|
+
let found = false;
|
|
1995
|
+
ts.walkPreorder(node, (child) => {
|
|
1996
|
+
if (found)
|
|
1997
|
+
return "stop";
|
|
1998
|
+
if (ts.isIdentifier(child) && child.text === name && !isMemberName(child)) {
|
|
1999
|
+
found = true;
|
|
2000
|
+
return "stop";
|
|
2001
|
+
}
|
|
2002
|
+
return undefined;
|
|
2003
|
+
});
|
|
2004
|
+
return found;
|
|
2005
|
+
}
|
|
1439
2006
|
/** The static property name a member declares, or null for a computed key
|
|
1440
2007
|
* (its name is not a compile-time fact). */
|
|
1441
2008
|
function propertyNameText(name) {
|