diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 82f41bc31e64c..5344e7f881f20 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7223,6 +7223,17 @@ namespace ts { return links.resolvedType; } + function getTupleTypeElementTypes(type: Type): Type[] { + Debug.assert(isTupleLikeType(type)); + const types = []; + let idx = 0; + let symbol: Symbol; + while (symbol = getPropertyOfObjectType(type, idx++ + "" as __String)) { + types.push(getTypeOfSymbol(symbol)); + } + return types; + } + interface TypeSet extends Array { containsAny?: boolean; containsUndefined?: boolean; @@ -15482,7 +15493,28 @@ namespace ts { return node.attributes.properties.length > 0 ? [node.attributes] : emptyArray; } else { - return node.arguments || emptyArray; + return flatMap(node.arguments || emptyArray, (arg: Expression) => { + if (arg.kind !== SyntaxKind.SpreadElement) { + return arg; + } + const spread = (arg as SpreadElement).expression; + if (spread.kind === SyntaxKind.ArrayLiteralExpression) { + return (spread as ArrayLiteralExpression).elements; + } + const type = getApparentType(checkExpression(spread)); + if (isTupleLikeType(type)) { + const types = getTupleTypeElementTypes(type); + // hack to make expression nodes for the elements: create element access nodes + return map(types, (el: Type, i: number) => { + const elNode = el && createElementAccess(spread, i); + elNode.parent = spread.parent; + return elNode; + }); + } + else { + return arg; + } + }); } } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index f1a8dfd676b70..be1a2a9a1426d 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -572,6 +572,9 @@ namespace ts { } export function getErrorSpanForNode(sourceFile: SourceFile, node: Node): TextSpan { + if (node.pos < 0) { + return getErrorSpanForNode(sourceFile, node.parent); + } let errorNode = node; switch (node.kind) { case SyntaxKind.SourceFile: diff --git a/tests/baselines/reference/callWithSpread2.errors.txt b/tests/baselines/reference/callWithSpread2.errors.txt index 89617ab6074c3..78ecb16828e87 100644 --- a/tests/baselines/reference/callWithSpread2.errors.txt +++ b/tests/baselines/reference/callWithSpread2.errors.txt @@ -1,21 +1,20 @@ +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(24,1): error TS2554: Expected 1 arguments, but got 3. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(27,1): error TS2554: Expected 0 arguments, but got 2. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(30,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(31,5): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. - Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(31,5): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(32,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(33,13): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. - Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(33,13): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(34,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(35,11): error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. - Type 'string' is not assignable to type 'number'. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(35,11): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(36,1): error TS2556: Expected 1-3 arguments, but got a minimum of 0. tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(37,1): error TS2556: Expected 1-3 arguments, but got a minimum of 0. -tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): error TS2556: Expected 1-3 arguments, but got a minimum of 0. +tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,8): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. -==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (9 errors) ==== +==== tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts (11 errors) ==== declare function all(a?: number, b?: number): void; declare function weird(a?: number | string, b?: number | string): void; declare function prefix(s: string, a?: number, b?: number): void; @@ -40,9 +39,13 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): erro normal("g", ...ns) normal("h", ...mixed) normal("i", ...tuple) + ~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2554: Expected 1 arguments, but got 3. thunk(...ns) thunk(...mixed) thunk(...tuple) + ~~~~~~~~~~~~~~~ +!!! error TS2554: Expected 0 arguments, but got 2. // bad all(...mixed) @@ -51,24 +54,21 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): erro !!! error TS2345: Type 'string' is not assignable to type 'number'. all(...tuple) ~~~~~~~~ -!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. prefix("b", ...mixed) ~~~~~~~~ !!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. !!! error TS2345: Type 'string' is not assignable to type 'number'. prefix("c", ...tuple) ~~~~~~~~ -!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. rest("e", ...mixed) ~~~~~~~~ !!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. !!! error TS2345: Type 'string' is not assignable to type 'number'. rest("f", ...tuple) ~~~~~~~~ -!!! error TS2345: Argument of type 'string | number' is not assignable to parameter of type 'number'. -!!! error TS2345: Type 'string' is not assignable to type 'number'. +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. prefix(...ns) // required parameters are required ~~~~~~~~~~~~~ !!! error TS2556: Expected 1-3 arguments, but got a minimum of 0. @@ -76,6 +76,6 @@ tests/cases/conformance/expressions/functionCalls/callWithSpread2.ts(38,1): erro ~~~~~~~~~~~~~~~~ !!! error TS2556: Expected 1-3 arguments, but got a minimum of 0. prefix(...tuple) - ~~~~~~~~~~~~~~~~ -!!! error TS2556: Expected 1-3 arguments, but got a minimum of 0. + ~~~~~~~~ +!!! error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'. \ No newline at end of file diff --git a/tests/baselines/reference/iteratorSpreadInCall12.errors.txt b/tests/baselines/reference/iteratorSpreadInCall12.errors.txt new file mode 100644 index 0000000000000..41291cf7cb6cf --- /dev/null +++ b/tests/baselines/reference/iteratorSpreadInCall12.errors.txt @@ -0,0 +1,37 @@ +tests/cases/conformance/es6/spread/iteratorSpreadInCall12.ts(31,36): error TS2345: Argument of type 'string' is not assignable to parameter of type 'symbol'. + + +==== tests/cases/conformance/es6/spread/iteratorSpreadInCall12.ts (1 errors) ==== + class Foo { + constructor(...s: T[]) { } + } + + class SymbolIterator { + next() { + return { + value: Symbol(), + done: false + }; + } + + [Symbol.iterator]() { + return this; + } + } + + class StringIterator { + next() { + return { + value: "", + done: false + }; + } + + [Symbol.iterator]() { + return this; + } + } + + new Foo(...[...new SymbolIterator, ...[...new StringIterator]]); + ~~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'symbol'. \ No newline at end of file diff --git a/tests/baselines/reference/iteratorSpreadInCall9.errors.txt b/tests/baselines/reference/iteratorSpreadInCall9.errors.txt index 773eb2a9fc84f..560980e8dff8b 100644 --- a/tests/baselines/reference/iteratorSpreadInCall9.errors.txt +++ b/tests/baselines/reference/iteratorSpreadInCall9.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/es6/spread/iteratorSpreadInCall9.ts(31,32): error TS2345: Argument of type 'string' is not assignable to parameter of type 'symbol'. +tests/cases/conformance/es6/spread/iteratorSpreadInCall9.ts(31,36): error TS2345: Argument of type 'string' is not assignable to parameter of type 'symbol'. ==== tests/cases/conformance/es6/spread/iteratorSpreadInCall9.ts (1 errors) ==== @@ -33,6 +33,6 @@ tests/cases/conformance/es6/spread/iteratorSpreadInCall9.ts(31,32): error TS2345 } new Foo(...new SymbolIterator, ...[...new StringIterator]); - ~~~~~~~~~~~~~~~~~~~~~~~~~~ + ~~~~~~~~~~~~~~~~~~~~~ !!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'symbol'. \ No newline at end of file diff --git a/tests/baselines/reference/keyofAndIndexedAccess.types b/tests/baselines/reference/keyofAndIndexedAccess.types index 671289527aa6d..abd2256027021 100644 --- a/tests/baselines/reference/keyofAndIndexedAccess.types +++ b/tests/baselines/reference/keyofAndIndexedAccess.types @@ -1717,8 +1717,8 @@ function f1(thing: Thing) { >'b' : "b" let x4 = path(thing, ...['a', 'x']); // any ->x4 : any ->path(thing, ...['a', 'x']) : any +>x4 : number +>path(thing, ...['a', 'x']) : number >path : { (obj: T, key1: K1): T[K1]; (obj: T, key1: K1, key2: K2): T[K1][K2]; (obj: T, key1: K1, key2: K2, key3: K3): T[K1][K2][K3]; (obj: any, ...keys: (string | number)[]): any; } >thing : Thing >...['a', 'x'] : string diff --git a/tests/baselines/reference/spreadTuples.js b/tests/baselines/reference/spreadTuples.js new file mode 100644 index 0000000000000..e716334e88e36 --- /dev/null +++ b/tests/baselines/reference/spreadTuples.js @@ -0,0 +1,10 @@ +//// [spreadTuples.ts] +function foo(x: number, y: number, z: number) {} +var args: [0, 1, 2] = [0, 1, 2]; +foo(...args); + + +//// [spreadTuples.js] +function foo(x, y, z) { } +var args = [0, 1, 2]; +foo.apply(void 0, args); diff --git a/tests/baselines/reference/spreadTuples.symbols b/tests/baselines/reference/spreadTuples.symbols new file mode 100644 index 0000000000000..c80f6d24cec3a --- /dev/null +++ b/tests/baselines/reference/spreadTuples.symbols @@ -0,0 +1,14 @@ +=== tests/cases/compiler/spreadTuples.ts === +function foo(x: number, y: number, z: number) {} +>foo : Symbol(foo, Decl(spreadTuples.ts, 0, 0)) +>x : Symbol(x, Decl(spreadTuples.ts, 0, 13)) +>y : Symbol(y, Decl(spreadTuples.ts, 0, 23)) +>z : Symbol(z, Decl(spreadTuples.ts, 0, 34)) + +var args: [0, 1, 2] = [0, 1, 2]; +>args : Symbol(args, Decl(spreadTuples.ts, 1, 3)) + +foo(...args); +>foo : Symbol(foo, Decl(spreadTuples.ts, 0, 0)) +>args : Symbol(args, Decl(spreadTuples.ts, 1, 3)) + diff --git a/tests/baselines/reference/spreadTuples.types b/tests/baselines/reference/spreadTuples.types new file mode 100644 index 0000000000000..639c81e5fc102 --- /dev/null +++ b/tests/baselines/reference/spreadTuples.types @@ -0,0 +1,20 @@ +=== tests/cases/compiler/spreadTuples.ts === +function foo(x: number, y: number, z: number) {} +>foo : (x: number, y: number, z: number) => void +>x : number +>y : number +>z : number + +var args: [0, 1, 2] = [0, 1, 2]; +>args : [0, 1, 2] +>[0, 1, 2] : [0, 1, 2] +>0 : 0 +>1 : 1 +>2 : 2 + +foo(...args); +>foo(...args) : void +>foo : (x: number, y: number, z: number) => void +>...args : 0 | 1 | 2 +>args : [0, 1, 2] + diff --git a/tests/cases/compiler/spreadTuples.ts b/tests/cases/compiler/spreadTuples.ts new file mode 100644 index 0000000000000..eb3482c2c3859 --- /dev/null +++ b/tests/cases/compiler/spreadTuples.ts @@ -0,0 +1,3 @@ +function foo(x: number, y: number, z: number) {} +var args: [0, 1, 2] = [0, 1, 2]; +foo(...args);