@scriptc/compiler 0.3.4 → 0.3.6
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 +409 -42
- package/dist/backend/llvm/array-search.js +1 -1
- package/dist/backend/llvm/array-search.js.map +1 -1
- package/dist/backend/llvm/call-lifetimes.d.ts +6 -0
- package/dist/backend/llvm/call-lifetimes.js +19 -0
- package/dist/backend/llvm/call-lifetimes.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.d.ts +2 -21
- package/dist/backend/llvm/constant-callbacks.js +36 -219
- package/dist/backend/llvm/constant-callbacks.js.map +1 -1
- package/dist/backend/llvm/constant-callbacks.test.js +22 -0
- package/dist/backend/llvm/constant-callbacks.test.js.map +1 -1
- package/dist/backend/llvm/dense-array-access.d.ts +9 -0
- package/dist/backend/llvm/dense-array-access.js +27 -1
- package/dist/backend/llvm/dense-array-access.js.map +1 -1
- package/dist/backend/llvm/dyn.d.ts +6 -0
- package/dist/backend/llvm/dyn.js +71 -7
- package/dist/backend/llvm/dyn.js.map +1 -1
- package/dist/backend/llvm/emitter.d.ts +120 -2
- package/dist/backend/llvm/emitter.js +820 -142
- package/dist/backend/llvm/emitter.js.map +1 -1
- package/dist/backend/llvm/expr-async.js +17 -7
- package/dist/backend/llvm/expr-async.js.map +1 -1
- package/dist/backend/llvm/expr-bytes.js +1 -1
- package/dist/backend/llvm/expr-callbacks.d.ts +11 -0
- package/dist/backend/llvm/expr-callbacks.js +53 -0
- package/dist/backend/llvm/expr-callbacks.js.map +1 -1
- package/dist/backend/llvm/expr-calls.js +88 -2
- package/dist/backend/llvm/expr-calls.js.map +1 -1
- package/dist/backend/llvm/expr-containers.js +50 -27
- package/dist/backend/llvm/expr-containers.js.map +1 -1
- package/dist/backend/llvm/expr-dispatch.js +1 -0
- package/dist/backend/llvm/expr-dispatch.js.map +1 -1
- package/dist/backend/llvm/expr-dynamic.js +25 -1
- package/dist/backend/llvm/expr-dynamic.js.map +1 -1
- package/dist/backend/llvm/expr-primitives.d.ts +1 -1
- package/dist/backend/llvm/expr-primitives.js +20 -1
- package/dist/backend/llvm/expr-primitives.js.map +1 -1
- package/dist/backend/llvm/expr-stream-bridges.js +4 -0
- package/dist/backend/llvm/expr-stream-bridges.js.map +1 -1
- package/dist/backend/llvm/integer-clones.d.ts +103 -0
- package/dist/backend/llvm/integer-clones.js +1336 -0
- package/dist/backend/llvm/integer-clones.js.map +1 -0
- package/dist/backend/llvm/integer-clones.test.d.ts +1 -0
- package/dist/backend/llvm/integer-clones.test.js +219 -0
- package/dist/backend/llvm/integer-clones.test.js.map +1 -0
- package/dist/backend/llvm/lib-datagram.js +14 -0
- package/dist/backend/llvm/lib-datagram.js.map +1 -1
- package/dist/backend/llvm/lib-dispatch.js +32 -1
- package/dist/backend/llvm/lib-dispatch.js.map +1 -1
- package/dist/backend/llvm/lib-filesystem.js +61 -1
- package/dist/backend/llvm/lib-filesystem.js.map +1 -1
- package/dist/backend/llvm/lib-network.js +21 -3
- package/dist/backend/llvm/lib-network.js.map +1 -1
- package/dist/backend/llvm/lib-process.js +34 -0
- package/dist/backend/llvm/lib-process.js.map +1 -1
- package/dist/backend/llvm/lib-shared.js +77 -2
- package/dist/backend/llvm/lib-shared.js.map +1 -1
- package/dist/backend/llvm/lib-test.js +16 -3
- package/dist/backend/llvm/lib-test.js.map +1 -1
- package/dist/backend/llvm/lib-tls.js +6 -0
- package/dist/backend/llvm/lib-tls.js.map +1 -1
- package/dist/backend/llvm/local-array-reads.js +1 -1
- package/dist/backend/llvm/local-array-reads.js.map +1 -1
- package/dist/backend/llvm/map-entry-fusion.d.ts +28 -0
- package/dist/backend/llvm/map-entry-fusion.js +233 -0
- package/dist/backend/llvm/map-entry-fusion.js.map +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.d.ts +1 -0
- package/dist/backend/llvm/map-entry-fusion.test.js +183 -0
- package/dist/backend/llvm/map-entry-fusion.test.js.map +1 -0
- package/dist/backend/llvm/map-number-lookup.d.ts +2 -0
- package/dist/backend/llvm/map-number-lookup.js +1 -1
- package/dist/backend/llvm/map-number-lookup.js.map +1 -1
- package/dist/backend/llvm/map-number-lookup.test.js +10 -11
- package/dist/backend/llvm/map-number-lookup.test.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.d.ts +2 -0
- package/dist/backend/llvm/map-read-lifetimes.js +3 -0
- package/dist/backend/llvm/map-read-lifetimes.js.map +1 -1
- package/dist/backend/llvm/map-read-lifetimes.test.js +2 -2
- package/dist/backend/llvm/nullable-unions.d.ts +6 -3
- package/dist/backend/llvm/nullable-unions.js +2 -0
- package/dist/backend/llvm/nullable-unions.js.map +1 -1
- package/dist/backend/llvm/publish.d.ts +16 -0
- package/dist/backend/llvm/publish.js +81 -10
- package/dist/backend/llvm/publish.js.map +1 -1
- package/dist/backend/llvm/publish.test.d.ts +1 -0
- package/dist/backend/llvm/publish.test.js +94 -0
- package/dist/backend/llvm/publish.test.js.map +1 -0
- package/dist/backend/llvm/record-results.d.ts +1 -1
- package/dist/backend/llvm/record-results.js +78 -4
- package/dist/backend/llvm/record-results.js.map +1 -1
- package/dist/backend/llvm/record-sources.d.ts +7 -0
- package/dist/backend/llvm/record-sources.js +14 -0
- package/dist/backend/llvm/record-sources.js.map +1 -0
- package/dist/backend/llvm/reference-writes.js +1 -0
- package/dist/backend/llvm/reference-writes.js.map +1 -1
- package/dist/backend/llvm/shapes.d.ts +12 -3
- package/dist/backend/llvm/shapes.js +23 -14
- package/dist/backend/llvm/shapes.js.map +1 -1
- package/dist/backend/llvm/shapes.test.js +5 -3
- package/dist/backend/llvm/shapes.test.js.map +1 -1
- package/dist/backend/llvm/speculative-integers.d.ts +74 -0
- package/dist/backend/llvm/speculative-integers.js +571 -0
- package/dist/backend/llvm/speculative-integers.js.map +1 -0
- package/dist/backend/llvm/speculative-integers.test.d.ts +1 -0
- package/dist/backend/llvm/speculative-integers.test.js +148 -0
- package/dist/backend/llvm/speculative-integers.test.js.map +1 -0
- package/dist/backend/llvm/string-lifetimes.test.js +75 -1
- package/dist/backend/llvm/string-lifetimes.test.js.map +1 -1
- package/dist/backend/llvm/walkers.d.ts +17 -0
- package/dist/backend/llvm/walkers.js +123 -0
- package/dist/backend/llvm/walkers.js.map +1 -1
- package/dist/backend/may-throw.js +2 -0
- package/dist/backend/may-throw.js.map +1 -1
- package/dist/backend/native/contracts.d.ts +2 -1
- package/dist/backend/native/executable.js +6 -1
- package/dist/backend/native/executable.js.map +1 -1
- package/dist/backend/native/runtime-inputs.d.ts +1 -1
- package/dist/backend/native/runtime-inputs.js +1 -0
- package/dist/backend/native/runtime-inputs.js.map +1 -1
- package/dist/backend/runtime-abi.d.ts +2 -2
- package/dist/backend/runtime-abi.js +2 -2
- package/dist/backend/runtime-pack-targets.test.js +1 -1
- package/dist/backend/runtime-pack.d.ts +7 -3
- package/dist/backend/runtime-pack.js +12 -6
- package/dist/backend/runtime-pack.js.map +1 -1
- package/dist/backend/runtime-pack.test.js +16 -7
- package/dist/backend/runtime-pack.test.js.map +1 -1
- package/dist/contracts/check.js +1 -0
- package/dist/contracts/check.js.map +1 -1
- package/dist/coverage/surface-manifest.js +3 -3
- package/dist/coverage/surface-manifest.js.map +1 -1
- package/dist/diagnostics/diagnostic.d.ts +1 -1
- package/dist/diagnostics/diagnostic.js +6 -2
- package/dist/diagnostics/diagnostic.js.map +1 -1
- package/dist/frontend/lowering/builtin-calls.js +13 -0
- package/dist/frontend/lowering/builtin-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/callable-aliases.js +82 -8
- package/dist/frontend/lowering/builtins/callable-aliases.js.map +1 -1
- package/dist/frontend/lowering/builtins/child-process-async.d.ts +8 -6
- package/dist/frontend/lowering/builtins/child-process-async.js +45 -29
- package/dist/frontend/lowering/builtins/child-process-async.js.map +1 -1
- package/dist/frontend/lowering/builtins/compression.d.ts +9 -0
- package/dist/frontend/lowering/builtins/compression.js +145 -30
- package/dist/frontend/lowering/builtins/compression.js.map +1 -1
- package/dist/frontend/lowering/builtins/crypto.js +12 -1
- package/dist/frontend/lowering/builtins/crypto.js.map +1 -1
- package/dist/frontend/lowering/builtins/errors.js +5 -3
- package/dist/frontend/lowering/builtins/errors.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem-calls.d.ts +6 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js +16 -0
- package/dist/frontend/lowering/builtins/filesystem-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/filesystem.d.ts +8 -0
- package/dist/frontend/lowering/builtins/filesystem.js +199 -2
- package/dist/frontend/lowering/builtins/filesystem.js.map +1 -1
- package/dist/frontend/lowering/builtins/fs-streams.d.ts +26 -0
- package/dist/frontend/lowering/builtins/fs-streams.js +131 -0
- package/dist/frontend/lowering/builtins/fs-streams.js.map +1 -0
- package/dist/frontend/lowering/builtins/hash-stream.d.ts +12 -0
- package/dist/frontend/lowering/builtins/hash-stream.js +80 -0
- package/dist/frontend/lowering/builtins/hash-stream.js.map +1 -0
- package/dist/frontend/lowering/builtins/module-calls.js +17 -3
- package/dist/frontend/lowering/builtins/module-calls.js.map +1 -1
- package/dist/frontend/lowering/builtins/process.js +9 -2
- package/dist/frontend/lowering/builtins/process.js.map +1 -1
- package/dist/frontend/lowering/builtins/readline.d.ts +45 -13
- package/dist/frontend/lowering/builtins/readline.js +812 -47
- package/dist/frontend/lowering/builtins/readline.js.map +1 -1
- package/dist/frontend/lowering/builtins/workers.d.ts +4 -0
- package/dist/frontend/lowering/builtins/workers.js +58 -0
- package/dist/frontend/lowering/builtins/workers.js.map +1 -1
- package/dist/frontend/lowering/class-dynamic-dispatch.js +150 -8
- package/dist/frontend/lowering/class-dynamic-dispatch.js.map +1 -1
- package/dist/frontend/lowering/class-protocols.d.ts +55 -0
- package/dist/frontend/lowering/class-protocols.js +735 -0
- package/dist/frontend/lowering/class-protocols.js.map +1 -1
- package/dist/frontend/lowering/containers/array-from-async.d.ts +18 -0
- package/dist/frontend/lowering/containers/array-from-async.js +282 -0
- package/dist/frontend/lowering/containers/array-from-async.js.map +1 -0
- package/dist/frontend/lowering/containers/bytes.js +33 -12
- package/dist/frontend/lowering/containers/bytes.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-grouping.js +2 -1
- package/dist/frontend/lowering/containers/collection-grouping.js.map +1 -1
- package/dist/frontend/lowering/containers/collection-methods.js +27 -23
- package/dist/frontend/lowering/containers/collection-methods.js.map +1 -1
- package/dist/frontend/lowering/devirtualize.js +20 -7
- package/dist/frontend/lowering/devirtualize.js.map +1 -1
- package/dist/frontend/lowering/divergences.js +188 -15
- package/dist/frontend/lowering/divergences.js.map +1 -1
- package/dist/frontend/lowering/lower-calls.js +129 -25
- package/dist/frontend/lowering/lower-calls.js.map +1 -1
- package/dist/frontend/lowering/lower-classes.js +46 -1
- package/dist/frontend/lowering/lower-classes.js.map +1 -1
- package/dist/frontend/lowering/lower-dgram.js +55 -15
- package/dist/frontend/lowering/lower-dgram.js.map +1 -1
- package/dist/frontend/lowering/lower-event-emitter.d.ts +9 -1
- package/dist/frontend/lowering/lower-event-emitter.js +88 -1
- package/dist/frontend/lowering/lower-event-emitter.js.map +1 -1
- package/dist/frontend/lowering/lower-exprs.d.ts +4 -0
- package/dist/frontend/lowering/lower-exprs.js +239 -71
- package/dist/frontend/lowering/lower-exprs.js.map +1 -1
- package/dist/frontend/lowering/lower-inspect.js +49 -3
- package/dist/frontend/lowering/lower-inspect.js.map +1 -1
- package/dist/frontend/lowering/lower-mock.d.ts +11 -1
- package/dist/frontend/lowering/lower-mock.js +377 -61
- package/dist/frontend/lowering/lower-mock.js.map +1 -1
- package/dist/frontend/lowering/lower-modules.js +1 -0
- package/dist/frontend/lowering/lower-modules.js.map +1 -1
- package/dist/frontend/lowering/lower-server.d.ts +2 -1
- package/dist/frontend/lowering/lower-server.js +234 -21
- package/dist/frontend/lowering/lower-server.js.map +1 -1
- package/dist/frontend/lowering/lower-stmts.js +60 -13
- package/dist/frontend/lowering/lower-stmts.js.map +1 -1
- package/dist/frontend/lowering/lower-stream.d.ts +1 -3
- package/dist/frontend/lowering/lower-stream.js +325 -20
- package/dist/frontend/lowering/lower-stream.js.map +1 -1
- package/dist/frontend/lowering/lower-test.js +147 -48
- package/dist/frontend/lowering/lower-test.js.map +1 -1
- package/dist/frontend/lowering/lowerer.d.ts +13 -1
- package/dist/frontend/lowering/lowerer.js +10 -2
- package/dist/frontend/lowering/lowerer.js.map +1 -1
- package/dist/frontend/lowering/null-prototype.d.ts +13 -0
- package/dist/frontend/lowering/null-prototype.js +33 -0
- package/dist/frontend/lowering/null-prototype.js.map +1 -0
- package/dist/frontend/lowering/record-sources.d.ts +15 -0
- package/dist/frontend/lowering/record-sources.js +46 -0
- package/dist/frontend/lowering/record-sources.js.map +1 -0
- package/dist/frontend/lowering/surfaces.d.ts +3 -3
- package/dist/frontend/lowering/surfaces.js +59 -5
- package/dist/frontend/lowering/surfaces.js.map +1 -1
- package/dist/frontend/mock-shapes.d.ts +5 -0
- package/dist/frontend/mock-shapes.js +27 -2
- package/dist/frontend/mock-shapes.js.map +1 -1
- package/dist/frontend/program.js +5 -4
- package/dist/frontend/program.js.map +1 -1
- package/dist/frontend/type-mapper.d.ts +3 -0
- package/dist/frontend/type-mapper.js +148 -4
- package/dist/frontend/type-mapper.js.map +1 -1
- package/dist/index.js +18 -8
- package/dist/index.js.map +1 -1
- package/dist/ir/analysis.d.ts +10 -0
- package/dist/ir/analysis.js +35 -0
- package/dist/ir/analysis.js.map +1 -1
- package/dist/ir/analysis.test.js +69 -1
- package/dist/ir/analysis.test.js.map +1 -1
- package/dist/ir/builtin-effects.js +72 -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 +258 -13
- package/dist/ir/builtin-signatures.js.map +1 -1
- package/dist/ir/capture-values.d.ts +107 -0
- package/dist/ir/capture-values.js +850 -0
- package/dist/ir/capture-values.js.map +1 -0
- package/dist/ir/capture-values.test.d.ts +1 -0
- package/dist/ir/capture-values.test.js +268 -0
- package/dist/ir/capture-values.test.js.map +1 -0
- package/dist/ir/field-values.d.ts +16 -0
- package/dist/ir/field-values.js +128 -0
- package/dist/ir/field-values.js.map +1 -0
- package/dist/ir/field-values.test.d.ts +1 -0
- package/dist/ir/field-values.test.js +160 -0
- package/dist/ir/field-values.test.js.map +1 -0
- package/dist/ir/final-fields.d.ts +4 -1
- package/dist/ir/final-fields.js +11 -3
- package/dist/ir/final-fields.js.map +1 -1
- package/dist/ir/function-references.test.js +2 -1
- package/dist/ir/function-references.test.js.map +1 -1
- package/dist/ir/init-only-globals.d.ts +16 -0
- package/dist/ir/init-only-globals.js +121 -0
- package/dist/ir/init-only-globals.js.map +1 -0
- package/dist/ir/init-only-globals.test.d.ts +1 -0
- package/dist/ir/init-only-globals.test.js +115 -0
- package/dist/ir/init-only-globals.test.js.map +1 -0
- package/dist/ir/initializer-bindings.d.ts +18 -1
- package/dist/ir/initializer-bindings.js +91 -1
- package/dist/ir/initializer-bindings.js.map +1 -1
- package/dist/ir/initializer-bindings.test.js +57 -2
- package/dist/ir/initializer-bindings.test.js.map +1 -1
- package/dist/ir/int32-slots.d.ts +22 -0
- package/dist/ir/int32-slots.js +398 -13
- package/dist/ir/int32-slots.js.map +1 -1
- package/dist/ir/int32-slots.test.js +119 -8
- package/dist/ir/int32-slots.test.js.map +1 -1
- package/dist/ir/integer-loop-facts.d.ts +27 -1
- package/dist/ir/integer-loop-facts.js +239 -7
- package/dist/ir/integer-loop-facts.js.map +1 -1
- package/dist/ir/integer-ranges.d.ts +8 -5
- package/dist/ir/integer-ranges.js +147 -59
- package/dist/ir/integer-ranges.js.map +1 -1
- package/dist/ir/integer-ranges.test.js +285 -7
- package/dist/ir/integer-ranges.test.js.map +1 -1
- package/dist/ir/ir.d.ts +22 -1
- package/dist/ir/ir.js +4 -0
- package/dist/ir/ir.js.map +1 -1
- package/dist/ir/property-bags.d.ts +14 -0
- package/dist/ir/property-bags.js +121 -0
- package/dist/ir/property-bags.js.map +1 -0
- package/dist/ir/receiver-readers.d.ts +21 -0
- package/dist/ir/receiver-readers.js +217 -0
- package/dist/ir/receiver-readers.js.map +1 -0
- package/dist/ir/runtime-features.d.ts +3 -1
- package/dist/ir/runtime-features.js +102 -7
- package/dist/ir/runtime-features.js.map +1 -1
- package/dist/ir/runtime-features.test.js +62 -0
- package/dist/ir/runtime-features.test.js.map +1 -1
- package/dist/ir/traverse.js +4 -0
- package/dist/ir/traverse.js.map +1 -1
- package/dist/ir/validate.js +71 -3
- package/dist/ir/validate.js.map +1 -1
- package/dist/ir/validate.test.js +59 -0
- package/dist/ir/validate.test.js.map +1 -1
- package/dist/library/int-infer.js +3 -0
- package/dist/library/int-infer.js.map +1 -1
- package/dist/library/ir-policy.js +5 -0
- package/dist/library/ir-policy.js.map +1 -1
- package/package.json +20 -20
- package/surface-manifest.json +57 -19
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* node:test's mock functions (Node 24.22, lib/internal/test_runner/mock):
|
|
2
|
-
* mock.fn and t.mock
|
|
2
|
+
* mock.fn, mock.method and their t.mock twins, the trackers' restoreAll
|
|
3
|
+
* and reset, and the fn.mock context's calls, callCount,
|
|
3
4
|
* mockImplementation, mockImplementationOnce, resetCalls and restore.
|
|
4
5
|
*
|
|
5
6
|
* mock.fn(original, implementation?) lowers to the hybrid record
|
|
@@ -8,11 +9,21 @@
|
|
|
8
9
|
* one-time implementation registered for this call index, or the current
|
|
9
10
|
* one, calls it, and appends { arguments, error, result, this } to the
|
|
10
11
|
* calls log before returning or rethrowing. The context's mutating
|
|
11
|
-
* methods are lifted helpers of the same type.
|
|
12
|
+
* methods are lifted helpers of the same type.
|
|
13
|
+
*
|
|
14
|
+
* mock.method(object, name, implementation?) mocks a function-valued field
|
|
15
|
+
* of a record: the field gets a second wrapper over the same context, one
|
|
16
|
+
* that records the object as `this`, and the context's %unmock closure
|
|
17
|
+
* writes the original back on restore(). Each mock registers a closure
|
|
18
|
+
* that calls its restore() with its tracker (scr_test.c): the module's
|
|
19
|
+
* `mock`, or the test's t.mock, which is reset when the test ends. */
|
|
12
20
|
import * as ts from "../ts7/adapter.js";
|
|
13
21
|
import { BOOL, CAUGHT, DYN, F64, UNDEFINED_T, VOID, typeKey, } from "../../ir/ir.js";
|
|
14
22
|
import { countedFor, dynUndefinedExpr, numLit, varRef } from "../../ir/build.js";
|
|
23
|
+
import { mockType as mockHybridType } from "../mock-shapes.js";
|
|
15
24
|
import { locOf } from "../program.js";
|
|
25
|
+
import { resultIsDiscarded } from "./call-position.js";
|
|
26
|
+
const RESTORE_FN = { kind: "func", params: [], ret: VOID };
|
|
16
27
|
/** The context record's parts, or null when `type` is not a mock context
|
|
17
28
|
* (mock-shapes.ts). */
|
|
18
29
|
function mockContextFields(lowerer, type) {
|
|
@@ -23,9 +34,11 @@ function mockContextFields(lowerer, type) {
|
|
|
23
34
|
const impl = field("%impl");
|
|
24
35
|
const once = field("%once");
|
|
25
36
|
const calls = field("calls");
|
|
37
|
+
const unmock = field("%unmock");
|
|
26
38
|
if (impl?.kind !== "func" ||
|
|
27
39
|
once?.kind !== "array" ||
|
|
28
40
|
calls?.kind !== "array" ||
|
|
41
|
+
unmock?.kind !== "array" ||
|
|
29
42
|
field("%original") === undefined)
|
|
30
43
|
return null;
|
|
31
44
|
const call = calls.elem;
|
|
@@ -34,7 +47,7 @@ function mockContextFields(lowerer, type) {
|
|
|
34
47
|
const args = callShape?.fields.find((f) => f.name === "arguments")?.type;
|
|
35
48
|
if (!result || !args)
|
|
36
49
|
return null;
|
|
37
|
-
return { fn: impl, call, calls, once, onceEntry: once.elem, result, args };
|
|
50
|
+
return { fn: impl, call, calls, once, onceEntry: once.elem, unmock, result, args };
|
|
38
51
|
}
|
|
39
52
|
export function isMockContextType(lowerer, type) {
|
|
40
53
|
return mockContextFields(lowerer, type) !== null;
|
|
@@ -69,9 +82,15 @@ const local = (id, name, type, mutable = false) => ({
|
|
|
69
82
|
type,
|
|
70
83
|
mutable,
|
|
71
84
|
});
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
|
|
85
|
+
/** A captured local of a lifted closure. */
|
|
86
|
+
const boxedLocal = (id, name, type) => ({
|
|
87
|
+
...local(id, name, type),
|
|
88
|
+
boxed: true,
|
|
89
|
+
});
|
|
90
|
+
/** Lifts one function per (context type, role), cached on the lowerer.
|
|
91
|
+
* `owner` overrides the context type's shape as the cache key. */
|
|
92
|
+
function liftOnce(lowerer, ctxType, role, build, owner = ctxType.shapeId) {
|
|
93
|
+
const key = `mock.${role}:${owner}`;
|
|
75
94
|
const existing = lowerer.assertHelpers.get(key);
|
|
76
95
|
if (existing)
|
|
77
96
|
return existing;
|
|
@@ -80,9 +99,10 @@ function liftOnce(lowerer, ctxType, role, build) {
|
|
|
80
99
|
build(name);
|
|
81
100
|
return name;
|
|
82
101
|
}
|
|
83
|
-
/** `%mock.wrap.N(ctx)`: the closure that records each call into ctx
|
|
84
|
-
|
|
85
|
-
|
|
102
|
+
/** `%mock.wrap.N(ctx)`: the closure that records each call into ctx, with
|
|
103
|
+
* `this` undefined. `%mock.wrapMethod.N(ctx, this)` records `this`. */
|
|
104
|
+
function mockWrapperFactory(lowerer, ctxType, loc, withThis = false) {
|
|
105
|
+
return liftOnce(lowerer, ctxType, withThis ? "wrapMethod" : "wrap", (name) => {
|
|
86
106
|
const { fn, call, calls, once, onceEntry, result, args } = mockContextFields(lowerer, ctxType);
|
|
87
107
|
const impl = `${name}.impl`;
|
|
88
108
|
const ctx = () => varRef("ctx.0", ctxType, loc);
|
|
@@ -90,12 +110,14 @@ function mockWrapperFactory(lowerer, ctxType, loc) {
|
|
|
90
110
|
const paramRefs = () => params.map((p) => varRef(p.localId, p.type, loc));
|
|
91
111
|
const argumentsValue = () => fn.rest
|
|
92
112
|
? paramRefs()[0]
|
|
93
|
-
:
|
|
94
|
-
kind: "
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
: args.kind === "array"
|
|
114
|
+
? { kind: "arrayLit", elems: [], type: args, loc }
|
|
115
|
+
: {
|
|
116
|
+
kind: "recordLit",
|
|
117
|
+
fields: paramRefs().map((value, i) => ({ name: String(i), value })),
|
|
118
|
+
type: args,
|
|
119
|
+
loc,
|
|
120
|
+
};
|
|
99
121
|
const record = (resultValue, error) => ({
|
|
100
122
|
kind: "exprStmt",
|
|
101
123
|
expr: {
|
|
@@ -109,7 +131,10 @@ function mockWrapperFactory(lowerer, ctxType, loc) {
|
|
|
109
131
|
{ name: "arguments", value: argumentsValue() },
|
|
110
132
|
{ name: "error", value: error },
|
|
111
133
|
{ name: "result", value: resultValue },
|
|
112
|
-
{
|
|
134
|
+
{
|
|
135
|
+
name: "this",
|
|
136
|
+
value: withThis ? varRef("this.0", DYN, loc) : dynUndefinedExpr(loc),
|
|
137
|
+
},
|
|
113
138
|
],
|
|
114
139
|
type: call,
|
|
115
140
|
loc,
|
|
@@ -217,10 +242,14 @@ function mockWrapperFactory(lowerer, ctxType, loc) {
|
|
|
217
242
|
name: impl,
|
|
218
243
|
params,
|
|
219
244
|
returnType: fn.ret,
|
|
220
|
-
captures: [
|
|
245
|
+
captures: [
|
|
246
|
+
{ localId: "ctx.0", name: "ctx", type: ctxType },
|
|
247
|
+
...(withThis ? [{ localId: "this.0", name: "this", type: DYN }] : []),
|
|
248
|
+
],
|
|
221
249
|
locals: [
|
|
222
250
|
...params.map((p) => local(p.localId, p.name, p.type)),
|
|
223
|
-
|
|
251
|
+
boxedLocal("ctx.0", "ctx", ctxType),
|
|
252
|
+
...(withThis ? [boxedLocal("this.0", "this", DYN)] : []),
|
|
224
253
|
local("n.0", "index", F64),
|
|
225
254
|
local("f.0", "implementation", fn, true),
|
|
226
255
|
local("i.0", "entry", F64, true),
|
|
@@ -242,13 +271,25 @@ function mockWrapperFactory(lowerer, ctxType, loc) {
|
|
|
242
271
|
});
|
|
243
272
|
lowerer.liftedFns.push({
|
|
244
273
|
name,
|
|
245
|
-
params: [
|
|
274
|
+
params: [
|
|
275
|
+
{ localId: "ctx.0", name: "ctx", type: ctxType },
|
|
276
|
+
...(withThis ? [{ localId: "this.0", name: "this", type: DYN }] : []),
|
|
277
|
+
],
|
|
246
278
|
returnType: fn,
|
|
247
|
-
locals: [
|
|
279
|
+
locals: [
|
|
280
|
+
boxedLocal("ctx.0", "ctx", ctxType),
|
|
281
|
+
...(withThis ? [boxedLocal("this.0", "this", DYN)] : []),
|
|
282
|
+
],
|
|
248
283
|
body: [
|
|
249
284
|
{
|
|
250
285
|
kind: "return",
|
|
251
|
-
value: {
|
|
286
|
+
value: {
|
|
287
|
+
kind: "closure",
|
|
288
|
+
fnName: impl,
|
|
289
|
+
captures: withThis ? ["ctx.0", "this.0"] : ["ctx.0"],
|
|
290
|
+
type: fn,
|
|
291
|
+
loc,
|
|
292
|
+
},
|
|
252
293
|
loc,
|
|
253
294
|
},
|
|
254
295
|
],
|
|
@@ -256,6 +297,138 @@ function mockWrapperFactory(lowerer, ctxType, loc) {
|
|
|
256
297
|
});
|
|
257
298
|
});
|
|
258
299
|
}
|
|
300
|
+
/** `%mock.restore.N(ctx)`: fn.mock.restore(). A method mock writes the
|
|
301
|
+
* original back to its object and keeps its implementation; a mock.fn mock
|
|
302
|
+
* goes back to its original implementation. */
|
|
303
|
+
function mockRestoreHelper(lowerer, ctxType, loc) {
|
|
304
|
+
const { fn, unmock } = mockContextFields(lowerer, ctxType);
|
|
305
|
+
return mockHelper(lowerer, ctxType, "restore", [], (ctx) => {
|
|
306
|
+
const unmockArray = () => recordGet(ctx(), "%unmock", unmock, loc);
|
|
307
|
+
return [
|
|
308
|
+
{
|
|
309
|
+
kind: "if",
|
|
310
|
+
cond: {
|
|
311
|
+
kind: "bin",
|
|
312
|
+
op: "===",
|
|
313
|
+
left: length(unmockArray(), loc),
|
|
314
|
+
right: numLit(0, loc),
|
|
315
|
+
type: BOOL,
|
|
316
|
+
loc,
|
|
317
|
+
},
|
|
318
|
+
then: [recordSet(ctx(), "%impl", recordGet(ctx(), "%original", fn, loc), loc)],
|
|
319
|
+
else_: [
|
|
320
|
+
{
|
|
321
|
+
kind: "exprStmt",
|
|
322
|
+
expr: {
|
|
323
|
+
kind: "callValue",
|
|
324
|
+
callee: {
|
|
325
|
+
kind: "arrayGet",
|
|
326
|
+
arr: unmockArray(),
|
|
327
|
+
index: numLit(0, loc),
|
|
328
|
+
type: RESTORE_FN,
|
|
329
|
+
loc,
|
|
330
|
+
},
|
|
331
|
+
args: [],
|
|
332
|
+
type: VOID,
|
|
333
|
+
loc,
|
|
334
|
+
},
|
|
335
|
+
loc,
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
loc,
|
|
339
|
+
},
|
|
340
|
+
];
|
|
341
|
+
}, loc);
|
|
342
|
+
}
|
|
343
|
+
/** `%mock.tracked.N(ctx)`: the closure a tracker keeps, which calls the
|
|
344
|
+
* mock's restore(). */
|
|
345
|
+
function mockTrackedFactory(lowerer, ctxType, loc) {
|
|
346
|
+
const restore = mockRestoreHelper(lowerer, ctxType, loc);
|
|
347
|
+
return liftOnce(lowerer, ctxType, "tracked", (name) => {
|
|
348
|
+
const impl = `${name}.impl`;
|
|
349
|
+
lowerer.liftedFns.push({
|
|
350
|
+
name: impl,
|
|
351
|
+
params: [],
|
|
352
|
+
returnType: VOID,
|
|
353
|
+
captures: [{ localId: "ctx.0", name: "ctx", type: ctxType }],
|
|
354
|
+
locals: [boxedLocal("ctx.0", "ctx", ctxType)],
|
|
355
|
+
body: [
|
|
356
|
+
{
|
|
357
|
+
kind: "exprStmt",
|
|
358
|
+
expr: {
|
|
359
|
+
kind: "call",
|
|
360
|
+
callee: restore,
|
|
361
|
+
args: [varRef("ctx.0", ctxType, loc)],
|
|
362
|
+
type: VOID,
|
|
363
|
+
loc,
|
|
364
|
+
},
|
|
365
|
+
loc,
|
|
366
|
+
},
|
|
367
|
+
{ kind: "return", value: null, loc },
|
|
368
|
+
],
|
|
369
|
+
loc,
|
|
370
|
+
});
|
|
371
|
+
lowerer.liftedFns.push({
|
|
372
|
+
name,
|
|
373
|
+
params: [{ localId: "ctx.0", name: "ctx", type: ctxType }],
|
|
374
|
+
returnType: RESTORE_FN,
|
|
375
|
+
locals: [boxedLocal("ctx.0", "ctx", ctxType)],
|
|
376
|
+
body: [
|
|
377
|
+
{
|
|
378
|
+
kind: "return",
|
|
379
|
+
value: { kind: "closure", fnName: impl, captures: ["ctx.0"], type: RESTORE_FN, loc },
|
|
380
|
+
loc,
|
|
381
|
+
},
|
|
382
|
+
],
|
|
383
|
+
loc,
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
/** `%mock.unmock.N(object, original)`: the closure that writes `original`
|
|
388
|
+
* back to the object's field. */
|
|
389
|
+
function mockUnmockFactory(lowerer, ctxType, objType, field, loc) {
|
|
390
|
+
const { fn } = mockContextFields(lowerer, ctxType);
|
|
391
|
+
return liftOnce(lowerer, ctxType, "unmock", (name) => {
|
|
392
|
+
const impl = `${name}.impl`;
|
|
393
|
+
const captures = [
|
|
394
|
+
{ localId: "obj.0", name: "object", type: objType },
|
|
395
|
+
{ localId: "orig.0", name: "original", type: fn },
|
|
396
|
+
];
|
|
397
|
+
const boxedLocals = captures.map((c) => boxedLocal(c.localId, c.name, c.type));
|
|
398
|
+
lowerer.liftedFns.push({
|
|
399
|
+
name: impl,
|
|
400
|
+
params: [],
|
|
401
|
+
returnType: VOID,
|
|
402
|
+
captures,
|
|
403
|
+
locals: boxedLocals,
|
|
404
|
+
body: [
|
|
405
|
+
recordSet(varRef("obj.0", objType, loc), field, varRef("orig.0", fn, loc), loc),
|
|
406
|
+
{ kind: "return", value: null, loc },
|
|
407
|
+
],
|
|
408
|
+
loc,
|
|
409
|
+
});
|
|
410
|
+
lowerer.liftedFns.push({
|
|
411
|
+
name,
|
|
412
|
+
params: captures,
|
|
413
|
+
returnType: RESTORE_FN,
|
|
414
|
+
locals: boxedLocals,
|
|
415
|
+
body: [
|
|
416
|
+
{
|
|
417
|
+
kind: "return",
|
|
418
|
+
value: {
|
|
419
|
+
kind: "closure",
|
|
420
|
+
fnName: impl,
|
|
421
|
+
captures: ["obj.0", "orig.0"],
|
|
422
|
+
type: RESTORE_FN,
|
|
423
|
+
loc,
|
|
424
|
+
},
|
|
425
|
+
loc,
|
|
426
|
+
},
|
|
427
|
+
],
|
|
428
|
+
loc,
|
|
429
|
+
});
|
|
430
|
+
}, `${objType.shapeId}.${JSON.stringify(field)}`);
|
|
431
|
+
}
|
|
259
432
|
/** A VOID helper over the context: `%mock.<role>.N(ctx, ...extra)`. */
|
|
260
433
|
function mockHelper(lowerer, ctxType, role, extra, body, loc) {
|
|
261
434
|
return liftOnce(lowerer, ctxType, role, (name) => {
|
|
@@ -277,8 +450,73 @@ function mockHelper(lowerer, ctxType, role, extra, body, loc) {
|
|
|
277
450
|
});
|
|
278
451
|
});
|
|
279
452
|
}
|
|
453
|
+
/** Registers a mock's restore with its tracker. */
|
|
454
|
+
function trackMock(lowerer, tracker, ctxType, ctx, loc) {
|
|
455
|
+
const restore = {
|
|
456
|
+
kind: "call",
|
|
457
|
+
callee: mockTrackedFactory(lowerer, ctxType, loc),
|
|
458
|
+
args: [ctx],
|
|
459
|
+
type: RESTORE_FN,
|
|
460
|
+
loc,
|
|
461
|
+
};
|
|
462
|
+
return {
|
|
463
|
+
kind: "exprStmt",
|
|
464
|
+
expr: {
|
|
465
|
+
kind: "libCall",
|
|
466
|
+
fn: tracker ? "test.ctxMockTrack" : "test.mockTrack",
|
|
467
|
+
args: tracker ? [tracker, restore] : [restore],
|
|
468
|
+
type: VOID,
|
|
469
|
+
loc,
|
|
470
|
+
},
|
|
471
|
+
loc,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
/** The context record literal of a new mock. */
|
|
475
|
+
function mockContextLiteral(ctxType, fields, implementation, original, unmock, loc) {
|
|
476
|
+
return {
|
|
477
|
+
kind: "recordLit",
|
|
478
|
+
fields: [
|
|
479
|
+
{ name: "%impl", value: implementation },
|
|
480
|
+
{ name: "%once", value: { kind: "arrayLit", elems: [], type: fields.once, loc } },
|
|
481
|
+
{ name: "%original", value: original },
|
|
482
|
+
{ name: "%unmock", value: { kind: "arrayLit", elems: unmock, type: fields.unmock, loc } },
|
|
483
|
+
{ name: "calls", value: { kind: "arrayLit", elems: [], type: fields.calls, loc } },
|
|
484
|
+
],
|
|
485
|
+
type: ctxType,
|
|
486
|
+
loc,
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
/** The Mock<F> record over a context: { %call: wrapper, mock: context }. */
|
|
490
|
+
function mockRecord(lowerer, mockType, ctxType, ctx, loc) {
|
|
491
|
+
const { fn } = mockContextFields(lowerer, ctxType);
|
|
492
|
+
return {
|
|
493
|
+
kind: "recordLit",
|
|
494
|
+
fields: [
|
|
495
|
+
{
|
|
496
|
+
name: "%call",
|
|
497
|
+
value: {
|
|
498
|
+
kind: "call",
|
|
499
|
+
callee: mockWrapperFactory(lowerer, ctxType, loc),
|
|
500
|
+
args: [ctx],
|
|
501
|
+
type: fn,
|
|
502
|
+
loc,
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
{ name: "mock", value: ctx },
|
|
506
|
+
],
|
|
507
|
+
type: mockType,
|
|
508
|
+
loc,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
/** A union return type needs an undefined arm: the calls log records
|
|
512
|
+
* undefined for calls that throw. */
|
|
513
|
+
function requireUndefinedResultArm(lowerer, fields, call, what) {
|
|
514
|
+
if (fields.fn.ret.kind === "union" && typeKey(fields.result) !== typeKey(fields.fn.ret)) {
|
|
515
|
+
lowerer.noLowering(`${what} of a function returning '${lowerer.fmt(fields.fn.ret)}'`, call, "a union return type needs an undefined arm here (the calls log records undefined for calls that throw)");
|
|
516
|
+
}
|
|
517
|
+
}
|
|
280
518
|
/** mock.fn(original, implementation?) and t.mock.fn(...). */
|
|
281
|
-
export function lowerMockFn(lowerer, call, what) {
|
|
519
|
+
export function lowerMockFn(lowerer, call, what, tracker) {
|
|
282
520
|
const loc = locOf(call);
|
|
283
521
|
const mockType = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
284
522
|
const shape = mockType?.kind === "record" ? lowerer.shapes.get(mockType.shapeId) : undefined;
|
|
@@ -289,12 +527,11 @@ export function lowerMockFn(lowerer, call, what) {
|
|
|
289
527
|
!shape.fields.some((f) => f.name === "%call") ||
|
|
290
528
|
!ctxType ||
|
|
291
529
|
!isMockContextType(lowerer, ctxType)) {
|
|
292
|
-
lowerer.noLowering(`${what} of this function type`, call, "mock functions lower for functions with fixed parameters, or a single rest array parameter");
|
|
293
|
-
}
|
|
294
|
-
const { fn, calls, once, result } = mockContextFields(lowerer, ctxType);
|
|
295
|
-
if (fn.ret.kind === "union" && typeKey(result) !== typeKey(fn.ret)) {
|
|
296
|
-
lowerer.noLowering(`${what} of a function returning '${lowerer.fmt(fn.ret)}'`, call, "a union return type needs an undefined arm here (the calls log records undefined for calls that throw)");
|
|
530
|
+
lowerer.noLowering(`${what} of this function type`, call, "mock functions lower for functions with fixed parameters, or a single rest array parameter, and an implementation of the same type");
|
|
297
531
|
}
|
|
532
|
+
const fields = mockContextFields(lowerer, ctxType);
|
|
533
|
+
const { fn } = fields;
|
|
534
|
+
requireUndefinedResultArm(lowerer, fields, call, what);
|
|
298
535
|
const args = call.arguments;
|
|
299
536
|
if (args.length === 0 || args.length > 2 || args.some(ts.isSpreadElement)) {
|
|
300
537
|
lowerer.noLowering(`${what} with ${args.length} arguments`, call, "the supported forms are mock.fn(original) and mock.fn(original, implementation); mock.fn() and mock options have no lowering");
|
|
@@ -311,48 +548,129 @@ export function lowerMockFn(lowerer, call, what) {
|
|
|
311
548
|
? lowerer.lowerExprExpecting(args[1], fn)
|
|
312
549
|
: varRef(originalLocal.id, fn, loc);
|
|
313
550
|
const ctxLocal = lowerer.declareHiddenLocal("%mockContext", ctxType);
|
|
551
|
+
const ctx = () => varRef(ctxLocal.id, ctxType, loc);
|
|
314
552
|
stmts.push({
|
|
315
553
|
kind: "varDecl",
|
|
316
554
|
localId: ctxLocal.id,
|
|
317
|
-
init:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
555
|
+
init: mockContextLiteral(ctxType, fields, implementation, varRef(originalLocal.id, fn, loc), [], loc),
|
|
556
|
+
loc,
|
|
557
|
+
}, trackMock(lowerer, tracker, ctxType, ctx(), loc));
|
|
558
|
+
return {
|
|
559
|
+
kind: "seqExpr",
|
|
560
|
+
stmts,
|
|
561
|
+
result: mockRecord(lowerer, mockType, ctxType, ctx(), loc),
|
|
562
|
+
type: mockType,
|
|
563
|
+
loc,
|
|
564
|
+
};
|
|
565
|
+
}
|
|
566
|
+
const METHOD_HINT = "mock.method lowers for objects whose type maps to a record (object literals and interface-typed objects) and a function-valued field named by a string literal";
|
|
567
|
+
/** mock.method(object, methodName, implementation?) and t.mock.method. The
|
|
568
|
+
* field's function type F is the mock's type; an implementation must have
|
|
569
|
+
* the same type, unless the call's result is discarded. */
|
|
570
|
+
export function lowerMockMethod(lowerer, call, what, tracker) {
|
|
571
|
+
const loc = locOf(call);
|
|
572
|
+
const args = call.arguments;
|
|
573
|
+
if (args.length < 2 || args.length > 3 || args.some(ts.isSpreadElement)) {
|
|
574
|
+
lowerer.noLowering(`${what} with ${args.length} arguments`, call, "the supported forms are mock.method(object, methodName) and mock.method(object, methodName, implementation); mock options have no lowering");
|
|
575
|
+
}
|
|
576
|
+
const nameArg = args[1];
|
|
577
|
+
if (!ts.isStringLiteralLike(nameArg)) {
|
|
578
|
+
lowerer.noLowering(`${what} with a computed method name`, nameArg, METHOD_HINT);
|
|
579
|
+
}
|
|
580
|
+
const field = nameArg.text;
|
|
581
|
+
if (args.length === 3 &&
|
|
582
|
+
lowerer.checker.getCallSignatures(lowerer.typeOf(args[2])).length === 0) {
|
|
583
|
+
lowerer.noLowering(`${what} with an options object`, args[2], "mock options (times, getter and setter) have no lowering");
|
|
584
|
+
}
|
|
585
|
+
const objType = lowerer.mapTypeOf(lowerer.typeOf(args[0]));
|
|
586
|
+
const objShape = objType?.kind === "record" ? lowerer.shapes.get(objType.shapeId) : undefined;
|
|
587
|
+
const fn = objShape?.fields.find((f) => f.name === field)?.type;
|
|
588
|
+
if (!objType || !objShape || fn?.kind !== "func") {
|
|
589
|
+
const typeName = lowerer.typeOf(args[0]).getSymbol()?.name;
|
|
590
|
+
lowerer.noLowering(typeName && !typeName.startsWith("__")
|
|
591
|
+
? `${what} on '${typeName}'`
|
|
592
|
+
: `${what} on this object`, args[0], METHOD_HINT);
|
|
593
|
+
}
|
|
594
|
+
const mockType = mockHybridType(fn, lowerer.typeCtx);
|
|
595
|
+
const ctxType = mockType?.kind === "record"
|
|
596
|
+
? lowerer.shapes.get(mockType.shapeId)?.fields.find((f) => f.name === "mock")?.type
|
|
597
|
+
: undefined;
|
|
598
|
+
if (!mockType || !ctxType || !isMockContextType(lowerer, ctxType)) {
|
|
599
|
+
lowerer.noLowering(`${what} of a '${lowerer.fmt(fn)}' method`, call, "mock functions lower for functions with fixed parameters, or a single rest array parameter");
|
|
600
|
+
}
|
|
601
|
+
if (!resultIsDiscarded(call)) {
|
|
602
|
+
const resultType = lowerer.mapTypeOf(lowerer.typeOf(call));
|
|
603
|
+
if (!resultType || typeKey(resultType) !== typeKey(mockType)) {
|
|
604
|
+
lowerer.noLowering(`${what} with an implementation of another type`, args[2] ?? call, "give the implementation the method's parameter and return types, or discard the result");
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
const fields = mockContextFields(lowerer, ctxType);
|
|
608
|
+
requireUndefinedResultArm(lowerer, fields, call, what);
|
|
609
|
+
const stmts = [];
|
|
610
|
+
const objLocal = lowerer.declareHiddenLocal("%mockObject", objType);
|
|
611
|
+
const obj = () => varRef(objLocal.id, objType, loc);
|
|
612
|
+
stmts.push({ kind: "varDecl", localId: objLocal.id, init: lowerer.lowerExpr(args[0]), loc });
|
|
613
|
+
const originalLocal = lowerer.declareHiddenLocal("%mockOriginal", fn);
|
|
614
|
+
const original = () => varRef(originalLocal.id, fn, loc);
|
|
615
|
+
stmts.push({
|
|
616
|
+
kind: "varDecl",
|
|
617
|
+
localId: originalLocal.id,
|
|
618
|
+
init: recordGet(obj(), field, fn, loc),
|
|
328
619
|
loc,
|
|
329
620
|
});
|
|
330
|
-
const
|
|
621
|
+
const implementation = args.length === 3 ? lowerer.lowerExprExpecting(args[2], fn) : original();
|
|
622
|
+
const unmock = {
|
|
623
|
+
kind: "call",
|
|
624
|
+
callee: mockUnmockFactory(lowerer, ctxType, objType, field, loc),
|
|
625
|
+
args: [obj(), original()],
|
|
626
|
+
type: RESTORE_FN,
|
|
627
|
+
loc,
|
|
628
|
+
};
|
|
629
|
+
const ctxLocal = lowerer.declareHiddenLocal("%mockContext", ctxType);
|
|
630
|
+
const ctx = () => varRef(ctxLocal.id, ctxType, loc);
|
|
631
|
+
stmts.push({
|
|
632
|
+
kind: "varDecl",
|
|
633
|
+
localId: ctxLocal.id,
|
|
634
|
+
init: mockContextLiteral(ctxType, fields, implementation, original(), [unmock], loc),
|
|
635
|
+
loc,
|
|
636
|
+
}, trackMock(lowerer, tracker, ctxType, ctx(), loc),
|
|
637
|
+
// The object's field: the wrapper that records the object as `this`.
|
|
638
|
+
recordSet(obj(), field, {
|
|
639
|
+
kind: "call",
|
|
640
|
+
callee: mockWrapperFactory(lowerer, ctxType, loc, true),
|
|
641
|
+
args: [ctx(), lowerer.coerceToExpected(obj(), DYN)],
|
|
642
|
+
type: fn,
|
|
643
|
+
loc,
|
|
644
|
+
}, loc));
|
|
331
645
|
return {
|
|
332
646
|
kind: "seqExpr",
|
|
333
647
|
stmts,
|
|
334
|
-
result:
|
|
335
|
-
kind: "recordLit",
|
|
336
|
-
fields: [
|
|
337
|
-
{
|
|
338
|
-
name: "%call",
|
|
339
|
-
value: {
|
|
340
|
-
kind: "call",
|
|
341
|
-
callee: factory,
|
|
342
|
-
args: [varRef(ctxLocal.id, ctxType, loc)],
|
|
343
|
-
type: fn,
|
|
344
|
-
loc,
|
|
345
|
-
},
|
|
346
|
-
},
|
|
347
|
-
{ name: "mock", value: varRef(ctxLocal.id, ctxType, loc) },
|
|
348
|
-
],
|
|
349
|
-
type: mockType,
|
|
350
|
-
loc,
|
|
351
|
-
},
|
|
648
|
+
result: mockRecord(lowerer, mockType, ctxType, ctx(), loc),
|
|
352
649
|
type: mockType,
|
|
353
650
|
loc,
|
|
354
651
|
};
|
|
355
652
|
}
|
|
653
|
+
/** The trackers' restoreAll() and reset(): `mock.restoreAll()`,
|
|
654
|
+
* `t.mock.reset()`. */
|
|
655
|
+
export function lowerMockTrackerCall(lowerer, call, member, tracker) {
|
|
656
|
+
if (call.arguments.length > 0) {
|
|
657
|
+
lowerer.noLowering(`MockTracker.${member} with ${call.arguments.length} arguments`, call);
|
|
658
|
+
}
|
|
659
|
+
const fn = tracker
|
|
660
|
+
? member === "reset"
|
|
661
|
+
? "test.ctxMockReset"
|
|
662
|
+
: "test.ctxMockRestoreAll"
|
|
663
|
+
: member === "reset"
|
|
664
|
+
? "test.mockReset"
|
|
665
|
+
: "test.mockRestoreAll";
|
|
666
|
+
return {
|
|
667
|
+
kind: "libCall",
|
|
668
|
+
fn,
|
|
669
|
+
args: tracker ? [tracker] : [],
|
|
670
|
+
type: VOID,
|
|
671
|
+
loc: locOf(call),
|
|
672
|
+
};
|
|
673
|
+
}
|
|
356
674
|
/** `fn.mock.calls`: a copy of the log, as Node's getter returns. Null for
|
|
357
675
|
* other reads. */
|
|
358
676
|
export function lowerMockContextProperty(lowerer, expr) {
|
|
@@ -492,11 +810,9 @@ export function lowerMockContextCall(lowerer, call, access) {
|
|
|
492
810
|
], loc);
|
|
493
811
|
return helperCall(helper, []);
|
|
494
812
|
}
|
|
495
|
-
case "restore":
|
|
813
|
+
case "restore":
|
|
496
814
|
arity(0);
|
|
497
|
-
|
|
498
|
-
return helperCall(helper, []);
|
|
499
|
-
}
|
|
815
|
+
return helperCall(mockRestoreHelper(lowerer, ctxType, loc), []);
|
|
500
816
|
default:
|
|
501
817
|
return lowerer.noLowering(`MockFunctionContext.${member}`, call, "calls, callCount, mockImplementation, mockImplementationOnce, resetCalls and restore are the supported mock context members");
|
|
502
818
|
}
|