-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Simplify generic function call error reporting #16439
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
Conversation
Good work! I've used the same error reporting trick in my PR #16104. It's nice seeing it applied throughout. |
Note that this fixes #15116 by deleting all the offending code. It also obsoletes the fix, but not the side effect, of #15221. The error messages should still widen literals to their base types using the same condition that is found in For example: var result = concat(1, ""); // error
~~
!!! error TS2345: Argument of type '""' is not assignable to parameter of type '1'. The error should actually be var result = concat(1, ""); // error
~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. I think it is a simple change to extract I'm still looking at the test changes, but the code in checker looks much improved. |
Looking at the baseline changes I see that the old code sometimes widened literals and sometimes didn't, and the new code sometimes widens literal and sometimes doesn't. Strange. |
|
||
var r4 = foo((x: typeof a) => a, (x: typeof b) => b); // typeof a => typeof a | ||
>r4 : (x: { x: number; y?: number; }) => { x: number; y?: number; } | ||
>foo((x: typeof a) => a, (x: typeof b) => b) : (x: { x: number; y?: number; }) => { x: number; y?: number; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This inference from from the first argument is kind of weird. The result will not have z?: number
from typeof b
. It's arguably better than the error it replaces, but ideally the result would be typeof a & typeof b
in this case. I don't think that result can be generalised though, so maybe "surprising success" is the best we can do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously we'd require that one be an exact subtype of the other, which would fail. Now, we allow the call because assignability succeeds even though neither is a subtype of the other. I don't think this corner case much matters, and you can make just as good a case for succeeding as for failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like a nice improvement to me. A couple of test comments need to be looked at and updated. And a couple of errors now go away and give surprising results.
return cb; | ||
} | ||
|
||
var r8 = foo6(a); // error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update or remove comment
@@ -8,13 +8,15 @@ tests/cases/conformance/jsx/file.tsx(20,19): error TS2322: Type '{ func: (a: num | |||
Type '{ func: (a: number, b: string) => void; }' is not assignable to type '{ func: (arg: number) => void; }'. | |||
Types of property 'func' are incompatible. | |||
Type '(a: number, b: string) => void' is not assignable to type '(arg: number) => void'. | |||
tests/cases/conformance/jsx/file.tsx(31,9): error TS2605: JSX element type 'Element' is not a constructor function for JSX elements. | |||
Property 'render' is missing in type 'Element'. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yuit or @RyanCavanaugh This error is gone in the update basedline. But it looks bogus. Is it?
@@ -11,7 +10,6 @@ tests/cases/compiler/typeArgumentInferenceWithConstraintAsCommonRoot.ts(7,1): er | |||
var g: Giraffe; | |||
var e: Elephant; | |||
f(g, e); // valid because both Giraffe and Elephant satisfy the constraint. T is Animal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
update comment. looks like it doesn't find a common supertype any more. is it supposed to?
var a: { x: number; y?: number; }; | ||
var b: { x: number; z?: number; }; | ||
|
||
var r = foo(a, b); // { x: number; y?: number; }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem right - there's no error, and the type of r
is pretty arbitrary now. It seems like it'd be better to infer from the intersection of the remaining supertypes - this would give r
the correct type ({ x: number; y?: number} & { x: number; z?: number }
), and the leaf-node error messages will still be good.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think inferring an intersection of the remaining supertypes would be very non-intuitive. For example, in the simplest of cases we'd be telling you that string
isn't assignable to string & number
. It would just be a bogus type generator!
@sandersn Regarding your comment on widening, we are reporting the widened types of inferred type arguments, but beyond that we just rely on normal error reporting (and we don't artificially widen types in argument error reporting). The particular |
* Simplify error reporting for generic functions * Accept new baselines * Fix fourslash tests
This PR simplifies the way we report errors related to type inference for generic functions. Previously, type inference could fail when there was no common supertype for the inferences. With this PR type inference always succeeds, but may infer a set of types that don't match the argument list (which in turn causes an error when the call is type checked). Specifically, for a given list of type inference candidates, we now infer the leftmost type for which no type to the right is a supertype. This change leads to simpler error messages that seem to better match programmer intuitions.
Consider:
Previously, we'd report the following error:
Now, we simply report:
Effectively, we pinpoint the first argument that causes inference to fail instead of abstractly listing the incompatible types with no identification of their origin.
In addition to providing more intuitive error messages, we eliminate 120 lines of complex error reporting code (which has been the source of bugs in the past).