Skip to content

Commit

Permalink
Make sure GenKind utils are backward compatible & don't generate loops (
Browse files Browse the repository at this point in the history
#2625)

Co-authored-by: Tim <hello@timsmart.co>
  • Loading branch information
mikearnaldi and tim-smart committed Apr 26, 2024
1 parent 027418e commit ffe4f4e
Show file tree
Hide file tree
Showing 18 changed files with 158 additions and 69 deletions.
5 changes: 5 additions & 0 deletions .changeset/clever-meals-remember.md
@@ -0,0 +1,5 @@
---
"effect": patch
---

Avoid circularity on generators
5 changes: 5 additions & 0 deletions .changeset/many-laws-flash.md
@@ -0,0 +1,5 @@
---
"effect": patch
---

Make sure GenKind utilities are backward compatible
2 changes: 1 addition & 1 deletion packages/effect/src/Cause.ts
Expand Up @@ -194,7 +194,7 @@ export interface YieldableError extends Pipeable, Inspectable, Readonly<Error> {
readonly [Stream.StreamTypeId]: Effect.Effect.VarianceStruct<never, this, never>
readonly [Sink.SinkTypeId]: Sink.Sink.VarianceStruct<never, unknown, never, this, never>
readonly [Channel.ChannelTypeId]: Channel.Channel.VarianceStruct<never, unknown, this, unknown, never, unknown, never>
[Symbol.iterator](): Generator<Effect.Effect<never, this, never>, never>
[Symbol.iterator](): Effect.EffectGenerator<Effect.Effect<never, this, never>>
}

/**
Expand Down
15 changes: 8 additions & 7 deletions packages/effect/src/Effect.ts
Expand Up @@ -58,6 +58,7 @@ import type * as Supervisor from "./Supervisor.js"
import type * as Tracer from "./Tracer.js"
import type { Concurrency, Covariant, MergeRecord, NoInfer, NotFunction } from "./Types.js"
import type * as Unify from "./Unify.js"
import type { YieldWrap } from "./Utils.js"

// -------------------------------------------------------------------------------------
// models
Expand Down Expand Up @@ -103,7 +104,7 @@ export interface Effect<out A, out E = never, out R = never> extends Effect.Vari
* @category models
*/
export interface EffectGenerator<T extends Effect<any, any, any>> {
next(...args: ReadonlyArray<any>): IteratorResult<T, Effect.Success<T>>
next(...args: ReadonlyArray<any>): IteratorResult<YieldWrap<T>, Effect.Success<T>>
}

/**
Expand Down Expand Up @@ -1130,20 +1131,20 @@ export const dieSync: (evaluate: LazyArg<unknown>) => Effect<never> = core.dieSy
* @category constructors
*/
export const gen: {
<Eff extends Effect<any, any, any>, AEff>(
<Eff extends YieldWrap<Effect<any, any, any>>, AEff>(
f: (resume: Adapter) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never] ? never : [Eff] extends [Effect<infer _A, infer E, infer _R>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [Effect<infer _A, infer _E, infer R>] ? R : never
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Effect<infer _A, infer E, infer _R>>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Effect<infer _A, infer _E, infer R>>] ? R : never
>
<Self, Eff extends Effect<any, any, any>, AEff>(
<Self, Eff extends YieldWrap<Effect<any, any, any>>, AEff>(
self: Self,
f: (this: Self, resume: Adapter) => Generator<Eff, AEff, never>
): Effect<
AEff,
[Eff] extends [never] ? never : [Eff] extends [Effect<infer _A, infer E, infer _R>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [Effect<infer _A, infer _E, infer R>] ? R : never
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Effect<infer _A, infer E, infer _R>>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<Effect<infer _A, infer _E, infer R>>] ? R : never
>
} = effect.gen

Expand Down
18 changes: 15 additions & 3 deletions packages/effect/src/Either.ts
Expand Up @@ -4,7 +4,7 @@

import * as Equivalence from "./Equivalence.js"
import type { LazyArg } from "./Function.js"
import { constNull, constUndefined, dual, identity, pipe } from "./Function.js"
import { constNull, constUndefined, dual, identity } from "./Function.js"
import type { TypeLambda } from "./HKT.js"
import type { Inspectable } from "./Inspectable.js"
import * as either from "./internal/either.js"
Expand All @@ -14,7 +14,7 @@ import type { Predicate, Refinement } from "./Predicate.js"
import { isFunction } from "./Predicate.js"
import type { Covariant, MergeRecord, NoInfer, NotFunction } from "./Types.js"
import type * as Unify from "./Unify.js"
import type * as Gen from "./Utils.js"
import * as Gen from "./Utils.js"

/**
* @category models
Expand Down Expand Up @@ -698,24 +698,36 @@ export const all: <const I extends Iterable<Either<any, any>> | Record<string, E
*/
export const flip = <R, L>(self: Either<R, L>): Either<L, R> => isLeft(self) ? right(self.left) : left(self.right)

const adapter = Gen.adapter<EitherTypeLambda>()

/**
* @category generators
* @since 2.0.0
*/
export const gen: Gen.Gen<EitherTypeLambda, Gen.Adapter<EitherTypeLambda>> = (f) => {
const iterator = f(pipe)
const iterator = f(adapter)
let state: IteratorYieldResult<any> | IteratorReturnResult<any> = iterator.next()
if (state.done) {
return right(state.value) as any
} else {
let current = state.value
if (Gen.isGenKind(current)) {
current = current.value
} else {
current = Gen.yieldWrapGet(current)
}
if (isLeft(current)) {
return current
}
while (!state.done) {
state = iterator.next(current.right as never)
if (!state.done) {
current = state.value
if (Gen.isGenKind(current)) {
current = current.value
} else {
current = Gen.yieldWrapGet(current)
}
if (isLeft(current)) {
return current
}
Expand Down
18 changes: 15 additions & 3 deletions packages/effect/src/Option.ts
Expand Up @@ -5,7 +5,7 @@ import type { Either } from "./Either.js"
import * as Equal from "./Equal.js"
import * as Equivalence from "./Equivalence.js"
import type { LazyArg } from "./Function.js"
import { constNull, constUndefined, dual, identity, isFunction, pipe } from "./Function.js"
import { constNull, constUndefined, dual, identity, isFunction } from "./Function.js"
import type { TypeLambda } from "./HKT.js"
import type { Inspectable } from "./Inspectable.js"
import * as either from "./internal/either.js"
Expand All @@ -16,7 +16,7 @@ import type { Pipeable } from "./Pipeable.js"
import type { Predicate, Refinement } from "./Predicate.js"
import type { Covariant, NoInfer, NotFunction } from "./Types.js"
import type * as Unify from "./Unify.js"
import type * as Gen from "./Utils.js"
import * as Gen from "./Utils.js"

/**
* @category models
Expand Down Expand Up @@ -1261,24 +1261,36 @@ export const bind: {
*/
export const Do: Option<{}> = some({})

const adapter = Gen.adapter<OptionTypeLambda>()

/**
* @category generators
* @since 2.0.0
*/
export const gen: Gen.Gen<OptionTypeLambda, Gen.Adapter<OptionTypeLambda>> = (f) => {
const iterator = f(pipe)
const iterator = f(adapter)
let state: IteratorYieldResult<any> | IteratorReturnResult<any> = iterator.next()
if (state.done) {
return some(state.value)
} else {
let current = state.value
if (Gen.isGenKind(current)) {
current = current.value
} else {
current = Gen.yieldWrapGet(current)
}
if (isNone(current)) {
return current
}
while (!state.done) {
state = iterator.next(current.value as never)
if (!state.done) {
current = state.value
if (Gen.isGenKind(current)) {
current = current.value
} else {
current = Gen.yieldWrapGet(current)
}
if (isNone(current)) {
return current
}
Expand Down
7 changes: 4 additions & 3 deletions packages/effect/src/STM.ts
Expand Up @@ -16,6 +16,7 @@ import type { Pipeable } from "./Pipeable.js"
import type { Predicate, Refinement } from "./Predicate.js"
import type { Covariant, MergeRecord, NoInfer } from "./Types.js"
import type * as Unify from "./Unify.js"
import type { YieldWrap } from "./Utils.js"

/**
* @since 2.0.0
Expand Down Expand Up @@ -1064,12 +1065,12 @@ export interface Adapter {
* @since 2.0.0
* @category constructors
*/
export const gen: <Eff extends STM<any, any, any>, AEff>(
export const gen: <Eff extends YieldWrap<STM<any, any, any>>, AEff>(
f: (resume: Adapter) => Generator<Eff, AEff, never>
) => STM<
AEff,
[Eff] extends [never] ? never : [Eff] extends [STM<infer _A, infer E, infer _R>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [STM<infer _A, infer _E, infer R>] ? R : never
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<STM<infer _A, infer E, infer _R>>] ? E : never,
[Eff] extends [never] ? never : [Eff] extends [YieldWrap<STM<infer _A, infer _E, infer R>>] ? R : never
> = stm.gen

/**
Expand Down

0 comments on commit ffe4f4e

Please sign in to comment.