diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5d4be5660aabe..c59fd8db2006e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -22056,7 +22056,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target); let generalizedSource = source; let generalizedSourceType = sourceType; - + // Don't generalize on 'never' - we really want the original type // to be displayed for use-cases like 'assertNever'. if (!(target.flags & TypeFlags.Never) && isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) { @@ -32130,7 +32130,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForAwaitOperand(parent as AwaitExpression, contextFlags); case SyntaxKind.CallExpression: case SyntaxKind.NewExpression: - return getContextualTypeForArgument(parent as CallExpression | NewExpression | Decorator, node); + return getContextualTypeForArgument(parent as CallExpression | NewExpression, node); case SyntaxKind.Decorator: return getContextualTypeForDecorator(parent as Decorator); case SyntaxKind.TypeAssertionExpression: diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts index 667cdf24ca8aa..cda6c70891eb9 100644 --- a/src/services/stringCompletions.ts +++ b/src/services/stringCompletions.ts @@ -27,6 +27,7 @@ import { CompletionEntry, CompletionEntryDetails, CompletionInfo, + concatenate, contains, containsPath, ContextFlags, @@ -83,6 +84,7 @@ import { isApplicableVersionedTypesKey, isArray, isCallExpression, + isCallLikeExpression, isIdentifier, isIdentifierText, isImportCall, @@ -411,7 +413,15 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL // }); return stringLiteralCompletionsForObjectLiteral(typeChecker, parent.parent); } - return fromContextualType() || fromContextualType(ContextFlags.None); + if (findAncestor(parent.parent, isCallLikeExpression)) { + const uniques = new Map(); + const stringLiteralTypes = concatenate( + getStringLiteralTypes(typeChecker.getContextualType(node, ContextFlags.None), uniques), + getStringLiteralTypes(typeChecker.getContextualType(node, ContextFlags.Completions), uniques), + ); + return toStringLiteralCompletionsFromTypes(stringLiteralTypes); + } + return fromContextualType(ContextFlags.None); case SyntaxKind.ElementAccessExpression: { const { expression, argumentExpression } = parent as ElementAccessExpression; @@ -521,14 +531,14 @@ function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringL function fromContextualType(contextFlags: ContextFlags = ContextFlags.Completions): StringLiteralCompletionsFromTypes | undefined { // Get completion for string literal from string literal type // i.e. var x: "hi" | "hello" = "/*completion position*/" - const types = getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker, contextFlags)); - if (!types.length) { - return; - } - return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false }; + return toStringLiteralCompletionsFromTypes(getStringLiteralTypes(getContextualTypeFromParent(node, typeChecker, contextFlags))); } } +function toStringLiteralCompletionsFromTypes(types: readonly StringLiteralType[]): StringLiteralCompletionsFromTypes | undefined { + return types.length ? { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false } : undefined; +} + function walkUpParentheses(node: Node) { switch (node.kind) { case SyntaxKind.ParenthesizedType: diff --git a/tests/baselines/reference/generatorTypeCheck64.symbols b/tests/baselines/reference/generatorTypeCheck64.symbols new file mode 100644 index 0000000000000..dd0656f99f5e8 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck64.symbols @@ -0,0 +1,35 @@ +//// [tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts] //// + +=== generatorTypeCheck64.ts === +function* g3(): Generator 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 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, --, --)) + + })(); +} + diff --git a/tests/baselines/reference/generatorTypeCheck64.types b/tests/baselines/reference/generatorTypeCheck64.types new file mode 100644 index 0000000000000..3bcc3d4917712 --- /dev/null +++ b/tests/baselines/reference/generatorTypeCheck64.types @@ -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 number>> { +>g3 : () => Generator 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 number>> { +>g4 : () => Iterator 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 +> : ^^^^^^ + + })(); +} + diff --git a/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts new file mode 100644 index 0000000000000..30e9e40d96f81 --- /dev/null +++ b/tests/cases/conformance/es6/yieldExpressions/generatorTypeCheck64.ts @@ -0,0 +1,15 @@ +// @strict: true +// @target: esnext +// @noEmit: true + +function* g3(): Generator number>> { + yield function* () { + yield x => x.length; + } () +} + +function* g4(): Iterator number>> { + yield (function* () { + yield (x) => x.length; + })(); +} diff --git a/tests/cases/fourslash/stringLiteralCompletionsWithinInferredObjectWhenItsKeysAreUsedOutsideOfIt.ts b/tests/cases/fourslash/stringLiteralCompletionsWithinInferredObjectWhenItsKeysAreUsedOutsideOfIt.ts new file mode 100644 index 0000000000000..55ce6d20995b7 --- /dev/null +++ b/tests/cases/fourslash/stringLiteralCompletionsWithinInferredObjectWhenItsKeysAreUsedOutsideOfIt.ts @@ -0,0 +1,33 @@ +/// + +// @strict: true + +//// declare function createMachine(config: { +//// initial: keyof T; +//// states: { +//// [K in keyof T]: { +//// on?: Record; +//// }; +//// }; +//// }): void; +//// +//// createMachine({ +//// initial: "a", +//// states: { +//// a: { +//// on: { +//// NEXT: "/*1*/", +//// }, +//// }, +//// b: { +//// on: { +//// NEXT: "/*2*/", +//// }, +//// }, +//// }, +//// }); + +verify.completions({ + marker: ["1", "2"], + exact: ["a", "b"] +}) diff --git a/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall.ts b/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall.ts index 6a9909c4a20e3..ce3d5fa967c32 100644 --- a/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall.ts +++ b/tests/cases/fourslash/typeErrorAfterStringCompletionsInNestedCall.ts @@ -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"] }); verify.getSemanticDiagnostics([{ code: 2322, message: `Type 'RaiseActionObject<{ type: "ALOHAx"; }>' is not assignable to type 'RaiseActionObject'.\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"'.`,