Skip to content

Regression in 7.1 (#64553): R inferred as unknown through a generic type alias call signature with a nested same-type argument #64757

Open

Description

@kennysarnoski-jarvis

Note

🤖 Claude Opus 5.5 writing on behalf of Kenny

🔎 Search Terms

inference unknown, generic type alias call signature, generator, invokeOnce, isDeeplyNestedType, #64553, cache inferences type arguments, regression 7.1

🕗 Version & Regression Information

⏯ Playground Link

No playground link. The code below is self-contained, with no dependencies.

💻 Code

interface Effect<out A, out R = never> {
  readonly _A: () => A;
  readonly _R: () => R;
  [Symbol.iterator](): Iterator<Effect<A, R>, A>;
}
declare function succeed<A>(value: A): Effect<A>;
declare function gen<Eff extends Effect<any, any>, AEff>(
  body: () => Generator<Eff, AEff, never>,
): () => Effect<AEff, Eff extends Effect<infer _A, infer R> ? R : never>;

interface Req { readonly url: string }
declare const req: Effect<Req, Req>;

type Make<P> = <R>(m: Effect<() => Effect<string, R>>) => [R];
declare const make: Make<unknown>;

const r = make(succeed(gen(function* () {
  yield* req;
  return "";
})));
const check: [1] = r; // error message shows what R was inferred as

tsconfig.json: { "compilerOptions": { "target": "ES2023", "module": "NodeNext", "strict": true, "noEmit": true } }

Version r
5.9.3 [Req]
7.1.0-dev.20260929.1 [Req]
7.1.0-dev.20261001.1 [unknown]
7.1.0-dev.20261012.1 [unknown]

🙁 Actual behavior

R is inferred as unknown, so r is [unknown].

🙂 Expected behavior

R is inferred as Req, so r is [Req], as in 5.9.3, 7.0.2 and 7.1.0-dev.20260929.1.

Additional information about the issue

The tsc-rs maintainers traced it to the depth-2 nesting check in invokeOnce (isDeeplyNestedType(..., 2), about line 363 of inference.go). #64553 now sends the Effect/Effect pair through it. For Effect<() => Effect<A, R>>, the check treats the inner pair as a cycle and infers nothing for the inner R. It only happens when the signature comes from an instantiated generic type alias (Make<P> above). Calling a plain generic function with the same shape infers Req.

Real-world impact: this is the shape of Effect 4's HttpRouter.middleware<...>()(...), whose signature is the generic alias middleware.Make<Provides, Handles>. A middleware written with Effect.fn or Effect.gen that reads the request gets R = unknown, and .layer resolves to the string type "Need to .combine(middleware) that satisfy the missing request dependencies". In one Effect app this cascades into 145 errors.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions