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

This commit is contained in:
Jake Bailey
2023-03-20 16:18:52 -07:00
committed by GitHub
parent f43a4fe401
commit e9836a4bec
7 changed files with 200 additions and 18 deletions

View File

@@ -19850,7 +19850,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
@@ -34656,12 +34656,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 = [];
@@ -34680,7 +34680,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

View File

@@ -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;
});

View File

@@ -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))
});

View File

@@ -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"
});

View File

@@ -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>'.
@@ -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;
@@ -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;

View File

@@ -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.
@@ -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.
}

View File

@@ -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;
});