Skip to content
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

Ensure rest type for source parameter is readonly in relations #53258

Merged
merged 2 commits into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19810,7 +19810,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const restIndex = sourceRestType || targetRestType ? paramCount - 1 : -1;

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

function getRestTypeAtPosition(source: Signature, pos: number): Type {
function getRestTypeAtPosition(source: Signature, pos: number, readonly = false): Type {
const parameterCount = getParameterCount(source);
const minArgumentCount = getMinArgumentCount(source);
const restType = getEffectiveRestType(source);
if (restType && pos >= parameterCount - 1) {
return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType));
return pos === parameterCount - 1 ? restType : createArrayType(getIndexedAccessType(restType, numberType), readonly);
}
const types = [];
const flags = [];
Expand All @@ -34589,7 +34589,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
names.push(name);
}
}
return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined);
return createTupleType(types, flags, readonly, length(names) === length(types) ? names : undefined);
}

// Return the number of parameters in a signature. The rest parameter, if present, counts as one
Expand Down
42 changes: 42 additions & 0 deletions tests/baselines/reference/contextualTupleTypeParameterReadonly.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//// [contextualTupleTypeParameterReadonly.ts]
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;

const cases = [
[1, '1'],
[2, '2'],
] as const;

const eacher = each(cases);

eacher((a, b) => {
a;
b;
});

eacher((...args) => {
const [a, b] = args;
a;
b;
});


//// [contextualTupleTypeParameterReadonly.js]
"use strict";
var cases = [
[1, '1'],
[2, '2'],
];
var eacher = each(cases);
eacher(function (a, b) {
a;
b;
});
eacher(function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var a = args[0], b = args[1];
a;
b;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
=== tests/cases/compiler/contextualTupleTypeParameterReadonly.ts ===
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
>each : Symbol(each, Decl(contextualTupleTypeParameterReadonly.ts, 0, 0))
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 0, 52))
>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))
>fn : Symbol(fn, Decl(contextualTupleTypeParameterReadonly.ts, 0, 79))
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 0, 84))
>T : Symbol(T, Decl(contextualTupleTypeParameterReadonly.ts, 0, 22))

const cases = [
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 2, 5))

[1, '1'],
[2, '2'],
] as const;
>const : Symbol(const)

const eacher = each(cases);
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
>each : Symbol(each, Decl(contextualTupleTypeParameterReadonly.ts, 0, 0))
>cases : Symbol(cases, Decl(contextualTupleTypeParameterReadonly.ts, 2, 5))

eacher((a, b) => {
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 9, 8))
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 9, 10))

a;
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 9, 8))

b;
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 9, 10))

});

eacher((...args) => {
>eacher : Symbol(eacher, Decl(contextualTupleTypeParameterReadonly.ts, 7, 5))
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 14, 8))

const [a, b] = args;
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 15, 11))
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 15, 13))
>args : Symbol(args, Decl(contextualTupleTypeParameterReadonly.ts, 14, 8))

a;
>a : Symbol(a, Decl(contextualTupleTypeParameterReadonly.ts, 15, 11))

b;
>b : Symbol(b, Decl(contextualTupleTypeParameterReadonly.ts, 15, 13))

});

Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
=== tests/cases/compiler/contextualTupleTypeParameterReadonly.ts ===
declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;
>each : <T extends readonly any[]>(cases: ReadonlyArray<T>) => (fn: (...args: T) => any) => void
>cases : readonly T[]
>fn : (...args: T) => any
>args : T

const cases = [
>cases : readonly [readonly [1, "1"], readonly [2, "2"]]
>[ [1, '1'], [2, '2'],] as const : readonly [readonly [1, "1"], readonly [2, "2"]]
>[ [1, '1'], [2, '2'],] : readonly [readonly [1, "1"], readonly [2, "2"]]

[1, '1'],
>[1, '1'] : readonly [1, "1"]
>1 : 1
>'1' : "1"

[2, '2'],
>[2, '2'] : readonly [2, "2"]
>2 : 2
>'2' : "2"

] as const;

const eacher = each(cases);
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
>each(cases) : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
>each : <T extends readonly any[]>(cases: readonly T[]) => (fn: (...args: T) => any) => void
>cases : readonly [readonly [1, "1"], readonly [2, "2"]]

eacher((a, b) => {
>eacher((a, b) => { a; b;}) : void
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
>(a, b) => { a; b;} : (a: 1 | 2, b: "1" | "2") => void
>a : 1 | 2
>b : "1" | "2"

a;
>a : 1 | 2

b;
>b : "1" | "2"

});

eacher((...args) => {
>eacher((...args) => { const [a, b] = args; a; b;}) : void
>eacher : (fn: (...args: readonly [1, "1"] | readonly [2, "2"]) => any) => void
>(...args) => { const [a, b] = args; a; b;} : (...args: readonly [1, "1"] | readonly [2, "2"]) => void
>args : readonly [1, "1"] | readonly [2, "2"]

const [a, b] = args;
>a : 1 | 2
>b : "1" | "2"
>args : readonly [1, "1"] | readonly [2, "2"]

a;
>a : 1 | 2

b;
>b : "1" | "2"

});

20 changes: 10 additions & 10 deletions tests/baselines/reference/genericRestParameters3.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(18,1): error TS2345
Source has 0 element(s) but target requires 2.
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'.
Types of parameters 'y' and 'args' are incompatible.
Type '[string] | [number, boolean]' is not assignable to type '[y: string]'.
Type '[number, boolean]' is not assignable to type '[y: string]'.
Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: string]'.
Type '[number, boolean]' is not assignable to type 'readonly [y: string]'.
Source has 2 element(s) but target allows only 1.
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'.
Types of parameters 'y' and 'args' are incompatible.
Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'.
Type '[string]' is not assignable to type '[y: number, z: boolean]'.
Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: number, z: boolean]'.
Type '[string]' is not assignable to type 'readonly [y: number, z: boolean]'.
Source has 1 element(s) but target requires 2.
tests/cases/conformance/types/rest/genericRestParameters3.ts(35,1): error TS2554: Expected 1 arguments, but got 0.
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'.
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'.
Types of parameters 'cb' and 'args' are incompatible.
Property '0' is missing in type 'CoolArray<any>' but required in type '[cb: (...args: any[]) => void]'.
Property '0' is missing in type 'CoolArray<any>' but required in type 'readonly [cb: (...args: any[]) => void]'.
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>'.
Property 'hello' is missing in type '[10, 20]' but required in type 'CoolArray<number>'.
tests/cases/conformance/types/rest/genericRestParameters3.ts(49,1): error TS2345: Argument of type '[]' is not assignable to parameter of type 'CoolArray<never>'.
Expand Down Expand Up @@ -69,15 +69,15 @@ tests/cases/conformance/types/rest/genericRestParameters3.ts(59,5): error TS2345
~~
!!! error TS2322: Type '(x: string, y: string) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
!!! error TS2322: Types of parameters 'y' and 'args' are incompatible.
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: string]'.
!!! error TS2322: Type '[number, boolean]' is not assignable to type '[y: string]'.
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: string]'.
!!! error TS2322: Type '[number, boolean]' is not assignable to type 'readonly [y: string]'.
!!! error TS2322: Source has 2 element(s) but target allows only 1.
f1 = f3; // Error
~~
!!! error TS2322: Type '(x: string, y: number, z: boolean) => void' is not assignable to type '(x: string, ...args: [string] | [number, boolean]) => void'.
!!! error TS2322: Types of parameters 'y' and 'args' are incompatible.
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type '[y: number, z: boolean]'.
!!! error TS2322: Type '[string]' is not assignable to type '[y: number, z: boolean]'.
!!! error TS2322: Type '[string] | [number, boolean]' is not assignable to type 'readonly [y: number, z: boolean]'.
!!! error TS2322: Type '[string]' is not assignable to type 'readonly [y: number, z: boolean]'.
!!! error TS2322: Source has 1 element(s) but target requires 2.
f1 = f4;

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

function bar<T extends any[]>(...args: T): T {
return args;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
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'.
Types of parameters 'b' and 'args' are incompatible.
Type 'T' is not assignable to type '[b: T[0], ...x: T[number][]]'.
Type 'any[]' is not assignable to type '[b: T[0], ...x: T[number][]]'.
Type 'T' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
Type 'any[]' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
Source provides no match for required element at position 0 in target.


Expand Down Expand Up @@ -65,8 +65,8 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error
~~~~~~~~~~~~~~~~~~
!!! 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'.
!!! error TS2345: Types of parameters 'b' and 'args' are incompatible.
!!! error TS2345: Type 'T' is not assignable to type '[b: T[0], ...x: T[number][]]'.
!!! error TS2345: Type 'any[]' is not assignable to type '[b: T[0], ...x: T[number][]]'.
!!! error TS2345: Type 'T' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
!!! error TS2345: Type 'any[]' is not assignable to type 'readonly [b: T[0], ...x: T[number][]]'.
!!! error TS2345: Source provides no match for required element at position 0 in target.
}

Expand Down
21 changes: 21 additions & 0 deletions tests/cases/compiler/contextualTupleTypeParameterReadonly.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// @strict: true

declare function each<T extends ReadonlyArray<any>>(cases: ReadonlyArray<T>): (fn: (...args: T) => any) => void;

const cases = [
[1, '1'],
[2, '2'],
] as const;

const eacher = each(cases);

eacher((a, b) => {
a;
b;
});

eacher((...args) => {
const [a, b] = args;
a;
b;
});