Skip to content

Commit 10a63a9

Browse files
authored
Fixed error spans for SatisfiesExpression check nodes (#56918)
1 parent 1982349 commit 10a63a9

File tree

5 files changed

+572
-6
lines changed

5 files changed

+572
-6
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -700,6 +700,7 @@ import {
700700
isRightSideOfQualifiedNameOrPropertyAccess,
701701
isRightSideOfQualifiedNameOrPropertyAccessOrJSDocMemberName,
702702
isSameEntityName,
703+
isSatisfiesExpression,
703704
isSetAccessor,
704705
isSetAccessorDeclaration,
705706
isShorthandAmbientModuleSymbol,
@@ -20654,7 +20655,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2065420655
const elem = node.elements[i];
2065520656
if (isOmittedExpression(elem)) continue;
2065620657
const nameType = getNumberLiteralType(i);
20657-
yield { errorNode: elem, innerExpression: elem, nameType };
20658+
const checkNode = getEffectiveCheckNode(elem);
20659+
yield { errorNode: checkNode, innerExpression: checkNode, nameType };
2065820660
}
2065920661
}
2066020662

@@ -34190,6 +34192,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3419034192
}
3419134193
}
3419234194

34195+
function getEffectiveCheckNode(argument: Expression): Expression {
34196+
argument = skipParentheses(argument);
34197+
return isSatisfiesExpression(argument) ? skipParentheses(argument.expression) : argument;
34198+
}
34199+
3419334200
function getSignatureApplicabilityError(
3419434201
node: CallLikeExpression,
3419534202
args: readonly Expression[],
@@ -34233,7 +34240,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3423334240
// we obtain the regular type of any object literal arguments because we may not have inferred complete
3423434241
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
3423534242
const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType;
34236-
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage, containingMessageChain, errorOutputContainer)) {
34243+
const effectiveCheckArgumentNode = getEffectiveCheckNode(arg);
34244+
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) {
3423734245
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors");
3423834246
maybeAddMissingAwaitInfo(arg, checkArgType, paramType);
3423934247
return errorOutputContainer.errors || emptyArray;
@@ -34245,7 +34253,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3424534253
const restArgCount = args.length - argCount;
3424634254
const errorNode = !reportErrors ? undefined :
3424734255
restArgCount === 0 ? node :
34248-
restArgCount === 1 ? args[argCount] :
34256+
restArgCount === 1 ? getEffectiveCheckNode(args[argCount]) :
3424934257
setTextRangePosEnd(createSyntheticExpression(node, spreadType), args[argCount].pos, args[args.length - 1].end);
3425034258
if (!checkTypeRelatedTo(spreadType, restType, relation, errorNode, headMessage, /*containingMessageChain*/ undefined, errorOutputContainer)) {
3425134259
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "rest parameter should have errors when reporting errors");
@@ -37536,12 +37544,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3753637544
const exprType = checkExpression(node.body);
3753737545
const returnOrPromisedType = returnType && unwrapReturnType(returnType, functionFlags);
3753837546
if (returnOrPromisedType) {
37547+
const effectiveCheckNode = getEffectiveCheckNode(node.body);
3753937548
if ((functionFlags & FunctionFlags.AsyncGenerator) === FunctionFlags.Async) { // Async function
37540-
const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, node.body, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
37541-
checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, node.body, node.body);
37549+
const awaitedType = checkAwaitedType(exprType, /*withAlias*/ false, effectiveCheckNode, Diagnostics.The_return_type_of_an_async_function_must_either_be_a_valid_promise_or_must_not_contain_a_callable_then_member);
37550+
checkTypeAssignableToAndOptionallyElaborate(awaitedType, returnOrPromisedType, effectiveCheckNode, effectiveCheckNode);
3754237551
}
3754337552
else { // Normal function
37544-
checkTypeAssignableToAndOptionallyElaborate(exprType, returnOrPromisedType, node.body, node.body);
37553+
checkTypeAssignableToAndOptionallyElaborate(exprType, returnOrPromisedType, effectiveCheckNode, effectiveCheckNode);
3754537554
}
3754637555
}
3754737556
}
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
typeSatisfaction_errorLocations1.ts(4,5): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ a: true; }'.
2+
Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
3+
typeSatisfaction_errorLocations1.ts(5,7): error TS2322: Type 'number' is not assignable to type 'true'.
4+
typeSatisfaction_errorLocations1.ts(6,5): error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: true; }'.
5+
Types of property 'a' are incompatible.
6+
Type 'number' is not assignable to type 'true'.
7+
typeSatisfaction_errorLocations1.ts(11,10): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ a: true; }'.
8+
Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
9+
typeSatisfaction_errorLocations1.ts(12,12): error TS2322: Type 'number' is not assignable to type 'true'.
10+
typeSatisfaction_errorLocations1.ts(13,10): error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: true; }'.
11+
Types of property 'a' are incompatible.
12+
Type 'number' is not assignable to type 'true'.
13+
typeSatisfaction_errorLocations1.ts(16,5): error TS2345: Argument of type '[{ a: boolean; }]' is not assignable to parameter of type 'T'.
14+
'T' could be instantiated with an arbitrary type which could be unrelated to '[{ a: boolean; }]'.
15+
typeSatisfaction_errorLocations1.ts(18,5): error TS2345: Argument of type '[{ a: true; }]' is not assignable to parameter of type 'T'.
16+
'[{ a: true; }]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ a: true; }[]'.
17+
typeSatisfaction_errorLocations1.ts(21,43): error TS2322: Type 'number' is not assignable to type 'boolean'.
18+
typeSatisfaction_errorLocations1.ts(23,23): error TS2322: Type 'boolean' is not assignable to type 'number'.
19+
typeSatisfaction_errorLocations1.ts(25,20): error TS1360: Type 'number' does not satisfy the expected type 'boolean'.
20+
typeSatisfaction_errorLocations1.ts(26,7): error TS2322: Type '1' is not assignable to type 'true'.
21+
typeSatisfaction_errorLocations1.ts(29,18): error TS2322: Type 'string' is not assignable to type 'number'.
22+
typeSatisfaction_errorLocations1.ts(31,20): error TS1360: Type 'readonly [10, "20"]' does not satisfy the expected type 'number[]'.
23+
The type 'readonly [10, "20"]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
24+
typeSatisfaction_errorLocations1.ts(34,9): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
25+
typeSatisfaction_errorLocations1.ts(36,9): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
26+
typeSatisfaction_errorLocations1.ts(39,3): error TS2322: Type 'string' is not assignable to type 'number'.
27+
typeSatisfaction_errorLocations1.ts(43,3): error TS2322: Type 'string' is not assignable to type 'number'.
28+
typeSatisfaction_errorLocations1.ts(43,16): error TS1360: Type 'string' does not satisfy the expected type 'number'.
29+
typeSatisfaction_errorLocations1.ts(46,22): error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
30+
typeSatisfaction_errorLocations1.ts(47,24): error TS2322: Type 'number' is not assignable to type 'true'.
31+
typeSatisfaction_errorLocations1.ts(48,21): error TS2322: Type '{ a: number; }' is not assignable to type '{ a: true; }'.
32+
Types of property 'a' are incompatible.
33+
Type 'number' is not assignable to type 'true'.
34+
35+
36+
==== typeSatisfaction_errorLocations1.ts (22 errors) ====
37+
const obj1 = { a: 1 };
38+
39+
const fn1 = (s: { a: true }) => {};
40+
fn1({} satisfies unknown);
41+
~~
42+
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type '{ a: true; }'.
43+
!!! error TS2345: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
44+
!!! related TS2728 typeSatisfaction_errorLocations1.ts:3:19: 'a' is declared here.
45+
fn1({ a: 1 } satisfies unknown);
46+
~
47+
!!! error TS2322: Type 'number' is not assignable to type 'true'.
48+
!!! related TS6500 typeSatisfaction_errorLocations1.ts:3:19: The expected type comes from property 'a' which is declared here on type '{ a: true; }'
49+
fn1(obj1 satisfies unknown);
50+
~~~~
51+
!!! error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: true; }'.
52+
!!! error TS2345: Types of property 'a' are incompatible.
53+
!!! error TS2345: Type 'number' is not assignable to type 'true'.
54+
55+
class Cls1 {
56+
constructor(p: { a: true }) {}
57+
}
58+
new Cls1({} satisfies unknown);
59+
~~
60+
!!! error TS2345: Argument of type '{}' is not assignable to parameter of type '{ a: true; }'.
61+
!!! error TS2345: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
62+
!!! related TS2728 typeSatisfaction_errorLocations1.ts:9:20: 'a' is declared here.
63+
new Cls1({ a: 1 } satisfies unknown);
64+
~
65+
!!! error TS2322: Type 'number' is not assignable to type 'true'.
66+
!!! related TS6500 typeSatisfaction_errorLocations1.ts:9:20: The expected type comes from property 'a' which is declared here on type '{ a: true; }'
67+
new Cls1(obj1 satisfies unknown);
68+
~~~~
69+
!!! error TS2345: Argument of type '{ a: number; }' is not assignable to parameter of type '{ a: true; }'.
70+
!!! error TS2345: Types of property 'a' are incompatible.
71+
!!! error TS2345: Type 'number' is not assignable to type 'true'.
72+
73+
function fn2<T extends { a: true }[]>(f: (...args: T) => void) {
74+
f({ a: true } satisfies unknown);
75+
~~~~~~~~~~~
76+
!!! error TS2345: Argument of type '[{ a: boolean; }]' is not assignable to parameter of type 'T'.
77+
!!! error TS2345: 'T' could be instantiated with an arbitrary type which could be unrelated to '[{ a: boolean; }]'.
78+
const o = { a: true as const };
79+
f(o satisfies unknown);
80+
~
81+
!!! error TS2345: Argument of type '[{ a: true; }]' is not assignable to parameter of type 'T'.
82+
!!! error TS2345: '[{ a: true; }]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '{ a: true; }[]'.
83+
}
84+
85+
const tuple1: [boolean, boolean] = [true, 100 satisfies unknown];
86+
~~~
87+
!!! error TS2322: Type 'number' is not assignable to type 'boolean'.
88+
89+
const obj2 = { a: 10, b: true } satisfies Record<string, number>;
90+
~
91+
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.
92+
93+
const literal1 = 1 satisfies boolean;
94+
~~~~~~~~~
95+
!!! error TS1360: Type 'number' does not satisfy the expected type 'boolean'.
96+
const literal2: true = 1 satisfies number;
97+
~~~~~~~~
98+
!!! error TS2322: Type '1' is not assignable to type 'true'.
99+
100+
declare function fn3(...args: unknown[]): void;
101+
fn3(10, ...([10, "20"] satisfies number[]));
102+
~~~~
103+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
104+
const tuple2 = [10, "20"] as const;
105+
fn3(10, ...(tuple2 satisfies number[]));
106+
~~~~~~~~~
107+
!!! error TS1360: Type 'readonly [10, "20"]' does not satisfy the expected type 'number[]'.
108+
!!! error TS1360: The type 'readonly [10, "20"]' is 'readonly' and cannot be assigned to the mutable type 'number[]'.
109+
110+
declare function fn4(...args: number[]): void;
111+
fn4(10, ...(["10", "20"] satisfies readonly string[]));
112+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
114+
const tuple3 = ["10", "20"] as const;
115+
fn4(10, ...(tuple3 satisfies readonly string[]));
116+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117+
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
118+
119+
function fn5(): number {
120+
return "foo" satisfies unknown;
121+
~~~~~~
122+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
123+
}
124+
125+
function fn6(): number {
126+
return "foo" satisfies number;
127+
~~~~~~
128+
!!! error TS2322: Type 'string' is not assignable to type 'number'.
129+
~~~~~~~~~
130+
!!! error TS1360: Type 'string' does not satisfy the expected type 'number'.
131+
}
132+
133+
((): { a: true } => ({}) satisfies unknown)();
134+
~~
135+
!!! error TS2741: Property 'a' is missing in type '{}' but required in type '{ a: true; }'.
136+
!!! related TS2728 typeSatisfaction_errorLocations1.ts:46:8: 'a' is declared here.
137+
((): { a: true } => ({ a: 1 }) satisfies unknown)();
138+
~
139+
!!! error TS2322: Type 'number' is not assignable to type 'true'.
140+
!!! related TS6500 typeSatisfaction_errorLocations1.ts:47:8: The expected type comes from property 'a' which is declared here on type '{ a: true; }'
141+
((): { a: true } => obj1 satisfies unknown)();
142+
~~~~
143+
!!! error TS2322: Type '{ a: number; }' is not assignable to type '{ a: true; }'.
144+
!!! error TS2322: Types of property 'a' are incompatible.
145+
!!! error TS2322: Type 'number' is not assignable to type 'true'.
146+
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//// [tests/cases/conformance/expressions/typeSatisfaction/typeSatisfaction_errorLocations1.ts] ////
2+
3+
=== typeSatisfaction_errorLocations1.ts ===
4+
const obj1 = { a: 1 };
5+
>obj1 : Symbol(obj1, Decl(typeSatisfaction_errorLocations1.ts, 0, 5))
6+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 0, 14))
7+
8+
const fn1 = (s: { a: true }) => {};
9+
>fn1 : Symbol(fn1, Decl(typeSatisfaction_errorLocations1.ts, 2, 5))
10+
>s : Symbol(s, Decl(typeSatisfaction_errorLocations1.ts, 2, 13))
11+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 2, 17))
12+
13+
fn1({} satisfies unknown);
14+
>fn1 : Symbol(fn1, Decl(typeSatisfaction_errorLocations1.ts, 2, 5))
15+
16+
fn1({ a: 1 } satisfies unknown);
17+
>fn1 : Symbol(fn1, Decl(typeSatisfaction_errorLocations1.ts, 2, 5))
18+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 4, 5))
19+
20+
fn1(obj1 satisfies unknown);
21+
>fn1 : Symbol(fn1, Decl(typeSatisfaction_errorLocations1.ts, 2, 5))
22+
>obj1 : Symbol(obj1, Decl(typeSatisfaction_errorLocations1.ts, 0, 5))
23+
24+
class Cls1 {
25+
>Cls1 : Symbol(Cls1, Decl(typeSatisfaction_errorLocations1.ts, 5, 28))
26+
27+
constructor(p: { a: true }) {}
28+
>p : Symbol(p, Decl(typeSatisfaction_errorLocations1.ts, 8, 14))
29+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 8, 18))
30+
}
31+
new Cls1({} satisfies unknown);
32+
>Cls1 : Symbol(Cls1, Decl(typeSatisfaction_errorLocations1.ts, 5, 28))
33+
34+
new Cls1({ a: 1 } satisfies unknown);
35+
>Cls1 : Symbol(Cls1, Decl(typeSatisfaction_errorLocations1.ts, 5, 28))
36+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 11, 10))
37+
38+
new Cls1(obj1 satisfies unknown);
39+
>Cls1 : Symbol(Cls1, Decl(typeSatisfaction_errorLocations1.ts, 5, 28))
40+
>obj1 : Symbol(obj1, Decl(typeSatisfaction_errorLocations1.ts, 0, 5))
41+
42+
function fn2<T extends { a: true }[]>(f: (...args: T) => void) {
43+
>fn2 : Symbol(fn2, Decl(typeSatisfaction_errorLocations1.ts, 12, 33))
44+
>T : Symbol(T, Decl(typeSatisfaction_errorLocations1.ts, 14, 13))
45+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 14, 24))
46+
>f : Symbol(f, Decl(typeSatisfaction_errorLocations1.ts, 14, 38))
47+
>args : Symbol(args, Decl(typeSatisfaction_errorLocations1.ts, 14, 42))
48+
>T : Symbol(T, Decl(typeSatisfaction_errorLocations1.ts, 14, 13))
49+
50+
f({ a: true } satisfies unknown);
51+
>f : Symbol(f, Decl(typeSatisfaction_errorLocations1.ts, 14, 38))
52+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 15, 5))
53+
54+
const o = { a: true as const };
55+
>o : Symbol(o, Decl(typeSatisfaction_errorLocations1.ts, 16, 7))
56+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 16, 13))
57+
>const : Symbol(const)
58+
59+
f(o satisfies unknown);
60+
>f : Symbol(f, Decl(typeSatisfaction_errorLocations1.ts, 14, 38))
61+
>o : Symbol(o, Decl(typeSatisfaction_errorLocations1.ts, 16, 7))
62+
}
63+
64+
const tuple1: [boolean, boolean] = [true, 100 satisfies unknown];
65+
>tuple1 : Symbol(tuple1, Decl(typeSatisfaction_errorLocations1.ts, 20, 5))
66+
67+
const obj2 = { a: 10, b: true } satisfies Record<string, number>;
68+
>obj2 : Symbol(obj2, Decl(typeSatisfaction_errorLocations1.ts, 22, 5))
69+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 22, 14))
70+
>b : Symbol(b, Decl(typeSatisfaction_errorLocations1.ts, 22, 21))
71+
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
72+
73+
const literal1 = 1 satisfies boolean;
74+
>literal1 : Symbol(literal1, Decl(typeSatisfaction_errorLocations1.ts, 24, 5))
75+
76+
const literal2: true = 1 satisfies number;
77+
>literal2 : Symbol(literal2, Decl(typeSatisfaction_errorLocations1.ts, 25, 5))
78+
79+
declare function fn3(...args: unknown[]): void;
80+
>fn3 : Symbol(fn3, Decl(typeSatisfaction_errorLocations1.ts, 25, 42))
81+
>args : Symbol(args, Decl(typeSatisfaction_errorLocations1.ts, 27, 21))
82+
83+
fn3(10, ...([10, "20"] satisfies number[]));
84+
>fn3 : Symbol(fn3, Decl(typeSatisfaction_errorLocations1.ts, 25, 42))
85+
86+
const tuple2 = [10, "20"] as const;
87+
>tuple2 : Symbol(tuple2, Decl(typeSatisfaction_errorLocations1.ts, 29, 5))
88+
>const : Symbol(const)
89+
90+
fn3(10, ...(tuple2 satisfies number[]));
91+
>fn3 : Symbol(fn3, Decl(typeSatisfaction_errorLocations1.ts, 25, 42))
92+
>tuple2 : Symbol(tuple2, Decl(typeSatisfaction_errorLocations1.ts, 29, 5))
93+
94+
declare function fn4(...args: number[]): void;
95+
>fn4 : Symbol(fn4, Decl(typeSatisfaction_errorLocations1.ts, 30, 40))
96+
>args : Symbol(args, Decl(typeSatisfaction_errorLocations1.ts, 32, 21))
97+
98+
fn4(10, ...(["10", "20"] satisfies readonly string[]));
99+
>fn4 : Symbol(fn4, Decl(typeSatisfaction_errorLocations1.ts, 30, 40))
100+
101+
const tuple3 = ["10", "20"] as const;
102+
>tuple3 : Symbol(tuple3, Decl(typeSatisfaction_errorLocations1.ts, 34, 5))
103+
>const : Symbol(const)
104+
105+
fn4(10, ...(tuple3 satisfies readonly string[]));
106+
>fn4 : Symbol(fn4, Decl(typeSatisfaction_errorLocations1.ts, 30, 40))
107+
>tuple3 : Symbol(tuple3, Decl(typeSatisfaction_errorLocations1.ts, 34, 5))
108+
109+
function fn5(): number {
110+
>fn5 : Symbol(fn5, Decl(typeSatisfaction_errorLocations1.ts, 35, 49))
111+
112+
return "foo" satisfies unknown;
113+
}
114+
115+
function fn6(): number {
116+
>fn6 : Symbol(fn6, Decl(typeSatisfaction_errorLocations1.ts, 39, 1))
117+
118+
return "foo" satisfies number;
119+
}
120+
121+
((): { a: true } => ({}) satisfies unknown)();
122+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 45, 6))
123+
124+
((): { a: true } => ({ a: 1 }) satisfies unknown)();
125+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 46, 6))
126+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 46, 22))
127+
128+
((): { a: true } => obj1 satisfies unknown)();
129+
>a : Symbol(a, Decl(typeSatisfaction_errorLocations1.ts, 47, 6))
130+
>obj1 : Symbol(obj1, Decl(typeSatisfaction_errorLocations1.ts, 0, 5))
131+

0 commit comments

Comments
 (0)