Skip to content

Commit e9836a4

Browse files
authored
Ensure rest type for source parameter is readonly in relations (#53258)
1 parent f43a4fe commit e9836a4

7 files changed

+200
-18
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19850,7 +19850,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1985019850
const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1;
1985119851

1985219852
for (let i = 0; i < paramCount; i++) {
19853-
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i) : tryGetTypeAtPosition(source, i);
19853+
const sourceType = i === restIndex ? getRestTypeAtPosition(source, i, /*readonly*/ true) : tryGetTypeAtPosition(source, i);
1985419854
const targetType = i === restIndex ? getRestTypeAtPosition(target, i) : tryGetTypeAtPosition(target, i);
1985519855
if (sourceType && targetType) {
1985619856
// In order to ensure that any generic type Foo<T> is at least co-variant with respect to T no matter
@@ -34656,12 +34656,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3465634656
return undefined;
3465734657
}
3465834658

34659-
function getRestTypeAtPosition(source: Signature, pos: number): Type {
34659+
function getRestTypeAtPosition(source: Signature, pos: number, readonly = false): Type {
3466034660
const parameterCount = getParameterCount(source);
3466134661
const minArgumentCount = getMinArgumentCount(source);
3466234662
const restType = getEffectiveRestType(source);
3466334663
if (restType && pos >= parameterCount - 1) {
34664-
return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType));
34664+
return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType), readonly);
3466534665
}
3466634666
const types = [];
3466734667
const flags = [];
@@ -34680,7 +34680,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3468034680
names.push(name);
3468134681
}
3468234682
}
34683-
return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined);
34683+
return createTupleType(types, flags, readonly, length(names) === length(types) ? names : undefined);
3468434684
}
3468534685

3468634686
// Return the number of parameters in a signature. The rest parameter, if present, counts as one
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//// [contextualTupleTypeParameterReadonly.ts]
2+
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
3+
4+
const cases = [
5+
[1, '1'],
6+
[2, '2'],
7+
] as const;
8+
9+
const eacher = each(cases);
10+
11+
eacher((a, b) => {
12+
a;
13+
b;
14+
});
15+
16+
eacher((...args) => {
17+
const [a, b] = args;
18+
a;
19+
b;
20+
});
21+
22+
23+
//// [contextualTupleTypeParameterReadonly.js]
24+
"use strict";
25+
var cases = [
26+
[1, '1'],
27+
[2, '2'],
28+
];
29+
var eacher = each(cases);
30+
eacher(function (a, b) {
31+
a;
32+
b;
33+
});
34+
eacher(function () {
35+
var args = [];
36+
for (var _i = 0; _i < arguments.length; _i++) {
37+
args[_i] = arguments[_i];
38+
}
39+
var a = args[0], b = args[1];
40+
a;
41+
b;
42+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
=== tests/cases/compiler/contextualTupleTypeParameterReadonly.ts ===
2+
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
3+
>each : Symbol(each, Decl(contextualTupleTypeParameterReadonly.ts, 0, 0))
4+
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))
5+
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
6+
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 0, 52))
7+
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
8+
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))
9+
>fn : Symbol(fn, Decl(contextualTupleTypeParameterReadonly.ts, 0, 79))
10+
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 0, 84))
11+
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))
12+
13+
const cases = [
14+
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 2, 5))
15+
16+
[1, '1'],
17+
[2, '2'],
18+
] as const;
19+
>const : Symbol(const)
20+
21+
const eacher = each(cases);
22+
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
23+
>each : Symbol(each, Decl(contextualTupleTypeParameterReadonly.ts, 0, 0))
24+
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 2, 5))
25+
26+
eacher((a, b) => {
27+
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
28+
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 9, 8))
29+
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 9, 10))
30+
31+
a;
32+
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 9, 8))
33+
34+
b;
35+
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 9, 10))
36+
37+
});
38+
39+
eacher((...args) => {
40+
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
41+
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 14, 8))
42+
43+
const [a, b] = args;
44+
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 15, 11))
45+
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 15, 13))
46+
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 14, 8))
47+
48+
a;
49+
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 15, 11))
50+
51+
b;
52+
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 15, 13))
53+
54+
});
55+
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=== tests/cases/compiler/contextualTupleTypeParameterReadonly.ts ===
2+
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
3+
>each : <T extends readonly any[]>(cases: ReadonlyArray<T>) => (fn: (...args: T) => any) => void
4+
>cases : readonly T[]
5+
>fn : (...args: T) => any
6+
>args : T
7+
8+
const cases = [
9+
>cases : readonly [readonly [1, "1"], readonly [2, "2"]]
10+
>[ [1, '1'], [2, '2'],] as const : readonly [readonly [1, "1"], readonly [2, "2"]]
11+
>[ [1, '1'], [2, '2'],] : readonly [readonly [1, "1"], readonly [2, "2"]]
12+
13+
[1, '1'],
14+
>[1, '1'] : readonly [1, "1"]
15+
>1 : 1
16+
>'1' : "1"
17+
18+
[2, '2'],
19+
>[2, '2'] : readonly [2, "2"]
20+
>2 : 2
21+
>'2' : "2"
22+
23+
] as const;
24+
25+
const eacher = each(cases);
26+
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
27+
>each(cases) : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
28+
>each : <T extends readonly any[]>(cases: readonly T[]) => (fn: (...args: T) => any) => void
29+
>cases : readonly [readonly [1, "1"], readonly [2, "2"]]
30+
31+
eacher((a, b) => {
32+
>eacher((a, b) => { a; b;}) : void
33+
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
34+
>(a, b) => { a; b;} : (a: 1 | 2, b: "1" | "2") => void
35+
>a : 1 | 2
36+
>b : "1" | "2"
37+
38+
a;
39+
>a : 1 | 2
40+
41+
b;
42+
>b : "1" | "2"
43+
44+
});
45+
46+
eacher((...args) => {
47+
>eacher((...args) => { const [a, b] = args; a; b;}) : void
48+
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
49+
>(...args) => { const [a, b] = args; a; b;} : (...args: readonly [1, "1"] | readonly [2, "2"]) => void
50+
>args : readonly [1, "1"] | readonly [2, "2"]
51+
52+
const [a, b] = args;
53+
>a : 1 | 2
54+
>b : "1" | "2"
55+
>args : readonly [1, "1"] | readonly [2, "2"]
56+
57+
a;
58+
>a : 1 | 2
59+
60+
b;
61+
>b : "1" | "2"
62+
63+
});
64+

tests/baselines/reference/genericRestParameters3.errors.txt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(18,1): error TS2345
66
Source has 0 element(s) but target requires 2.
77
tests/cases/conformance/types/rest/genericRestParameters3.ts(23,1): error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
88
Types of parameters 'y' and 'args' are incompatible.
9-
Type '[string] | [number, boolean]' is not assignable to type '[y: string]'.
10-
Type '[number, boolean]' is not assignable to type '[y: string]'.
9+
Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: string]'.
10+
Type '[number, boolean]' is not assignable to type 'readonly [y: string]'.
1111
Source has 2 element(s) but target allows only 1.
1212
tests/cases/conformance/types/rest/genericRestParameters3.ts(24,1): error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
1313
Types of parameters 'y' and 'args' are incompatible.
14-
Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'.
15-
Type '[string]' is not assignable to type '[y: number, z: boolean]'.
14+
Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: number, z: boolean]'.
15+
Type '[string]' is not assignable to type 'readonly [y: number, z: boolean]'.
1616
Source has 1 element(s) but target requires 2.
1717
tests/cases/conformance/types/rest/genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0.
1818
tests/cases/conformance/types/rest/genericRestParameters3.ts(36,21): error TS2345: Argument of type 'number' is not assignable to parameter of type '(...args: CoolArray<any>) => void'.
1919
tests/cases/conformance/types/rest/genericRestParameters3.ts(37,21): error TS2345: Argument of type '<T extends any[]>(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray<any>) => void'.
2020
Types of parameters 'cb' and 'args' are incompatible.
21-
Property '0' is missing in type 'CoolArray<any>' but required in type '[cb: (...args: any[]) => void]'.
21+
Property '0' is missing in type 'CoolArray<any>' but required in type 'readonly [cb: (...args: any[]) => void]'.
2222
tests/cases/conformance/types/rest/genericRestParameters3.ts(44,32): error TS2345: Argument of type '[10, 20]' is not assignable to parameter of type 'CoolArray<number>'.
2323
Property 'hello' is missing in type '[10, 20]' but required in type 'CoolArray<number>'.
2424
tests/cases/conformance/types/rest/genericRestParameters3.ts(49,1): error TS2345: Argument of type '[]' is not assignable to parameter of type 'CoolArray<never>'.
@@ -69,15 +69,15 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345
6969
~~
7070
!!! error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
7171
!!! error TS2322: Types of parameters 'y' and 'args' are incompatible.
72-
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: string]'.
73-
!!! error TS2322: Type '[number, boolean]' is not assignable to type '[y: string]'.
72+
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: string]'.
73+
!!! error TS2322: Type '[number, boolean]' is not assignable to type 'readonly [y: string]'.
7474
!!! error TS2322: Source has 2 element(s) but target allows only 1.
7575
f1 = f3; // Error
7676
~~
7777
!!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
7878
!!! error TS2322: Types of parameters 'y' and 'args' are incompatible.
79-
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'.
80-
!!! error TS2322: Type '[string]' is not assignable to type '[y: number, z: boolean]'.
79+
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: number, z: boolean]'.
80+
!!! error TS2322: Type '[string]' is not assignable to type 'readonly [y: number, z: boolean]'.
8181
!!! error TS2322: Source has 1 element(s) but target requires 2.
8282
f1 = f4;
8383

@@ -100,7 +100,7 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345
100100
~~~
101101
!!! error TS2345: Argument of type '<T extends any[]>(cb: (...args: T) => void) => void' is not assignable to parameter of type '(...args: CoolArray<any>) => void'.
102102
!!! error TS2345: Types of parameters 'cb' and 'args' are incompatible.
103-
!!! error TS2345: Property '0' is missing in type 'CoolArray<any>' but required in type '[cb: (...args: any[]) => void]'.
103+
!!! error TS2345: Property '0' is missing in type 'CoolArray<any>' but required in type 'readonly [cb: (...args: any[]) => void]'.
104104

105105
function bar<T extends any[]>(...args: T): T {
106106
return args;

tests/baselines/reference/restTuplesFromContextualTypes.errors.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error TS2345: Argument of type '(a: number, b: T[0], ...x: T[number][]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
22
Types of parameters 'b' and 'args' are incompatible.
3-
Type 'T' is not assignable to type '[b: T[0], ...x: T[number][]]'.
4-
Type 'any[]' is not assignable to type '[b: T[0], ...x: T[number][]]'.
3+
Type 'T' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
4+
Type 'any[]' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
55
Source provides no match for required element at position 0 in target.
66

77

@@ -65,8 +65,8 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
6565
~~~~~~~~~~~~~~~~~~
6666
!!! error TS2345: Argument of type '(a: number, b: T[0], ...x: T[number][]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'.
6767
!!! error TS2345: Types of parameters 'b' and 'args' are incompatible.
68-
!!! error TS2345: Type 'T' is not assignable to type '[b: T[0], ...x: T[number][]]'.
69-
!!! error TS2345: Type 'any[]' is not assignable to type '[b: T[0], ...x: T[number][]]'.
68+
!!! error TS2345: Type 'T' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
69+
!!! error TS2345: Type 'any[]' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
7070
!!! error TS2345: Source provides no match for required element at position 0 in target.
7171
}
7272

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// @strict: true
2+
3+
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
4+
5+
const cases = [
6+
[1, '1'],
7+
[2, '2'],
8+
] as const;
9+
10+
const eacher = each(cases);
11+
12+
eacher((a, b) => {
13+
a;
14+
b;
15+
});
16+
17+
eacher((...args) => {
18+
const [a, b] = args;
19+
a;
20+
b;
21+
});

0 commit comments

Comments
 (0)