From 86d13eca9bb3ecd28108ae65e3979280334689b3 Mon Sep 17 00:00:00 2001 From: Michael Arnaldi Date: Tue, 21 May 2024 16:46:18 +0200 Subject: [PATCH] Improve internalization of functions to clean stack traces --- .changeset/giant-cows-grab.md | 5 ++++ packages/effect/src/Utils.ts | 23 +++++++++++++++++ packages/effect/src/internal/cause.ts | 15 +++++++---- packages/effect/src/internal/core-effect.ts | 16 +++++------- packages/effect/src/internal/core.ts | 24 ++++++++--------- packages/effect/src/internal/fiberRuntime.ts | 27 +++++++++++--------- packages/effect/src/internal/stm/core.ts | 23 ++++++++++------- 7 files changed, 84 insertions(+), 49 deletions(-) create mode 100644 .changeset/giant-cows-grab.md diff --git a/.changeset/giant-cows-grab.md b/.changeset/giant-cows-grab.md new file mode 100644 index 0000000000..16afb9de4b --- /dev/null +++ b/.changeset/giant-cows-grab.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Improve internalization of functions to clean stack traces diff --git a/packages/effect/src/Utils.ts b/packages/effect/src/Utils.ts index 9e372e8c67..66e108a98e 100644 --- a/packages/effect/src/Utils.ts +++ b/packages/effect/src/Utils.ts @@ -784,3 +784,26 @@ export const structuralRegion = (body: () => A, tester?: (a: unknown, b: unkn structuralRegionState.tester = currentTester } } + +export const { + /** + * @since 3.2.2 + * @status experimental + * @category tracing + */ + internalCall, + /** + * @since 3.2.2 + * @status experimental + * @category tracing + */ + internalGeneratorCall +} = (() => { + const internalCall = (body: () => A): A => body() + const internalGeneratorCall = (body: () => A): A => body() + + Object.defineProperty(internalCall, "name", { value: "effect_internal_function" }) + Object.defineProperty(internalGeneratorCall, "name", { value: "effect_internal_generator" }) + + return { internalCall, internalGeneratorCall } +})() diff --git a/packages/effect/src/internal/cause.ts b/packages/effect/src/internal/cause.ts index d4714d8841..dcdfe6b6e9 100644 --- a/packages/effect/src/internal/cause.ts +++ b/packages/effect/src/internal/cause.ts @@ -1057,15 +1057,20 @@ const prettyErrorStack = (message: string, stack: string, span?: Span | undefine const lines = stack.split("\n") for (let i = 1; i < lines.length; i++) { - if (lines[i].includes("effect_cutpoint") || lines[i].includes("Generator.next")) { + if (lines[i].includes("effect_internal_function")) { + out.pop() break } - out.push( - lines[i].replace(/at .*effect_instruction_i.*\((.*)\)/, "at $1").replace(/EffectPrimitive\.\w+/, "") - ) - if (lines[i].includes("effect_instruction_i")) { + if (lines[i].includes("effect_internal_generator")) { + out.pop() + out.pop() break } + out.push( + lines[i] + .replace(/at .*effect_instruction_i.*\((.*)\)/, "at $1") + .replace(/EffectPrimitive\.\w+/, "") + ) } if (span) { diff --git a/packages/effect/src/internal/core-effect.ts b/packages/effect/src/internal/core-effect.ts index d8fed1c20a..aae00cfc55 100644 --- a/packages/effect/src/internal/core-effect.ts +++ b/packages/effect/src/internal/core-effect.ts @@ -1,3 +1,4 @@ +import { internalCall, internalGeneratorCall } from "effect/Utils" import * as Arr from "../Array.js" import type * as Cause from "../Cause.js" import * as Chunk from "../Chunk.js" @@ -771,13 +772,16 @@ export const gen: typeof Effect.gen = function() { } return core.suspend(() => { const iterator = f(pipe) - const state = iterator.next() + const state = internalGeneratorCall(() => iterator.next()) const run = ( state: IteratorYieldResult | IteratorReturnResult ): Effect.Effect => { return (state.done ? core.succeed(state.value) - : core.flatMap(yieldWrapGet(state.value) as any, (val: any) => run(iterator.next(val)))) + : core.flatMap( + yieldWrapGet(state.value) as any, + (val: any) => run(internalGeneratorCall(() => iterator.next(val))) + )) } return run(state) }) @@ -2166,18 +2170,12 @@ export const functionWithSpan = , Ret extends Effect.Eff captureStackTrace = stack.slice(2).join("\n").trim() } } - // eslint-disable-next-line @typescript-eslint/no-this-alias - const self = this - const args = arguments return core.suspend(() => { const opts = typeof options.options === "function" ? options.options.apply(null, arguments as any) : options.options - return withSpan( - core.custom(options.body, function() { - return this.effect_instruction_i0.apply(self, args as any) - }), + core.suspend(() => internalCall(() => options.body.apply(this, arguments as any))), opts.name, { ...opts, diff --git a/packages/effect/src/internal/core.ts b/packages/effect/src/internal/core.ts index 0924417510..639df94431 100644 --- a/packages/effect/src/internal/core.ts +++ b/packages/effect/src/internal/core.ts @@ -1,3 +1,4 @@ +import { internalCall } from "effect/Utils" import * as Arr from "../Array.js" import type * as Cause from "../Cause.js" import * as Chunk from "../Chunk.js" @@ -459,10 +460,6 @@ export const as: { /* @internal */ export const asVoid = (self: Effect.Effect): Effect.Effect => as(self, void 0) -function commitCallCutpoint(this: any) { - return this.effect_cutpoint() -} - /* @internal */ export const custom: { (i0: X, body: (this: { effect_instruction_i0: X }) => Effect.Effect): Effect.Effect @@ -481,24 +478,23 @@ export const custom: { ): Effect.Effect } = function() { const wrapper = new EffectPrimitive(OpCodes.OP_COMMIT) as any - wrapper.commit = commitCallCutpoint switch (arguments.length) { case 2: { wrapper.effect_instruction_i0 = arguments[0] - wrapper.effect_cutpoint = arguments[1] + wrapper.commit = arguments[1] break } case 3: { wrapper.effect_instruction_i0 = arguments[0] wrapper.effect_instruction_i1 = arguments[1] - wrapper.effect_cutpoint = arguments[2] + wrapper.commit = arguments[2] break } case 4: { wrapper.effect_instruction_i0 = arguments[0] wrapper.effect_instruction_i1 = arguments[1] wrapper.effect_instruction_i2 = arguments[2] - wrapper.effect_cutpoint = arguments[3] + wrapper.commit = arguments[3] break } default: { @@ -538,9 +534,9 @@ export const async = ( let controllerRef: AbortController | void = undefined if (this.effect_instruction_i0.length !== 1) { controllerRef = new AbortController() - cancelerRef = this.effect_instruction_i0(proxyResume, controllerRef.signal) + cancelerRef = internalCall(() => this.effect_instruction_i0(proxyResume, controllerRef!.signal)) } else { - cancelerRef = (this.effect_instruction_i0 as any)(proxyResume) + cancelerRef = internalCall(() => (this.effect_instruction_i0 as any)(proxyResume)) } return (cancelerRef || controllerRef) ? onInterrupt(effect, (_) => { @@ -1011,8 +1007,8 @@ export const interruptibleMask = ( effect.effect_instruction_i0 = RuntimeFlagsPatch.enable(_runtimeFlags.Interruption) effect.effect_instruction_i1 = (oldFlags: RuntimeFlags.RuntimeFlags) => _runtimeFlags.interruption(oldFlags) - ? this.effect_instruction_i0(interruptible) - : this.effect_instruction_i0(uninterruptible) + ? internalCall(() => this.effect_instruction_i0(interruptible)) + : internalCall(() => this.effect_instruction_i0(uninterruptible)) return effect }) @@ -1327,8 +1323,8 @@ export const uninterruptibleMask = ( effect.effect_instruction_i0 = RuntimeFlagsPatch.disable(_runtimeFlags.Interruption) effect.effect_instruction_i1 = (oldFlags: RuntimeFlags.RuntimeFlags) => _runtimeFlags.interruption(oldFlags) - ? this.effect_instruction_i0(interruptible) - : this.effect_instruction_i0(uninterruptible) + ? internalCall(() => this.effect_instruction_i0(interruptible)) + : internalCall(() => this.effect_instruction_i0(uninterruptible)) return effect }) diff --git a/packages/effect/src/internal/fiberRuntime.ts b/packages/effect/src/internal/fiberRuntime.ts index f61565e808..96d204ae60 100644 --- a/packages/effect/src/internal/fiberRuntime.ts +++ b/packages/effect/src/internal/fiberRuntime.ts @@ -1,3 +1,4 @@ +import { internalCall } from "effect/Utils" import * as RA from "../Array.js" import * as Boolean from "../Boolean.js" import type * as Cause from "../Cause.js" @@ -146,7 +147,7 @@ const contOpSuccess = { cont: core.OnSuccess, value: unknown ) => { - return cont.effect_instruction_i1(value) + return internalCall(() => cont.effect_instruction_i1(value)) }, ["OnStep"]: ( _: FiberRuntime, @@ -160,7 +161,7 @@ const contOpSuccess = { cont: core.OnSuccessAndFailure, value: unknown ) => { - return cont.effect_instruction_i2(value) + return internalCall(() => cont.effect_instruction_i2(value)) }, [OpCodes.OP_REVERT_FLAGS]: ( self: FiberRuntime, @@ -179,10 +180,10 @@ const contOpSuccess = { cont: core.While, value: unknown ) => { - cont.effect_instruction_i2(value) - if (cont.effect_instruction_i0()) { + internalCall(() => cont.effect_instruction_i2(value)) + if (internalCall(() => cont.effect_instruction_i0())) { self.pushStack(cont) - return cont.effect_instruction_i1() + return internalCall(() => cont.effect_instruction_i1()) } else { return core.void } @@ -1073,7 +1074,7 @@ export class FiberRuntime implements Fiber.RuntimeFi } [OpCodes.OP_SYNC](op: core.Primitive & { _op: OpCodes.OP_SYNC }) { - const value = op.effect_instruction_i0() + const value = internalCall(() => op.effect_instruction_i0()) const cont = this.getNextSuccessCont() if (cont !== undefined) { if (!(cont._op in contOpSuccess)) { @@ -1112,7 +1113,7 @@ export class FiberRuntime implements Fiber.RuntimeFi case OpCodes.OP_ON_FAILURE: case OpCodes.OP_ON_SUCCESS_AND_FAILURE: { if (!(_runtimeFlags.interruptible(this._runtimeFlags) && this.isInterrupted())) { - return cont.effect_instruction_i1(cause) + return internalCall(() => cont.effect_instruction_i1(cause)) } else { return core.exitFailCause(internalCause.stripFailures(cause)) } @@ -1143,9 +1144,11 @@ export class FiberRuntime implements Fiber.RuntimeFi } [OpCodes.OP_WITH_RUNTIME](op: core.Primitive & { _op: OpCodes.OP_WITH_RUNTIME }) { - return op.effect_instruction_i0( - this as FiberRuntime, - FiberStatus.running(this._runtimeFlags) as FiberStatus.Running + return internalCall(() => + op.effect_instruction_i0( + this as FiberRuntime, + FiberStatus.running(this._runtimeFlags) as FiberStatus.Running + ) ) } @@ -1207,7 +1210,7 @@ export class FiberRuntime implements Fiber.RuntimeFi // Since we updated the flags, we need to revert them const revertFlags = _runtimeFlags.diff(newRuntimeFlags, oldRuntimeFlags) this.pushStack(new core.RevertFlags(revertFlags, op)) - return op.effect_instruction_i1(oldRuntimeFlags) + return internalCall(() => op.effect_instruction_i1!(oldRuntimeFlags)) } else { return core.exitVoid } @@ -1259,7 +1262,7 @@ export class FiberRuntime implements Fiber.RuntimeFi } [OpCodes.OP_COMMIT](op: core.Primitive & { _op: OpCodes.OP_COMMIT }) { - return op.commit() + return internalCall(() => op.commit()) } /** diff --git a/packages/effect/src/internal/stm/core.ts b/packages/effect/src/internal/stm/core.ts index b60bf51a93..f89369bad0 100644 --- a/packages/effect/src/internal/stm/core.ts +++ b/packages/effect/src/internal/stm/core.ts @@ -1,3 +1,4 @@ +import { internalCall } from "effect/Utils" import * as Cause from "../../Cause.js" import * as Context from "../../Context.js" import * as Effect from "../../Effect.js" @@ -504,15 +505,17 @@ export class STMDriver { case "Commit": { switch (current.effect_instruction_i0) { case OpCodes.OP_DIE: { - exit = TExit.die(current.effect_instruction_i1()) + exit = TExit.die(internalCall(() => current.effect_instruction_i1())) break } case OpCodes.OP_FAIL: { const cont = this.nextFailure() if (cont === undefined) { - exit = TExit.fail(current.effect_instruction_i1()) + exit = TExit.fail(internalCall(() => current.effect_instruction_i1())) } else { - curr = cont.effect_instruction_i2(current.effect_instruction_i1()) as Primitive + curr = internalCall(() => + cont.effect_instruction_i2(internalCall(() => current.effect_instruction_i1())) as Primitive + ) } break } @@ -521,7 +524,7 @@ export class STMDriver { if (cont === undefined) { exit = TExit.retry } else { - curr = cont.effect_instruction_i2() as Primitive + curr = internalCall(() => cont.effect_instruction_i2() as Primitive) } break } @@ -530,7 +533,9 @@ export class STMDriver { break } case OpCodes.OP_WITH_STM_RUNTIME: { - curr = current.effect_instruction_i1(this as STMDriver) as Primitive + curr = internalCall(() => + current.effect_instruction_i1(this as STMDriver) as Primitive + ) break } case OpCodes.OP_ON_SUCCESS: @@ -542,7 +547,7 @@ export class STMDriver { } case OpCodes.OP_PROVIDE: { const env = this.env - this.env = current.effect_instruction_i2(env) + this.env = internalCall(() => current.effect_instruction_i2(env)) curr = pipe( current.effect_instruction_i1, ensuring(sync(() => (this.env = env))) @@ -555,17 +560,17 @@ export class STMDriver { if (cont === undefined) { exit = TExit.succeed(value) } else { - curr = cont.effect_instruction_i2(value) as Primitive + curr = internalCall(() => cont.effect_instruction_i2(value) as Primitive) } break } case OpCodes.OP_SYNC: { - const value = current.effect_instruction_i1() + const value = internalCall(() => current.effect_instruction_i1()) const cont = this.nextSuccess() if (cont === undefined) { exit = TExit.succeed(value) } else { - curr = cont.effect_instruction_i2(value) as Primitive + curr = internalCall(() => cont.effect_instruction_i2(value) as Primitive) } break }