Skip to content

Commit

Permalink
move rehydration to capture
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-smart committed Sep 12, 2024
1 parent 212444d commit 7714ce1
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 129 deletions.
6 changes: 0 additions & 6 deletions packages/effect/src/Cause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1055,9 +1055,3 @@ export const FailureSpan: Context.Tag<"FailureSpan", Span> = internal.FailureSpa
* @category annotations
*/
export const InterruptorSpan: Context.Tag<"InterruptorSpan", Span> = internal.InterruptorSpan

/**
* @since 3.8.0
* @category annotations
*/
export const withAnnotationPropagationDisabled: <A>(f: () => A) => A = internal.withAnnotationPropagationDisabled
204 changes: 89 additions & 115 deletions packages/effect/src/internal/cause.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,15 @@ export const fail = <E>(error: E): Cause.Cause<E> => {
const o = Object.create(proto)
o._tag = OpCodes.OP_FAIL
o.error = error
return rehydrateAnnotations(o, error)
return o
}

/** @internal */
export const die = (defect: unknown): Cause.Cause<never> => {
const o = Object.create(proto)
o._tag = OpCodes.OP_DIE
o.defect = defect
return rehydrateAnnotations(o, defect)
return o
}

/** @internal */
Expand Down Expand Up @@ -987,95 +987,91 @@ export const reduce = dual<
export const reduceWithContext = dual<
<C, E, Z>(context: C, reducer: Cause.CauseReducer<C, E, Z>) => (self: Cause.Cause<E>) => Z,
<C, E, Z>(self: Cause.Cause<E>, context: C, reducer: Cause.CauseReducer<C, E, Z>) => Z
>(
3,
<C, E, Z>(self: Cause.Cause<E>, context: C, reducer: Cause.CauseReducer<C, E, Z>) =>
withAnnotationPropagationDisabled(() => {
let annotations = Context.empty()
const input: Array<Cause.Cause<E>> = [self]
const output: Array<Either.Either<Z, CauseCase>> = []
while (input.length > 0) {
const cause = input.pop()!
switch (cause._tag) {
case OpCodes.OP_EMPTY: {
output.push(Either.right(reducer.emptyCase(context, annotations)))
break
}
case OpCodes.OP_FAIL: {
output.push(Either.right(reducer.failCase(context, cause.error, annotations)))
break
}
case OpCodes.OP_DIE: {
output.push(Either.right(reducer.dieCase(context, cause.defect, annotations)))
break
}
case OpCodes.OP_INTERRUPT: {
output.push(Either.right(reducer.interruptCase(context, cause.fiberId, annotations)))
break
}
case OpCodes.OP_SEQUENTIAL: {
input.push(cause.right)
input.push(cause.left)
output.push(Either.left({ _tag: OP_SEQUENTIAL_CASE, annotations }))
break
}
case OpCodes.OP_PARALLEL: {
input.push(cause.right)
input.push(cause.left)
output.push(Either.left({ _tag: OP_PARALLEL_CASE, annotations }))
break
}
case OpCodes.OP_ANNOTATED: {
input.push(cause.cause)
output.push(Either.left({ _tag: OP_ANNOTATED_CASE, context: cause.context, annotations }))
annotations = Context.merge(annotations, cause.context)
>(3, <C, E, Z>(self: Cause.Cause<E>, context: C, reducer: Cause.CauseReducer<C, E, Z>) => {
let annotations = Context.empty()
const input: Array<Cause.Cause<E>> = [self]
const output: Array<Either.Either<Z, CauseCase>> = []
while (input.length > 0) {
const cause = input.pop()!
switch (cause._tag) {
case OpCodes.OP_EMPTY: {
output.push(Either.right(reducer.emptyCase(context, annotations)))
break
}
case OpCodes.OP_FAIL: {
output.push(Either.right(reducer.failCase(context, cause.error, annotations)))
break
}
case OpCodes.OP_DIE: {
output.push(Either.right(reducer.dieCase(context, cause.defect, annotations)))
break
}
case OpCodes.OP_INTERRUPT: {
output.push(Either.right(reducer.interruptCase(context, cause.fiberId, annotations)))
break
}
case OpCodes.OP_SEQUENTIAL: {
input.push(cause.right)
input.push(cause.left)
output.push(Either.left({ _tag: OP_SEQUENTIAL_CASE, annotations }))
break
}
case OpCodes.OP_PARALLEL: {
input.push(cause.right)
input.push(cause.left)
output.push(Either.left({ _tag: OP_PARALLEL_CASE, annotations }))
break
}
case OpCodes.OP_ANNOTATED: {
input.push(cause.cause)
output.push(Either.left({ _tag: OP_ANNOTATED_CASE, context: cause.context, annotations }))
annotations = Context.merge(annotations, cause.context)
break
}
}
}
const accumulator: Array<Z> = []
while (output.length > 0) {
const either = output.pop()!
switch (either._tag) {
case "Left": {
switch (either.left._tag) {
case OP_SEQUENTIAL_CASE: {
const left = accumulator.pop()!
const right = accumulator.pop()!
const value = reducer.sequentialCase(context, left, right, either.left.annotations)
accumulator.push(value)
break
}
}
}
const accumulator: Array<Z> = []
while (output.length > 0) {
const either = output.pop()!
switch (either._tag) {
case "Left": {
switch (either.left._tag) {
case OP_SEQUENTIAL_CASE: {
const left = accumulator.pop()!
const right = accumulator.pop()!
const value = reducer.sequentialCase(context, left, right, either.left.annotations)
accumulator.push(value)
break
}
case OP_PARALLEL_CASE: {
const left = accumulator.pop()!
const right = accumulator.pop()!
const value = reducer.parallelCase(context, left, right, either.left.annotations)
accumulator.push(value)
break
}
case OP_ANNOTATED_CASE: {
const out = accumulator.pop()!
const value = reducer.annotatedCase(context, out, either.left.context, either.left.annotations)
accumulator.push(value)
break
}
}
case OP_PARALLEL_CASE: {
const left = accumulator.pop()!
const right = accumulator.pop()!
const value = reducer.parallelCase(context, left, right, either.left.annotations)
accumulator.push(value)
break
}
case "Right": {
accumulator.push(either.right)
case OP_ANNOTATED_CASE: {
const out = accumulator.pop()!
const value = reducer.annotatedCase(context, out, either.left.context, either.left.annotations)
accumulator.push(value)
break
}
}
break
}
if (accumulator.length === 0) {
throw new Error(
"BUG: Cause.reduceWithContext - please report an issue at https://github.com/Effect-TS/effect/issues"
)
case "Right": {
accumulator.push(either.right)
break
}
return accumulator.pop()!
})
)
}
}
if (accumulator.length === 0) {
throw new Error(
"BUG: Cause.reduceWithContext - please report an issue at https://github.com/Effect-TS/effect/issues"
)
}
return accumulator.pop()!
})

// -----------------------------------------------------------------------------
// Pretty Printing
Expand Down Expand Up @@ -1285,9 +1281,6 @@ export const InterruptorSpan = Context.GenericTag<"InterruptorSpan", Span>("effe

const originalAnnotationsSymbol = Symbol.for("effect/Cause/originalAnnotationsSymbol")
const originalInstanceSymbol = Symbol.for("effect/Cause/originalInstanceSymbol")
const annotationState = globalValue("effect/Cause/annotationState", () => ({
disablePropagation: false
}))

/* @internal */
export const originalAnnotations = <E>(obj: E): Context.Context<never> | undefined => {
Expand Down Expand Up @@ -1328,36 +1321,17 @@ function addOriginalAnnotations<E>(obj: E, annotations: Context.Context<never>):
})
}

const AnnotationsReducer: Cause.CauseReducer<Context.Context<never>, unknown, Cause.Cause<any>> = {
emptyCase: (_) => empty,
failCase: (context, error, annotations) => fail(addOriginalAnnotations(error, Context.merge(context, annotations))),
dieCase: (context, defect, annotations) => die(addOriginalAnnotations(defect, Context.merge(context, annotations))),
interruptCase: (_, fiberId) => interrupt(fiberId),
sequentialCase: (_, left, right) => sequential(left, right),
parallelCase: (_, left, right) => parallel(left, right),
annotatedCase: (context, cause, annotations) => annotated(cause, Context.merge(context, annotations))
}

const propagateAnnotations = <E>(self: Cause.Cause<E>, context: Context.Context<never>): Cause.Cause<E> =>
annotationState.disablePropagation ? self : reduceWithContext(self, context, AnnotationsReducer)

const rehydrateAnnotations = <E>(self: Cause.Cause<E>, obj: unknown): Cause.Cause<E> => {
if (annotationState.disablePropagation) {
return self
}
if (hasProperty(obj, originalAnnotationsSymbol)) {
return annotated(self, (obj as any)[originalAnnotationsSymbol])
}
return self
}

/** @internal */
export const withAnnotationPropagationDisabled = <A>(f: () => A): A => {
try {
annotationState.disablePropagation = true
return f()
} finally {
annotationState.disablePropagation = false
const propagateAnnotations = <E>(self: Cause.Cause<E>, context: Context.Context<never>): Cause.Cause<E> => {
switch (self._tag) {
case "Die": {
return die(addOriginalAnnotations(self.defect, context))
}
case "Fail": {
return fail(addOriginalAnnotations(self.error, context))
}
default: {
return self
}
}
}

Expand Down
22 changes: 14 additions & 8 deletions packages/effect/src/internal/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -662,14 +662,19 @@ export const checkInterruptible = <A, E, R>(
f: (isInterruptible: boolean) => Effect.Effect<A, E, R>
): Effect.Effect<A, E, R> => withFiberRuntime((_, status) => f(_runtimeFlags.interruption(status.runtimeFlags)))

const capture = <E>(cause: Cause.Cause<E>): Effect.Effect<never, E> =>
const capture = <E>(cause: Cause.Cause<E>, obj?: unknown): Effect.Effect<never, E> =>
withFiberRuntime((fiber) => {
const span = currentSpanFromFiber(fiber)
let context = Context.empty()
if (span._tag === "Some") {
context = Context.add(context, internalCause.FailureSpan, span.value)
const originalAnnotations = internalCause.originalAnnotations(obj)
if (originalAnnotations) {
cause = internalCause.annotated(cause, originalAnnotations)
} else {
const span = currentSpanFromFiber(fiber)
let context = Context.empty()
if (span._tag === "Some") {
context = Context.add(context, internalCause.FailureSpan, span.value)
}
cause = Context.isEmpty(context) ? cause : internalCause.annotated(cause, context)
}
cause = Context.isEmpty(context) ? cause : internalCause.annotated(cause, context)
const effect = new EffectPrimitiveFailure(OpCodes.OP_FAILURE) as any
effect.effect_instruction_i0 = cause
return effect
Expand Down Expand Up @@ -709,10 +714,11 @@ export const failSync = <E>(evaluate: LazyArg<E>): Effect.Effect<never, E> => fl
export const failCause = <E>(cause: Cause.Cause<E>): Effect.Effect<never, E> => {
switch (cause._tag) {
case "Fail":
return capture(cause, cause.error)
case "Die":
case "Interrupt": {
return capture(cause, cause.defect)
case "Interrupt":
return capture(cause)
}
default: {
const effect = new EffectPrimitiveFailure(OpCodes.OP_FAILURE) as any
effect.effect_instruction_i0 = cause
Expand Down

0 comments on commit 7714ce1

Please sign in to comment.