Skip to content

Conditional type triggers "No error for last overload signature" exception #55217

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

Open
Oblosys opened this issue Jul 31, 2023 · 4 comments · May be fixed by #55222
Open

Conditional type triggers "No error for last overload signature" exception #55217

Oblosys opened this issue Jul 31, 2023 · 4 comments · May be fixed by #55222
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone

Comments

@Oblosys
Copy link

Oblosys commented Jul 31, 2023

Bug Report

🔎 Search Terms

"No error for last overload signature" yields stale issue 35186, and a couple of more recent issues that got resolved: 48636, 37974. (The stale 35186 appears to be a different issue as it also occurs in versions before v5.0.4.)

🕗 Version & Regression Information

  • This is a crash
  • This changed between versions 4.9.5 and 5.0.4, and still occurs up to typescript@next.

⏯ Playground Link

Bug-workbench link with relevant code

💻 Code

// @filename: types.ts
export type ProductName = 'a' | 'b'

export type SubproductNameForProductName<P extends ProductName> = P extends unknown
  ? keyof EntitiesByProductName[P]
  : never

type EntitiesByProductName = {
  a: { a1: { value: 'a-a1' } }
  b: { b1: { value: 'b-b1' } }
}

export type DiscriminatedUnion<
  P extends ProductName = ProductName,
  E extends SubproductNameForProductName<P> = SubproductNameForProductName<P>,
> = P extends ProductName
    ? E extends SubproductNameForProductName<P>
    // ? E extends unknown // With unknown, the exception doesn't happen. 
      ? EntitiesByProductName[P][E]
      : never
    : never

// @filename: app.ts
import { SubproductNameForProductName, DiscriminatedUnion, ProductName } from './types'

export const bug = <P extends ProductName>() => {
  const subproducts: DiscriminatedUnion<P, SubproductNameForProductName<P>>[] = []
  subproducts.map((_: DiscriminatedUnion) => null)
}

🙁 Actual behavior

The compiler throws an exception:

/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:114747
      throw e;
      ^

Error: Debug Failure. No error for last overload signature
    at resolveCall (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:70223:19)
    at resolveCallExpression (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:70605:12)
    at resolveSignature (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:70988:16)
    at getResolvedSignature (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:71008:18)
    at checkCallExpression (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:71120:23)
    at checkExpressionWorker (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:74278:16)
    at checkExpression (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:74189:32)
    at maybeCheckExpression (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:73280:28)
    at BinaryExpressionStateMachine.onLeft (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:73216:16)
    at Array.left (/Users/martijn/git/Insify/insify-core/node_modules/typescript/lib/tsc.js:25140:30)

🙂 Expected behavior

No compiler exception.

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Jul 31, 2023
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 5.3.0 milestone Jul 31, 2023
@jakebailey
Copy link
Member

This crash bisects to #51771. @weswigham

@jakebailey
Copy link
Member

Adding this after structuredTypeRelatedTo in recusiveTypeRelatedTo shows the problem:

if (entry !== undefined) {
    // If the previous entry and the result disagree, then something has gone wrong.
    Debug.assert(!!(entry & RelationComparisonResult.Succeeded) === (result !== Ternary.False), "Cached relationship does not match recalculated result");
}

We first check if two types are related during call resolution. We get a failed relation result the first time, and add the node to a list to process later if all fail, ignoring errors (since a later candidate may work). That happens in this example, but when we check a second time with errors enabled, we somehow decide that they are related and then don't report any errors, firing the debug assert later.

@Andarist
Copy link
Contributor

When errors are not being reported relateVariances take a fast path here:
https://github.dev/microsoft/TypeScript/blob/cd23992100f8edd29ef9c29e29758008cdbeb8ec/src/compiler/checker.ts#L21954-L21956

Those variances fail there with:

Type 'ProductName' is not assignable to type 'P'.
  'ProductName' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'ProductName'.
    Type '"a"' is not assignable to type 'P'.
      '"a"' is assignable to the constraint of type 'P', but 'P' could be instantiated with a different subtype of constraint 'ProductName'.

When errors are reported though the compiler skips over that fast path and continues. It manages to successfully relate those types here with:

type DistributiveConstraint = (SubproductNameForProductName<P> extends "a1" ? { a1: { value: "a-a1"; }; }["a1" & SubproductNameForProductName<P>] : never) | (SubproductNameForProductName<P> extends "b1" ? { b1: { value: "b-b1"; }; }["b1" & SubproductNameForProductName<P>] : never)
type Target = DiscriminatedUnion

@jakebailey
Copy link
Member

Thanks for looking; deleting reportErrors && "fixes" things, it seems (code from #29817). Not sure if it's slower or something though. I may post that as a PR just to see what happens.

@jakebailey jakebailey linked a pull request Jul 31, 2023 that will close this issue
@jakebailey jakebailey added the Fix Available A PR has been opened for this issue label Aug 15, 2023
@RyanCavanaugh RyanCavanaugh added the Rescheduled This issue was previously scheduled to an earlier milestone label Mar 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue Rescheduled This issue was previously scheduled to an earlier milestone
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants