Skip to content

Commit 69a0879

Browse files
authored
Include source node inferences in string literal completions deeper in arguments (#56182)
1 parent b2327c0 commit 69a0879

File tree

7 files changed

+167
-8
lines changed

7 files changed

+167
-8
lines changed

src/compiler/checker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32706,7 +32706,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3270632706
return getContextualTypeForAwaitOperand(parent as AwaitExpression, contextFlags);
3270732707
case SyntaxKind.CallExpression:
3270832708
case SyntaxKind.NewExpression:
32709-
return getContextualTypeForArgument(parent as CallExpression | NewExpression | Decorator, node);
32709+
return getContextualTypeForArgument(parent as CallExpression | NewExpression, node);
3271032710
case SyntaxKind.Decorator:
3271132711
return getContextualTypeForDecorator(parent as Decorator);
3271232712
case SyntaxKind.TypeAssertionExpression:

src/services/stringCompletions.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ import {
9191
isApplicableVersionedTypesKey,
9292
isArray,
9393
isCallExpression,
94+
isCallLikeExpression,
9495
isIdentifier,
9596
isIdentifierText,
9697
isImportCall,
@@ -429,7 +430,15 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
429430
// });
430431
return stringLiteralCompletionsForObjectLiteral(typeChecker, parent.parent);
431432
}
432-
return fromContextualType() || fromContextualType(ContextFlags.None);
433+
if (findAncestor(parent.parent, isCallLikeExpression)) {
434+
const uniques = new Set<string>();
435+
const stringLiteralTypes = concatenate(
436+
getStringLiteralTypes(typeChecker.getContextualType(node, ContextFlags.None), uniques),
437+
getStringLiteralTypes(typeChecker.getContextualType(node, ContextFlags.Completions), uniques),
438+
);
439+
return toStringLiteralCompletionsFromTypes(stringLiteralTypes);
440+
}
441+
return fromContextualType(ContextFlags.None);
433442

434443
case SyntaxKind.ElementAccessExpression: {
435444
const { expression, argumentExpression } = parent as ElementAccessExpression;
@@ -556,14 +565,14 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL
556565
function fromContextualType(contextFlags: ContextFlags = ContextFlags.IgnoreNodeInferences): StringLiteralCompletionsFromTypes | undefined {
557566
// Get completion for string literal from string literal type
558567
// i.e. var x: "hi" | "hello" = "/*completion position*/"
559-
const types = getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker, contextFlags));
560-
if (!types.length) {
561-
return;
562-
}
563-
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
568+
return toStringLiteralCompletionsFromTypes(getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker, contextFlags)));
564569
}
565570
}
566571

572+
function toStringLiteralCompletionsFromTypes(types: readonly StringLiteralType[]): StringLiteralCompletionsFromTypes | undefined {
573+
return types.length ? { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false } : undefined;
574+
}
575+
567576
function walkUpParentheses(node: Node) {
568577
switch (node.kind) {
569578
case SyntaxKind.ParenthesizedType:
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//// [tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts] ////
2+
3+
=== generatorTypeCheck64.ts ===
4+
function* g3(): Generator<Generator<(x: string) => number>> {
5+
>g3 : Symbol(g3, Decl(generatorTypeCheck64.ts, 0, 0))
6+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
7+
>Generator : Symbol(Generator, Decl(lib.es2015.generator.d.ts, --, --))
8+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 0, 37))
9+
10+
yield function* () {
11+
yield x => x.length;
12+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 2, 13))
13+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
14+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 2, 13))
15+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
16+
17+
} ()
18+
}
19+
20+
function* g4(): Iterator<Iterable<(x: string) => number>> {
21+
>g4 : Symbol(g4, Decl(generatorTypeCheck64.ts, 4, 1))
22+
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.esnext.iterator.d.ts, --, --))
23+
>Iterable : Symbol(Iterable, Decl(lib.es2015.iterable.d.ts, --, --))
24+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 6, 35))
25+
26+
yield (function* () {
27+
yield (x) => x.length;
28+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 8, 11))
29+
>x.length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
30+
>x : Symbol(x, Decl(generatorTypeCheck64.ts, 8, 11))
31+
>length : Symbol(String.length, Decl(lib.es5.d.ts, --, --))
32+
33+
})();
34+
}
35+
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//// [tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts] ////
2+
3+
=== Performance Stats ===
4+
Type Count: 1,000
5+
Instantiation count: 2,500
6+
7+
=== generatorTypeCheck64.ts ===
8+
function* g3(): Generator<Generator<(x: string) => number>> {
9+
>g3 : () => Generator<Generator<(x: string) => number>>
10+
> : ^^^^^^
11+
>x : string
12+
> : ^^^^^^
13+
14+
yield function* () {
15+
>yield function* () { yield x => x.length; } () : any
16+
>function* () { yield x => x.length; } () : Generator<(x: string) => number, void, any>
17+
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
>function* () { yield x => x.length; } : () => Generator<(x: string) => number, void, any>
19+
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
20+
21+
yield x => x.length;
22+
>yield x => x.length : any
23+
>x => x.length : (x: string) => number
24+
> : ^ ^^^^^^^^^^^^^^^^^^^
25+
>x : string
26+
> : ^^^^^^
27+
>x.length : number
28+
> : ^^^^^^
29+
>x : string
30+
> : ^^^^^^
31+
>length : number
32+
> : ^^^^^^
33+
34+
} ()
35+
}
36+
37+
function* g4(): Iterator<Iterable<(x: string) => number>> {
38+
>g4 : () => Iterator<Iterable<(x: string) => number>>
39+
> : ^^^^^^
40+
>x : string
41+
> : ^^^^^^
42+
43+
yield (function* () {
44+
>yield (function* () { yield (x) => x.length; })() : any
45+
>(function* () { yield (x) => x.length; })() : Generator<(x: string) => number, void, any>
46+
> : ^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
47+
>(function* () { yield (x) => x.length; }) : () => Generator<(x: string) => number, void, any>
48+
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49+
>function* () { yield (x) => x.length; } : () => Generator<(x: string) => number, void, any>
50+
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
51+
52+
yield (x) => x.length;
53+
>yield (x) => x.length : any
54+
>(x) => x.length : (x: string) => number
55+
> : ^ ^^^^^^^^^^^^^^^^^^^
56+
>x : string
57+
> : ^^^^^^
58+
>x.length : number
59+
> : ^^^^^^
60+
>x : string
61+
> : ^^^^^^
62+
>length : number
63+
> : ^^^^^^
64+
65+
})();
66+
}
67+
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// @strict: true
2+
// @target: esnext
3+
// @noEmit: true
4+
5+
function* g3(): Generator<Generator<(x: string) => number>> {
6+
yield function* () {
7+
yield x => x.length;
8+
} ()
9+
}
10+
11+
function* g4(): Iterator<Iterable<(x: string) => number>> {
12+
yield (function* () {
13+
yield (x) => x.length;
14+
})();
15+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @strict: true
4+
5+
//// declare function createMachine<T>(config: {
6+
//// initial: keyof T;
7+
//// states: {
8+
//// [K in keyof T]: {
9+
//// on?: Record<string, keyof T>;
10+
//// };
11+
//// };
12+
//// }): void;
13+
////
14+
//// createMachine({
15+
//// initial: "a",
16+
//// states: {
17+
//// a: {
18+
//// on: {
19+
//// NEXT: "/*1*/",
20+
//// },
21+
//// },
22+
//// b: {
23+
//// on: {
24+
//// NEXT: "/*2*/",
25+
//// },
26+
//// },
27+
//// },
28+
//// });
29+
30+
verify.completions({
31+
marker: ["1", "2"],
32+
exact: ["a", "b"]
33+
})

tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
goTo.marker("1");
2727
edit.insert(`x`)
28-
verify.completions({ exact: ["MORNING", "LUNCH_TIME", "ALOHA"] });
28+
verify.completions({ exact: ["ALOHAx", "MORNING", "LUNCH_TIME", "ALOHA"] });
2929
verify.getSemanticDiagnostics([{
3030
code: 2322,
3131
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"'.`,

0 commit comments

Comments
 (0)