-
Notifications
You must be signed in to change notification settings - Fork 13.1k
Fixed false positive circular errors for await expressions with simple non-generic calls in CFA loops #51126
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
Changes from 1 commit
d234453
35e20a8
75c096f
c5fd66c
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 |
|---|---|---|
|
|
@@ -35339,7 +35339,7 @@ namespace ts { | |
| return type; | ||
| } | ||
|
|
||
| function getQuickTypeOfExpression(node: Expression) { | ||
| function getQuickTypeOfExpression(node: Expression): Type | undefined { | ||
| let expr = skipParentheses(node, /*excludeJSDocTypeAssertions*/ true); | ||
| if (isJSDocTypeAssertion(expr)) { | ||
| const type = getJSDocTypeAssertionType(expr); | ||
|
|
@@ -35348,20 +35348,20 @@ namespace ts { | |
| } | ||
| } | ||
| expr = skipParentheses(node); | ||
| if (isAwaitExpression(expr)) { | ||
| const type = getQuickTypeOfExpression(expr.expression); | ||
| return type ? getAwaitedType(type) : undefined; | ||
| } | ||
| // Optimize for the common case of a call to a function with a single non-generic call | ||
| // signature where we can just fetch the return type without checking the arguments. | ||
| if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { | ||
| const type = isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : | ||
| else if (isCallExpression(expr) && expr.expression.kind !== SyntaxKind.SuperKeyword && !isRequireCall(expr, /*checkArgumentIsStringLiteralLike*/ true) && !isSymbolOrSymbolForCall(expr)) { | ||
| return isCallChain(expr) ? getReturnTypeOfSingleNonGenericSignatureOfCallChain(expr) : | ||
| getReturnTypeOfSingleNonGenericCallSignature(checkNonNullExpression(expr.expression)); | ||
| if (type) { | ||
| return type; | ||
| } | ||
|
||
| } | ||
| else if (isAssertionExpression(expr) && !isConstTypeReference(expr.type)) { | ||
| return getTypeFromTypeNode((expr as TypeAssertion).type); | ||
| } | ||
| else if (node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral || | ||
| node.kind === SyntaxKind.TrueKeyword || node.kind === SyntaxKind.FalseKeyword) { | ||
| else if (isLiteralExpression(node)) { | ||
|
||
| return checkExpression(node); | ||
| } | ||
| return undefined; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| tests/cases/conformance/controlFlow/controlFlowIterationErrorsAsync.ts(11,23): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| Type 'number' is not assignable to type 'string'. | ||
| tests/cases/conformance/controlFlow/controlFlowIterationErrorsAsync.ts(22,23): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| Type 'number' is not assignable to type 'string'. | ||
| tests/cases/conformance/controlFlow/controlFlowIterationErrorsAsync.ts(34,23): error TS2769: No overload matches this call. | ||
| Overload 1 of 2, '(x: string): Promise<number>', gave the following error. | ||
| Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| Type 'number' is not assignable to type 'string'. | ||
| Overload 2 of 2, '(x: number): Promise<string>', gave the following error. | ||
| Argument of type 'string | number' is not assignable to parameter of type 'number'. | ||
| Type 'string' is not assignable to type 'number'. | ||
| tests/cases/conformance/controlFlow/controlFlowIterationErrorsAsync.ts(45,23): error TS2769: No overload matches this call. | ||
| Overload 1 of 2, '(x: string): Promise<number>', gave the following error. | ||
| Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| Type 'number' is not assignable to type 'string'. | ||
| Overload 2 of 2, '(x: number): Promise<string>', gave the following error. | ||
| Argument of type 'string | number' is not assignable to parameter of type 'number'. | ||
| Type 'string' is not assignable to type 'number'. | ||
|
|
||
|
|
||
| ==== tests/cases/conformance/controlFlow/controlFlowIterationErrorsAsync.ts (4 errors) ==== | ||
| let cond: boolean; | ||
|
|
||
| async function len(s: string) { | ||
| return s.length; | ||
| } | ||
|
|
||
| async function f1() { | ||
| let x: string | number | boolean; | ||
| x = ""; | ||
| while (cond) { | ||
| x = await len(x); | ||
| ~ | ||
| !!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| !!! error TS2345: Type 'number' is not assignable to type 'string'. | ||
| x; | ||
| } | ||
| x; | ||
| } | ||
|
|
||
| async function f2() { | ||
| let x: string | number | boolean; | ||
| x = ""; | ||
| while (cond) { | ||
| x; | ||
| x = await len(x); | ||
| ~ | ||
| !!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| !!! error TS2345: Type 'number' is not assignable to type 'string'. | ||
| } | ||
| x; | ||
| } | ||
|
|
||
| declare function foo(x: string): Promise<number>; | ||
| declare function foo(x: number): Promise<string>; | ||
|
|
||
| async function g1() { | ||
| let x: string | number | boolean; | ||
| x = ""; | ||
| while (cond) { | ||
| x = await foo(x); | ||
| ~ | ||
| !!! error TS2769: No overload matches this call. | ||
| !!! error TS2769: Overload 1 of 2, '(x: string): Promise<number>', gave the following error. | ||
| !!! error TS2769: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| !!! error TS2769: Type 'number' is not assignable to type 'string'. | ||
| !!! error TS2769: Overload 2 of 2, '(x: number): Promise<string>', gave the following error. | ||
| !!! error TS2769: Argument of type 'string | number' is not assignable to parameter of type 'number'. | ||
| !!! error TS2769: Type 'string' is not assignable to type 'number'. | ||
| x; | ||
| } | ||
| x; | ||
| } | ||
|
|
||
| async function g2() { | ||
| let x: string | number | boolean; | ||
| x = ""; | ||
| while (cond) { | ||
| x; | ||
| x = await foo(x); | ||
| ~ | ||
| !!! error TS2769: No overload matches this call. | ||
| !!! error TS2769: Overload 1 of 2, '(x: string): Promise<number>', gave the following error. | ||
| !!! error TS2769: Argument of type 'string | number' is not assignable to parameter of type 'string'. | ||
| !!! error TS2769: Type 'number' is not assignable to type 'string'. | ||
| !!! error TS2769: Overload 2 of 2, '(x: number): Promise<string>', gave the following error. | ||
| !!! error TS2769: Argument of type 'string | number' is not assignable to parameter of type 'number'. | ||
| !!! error TS2769: Type 'string' is not assignable to type 'number'. | ||
| } | ||
| x; | ||
| } | ||
|
|
||
| async function asNumber(x: string | number): Promise<number> { | ||
| return +x; | ||
| } | ||
|
|
||
| async function h1() { | ||
| let x: string | number | boolean; | ||
| x = "0"; | ||
| while (cond) { | ||
| x = +x + 1; | ||
| x; | ||
| } | ||
| } | ||
|
|
||
| async function h2() { | ||
| let x: string | number | boolean; | ||
| x = "0"; | ||
| while (cond) { | ||
| x = await asNumber(x) + 1; | ||
| x; | ||
| } | ||
| } | ||
|
|
||
| async function h3() { | ||
| let x: string | number | boolean; | ||
| x = "0"; | ||
| while (cond) { | ||
| let y = await asNumber(x); | ||
| x = y + 1; | ||
| x; | ||
| } | ||
| } | ||
|
|
||
| async function h4() { | ||
| let x: string | number | boolean; | ||
| x = "0"; | ||
| while (cond) { | ||
| x; | ||
| let y = await asNumber(x); | ||
| x = y + 1; | ||
| x; | ||
| } | ||
| } | ||
|
|
||
| // repro #51115 | ||
|
|
||
| async function get_things(_: number | undefined) { | ||
| return [0]; | ||
| } | ||
|
|
||
| async function foobar() { | ||
| let before: number | undefined = undefined; | ||
| for (let i = 0; i < 2; i++) { | ||
| const results = await get_things(before); | ||
| before = results[0]; | ||
| } | ||
| } | ||
|
|
||
| // repro #43047#issuecomment-821453073 | ||
|
|
||
| declare function foox(x: string | undefined): Promise<string> | ||
|
|
||
| async () => { | ||
| let bar: string | undefined = undefined; | ||
| do { | ||
| const baz = await foox(bar); | ||
| bar = baz | ||
| } while (bar) | ||
| } | ||
|
|
||
| // repro #43047#issuecomment-874221939 | ||
|
|
||
| declare function myQuery(input: { lastId: number | undefined }): Promise<{ entities: number[] }>; | ||
|
|
||
| async function myFunc(): Promise<void> { | ||
| let lastId: number | undefined = undefined; | ||
|
|
||
| while (true) { | ||
| const { entities } = await myQuery({ | ||
| lastId, | ||
| }); | ||
|
|
||
| lastId = entities[entities.length - 1]; | ||
| } | ||
| } | ||
|
|
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 is the core of the fix