From 796450a03d296a3bc91e045a3bf0cb1e24a93dc5 Mon Sep 17 00:00:00 2001 From: Oliver Joseph Ash Date: Tue, 17 Dec 2024 20:42:26 +0000 Subject: [PATCH] Improve error position/range for arrow functions with expression body Fixes https://github.com/microsoft/typescript/issues/57866 diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1ff3a2acad..2ea2c5ee56 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2527,6 +2527,14 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa } } + if (node.parent !== undefined && node.parent.kind === SyntaxKind.ArrowFunction) { + const arrowFn = node.parent as ArrowFunction; + if (arrowFn.body === node && arrowFn.type !== undefined) { + const pos = skipTrivia(sourceFile.text, arrowFn.type.pos); + return getSpanOfTokenAtPosition(sourceFile, pos); + } + } + if (errorNode === undefined) { // If we don't have a better node, then just set the error on the first token of // construct. diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index aa2ae24033..476345ed9f 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -73,7 +73,7 @@ conditionalTypes1.ts(160,5): error TS2322: Type 'T' is not assignable to type 'Z Type 'string | number' is not assignable to type 'ZeroOf'. Type 'string' is not assignable to type 'ZeroOf'. conditionalTypes1.ts(263,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'z' must be of type 'T1', but here has type 'Foo'. -conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to type 'T94'. +conditionalTypes1.ts(288,33): error TS2322: Type 'T95' is not assignable to type 'T94'. Type 'number | boolean' is not assignable to type 'T94'. Type 'number' is not assignable to type 'T94'. Type 'boolean' is not assignable to type 'true'. @@ -465,7 +465,7 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t type T95 = T extends string ? boolean : number; const f44 = (value: T94): T95 => value; const f45 = (value: T95): T94 => value; // Error - ~~~~~ + ~~~ !!! error TS2322: Type 'T95' is not assignable to type 'T94'. !!! error TS2322: Type 'number | boolean' is not assignable to type 'T94'. !!! error TS2322: Type 'number' is not assignable to type 'T94'. diff --git a/tests/baselines/reference/mappedTypeConstraints2.errors.txt b/tests/baselines/reference/mappedTypeConstraints2.errors.txt index 0d3b3244c9..098bbd3f4b 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -6,7 +6,7 @@ mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3[Uppercase]' mappedTypeConstraints2.ts(42,7): error TS2322: Type 'Mapped6[keyof Mapped6]' is not assignable to type '`_${string}`'. Type 'Mapped6[string] | Mapped6[number] | Mapped6[symbol]' is not assignable to type '`_${string}`'. Type 'Mapped6[string]' is not assignable to type '`_${string}`'. -mappedTypeConstraints2.ts(51,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. +mappedTypeConstraints2.ts(51,52): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys[`_${K}`]' is not assignable to type 'true'. Type 'ObjectWithUnderscoredKeys[`_${string}`]' is not assignable to type 'true'. @@ -75,7 +75,7 @@ mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys(t: T, foo: Foo): T => foo[`get${t}`]; // Type 'Foo[`get${T}`]' is not assignable to type 'T' - ~~~~~~~~~~~~~~ + ~ !!! error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. !!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. diff --git a/tests/baselines/reference/parserArrowFunctionExpression17.errors.txt b/tests/baselines/reference/parserArrowFunctionExpression17.errors.txt index 28091b1745..73c2b637f0 100644 --- a/tests/baselines/reference/parserArrowFunctionExpression17.errors.txt +++ b/tests/baselines/reference/parserArrowFunctionExpression17.errors.txt @@ -1,12 +1,12 @@ fileJs.js(1,1): error TS2304: Cannot find name 'a'. fileJs.js(1,5): error TS2304: Cannot find name 'b'. fileJs.js(1,15): error TS2304: Cannot find name 'd'. +fileJs.js(1,15): error TS2304: Cannot find name 'e'. fileJs.js(1,15): error TS8010: Type annotations can only be used in TypeScript files. -fileJs.js(1,20): error TS2304: Cannot find name 'e'. fileTs.ts(1,1): error TS2304: Cannot find name 'a'. fileTs.ts(1,5): error TS2304: Cannot find name 'b'. fileTs.ts(1,15): error TS2304: Cannot find name 'd'. -fileTs.ts(1,20): error TS2304: Cannot find name 'e'. +fileTs.ts(1,15): error TS2304: Cannot find name 'e'. ==== fileJs.js (5 errors) ==== @@ -18,9 +18,9 @@ fileTs.ts(1,20): error TS2304: Cannot find name 'e'. ~ !!! error TS2304: Cannot find name 'd'. ~ -!!! error TS8010: Type annotations can only be used in TypeScript files. - ~ !!! error TS2304: Cannot find name 'e'. + ~ +!!! error TS8010: Type annotations can only be used in TypeScript files. ==== fileTs.ts (4 errors) ==== a ? b : (c) : d => e @@ -30,6 +30,6 @@ fileTs.ts(1,20): error TS2304: Cannot find name 'e'. !!! error TS2304: Cannot find name 'b'. ~ !!! error TS2304: Cannot find name 'd'. - ~ + ~ !!! error TS2304: Cannot find name 'e'. \ No newline at end of file --- src/compiler/utilities.ts | 8 ++++++++ .../reference/arrowFunctionReturnTypeErrorSpan.errors.txt | 8 ++++---- tests/baselines/reference/conditionalTypes1.errors.txt | 4 ++-- .../baselines/reference/mappedTypeConstraints2.errors.txt | 4 ++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 1ff3a2acada46..2ea2c5ee567ca 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2527,6 +2527,14 @@ export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpa } } + if (node.parent !== undefined && node.parent.kind === SyntaxKind.ArrowFunction) { + const arrowFn = node.parent as ArrowFunction; + if (arrowFn.body === node && arrowFn.type !== undefined) { + const pos = skipTrivia(sourceFile.text, arrowFn.type.pos); + return getSpanOfTokenAtPosition(sourceFile, pos); + } + } + if (errorNode === undefined) { // If we don't have a better node, then just set the error on the first token of // construct. diff --git a/tests/baselines/reference/arrowFunctionReturnTypeErrorSpan.errors.txt b/tests/baselines/reference/arrowFunctionReturnTypeErrorSpan.errors.txt index 872b82ec0a4ec..2a6d10bafae8c 100644 --- a/tests/baselines/reference/arrowFunctionReturnTypeErrorSpan.errors.txt +++ b/tests/baselines/reference/arrowFunctionReturnTypeErrorSpan.errors.txt @@ -1,7 +1,7 @@ arrowFunctionReturnTypeErrorSpan.ts(3,3): error TS2322: Type 'string' is not assignable to type 'number'. -arrowFunctionReturnTypeErrorSpan.ts(7,25): error TS2322: Type 'string' is not assignable to type 'number'. -arrowFunctionReturnTypeErrorSpan.ts(10,28): error TS2322: Type 'string' is not assignable to type 'number'. arrowFunctionReturnTypeErrorSpan.ts(12,25): error TS2304: Cannot find name 'missing'. +arrowFunctionReturnTypeErrorSpan.ts(7,15): error TS2322: Type 'string' is not assignable to type 'number'. +arrowFunctionReturnTypeErrorSpan.ts(10,15): error TS2322: Type 'string' is not assignable to type 'number'. ==== arrowFunctionReturnTypeErrorSpan.ts (4 errors) ==== @@ -14,12 +14,12 @@ arrowFunctionReturnTypeErrorSpan.ts(12,25): error TS2304: Cannot find name 'miss // expression body const b = (): number => "foo"; - ~~~~~ + ~~~~~~ !!! error TS2322: Type 'string' is not assignable to type 'number'. type F = T; const c = (): F => "foo"; - ~~~~~ + ~ !!! error TS2322: Type 'string' is not assignable to type 'number'. const d = (): number => missing; diff --git a/tests/baselines/reference/conditionalTypes1.errors.txt b/tests/baselines/reference/conditionalTypes1.errors.txt index aa2ae24033b16..476345ed9f1ac 100644 --- a/tests/baselines/reference/conditionalTypes1.errors.txt +++ b/tests/baselines/reference/conditionalTypes1.errors.txt @@ -73,7 +73,7 @@ conditionalTypes1.ts(160,5): error TS2322: Type 'T' is not assignable to type 'Z Type 'string | number' is not assignable to type 'ZeroOf'. Type 'string' is not assignable to type 'ZeroOf'. conditionalTypes1.ts(263,9): error TS2403: Subsequent variable declarations must have the same type. Variable 'z' must be of type 'T1', but here has type 'Foo'. -conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to type 'T94'. +conditionalTypes1.ts(288,33): error TS2322: Type 'T95' is not assignable to type 'T94'. Type 'number | boolean' is not assignable to type 'T94'. Type 'number' is not assignable to type 'T94'. Type 'boolean' is not assignable to type 'true'. @@ -465,7 +465,7 @@ conditionalTypes1.ts(288,43): error TS2322: Type 'T95' is not assignable to t type T95 = T extends string ? boolean : number; const f44 = (value: T94): T95 => value; const f45 = (value: T95): T94 => value; // Error - ~~~~~ + ~~~ !!! error TS2322: Type 'T95' is not assignable to type 'T94'. !!! error TS2322: Type 'number | boolean' is not assignable to type 'T94'. !!! error TS2322: Type 'number' is not assignable to type 'T94'. diff --git a/tests/baselines/reference/mappedTypeConstraints2.errors.txt b/tests/baselines/reference/mappedTypeConstraints2.errors.txt index 0d3b3244c9e66..098bbd3f4b21a 100644 --- a/tests/baselines/reference/mappedTypeConstraints2.errors.txt +++ b/tests/baselines/reference/mappedTypeConstraints2.errors.txt @@ -6,7 +6,7 @@ mappedTypeConstraints2.ts(16,11): error TS2322: Type 'Mapped3[Uppercase]' mappedTypeConstraints2.ts(42,7): error TS2322: Type 'Mapped6[keyof Mapped6]' is not assignable to type '`_${string}`'. Type 'Mapped6[string] | Mapped6[number] | Mapped6[symbol]' is not assignable to type '`_${string}`'. Type 'Mapped6[string]' is not assignable to type '`_${string}`'. -mappedTypeConstraints2.ts(51,57): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. +mappedTypeConstraints2.ts(51,52): error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'. mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys[`_${K}`]' is not assignable to type 'true'. Type 'ObjectWithUnderscoredKeys[`_${string}`]' is not assignable to type 'true'. @@ -75,7 +75,7 @@ mappedTypeConstraints2.ts(82,9): error TS2322: Type 'ObjectWithUnderscoredKeys(t: T, foo: Foo): T => foo[`get${t}`]; // Type 'Foo[`get${T}`]' is not assignable to type 'T' - ~~~~~~~~~~~~~~ + ~ !!! error TS2322: Type 'Foo[`get${T}`]' is not assignable to type 'T'. !!! error TS2322: 'T' could be instantiated with an arbitrary type which could be unrelated to 'Foo[`get${T}`]'.