-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Fix inference for contextually typed parameters with initializers #29576
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
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
8f5ef10
Don't infer from initializers of parameters of contextually typed fun…
ahejlsberg 318678a
Accept new baselines
ahejlsberg 1bc4389
Add tests
ahejlsberg 58e39ea
Accept new baselines
ahejlsberg 22d46ac
Don't report circularities when parameter has itself as contextual type
ahejlsberg c6ccc5b
Address CR feedback
ahejlsberg 69d1048
Accept new baselines
ahejlsberg 25ac1ed
Merge branch 'master' into fixContextuallyTypedParameters
ahejlsberg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
42 changes: 42 additions & 0 deletions
42
tests/baselines/reference/contextuallyTypedParametersWithInitializers.errors.txt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(8,29): error TS7031: Binding element 'foo' implicitly has an 'any' type. | ||
tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(14,27): error TS7006: Parameter 'foo' implicitly has an 'any' type. | ||
tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts(27,42): error TS7031: Binding element 'foo' implicitly has an 'any' type. | ||
|
||
|
||
==== tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts (3 errors) ==== | ||
declare function id1<T>(input: T): T; | ||
declare function id2<T extends (x: any) => any>(input: T): T; | ||
declare function id3<T extends (x: { foo: any }) => any>(input: T): T; | ||
declare function id4<T extends (x: { foo?: number }) => any>(input: T): T; | ||
declare function id5<T extends (x?: number) => any>(input: T): T; | ||
|
||
const f10 = function ({ foo = 42 }) { return foo }; | ||
const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error | ||
~~~ | ||
!!! error TS7031: Binding element 'foo' implicitly has an 'any' type. | ||
const f12 = id2(function ({ foo = 42 }) { return foo }); | ||
const f13 = id3(function ({ foo = 42 }) { return foo }); | ||
const f14 = id4(function ({ foo = 42 }) { return foo }); | ||
|
||
const f20 = function (foo = 42) { return foo }; | ||
const f21 = id1(function (foo = 42) { return foo }); // Implicit any error | ||
~~~~~~~~ | ||
!!! error TS7006: Parameter 'foo' implicitly has an 'any' type. | ||
const f22 = id2(function (foo = 42) { return foo }); | ||
const f25 = id5(function (foo = 42) { return foo }); | ||
|
||
// Repro from #28816 | ||
|
||
function id<T>(input: T): T { return input } | ||
|
||
function getFoo ({ foo = 42 }) { | ||
return foo; | ||
} | ||
|
||
const newGetFoo = id(getFoo); | ||
const newGetFoo2 = id(function getFoo ({ foo = 42 }) { | ||
~~~ | ||
!!! error TS7031: Binding element 'foo' implicitly has an 'any' type. | ||
return foo; | ||
}); | ||
|
114 changes: 114 additions & 0 deletions
114
tests/baselines/reference/contextuallyTypedParametersWithInitializers.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
//// [contextuallyTypedParametersWithInitializers.ts] | ||
declare function id1<T>(input: T): T; | ||
declare function id2<T extends (x: any) => any>(input: T): T; | ||
declare function id3<T extends (x: { foo: any }) => any>(input: T): T; | ||
declare function id4<T extends (x: { foo?: number }) => any>(input: T): T; | ||
declare function id5<T extends (x?: number) => any>(input: T): T; | ||
|
||
const f10 = function ({ foo = 42 }) { return foo }; | ||
const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error | ||
const f12 = id2(function ({ foo = 42 }) { return foo }); | ||
const f13 = id3(function ({ foo = 42 }) { return foo }); | ||
const f14 = id4(function ({ foo = 42 }) { return foo }); | ||
|
||
const f20 = function (foo = 42) { return foo }; | ||
const f21 = id1(function (foo = 42) { return foo }); // Implicit any error | ||
const f22 = id2(function (foo = 42) { return foo }); | ||
const f25 = id5(function (foo = 42) { return foo }); | ||
|
||
// Repro from #28816 | ||
|
||
function id<T>(input: T): T { return input } | ||
|
||
function getFoo ({ foo = 42 }) { | ||
return foo; | ||
} | ||
|
||
const newGetFoo = id(getFoo); | ||
const newGetFoo2 = id(function getFoo ({ foo = 42 }) { | ||
return foo; | ||
}); | ||
|
||
|
||
//// [contextuallyTypedParametersWithInitializers.js] | ||
"use strict"; | ||
var f10 = function (_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}; | ||
var f11 = id1(function (_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}); // Implicit any error | ||
var f12 = id2(function (_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}); | ||
var f13 = id3(function (_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}); | ||
var f14 = id4(function (_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}); | ||
var f20 = function (foo) { | ||
if (foo === void 0) { foo = 42; } | ||
return foo; | ||
}; | ||
var f21 = id1(function (foo) { | ||
if (foo === void 0) { foo = 42; } | ||
return foo; | ||
}); // Implicit any error | ||
var f22 = id2(function (foo) { | ||
if (foo === void 0) { foo = 42; } | ||
return foo; | ||
}); | ||
var f25 = id5(function (foo) { | ||
if (foo === void 0) { foo = 42; } | ||
return foo; | ||
}); | ||
// Repro from #28816 | ||
function id(input) { return input; } | ||
function getFoo(_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
} | ||
var newGetFoo = id(getFoo); | ||
var newGetFoo2 = id(function getFoo(_a) { | ||
var _b = _a.foo, foo = _b === void 0 ? 42 : _b; | ||
return foo; | ||
}); | ||
|
||
|
||
//// [contextuallyTypedParametersWithInitializers.d.ts] | ||
declare function id1<T>(input: T): T; | ||
declare function id2<T extends (x: any) => any>(input: T): T; | ||
declare function id3<T extends (x: { | ||
foo: any; | ||
}) => any>(input: T): T; | ||
declare function id4<T extends (x: { | ||
foo?: number; | ||
}) => any>(input: T): T; | ||
declare function id5<T extends (x?: number) => any>(input: T): T; | ||
declare const f10: ({ foo }: { | ||
foo?: number | undefined; | ||
}) => number; | ||
declare const f11: ({ foo }: any) => any; | ||
declare const f12: ({ foo }: any) => any; | ||
declare const f13: ({ foo }: { | ||
foo: any; | ||
}) => any; | ||
declare const f14: ({ foo }: { | ||
foo?: number | undefined; | ||
}) => number; | ||
declare const f20: (foo?: number) => number; | ||
declare const f21: (foo?: any) => any; | ||
declare const f22: (foo?: any) => any; | ||
declare const f25: (foo?: number | undefined) => number; | ||
declare function id<T>(input: T): T; | ||
declare function getFoo({ foo }: { | ||
foo?: number | undefined; | ||
}): number; | ||
declare const newGetFoo: typeof getFoo; | ||
declare const newGetFoo2: ({ foo }: any) => any; |
128 changes: 128 additions & 0 deletions
128
tests/baselines/reference/contextuallyTypedParametersWithInitializers.symbols
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
=== tests/cases/compiler/contextuallyTypedParametersWithInitializers.ts === | ||
declare function id1<T>(input: T): T; | ||
>id1 : Symbol(id1, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 0)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 21)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 24)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 21)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 21)) | ||
|
||
declare function id2<T extends (x: any) => any>(input: T): T; | ||
>id2 : Symbol(id2, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 37)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 21)) | ||
>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 32)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 48)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 21)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 21)) | ||
|
||
declare function id3<T extends (x: { foo: any }) => any>(input: T): T; | ||
>id3 : Symbol(id3, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 61)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 21)) | ||
>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 32)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 36)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 57)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 21)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 21)) | ||
|
||
declare function id4<T extends (x: { foo?: number }) => any>(input: T): T; | ||
>id4 : Symbol(id4, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 70)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 21)) | ||
>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 32)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 36)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 61)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 21)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 21)) | ||
|
||
declare function id5<T extends (x?: number) => any>(input: T): T; | ||
>id5 : Symbol(id5, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 74)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 4, 21)) | ||
>x : Symbol(x, Decl(contextuallyTypedParametersWithInitializers.ts, 4, 32)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 4, 52)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 4, 21)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 4, 21)) | ||
|
||
const f10 = function ({ foo = 42 }) { return foo }; | ||
>f10 : Symbol(f10, Decl(contextuallyTypedParametersWithInitializers.ts, 6, 5)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 6, 23)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 6, 23)) | ||
|
||
const f11 = id1(function ({ foo = 42 }) { return foo }); // Implicit any error | ||
>f11 : Symbol(f11, Decl(contextuallyTypedParametersWithInitializers.ts, 7, 5)) | ||
>id1 : Symbol(id1, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 0)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 7, 27)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 7, 27)) | ||
|
||
const f12 = id2(function ({ foo = 42 }) { return foo }); | ||
>f12 : Symbol(f12, Decl(contextuallyTypedParametersWithInitializers.ts, 8, 5)) | ||
>id2 : Symbol(id2, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 37)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 8, 27)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 8, 27)) | ||
|
||
const f13 = id3(function ({ foo = 42 }) { return foo }); | ||
>f13 : Symbol(f13, Decl(contextuallyTypedParametersWithInitializers.ts, 9, 5)) | ||
>id3 : Symbol(id3, Decl(contextuallyTypedParametersWithInitializers.ts, 1, 61)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 9, 27)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 9, 27)) | ||
|
||
const f14 = id4(function ({ foo = 42 }) { return foo }); | ||
>f14 : Symbol(f14, Decl(contextuallyTypedParametersWithInitializers.ts, 10, 5)) | ||
>id4 : Symbol(id4, Decl(contextuallyTypedParametersWithInitializers.ts, 2, 70)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 10, 27)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 10, 27)) | ||
|
||
const f20 = function (foo = 42) { return foo }; | ||
>f20 : Symbol(f20, Decl(contextuallyTypedParametersWithInitializers.ts, 12, 5)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 12, 22)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 12, 22)) | ||
|
||
const f21 = id1(function (foo = 42) { return foo }); // Implicit any error | ||
>f21 : Symbol(f21, Decl(contextuallyTypedParametersWithInitializers.ts, 13, 5)) | ||
>id1 : Symbol(id1, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 0)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 13, 26)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 13, 26)) | ||
|
||
const f22 = id2(function (foo = 42) { return foo }); | ||
>f22 : Symbol(f22, Decl(contextuallyTypedParametersWithInitializers.ts, 14, 5)) | ||
>id2 : Symbol(id2, Decl(contextuallyTypedParametersWithInitializers.ts, 0, 37)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 14, 26)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 14, 26)) | ||
|
||
const f25 = id5(function (foo = 42) { return foo }); | ||
>f25 : Symbol(f25, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 5)) | ||
>id5 : Symbol(id5, Decl(contextuallyTypedParametersWithInitializers.ts, 3, 74)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 26)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 26)) | ||
|
||
// Repro from #28816 | ||
|
||
function id<T>(input: T): T { return input } | ||
>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 15)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) | ||
>T : Symbol(T, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 12)) | ||
>input : Symbol(input, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 15)) | ||
|
||
function getFoo ({ foo = 42 }) { | ||
>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 44)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 18)) | ||
|
||
return foo; | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 21, 18)) | ||
} | ||
|
||
const newGetFoo = id(getFoo); | ||
>newGetFoo : Symbol(newGetFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 25, 5)) | ||
>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) | ||
>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 19, 44)) | ||
|
||
const newGetFoo2 = id(function getFoo ({ foo = 42 }) { | ||
>newGetFoo2 : Symbol(newGetFoo2, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 5)) | ||
>id : Symbol(id, Decl(contextuallyTypedParametersWithInitializers.ts, 15, 52)) | ||
>getFoo : Symbol(getFoo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 22)) | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 40)) | ||
|
||
return foo; | ||
>foo : Symbol(foo, Decl(contextuallyTypedParametersWithInitializers.ts, 26, 40)) | ||
|
||
}); | ||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
Wouldn't we rather write
declaration.initializer && !(declaration.kind === SyntaxKind.Parameter && getContextualType(<Expression>declaration.parent))
so we only callgetContextualType
if we absolutely need to?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.
Or, since it's used below, write
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.
Yeah, possibly. The value is precomputed because I use it in two locations. But I supposed I could turn it into a function that we only call when appropriate.