From 9a0a838d1270d46212848ca0e7cafa435a65112d Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 10 Feb 2019 07:48:22 -0800 Subject: [PATCH 1/4] Use getIndexedAccess to compute type for contextual rest parameters --- src/compiler/checker.ts | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f7cc72c534d05..354d6af67bec5 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21550,13 +21550,8 @@ namespace ts { } if (signature.hasRestParameter) { const restType = getTypeOfSymbol(signature.parameters[paramCount]); - if (isTupleType(restType)) { - if (pos - paramCount < getLengthOfTupleType(restType)) { - return restType.typeArguments![pos - paramCount]; - } - return getRestTypeOfTupleType(restType); - } - return getIndexTypeOfType(restType, IndexKind.Number); + const indexType = getLiteralType(pos - paramCount); + return getIndexedAccessType(restType, indexType); } return undefined; } @@ -21564,18 +21559,22 @@ namespace ts { function getRestTypeAtPosition(source: Signature, pos: number): Type { const paramCount = getParameterCount(source); const restType = getEffectiveRestType(source); - if (restType && pos === paramCount - 1) { + const nonRestCount = paramCount - (restType ? 1 : 0); + if (restType && pos === nonRestCount) { return restType; } - const start = restType ? Math.min(pos, paramCount - 1) : pos; const types = []; const names = []; - for (let i = start; i < paramCount; i++) { + for (let i = pos; i < nonRestCount; i++) { types.push(getTypeAtPosition(source, i)); names.push(getParameterNameAtPosition(source, i)); } + if (restType) { + types.push(getIndexedAccessType(restType, numberType)); + names.push(getParameterNameAtPosition(source, nonRestCount)); + } const minArgumentCount = getMinArgumentCount(source); - const minLength = minArgumentCount < start ? 0 : minArgumentCount - start; + const minLength = minArgumentCount < pos ? 0 : minArgumentCount - pos; return createTupleType(types, minLength, !!restType, /*readonly*/ false, names); } From 36be6c8b6859ea5b8a18e375609133311fd0cce3 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 11 Feb 2019 09:41:38 -0800 Subject: [PATCH 2/4] Accept new baselines --- .../restTuplesFromContextualTypes.errors.txt | 12 ++++++------ .../reference/restTuplesFromContextualTypes.types | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt index d2246fbfd8409..7af71017a7119 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt +++ b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'. +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 '[any, ...any[]]'. - Property '0' is missing in type 'any[]' but required in type '[any, ...any[]]'. + Type 'T' is not assignable to type '[T[0], ...T[number][]]'. + Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'. ==== tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts (1 errors) ==== @@ -62,10 +62,10 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error f((a, ...x) => {}); f((a, b, ...x) => {}); ~~~~~~~~~~~~~~~~~~ -!!! error TS2345: Argument of type '(a: number, b: any, ...x: any[]) => void' is not assignable to parameter of type '(x: number, ...args: T) => void'. +!!! 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 '[any, ...any[]]'. -!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[any, ...any[]]'. +!!! error TS2345: Type 'T' is not assignable to type '[T[0], ...T[number][]]'. +!!! error TS2345: Property '0' is missing in type 'any[]' but required in type '[T[0], ...T[number][]]'. } // Repro from #25288 diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.types b/tests/baselines/reference/restTuplesFromContextualTypes.types index ee63057b9ebb2..ad5a4788426e0 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.types +++ b/tests/baselines/reference/restTuplesFromContextualTypes.types @@ -332,8 +332,8 @@ function f4(t: T) { f((...x) => {}); >f((...x) => {}) : void >f : (cb: (x: number, ...args: T) => void) => void ->(...x) => {} : (x: number, ...args: any[]) => void ->x : [number, ...any[]] +>(...x) => {} : (x: number, ...args: T[number][]) => void +>x : [number, ...T[number][]] f((a, ...x) => {}); >f((a, ...x) => {}) : void @@ -345,10 +345,10 @@ function f4(t: T) { f((a, b, ...x) => {}); >f((a, b, ...x) => {}) : void >f : (cb: (x: number, ...args: T) => void) => void ->(a, b, ...x) => {} : (a: number, b: any, ...x: any[]) => void +>(a, b, ...x) => {} : (a: number, b: T[0], ...x: T[number][]) => void >a : number ->b : any ->x : any[] +>b : T[0] +>x : T[number][] } // Repro from #25288 From 710826e37e9fc2627e1c4ea2746645d1befb7b89 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 11 Feb 2019 09:46:02 -0800 Subject: [PATCH 3/4] Add regression test --- .../types/rest/restTuplesFromContextualTypes.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts b/tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts index 84bf81195b0b1..d5623a000a20d 100644 --- a/tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts +++ b/tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts @@ -70,3 +70,17 @@ declare function take(cb: (a: number, b: string) => void): void; (function foo(...rest){}(1, '')); take(function(...rest){}); + +// Repro from #29833 + +type ArgsUnion = [number, string] | [number, Error]; +type TupleUnionFunc = (...params: ArgsUnion) => number; + +const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => { + return num; +}; + +const funcUnionTupleRest: TupleUnionFunc = (...params) => { + const [num, strOrErr] = params; + return num; +}; From f33c740b8c29d5b2b07ec6d01422ccd16e7a0d63 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 11 Feb 2019 09:46:10 -0800 Subject: [PATCH 4/4] Accept new baselines --- .../restTuplesFromContextualTypes.errors.txt | 14 +++++++ .../restTuplesFromContextualTypes.js | 29 +++++++++++++++ .../restTuplesFromContextualTypes.symbols | 37 +++++++++++++++++++ .../restTuplesFromContextualTypes.types | 35 ++++++++++++++++++ 4 files changed, 115 insertions(+) diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt index 7af71017a7119..2b94b57f462b6 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt +++ b/tests/baselines/reference/restTuplesFromContextualTypes.errors.txt @@ -79,4 +79,18 @@ tests/cases/conformance/types/rest/restTuplesFromContextualTypes.ts(56,7): error (function foo(...rest){}(1, '')); take(function(...rest){}); + + // Repro from #29833 + + type ArgsUnion = [number, string] | [number, Error]; + type TupleUnionFunc = (...params: ArgsUnion) => number; + + const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => { + return num; + }; + + const funcUnionTupleRest: TupleUnionFunc = (...params) => { + const [num, strOrErr] = params; + return num; + }; \ No newline at end of file diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.js b/tests/baselines/reference/restTuplesFromContextualTypes.js index 3db6c53f384fd..34e75fcea6e30 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.js +++ b/tests/baselines/reference/restTuplesFromContextualTypes.js @@ -68,6 +68,20 @@ declare function take(cb: (a: number, b: string) => void): void; (function foo(...rest){}(1, '')); take(function(...rest){}); + +// Repro from #29833 + +type ArgsUnion = [number, string] | [number, Error]; +type TupleUnionFunc = (...params: ArgsUnion) => number; + +const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => { + return num; +}; + +const funcUnionTupleRest: TupleUnionFunc = (...params) => { + const [num, strOrErr] = params; + return num; +}; //// [restTuplesFromContextualTypes.js] @@ -274,6 +288,17 @@ take(function () { rest[_i] = arguments[_i]; } }); +var funcUnionTupleNoRest = function (num, strOrErr) { + return num; +}; +var funcUnionTupleRest = function () { + var params = []; + for (var _i = 0; _i < arguments.length; _i++) { + params[_i] = arguments[_i]; + } + var num = params[0], strOrErr = params[1]; + return num; +}; //// [restTuplesFromContextualTypes.d.ts] @@ -286,3 +311,7 @@ declare function f3(cb: (x: number, ...args: typeof t3) => void): void; declare function f4(t: T): void; declare var tuple: [number, string]; declare function take(cb: (a: number, b: string) => void): void; +declare type ArgsUnion = [number, string] | [number, Error]; +declare type TupleUnionFunc = (...params: ArgsUnion) => number; +declare const funcUnionTupleNoRest: TupleUnionFunc; +declare const funcUnionTupleRest: TupleUnionFunc; diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.symbols b/tests/baselines/reference/restTuplesFromContextualTypes.symbols index d9b2310b5e27c..c58e8cabcae7d 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.symbols +++ b/tests/baselines/reference/restTuplesFromContextualTypes.symbols @@ -265,3 +265,40 @@ take(function(...rest){}); >take : Symbol(take, Decl(restTuplesFromContextualTypes.ts, 61, 33)) >rest : Symbol(rest, Decl(restTuplesFromContextualTypes.ts, 68, 14)) +// Repro from #29833 + +type ArgsUnion = [number, string] | [number, Error]; +>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26)) +>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --)) + +type TupleUnionFunc = (...params: ArgsUnion) => number; +>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52)) +>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 73, 23)) +>ArgsUnion : Symbol(ArgsUnion, Decl(restTuplesFromContextualTypes.ts, 68, 26)) + +const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => { +>funcUnionTupleNoRest : Symbol(funcUnionTupleNoRest, Decl(restTuplesFromContextualTypes.ts, 75, 5)) +>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52)) +>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46)) +>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 75, 50)) + + return num; +>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 75, 46)) + +}; + +const funcUnionTupleRest: TupleUnionFunc = (...params) => { +>funcUnionTupleRest : Symbol(funcUnionTupleRest, Decl(restTuplesFromContextualTypes.ts, 79, 5)) +>TupleUnionFunc : Symbol(TupleUnionFunc, Decl(restTuplesFromContextualTypes.ts, 72, 52)) +>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44)) + + const [num, strOrErr] = params; +>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9)) +>strOrErr : Symbol(strOrErr, Decl(restTuplesFromContextualTypes.ts, 80, 13)) +>params : Symbol(params, Decl(restTuplesFromContextualTypes.ts, 79, 44)) + + return num; +>num : Symbol(num, Decl(restTuplesFromContextualTypes.ts, 80, 9)) + +}; + diff --git a/tests/baselines/reference/restTuplesFromContextualTypes.types b/tests/baselines/reference/restTuplesFromContextualTypes.types index ad5a4788426e0..c282dbbae311e 100644 --- a/tests/baselines/reference/restTuplesFromContextualTypes.types +++ b/tests/baselines/reference/restTuplesFromContextualTypes.types @@ -389,3 +389,38 @@ take(function(...rest){}); >function(...rest){} : (a: number, b: string) => void >rest : [number, string] +// Repro from #29833 + +type ArgsUnion = [number, string] | [number, Error]; +>ArgsUnion : ArgsUnion + +type TupleUnionFunc = (...params: ArgsUnion) => number; +>TupleUnionFunc : TupleUnionFunc +>params : ArgsUnion + +const funcUnionTupleNoRest: TupleUnionFunc = (num, strOrErr) => { +>funcUnionTupleNoRest : TupleUnionFunc +>(num, strOrErr) => { return num;} : (num: number, strOrErr: string | Error) => number +>num : number +>strOrErr : string | Error + + return num; +>num : number + +}; + +const funcUnionTupleRest: TupleUnionFunc = (...params) => { +>funcUnionTupleRest : TupleUnionFunc +>(...params) => { const [num, strOrErr] = params; return num;} : (...params: ArgsUnion) => number +>params : ArgsUnion + + const [num, strOrErr] = params; +>num : number +>strOrErr : string | Error +>params : ArgsUnion + + return num; +>num : number + +}; +