-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Include source node inferences in string literal completions deeper in arguments #56182
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
base: main
Are you sure you want to change the base?
Changes from all commits
183578b
fa9a5f5
1614651
f98b92b
6152848
5daf0c0
9422555
39ddd44
dc19f47
6adcd82
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
//// [tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts] //// | ||
|
||
=== generatorTypeCheck64.ts === | ||
function* g3(): Generator<Generator<(x: string) => number>> { | ||
>g3 : Symbol(g3, Decl(generatorTypeCheck64.ts, 0, 0)) | ||
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) | ||
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --)) | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 0, 37)) | ||
|
||
yield function* () { | ||
yield x => x.length; | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 2, 13)) | ||
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 2, 13)) | ||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) | ||
|
||
} () | ||
} | ||
|
||
function* g4(): Iterator<Iterable<(x: string) => number>> { | ||
>g4 : Symbol(g4, Decl(generatorTypeCheck64.ts, 4, 1)) | ||
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.esnext.iterator.d.ts, --, --)) | ||
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --)) | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 6, 35)) | ||
|
||
yield (function* () { | ||
yield (x) => x.length; | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 8, 11)) | ||
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) | ||
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 8, 11)) | ||
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --)) | ||
|
||
})(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
//// [tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts] //// | ||
|
||
=== Performance Stats === | ||
Type Count: 1,000 | ||
Instantiation count: 2,500 | ||
|
||
=== generatorTypeCheck64.ts === | ||
function* g3(): Generator<Generator<(x: string) => number>> { | ||
>g3 : () => Generator<Generator<(x: string) => number>> | ||
> : ^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
|
||
yield function* () { | ||
>yield function* () { yield x => x.length; } () : any | ||
>function* () { yield x => x.length; } () : Generator<(x: string) => number, void, any> | ||
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
>function* () { yield x => x.length; } : () => Generator<(x: string) => number, void, any> | ||
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
yield x => x.length; | ||
>yield x => x.length : any | ||
>x => x.length : (x: string) => number | ||
> : ^ ^^^^^^^^^^^^^^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
>x.length : number | ||
> : ^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
>length : number | ||
> : ^^^^^^ | ||
|
||
} () | ||
} | ||
|
||
function* g4(): Iterator<Iterable<(x: string) => number>> { | ||
>g4 : () => Iterator<Iterable<(x: string) => number>> | ||
> : ^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
|
||
yield (function* () { | ||
>yield (function* () { yield (x) => x.length; })() : any | ||
>(function* () { yield (x) => x.length; })() : Generator<(x: string) => number, void, any> | ||
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
>(function* () { yield (x) => x.length; }) : () => Generator<(x: string) => number, void, any> | ||
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
>function* () { yield (x) => x.length; } : () => Generator<(x: string) => number, void, any> | ||
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
yield (x) => x.length; | ||
>yield (x) => x.length : any | ||
>(x) => x.length : (x: string) => number | ||
> : ^ ^^^^^^^^^^^^^^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
>x.length : number | ||
> : ^^^^^^ | ||
>x : string | ||
> : ^^^^^^ | ||
>length : number | ||
> : ^^^^^^ | ||
|
||
})(); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
// @strict: true | ||
// @target: esnext | ||
// @noEmit: true | ||
|
||
function* g3(): Generator<Generator<(x: string) => number>> { | ||
yield function* () { | ||
yield x => x.length; | ||
} () | ||
} | ||
|
||
function* g4(): Iterator<Iterable<(x: string) => number>> { | ||
yield (function* () { | ||
yield (x) => x.length; | ||
})(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
/// <reference path="fourslash.ts" /> | ||
|
||
// @strict: true | ||
|
||
//// declare function createMachine<T>(config: { | ||
//// initial: keyof T; | ||
//// states: { | ||
//// [K in keyof T]: { | ||
//// on?: Record<string, keyof T>; | ||
//// }; | ||
//// }; | ||
//// }): void; | ||
//// | ||
//// createMachine({ | ||
//// initial: "a", | ||
//// states: { | ||
//// a: { | ||
//// on: { | ||
//// NEXT: "/*1*/", | ||
//// }, | ||
//// }, | ||
//// b: { | ||
//// on: { | ||
//// NEXT: "/*2*/", | ||
//// }, | ||
//// }, | ||
//// }, | ||
//// }); | ||
|
||
verify.completions({ | ||
marker: ["1", "2"], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It didn't work for marker 1 because the completions type took priority over the regular contextual type. With inference blocked and all the Note that this PR doesn't improve the very same situation for regular (non-string) completions - when we have a node with |
||
exact: ["a", "b"] | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,7 +25,7 @@ | |
|
||
goTo.marker("1"); | ||
edit.insert(`x`) | ||
verify.completions({ exact: ["MORNING", "LUNCH_TIME", "ALOHA"] }); | ||
verify.completions({ exact: ["ALOHAx", "MORNING", "LUNCH_TIME", "ALOHA"] }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, actually... it doesn't show it when typing (the completions popup goes away when my input goes outside of the valid values) but it does show up when requested explicitly with cmd+space. I still feel like this is an improvement though as the invalid value can be somewhat easily ignored by the user. Maybe this is something that could be improved on the VS Code side though unless this is the intended behavior here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This kind of makes sense since it is actively changing the inference to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't know, on second thought, if you change the token text to a substring of one of the valid options, like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This is not a new problem so I think it shouldn't be a blocker here (TS playground): type GreetingEvent =
| "MORNING"
| "LUNCH_TIME"
| "ALOHA";
interface RaiseActionObject<TEvent> {
type: "raise";
event: TEvent;
}
declare function raise<TEvent>(
ev: TEvent
): RaiseActionObject<TEvent>;
declare function createMachine<TEvent>(config: {
actions: RaiseActionObject<TEvent>;
}): void;
createMachine<GreetingEvent>({
actions: raise("ALO"),
}); We can get those completions here: All this PR does is reusing the existing algorithm in a new code path. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hm, I see that in the playground, but the diff in the fourslash test makes it look like a new problem, doesn’t it? What am I missing? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The cases in the TS playground above and in the added fourslash test are different (and yet the same :P). Strings used directly at argument positions and somewhere deeper within arguments (like as property values) hit 2 different codepaths. So what we observe on the TS playground above is a result of that other codepath and what this PR does is to port some logic from that other codepath to the other place. So now this fourslash test starts to behave like the TS playground above. |
||
verify.getSemanticDiagnostics([{ | ||
code: 2322, | ||
message: `Type 'RaiseActionObject<{ type: "ALOHAx"; }>' is not assignable to type 'RaiseActionObject<GreetingEvent>'.\n Type '{ type: "ALOHAx"; }' is not assignable to type 'GreetingEvent'.\n Type '{ type: "ALOHAx"; }' is not assignable to type '{ type: "ALOHA"; }'.\n Types of property 'type' are incompatible.\n Type '"ALOHAx"' is not assignable to type '"ALOHA"'.`, | ||
|
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.
Nothing you did (this is preexisting), but it sure does make me sad to see
Map<T, true>
in 2024 😄