Typescript: 3.6 regression: `Error: Debug Failure. No error for last overload signature`

Created on 29 Aug 2019  Β·  14Comments  Β·  Source: microsoft/TypeScript


TypeScript Version: 3.6.2


Search Terms: debug failure overload signature

After upgrading our large app from TS 3.5.2 to to TS 3.6.2, we get the following error when running tsc:

$ tsc  --project tsconfig.json
/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:75634
                throw e;
                ^

Error: Debug Failure. No error for last overload signature
    at resolveCall (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:43576:38)
    at resolveJsxOpeningLikeElement (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44148:20)
    at resolveSignature (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44169:28)
    at getResolvedSignature (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44180:26)
    at checkJsxOpeningLikeElementOrOpeningFragment (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:42398:27)
    at checkJsxSelfClosingElementDeferred (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:42042:13)
    at checkDeferredNode (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50211:21)
    at Map.forEach (<anonymous>)
    at checkDeferredNodes (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50189:37)
    at checkSourceFileWorker (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50249:17)
Bug Crash Fix Available

Most helpful comment

Standalone repro:

interface F<P> {
    (props: P & { children?: boolean }): void;
    propTypes: { [K in keyof P]: null extends P ? K : K };
}
declare function g(C: F<unknown>): string;
export function wu<CP extends { o: object }>(CC: F<CP>) {
    class WU {
        m() {
            g(CC)
            return <CC {...(null as CP)} />;
        }
    }
}

This is, admittedly, super weird.

All 14 comments

I added that assert in 3.6 to catch an incorrect state during error reporting. So, uh, looks like you caught it!

This needs a smaller repro before I can continue. When I get to my desk I’ll come up with an assert message that dumps the current file or the text of the node. That way you can modify tsc.js to pinpoint the call.

That would be great, thanks @sandersn

  1. In tsc.js, search for
                            Debug.fail("No error for last overload signature");

and change to

                            var s = "\nCall:"  + getTextOfNode(node) + "\nDeclarations:\t" + candidatesForArgumentError.map(c => c.declaration ? getTextOfNode(c.declaration) : "no declaration found").join(",");
                            Debug.fail("No error for last overload signature" + s);

We should consider making Debug.fail take a node or nodes to print.

Had to change getTextOfNode to ts.getTextOfNode and Debug to ts.Debug, then I got this:

$ tsc  --project tsconfig.json
/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:75635
                throw e;
                ^

Error: Debug Failure. No error for last overload signature
Call:<ComposedComponent
                {
                  // Cast is workaround for https://github.com/microsoft/TypeScript/issues/28884
                  ...({
                    renderType,
                    ...this.props,
                  } as ComposedProps)
                }
              />
Declarations:   (props: PropsWithChildren<P>, context?: any): ReactElement | null;
    at resolveCall (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:43577:38)
    at resolveJsxOpeningLikeElement (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44149:20)
    at resolveSignature (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44170:28)
    at getResolvedSignature (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:44181:26)
    at checkJsxOpeningLikeElementOrOpeningFragment (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:42398:27)
    at checkJsxSelfClosingElementDeferred (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:42042:13)
    at checkDeferredNode (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50212:21)
    at Map.forEach (<anonymous>)
    at checkDeferredNodes (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50190:37)
    at checkSourceFileWorker (/Users/oliverash/Development/unsplash-web/node_modules/typescript/lib/tsc.js:50250:17)

The code printed in this error is from this file: https://gist.github.com/OliverJAsh/bebfe1c5690d2e79317103c2b6c4bb9e

Thanks, that's a pretty small repro. Hopefully the external dependencies (besides react) are not needed.

Here's a reduced test case:

./package.json:

{
  "dependencies": {
    "@types/react": "16.9.2",
    "typescript": "3.6.2"
  }
}

./tsconfig.json:

{
    "compilerOptions": {
        "target": "es2015",
        "jsx": "react",
        "moduleResolution": "node"
    }
}

./main.tsx:

import * as React from 'react';
import { Component, ComponentType } from 'react';

const getDisplayName = (ComposedComponent: ComponentType<unknown>) =>
    ComposedComponent.displayName;

type RenderTypeProp = { renderType: object };

export const withRenderType = <ComposedProps extends RenderTypeProp>(
    ComposedComponent: ComponentType<ComposedProps>,
) => {
    const displayName = `WithRenderType(${getDisplayName(ComposedComponent)})`;

    class WithRenderType extends Component<ComposedProps> {
        static displayName = displayName;

        render() {
            return <ComposedComponent {...(this.props as ComposedProps)} />;
        }
    }

    return WithRenderType;
};

Workaround for now:

-    const displayName = `WithRenderType(${getDisplayName(ComposedComponent)})`;
+    const displayName = `WithRenderType(${ComposedComponent.displayName})`;

Requires "strict": false to repro.

Specifically, strictFunctionTypes: false

Smaller repro:

import { ComponentType } from 'react';
declare function getDisplayName(ComposedComponent: ComponentType<unknown>): string;
export function wu<CP extends { renderType: object }>(CC: ComponentType<CP>) {
    class WU {
        m() {
            getDisplayName(CC)
            return <CC {...(this.props as CP)} />;
        }
    }
};

Standalone repro:

interface F<P> {
    (props: P & { children?: boolean }): void;
    propTypes: { [K in keyof P]: null extends P ? K : K };
}
declare function g(C: F<unknown>): string;
export function wu<CP extends { o: object }>(CC: F<CP>) {
    class WU {
        m() {
            g(CC)
            return <CC {...(null as CP)} />;
        }
    }
}

This is, admittedly, super weird.

The basic problem is that the flag isIntersectionConstituent, which is used to exempt intersection constituents from common-property checks ("weak types"), isn't threaded through one particular intersection call in assignability checking. I missed it when threading that flag through more calls in 3.6 (https://github.com/microsoft/TypeScript/pull/32582), and my new assertion in overload error reporting caught the mistake. It's quite likely that this assert would have fired a lot more before #32582.

@sandersn Works for me now in [email protected]. Thanks!

I ran into this with 3.8. Should I try to make a reproduction repo?

For my own ref: this happened at 27541dbd0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wmaurer picture wmaurer  Β·  3Comments

Antony-Jones picture Antony-Jones  Β·  3Comments

fwanicka picture fwanicka  Β·  3Comments

kyasbal-1994 picture kyasbal-1994  Β·  3Comments

zhuravlikjb picture zhuravlikjb  Β·  3Comments