Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve internalization of functions to clean stack traces #2797

Merged
merged 1 commit into from
May 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/giant-cows-grab.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

Improve internalization of functions to clean stack traces
20 changes: 20 additions & 0 deletions packages/effect/src/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -784,3 +784,23 @@ export const structuralRegion = <A>(body: () => A, tester?: (a: unknown, b: unkn
structuralRegionState.tester = currentTester
}
}

const tracingFunction = (name: string) => {
const internalCall = <A>(body: () => A): A => body()
tim-smart marked this conversation as resolved.
Show resolved Hide resolved
Object.defineProperty(internalCall, "name", { value: name })
return internalCall
}

/**
* @since 3.2.2
* @status experimental
* @category tracing
*/
export const internalCall = tracingFunction("effect_internal_function")

/**
* @since 3.2.2
* @status experimental
* @category tracing
*/
export const internalGeneratorCall = tracingFunction("effect_internal_generator")
15 changes: 10 additions & 5 deletions packages/effect/src/internal/cause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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+/, "<anonymous>")
)
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+/, "<anonymous>")
)
}

if (span) {
Expand Down
16 changes: 7 additions & 9 deletions packages/effect/src/internal/core-effect.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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<any> | IteratorReturnResult<any>
): Effect.Effect<any, any, any> => {
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)
})
Expand Down Expand Up @@ -2166,18 +2170,12 @@ export const functionWithSpan = <Args extends Array<any>, 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,
Expand Down
24 changes: 10 additions & 14 deletions packages/effect/src/internal/core.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -459,10 +460,6 @@ export const as: {
/* @internal */
export const asVoid = <A, E, R>(self: Effect.Effect<A, E, R>): Effect.Effect<void, E, R> => as(self, void 0)

function commitCallCutpoint(this: any) {
return this.effect_cutpoint()
}

/* @internal */
export const custom: {
<X, A, E, R>(i0: X, body: (this: { effect_instruction_i0: X }) => Effect.Effect<A, E, R>): Effect.Effect<A, E, R>
Expand All @@ -481,24 +478,23 @@ export const custom: {
): Effect.Effect<A, E, R>
} = 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: {
Expand Down Expand Up @@ -538,9 +534,9 @@ export const async = <A, E = never, R = never>(
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, (_) => {
Expand Down Expand Up @@ -1011,8 +1007,8 @@ export const interruptibleMask = <A, E, R>(
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
})

Expand Down Expand Up @@ -1327,8 +1323,8 @@ export const uninterruptibleMask = <A, E, R>(
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
})

Expand Down
27 changes: 15 additions & 12 deletions packages/effect/src/internal/fiberRuntime.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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<any, any>,
Expand All @@ -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<any, any>,
Expand All @@ -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
}
Expand Down Expand Up @@ -1073,7 +1074,7 @@ export class FiberRuntime<in out A, in out E = never> 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)) {
Expand Down Expand Up @@ -1112,7 +1113,7 @@ export class FiberRuntime<in out A, in out E = never> 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))
}
Expand Down Expand Up @@ -1143,9 +1144,11 @@ export class FiberRuntime<in out A, in out E = never> implements Fiber.RuntimeFi
}

[OpCodes.OP_WITH_RUNTIME](op: core.Primitive & { _op: OpCodes.OP_WITH_RUNTIME }) {
return op.effect_instruction_i0(
this as FiberRuntime<unknown, unknown>,
FiberStatus.running(this._runtimeFlags) as FiberStatus.Running
return internalCall(() =>
op.effect_instruction_i0(
this as FiberRuntime<unknown, unknown>,
FiberStatus.running(this._runtimeFlags) as FiberStatus.Running
)
)
}

Expand Down Expand Up @@ -1207,7 +1210,7 @@ export class FiberRuntime<in out A, in out E = never> 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
}
Expand Down Expand Up @@ -1259,7 +1262,7 @@ export class FiberRuntime<in out A, in out E = never> implements Fiber.RuntimeFi
}

[OpCodes.OP_COMMIT](op: core.Primitive & { _op: OpCodes.OP_COMMIT }) {
return op.commit()
return internalCall(() => op.commit())
}

/**
Expand Down
23 changes: 14 additions & 9 deletions packages/effect/src/internal/stm/core.ts
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -504,15 +505,17 @@ export class STMDriver<in out R, out E, out A> {
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
}
Expand All @@ -521,7 +524,7 @@ export class STMDriver<in out R, out E, out A> {
if (cont === undefined) {
exit = TExit.retry
} else {
curr = cont.effect_instruction_i2() as Primitive
curr = internalCall(() => cont.effect_instruction_i2() as Primitive)
}
break
}
Expand All @@ -530,7 +533,9 @@ export class STMDriver<in out R, out E, out A> {
break
}
case OpCodes.OP_WITH_STM_RUNTIME: {
curr = current.effect_instruction_i1(this as STMDriver<unknown, unknown, unknown>) as Primitive
curr = internalCall(() =>
current.effect_instruction_i1(this as STMDriver<unknown, unknown, unknown>) as Primitive
)
break
}
case OpCodes.OP_ON_SUCCESS:
Expand All @@ -542,7 +547,7 @@ export class STMDriver<in out R, out E, out A> {
}
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)))
Expand All @@ -555,17 +560,17 @@ export class STMDriver<in out R, out E, out A> {
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
}
Expand Down