diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index a7e94da09d995..160211d19f120 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -3358,6 +3358,7 @@ namespace ts {
case SyntaxKind.TypeLiteral:
case SyntaxKind.ArrayType:
case SyntaxKind.TupleType:
+ case SyntaxKind.TypeSpread:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
case SyntaxKind.ParenthesizedType:
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 82f41bc31e64c..c6d43db5d24db 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -1,6 +1,9 @@
///
///
///
+///
+
+declare var console: Console;
/* @internal */
namespace ts {
@@ -239,6 +242,7 @@ namespace ts {
const intersectionTypes = createMap();
const literalTypes = createMap();
const indexedAccessTypes = createMap();
+ const spreadTypes = createMap();
const evolvingArrayTypes: EvolvingArrayType[] = [];
const unknownSymbol = createSymbol(SymbolFlags.Property, "unknown" as __String);
@@ -2542,6 +2546,10 @@ namespace ts {
const indexTypeNode = typeToTypeNodeHelper((type).indexType, context);
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
}
+ if (type.flags & TypeFlags.TypeSpread) {
+ const typeNode = typeToTypeNodeHelper((type).type, context);
+ return createTypeSpread(typeNode);
+ }
Debug.fail("Should be unreachable.");
@@ -3305,6 +3313,10 @@ namespace ts {
writeType((type).indexType, TypeFormatFlags.None);
writePunctuation(writer, SyntaxKind.CloseBracketToken);
}
+ else if (type.flags & TypeFlags.TypeSpread) {
+ writePunctuation(writer, SyntaxKind.DotDotDotToken);
+ writeType((type).type, TypeFormatFlags.None);
+ }
else {
// Should never get here
// { ... }
@@ -5392,6 +5404,7 @@ namespace ts {
}
function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) {
+ if (allowSyntheticDefaultImports) console.log("resolveObjectTypeMembers", typeToString(type));
let mapper: TypeMapper;
let members: SymbolTable;
let callSignatures: Signature[];
@@ -6799,7 +6812,7 @@ namespace ts {
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, node));
return createTypeReference(type, typeArguments);
}
- if (node.typeArguments) {
+ if (node.typeArguments && node.typeArguments.length) {
error(node, Diagnostics.Type_0_is_not_generic, typeToString(type));
return unknownType;
}
@@ -6841,7 +6854,7 @@ namespace ts {
}
return getTypeAliasInstantiation(symbol, typeArguments);
}
- if (node.typeArguments) {
+ if (node.typeArguments && node.typeArguments.length) {
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
return unknownType;
}
@@ -6852,7 +6865,7 @@ namespace ts {
* Get type from reference to named type that cannot be generic (enum or type parameter)
*/
function getTypeFromNonGenericTypeReference(node: TypeReferenceType, symbol: Symbol): Type {
- if (node.typeArguments) {
+ if (node.typeArguments && node.typeArguments.length) {
error(node, Diagnostics.Type_0_is_not_generic, symbolToString(symbol));
return unknownType;
}
@@ -7218,11 +7231,69 @@ namespace ts {
function getTypeFromTupleTypeNode(node: TupleTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
- links.resolvedType = createTupleType(map(node.elementTypes, getTypeFromTypeNode));
+ links.resolvedType = createTupleType(flatMap(node.elementTypes, getTypeFromTupleElement));
}
return links.resolvedType;
}
+ function getTypeSpreadTypes(tuple: Type): Type[] {
+ if (isGenericTupleType(tuple)) {
+ // Defer the operation by creating a spread type.
+ const id = "" + tuple.id;
+ let type = spreadTypes.get(id);
+ if (!type) {
+ spreadTypes.set(id, type = createTypeSpreadType(tuple));
+ }
+ return [type];
+ }
+ else {
+ // const type = getApparentType(nodeType);
+ if (allowSyntheticDefaultImports) {
+ console.log("type", typeToString(tuple));
+ console.log("isTupleLikeType(type)", isTupleLikeType(tuple));
+ }
+ if (isTupleLikeType(tuple)) {
+ // return map(getPropertiesOfType(tuple), getTypeOfSymbol);
+ return getTupleTypeElementTypes(tuple);
+ }
+ else {
+ // error(typeNode, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
+ console.log("not a tuple, don't resolve?");
+ return [];
+ }
+ }
+ }
+
+ function isGenericTupleType(type: Type): boolean {
+ return type.flags & TypeFlags.TypeVariable ? true :
+ type.flags & TypeFlags.UnionOrIntersection ? forEach((type).types, isGenericTupleType) :
+ false;
+ }
+
+ 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;
+ }
+
+ function getTypeFromTupleElement(node: TypeNode | TypeSpreadTypeNode): Type | Type[] {
+ if (node.kind === SyntaxKind.TypeSpread) {
+ const links = getNodeLinks(node);
+ if (!links.resolvedType) {
+ links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type);
+ }
+ return getTypeSpreadTypes(links.resolvedType);
+ }
+ else {
+ return getTypeFromTypeNode(node as TypeNode);
+ }
+ }
+
interface TypeSet extends Array {
containsAny?: boolean;
containsUndefined?: boolean;
@@ -7553,6 +7624,24 @@ namespace ts {
return links.resolvedType;
}
+ function getTypeFromTypeCallNode(node: TypeCallTypeNode): Type {
+ const fn = typeNodeToExpression(node.type);
+ const args = map(node.arguments, (type: TypeNode) => {
+ if (type.kind === SyntaxKind.TypeSpread) {
+ return createSpread(typeNodeToExpression((type as TypeSpreadTypeNode).type));
+ } else {
+ return typeNodeToExpression(type);
+ }
+ });
+ const callExpr = createCall(fn, node.typeArguments, args);
+ return checkExpression(callExpr);
+ }
+
+ // null! as type
+ function typeNodeToExpression(type: TypeNode): Expression {
+ return createAsExpression(createNonNullExpression(createNull()), type);
+ }
+
function createIndexedAccessType(objectType: Type, indexType: Type) {
const type = createType(TypeFlags.IndexedAccess);
type.objectType = objectType;
@@ -7560,6 +7649,13 @@ namespace ts {
return type;
}
+ function createTypeSpreadType(tuple: Type) {
+ console.log("createTypeSpreadType");
+ const type = createType(TypeFlags.TypeSpread);
+ type.type = tuple;
+ return type;
+ }
+
function getPropertyTypeForIndexType(objectType: Type, indexType: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode, cacheSymbol: boolean) {
const accessExpression = accessNode && accessNode.kind === SyntaxKind.ElementAccessExpression ? accessNode : undefined;
const propName = indexType.flags & TypeFlags.StringOrNumberLiteral ?
@@ -8010,6 +8106,8 @@ namespace ts {
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
case SyntaxKind.TypeOperator:
return getTypeFromTypeOperatorNode(node);
+ case SyntaxKind.TypeCall:
+ return getTypeFromTypeCallNode(node);
case SyntaxKind.IndexedAccessType:
return getTypeFromIndexedAccessTypeNode(node);
case SyntaxKind.MappedType:
@@ -8375,6 +8473,9 @@ namespace ts {
if (type.flags & TypeFlags.IndexedAccess) {
return getIndexedAccessType(instantiateType((type).objectType, mapper), instantiateType((type).indexType, mapper));
}
+ // if (type.flags & TypeFlags.TypeSpread) {
+ // return getTypeSpreadTypes(instantiateType((type).type, mapper));
+ // }
return type;
}
@@ -13247,7 +13348,7 @@ namespace ts {
return node.contextualType;
}
const parent = node.parent;
- switch (parent.kind) {
+ switch (parent && parent.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
@@ -18782,7 +18883,7 @@ namespace ts {
}
const type = getTypeFromTypeReference(node);
if (type !== unknownType) {
- if (node.typeArguments) {
+ if (node.typeArguments && node.typeArguments.length) {
// Do type argument local checks only if referenced type is successfully resolved
forEach(node.typeArguments, checkSourceElement);
if (produceDiagnostics) {
@@ -18835,6 +18936,22 @@ namespace ts {
forEach(node.elementTypes, checkSourceElement);
}
+ function checkTypeSpreadTypeNode(node: TypeSpreadTypeNode) {
+ checkSourceElement(node.type);
+ // checkTypeSpreadType( getTypeFromTypeNode(node.type), node);
+ const type = getApparentType(getTypeFromTypeNode(node.type));
+ if (!isArrayLikeType(type)) { // isTupleLikeType
+ grammarErrorOnNode(node, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
+ }
+ }
+
+ // function checkTypeSpreadType(spread: TypeSpreadType, node: TypeSpreadTypeNode) {
+ // const type = getApparentType(spread.type);
+ // if (!isArrayLikeType(type)) { // isTupleLikeType
+ // grammarErrorOnNode(node, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types);
+ // }
+ // }
+
function checkUnionOrIntersectionType(node: UnionOrIntersectionTypeNode) {
forEach(node.types, checkSourceElement);
}
@@ -22370,6 +22487,8 @@ namespace ts {
return checkArrayType(node);
case SyntaxKind.TupleType:
return checkTupleType(node);
+ case SyntaxKind.TypeSpread:
+ return checkTypeSpreadTypeNode(node);
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
return checkUnionOrIntersectionType(node);
@@ -24338,7 +24457,7 @@ namespace ts {
function checkGrammarTypeArguments(node: Node, typeArguments: NodeArray): boolean {
return checkGrammarForDisallowedTrailingComma(typeArguments) ||
- checkGrammarForAtLeastOneTypeArgument(node, typeArguments);
+ false && checkGrammarForAtLeastOneTypeArgument(node, typeArguments);
}
function checkGrammarForOmittedArgument(args: NodeArray): boolean {
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index 8121f036ceabb..4a43ef26ea953 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -2208,6 +2208,10 @@
"category": "Error",
"code": 2713
},
+ "Tuple type spreads may only be created from tuple types.": {
+ "category": "Error",
+ "code": 2714
+ },
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 5444c618353bd..1bb2ec4861a60 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -697,6 +697,8 @@ namespace ts {
return emitShorthandPropertyAssignment(node);
case SyntaxKind.SpreadAssignment:
return emitSpreadAssignment(node as SpreadAssignment);
+ case SyntaxKind.TypeSpread:
+ return emitTypeSpread(node as TypeSpreadTypeNode);
// Enum
case SyntaxKind.EnumMember:
@@ -753,6 +755,8 @@ namespace ts {
return emitPropertyAccessExpression(node);
case SyntaxKind.ElementAccessExpression:
return emitElementAccessExpression(node);
+ case SyntaxKind.TypeCall:
+ return emitTypeCall(node);
case SyntaxKind.CallExpression:
return emitCallExpression(node);
case SyntaxKind.NewExpression:
@@ -1240,6 +1244,12 @@ namespace ts {
write("]");
}
+ function emitTypeCall(node: TypeCallTypeNode) {
+ emit(node.type);
+ emitTypeArguments(node, node.typeArguments);
+ emitList(node, node.arguments, ListFormat.CallExpressionArguments);
+ }
+
function emitCallExpression(node: CallExpression) {
emitExpression(node.expression);
emitTypeArguments(node, node.typeArguments);
@@ -2193,6 +2203,13 @@ namespace ts {
}
}
+ function emitTypeSpread(node: TypeSpreadTypeNode) {
+ if (node.type) {
+ write("...");
+ emit(node.type);
+ }
+ }
+
//
// Enum
//
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index daec1bce1e8b5..2514c0d90aa76 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -888,6 +888,22 @@ namespace ts {
: node;
}
+ export function createTypeCall(type: TypeNode, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray) {
+ const node = createSynthesizedNode(SyntaxKind.TypeCall);
+ node.type = parenthesizeElementTypeMember(type);
+ node.typeArguments = asNodeArray(typeArguments);
+ node.arguments = parenthesizeElementTypeMembers(createNodeArray(argumentsArray));
+ return node;
+ }
+
+ export function updateTypeCall(node: TypeCallTypeNode, type: TypeNode, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray) {
+ return node.type !== type
+ || node.typeArguments !== typeArguments
+ || node.arguments !== argumentsArray
+ ? updateNode(createTypeCall(type, typeArguments, argumentsArray), node)
+ : node;
+ }
+
export function createCall(expression: Expression, typeArguments: ReadonlyArray | undefined, argumentsArray: ReadonlyArray) {
const node = createSynthesizedNode(SyntaxKind.CallExpression);
node.expression = parenthesizeForAccess(expression);
@@ -2185,6 +2201,19 @@ namespace ts {
: node;
}
+ export function createTypeSpread(type: TypeNode) {
+ console.log("createTypeSpread");
+ const node = createSynthesizedNode(SyntaxKind.TypeSpread);
+ node.type = type !== undefined ? parenthesizeElementTypeMember(type) : undefined;
+ return node;
+ }
+
+ export function updateTypeSpread(node: TypeSpreadTypeNode, type: TypeNode) {
+ return node.type !== type
+ ? updateNode(createTypeSpread(type), node)
+ : node;
+ }
+
// Enum
export function createEnumMember(name: string | PropertyName, initializer?: Expression) {
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index 7486c7541bed4..7c819727de264 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -85,6 +85,8 @@ namespace ts {
visitNode(cbNode, (node).objectAssignmentInitializer);
case SyntaxKind.SpreadAssignment:
return visitNode(cbNode, (node).expression);
+ case SyntaxKind.TypeSpread:
+ return visitNode(cbNode, (node).type);
case SyntaxKind.Parameter:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
@@ -170,6 +172,10 @@ namespace ts {
case SyntaxKind.ElementAccessExpression:
return visitNode(cbNode, (node).expression) ||
visitNode(cbNode, (node).argumentExpression);
+ case SyntaxKind.TypeCall:
+ return visitNode(cbNode, (node).type) ||
+ visitNodes(cbNode, cbNodes, (node).typeArguments) ||
+ visitNodes(cbNode, cbNodes, (node).arguments);
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
return visitNode(cbNode, (node).expression) ||
@@ -1378,8 +1384,9 @@ namespace ts {
case ParsingContext.Parameters:
return isStartOfParameter();
case ParsingContext.TypeArguments:
- case ParsingContext.TupleElementTypes:
return token() === SyntaxKind.CommaToken || isStartOfType();
+ case ParsingContext.TupleElementTypes:
+ return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isStartOfType();
case ParsingContext.HeritageClauses:
return isHeritageClause();
case ParsingContext.ImportOrExportSpecifiers:
@@ -2585,7 +2592,7 @@ namespace ts {
function parseTupleType(): TupleTypeNode {
const node = createNode(SyntaxKind.TupleType);
- node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseType, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
+ node.elementTypes = parseBracketedList(ParsingContext.TupleElementTypes, parseTupleElement, SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken);
return finishNode(node);
}
@@ -2739,8 +2746,8 @@ namespace ts {
return token() === SyntaxKind.CloseParenToken || isStartOfParameter() || isStartOfType();
}
- function parseJSDocPostfixTypeOrHigher(): TypeNode {
- const type = parseNonArrayType();
+ function parseJSDocPostfixTypeOrHigher(typeNode?: TypeNode): TypeNode {
+ const type = typeNode || parseNonArrayType();
const kind = getKind(token());
if (!kind) return type;
nextToken();
@@ -2762,8 +2769,8 @@ namespace ts {
}
}
- function parseArrayTypeOrHigher(): TypeNode {
- let type = parseJSDocPostfixTypeOrHigher();
+ function parseArrayTypeOrHigher(typeNode?: TypeNode): TypeNode {
+ let type = parseJSDocPostfixTypeOrHigher(typeNode);
while (!scanner.hasPrecedingLineBreak() && parseOptional(SyntaxKind.OpenBracketToken)) {
if (isStartOfType()) {
const node = createNode(SyntaxKind.IndexedAccessType, type.pos);
@@ -2795,7 +2802,7 @@ namespace ts {
case SyntaxKind.KeyOfKeyword:
return parseTypeOperator(SyntaxKind.KeyOfKeyword);
}
- return parseArrayTypeOrHigher();
+ return parseTypeCallRest();
}
function parseUnionOrIntersectionType(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, parseConstituentType: () => TypeNode, operator: SyntaxKind.BarToken | SyntaxKind.AmpersandToken): TypeNode {
@@ -4241,6 +4248,46 @@ namespace ts {
}
}
+ // type equivalent of parseCallExpressionRest
+ function parseTypeCallRest(type?: TypeNode): TypeNode {
+ while (true) {
+ type = parseArrayTypeOrHigher(type);
+ if (token() === SyntaxKind.LessThanToken) {
+ // See if this is the start of a generic invocation. If so, consume it and
+ // keep checking for postfix expressions. Otherwise, it's just a '<' that's
+ // part of an arithmetic expression. Break out so we consume it higher in the
+ // stack.
+ const typeArguments = tryParse(parseTypeArgumentsInExpression);
+ if (!typeArguments) {
+ return type;
+ }
+
+ const callExpr = createNode(SyntaxKind.TypeCall, type.pos);
+ callExpr.type = type;
+ callExpr.typeArguments = typeArguments;
+ callExpr.arguments = parseTypeArgumentList();
+ type = finishNode(callExpr);
+ continue;
+ }
+ else if (token() === SyntaxKind.OpenParenToken) {
+ const callExpr = createNode(SyntaxKind.TypeCall, type.pos);
+ callExpr.type = type;
+ callExpr.arguments = parseTypeArgumentList();
+ type = finishNode(callExpr);
+ continue;
+ }
+
+ return type;
+ }
+ }
+
+ function parseTypeArgumentList() {
+ parseExpected(SyntaxKind.OpenParenToken);
+ const result = parseDelimitedList(ParsingContext.TypeArguments, parseTupleElement);
+ parseExpected(SyntaxKind.CloseParenToken);
+ return result;
+ }
+
function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression {
while (true) {
expression = parseMemberExpressionRest(expression);
@@ -5161,6 +5208,19 @@ namespace ts {
return finishNode(node);
}
+ function parseTupleElement(): TypeSpreadTypeNode | TypeNode {
+ return (token() === SyntaxKind.DotDotDotToken) ?
+ parseTypeSpread() :
+ parseType();
+ }
+
+ function parseTypeSpread(): TypeSpreadTypeNode {
+ const node = createNode(SyntaxKind.TypeSpread);
+ parseExpected(SyntaxKind.DotDotDotToken);
+ node.type = parseTypeOperatorOrHigher();
+ return finishNode(node);
+ }
+
function parseObjectBindingElement(): BindingElement {
const node = createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 8fe602ea6f94f..17e477ffd64c0 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -240,6 +240,7 @@ namespace ts {
IndexedAccessType,
MappedType,
LiteralType,
+ TypeCall,
// Binding patterns
ObjectBindingPattern,
ArrayBindingPattern,
@@ -343,6 +344,7 @@ namespace ts {
PropertyAssignment,
ShorthandPropertyAssignment,
SpreadAssignment,
+ TypeSpread,
// Enum
EnumMember,
@@ -398,7 +400,7 @@ namespace ts {
FirstFutureReservedWord = ImplementsKeyword,
LastFutureReservedWord = YieldKeyword,
FirstTypeNode = TypePredicate,
- LastTypeNode = LiteralType,
+ LastTypeNode = TypeCall,
FirstPunctuation = OpenBraceToken,
LastPunctuation = CaretEqualsToken,
FirstToken = Unknown,
@@ -950,7 +952,12 @@ namespace ts {
export interface TupleTypeNode extends TypeNode {
kind: SyntaxKind.TupleType;
- elementTypes: NodeArray;
+ elementTypes: NodeArray;
+ }
+
+ export interface TypeSpreadTypeNode extends TypeNode {
+ kind: SyntaxKind.TypeSpread;
+ type: TypeNode;
}
export type UnionOrIntersectionTypeNode = UnionTypeNode | IntersectionTypeNode;
@@ -1495,6 +1502,13 @@ namespace ts {
arguments: NodeArray;
}
+ export interface TypeCallTypeNode extends TypeNode {
+ kind: SyntaxKind.TypeCall;
+ type: TypeNode;
+ typeArguments?: NodeArray;
+ arguments: NodeArray;
+ }
+
// see: https://tc39.github.io/ecma262/#prod-SuperCall
export interface SuperCall extends CallExpression {
expression: SuperExpression;
@@ -3150,6 +3164,7 @@ namespace ts {
NonPrimitive = 1 << 24, // intrinsic object type
/* @internal */
JsxAttributes = 1 << 25, // Jsx attributes type
+ TypeSpread = 1 << 26, // spread in tuple types
/* @internal */
Nullable = Undefined | Null,
@@ -3398,6 +3413,11 @@ namespace ts {
constraint?: Type;
}
+ // type spread types (TypeFlags.TypeSpread)
+ export interface TypeSpreadType extends TypeVariable {
+ type: Type;
+ }
+
// keyof T types (TypeFlags.Index)
export interface IndexType extends Type {
type: TypeVariable | UnionOrIntersectionType;
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index f1a8dfd676b70..a979e1f06996e 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -4506,6 +4506,10 @@ namespace ts {
return node.kind === SyntaxKind.SpreadAssignment;
}
+ export function isTypeSpread(node: Node): node is TypeSpreadTypeNode {
+ return node.kind === SyntaxKind.TypeSpread;
+ }
+
// Enum
export function isEnumMember(node: Node): node is EnumMember {
diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts
index 1ce42199372d8..5203f775cd00e 100644
--- a/src/compiler/visitor.ts
+++ b/src/compiler/visitor.ts
@@ -446,6 +446,12 @@ namespace ts {
visitNode((node).expression, visitor, isExpression),
visitNode((node).argumentExpression, visitor, isExpression));
+ case SyntaxKind.TypeCall:
+ return updateTypeCall(node,
+ visitNode((node).type, visitor, isTypeNode),
+ nodesVisitor((node).typeArguments, visitor, isTypeNode),
+ nodesVisitor((node).arguments, visitor, isTypeNode));
+
case SyntaxKind.CallExpression:
return updateCall(node,
visitNode((node).expression, visitor, isExpression),
@@ -869,6 +875,10 @@ namespace ts {
return updateSpreadAssignment(node,
visitNode((node).expression, visitor, isExpression));
+ case SyntaxKind.TypeSpread:
+ return updateTypeSpread(node,
+ visitNode((node).type, visitor, isTypeNode));
+
// Enum
case SyntaxKind.EnumMember:
return updateEnumMember(node,
@@ -1391,6 +1401,14 @@ namespace ts {
result = reduceNode((node).expression, cbNode, result);
break;
+ case SyntaxKind.TypeCall:
+ result = reduceNode((node).type, cbNode, result);
+ break;
+
+ case SyntaxKind.TypeSpread:
+ result = reduceNode((node).type, cbNode, result);
+ break;
+
// Enum
case SyntaxKind.EnumMember:
result = reduceNode((node).name, cbNode, result);
diff --git a/tests/baselines/reference/arrayTypeOfTypeOf.errors.txt b/tests/baselines/reference/arrayTypeOfTypeOf.errors.txt
index 1c37f04be72b8..3479bd8044388 100644
--- a/tests/baselines/reference/arrayTypeOfTypeOf.errors.txt
+++ b/tests/baselines/reference/arrayTypeOfTypeOf.errors.txt
@@ -1,28 +1,16 @@
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(6,5): error TS2322: Type 'number' is not assignable to type 'ArrayConstructor'.
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(6,22): error TS1005: '=' expected.
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(6,30): error TS1109: Expression expected.
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(7,5): error TS2322: Type 'number' is not assignable to type 'ArrayConstructor'.
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(7,22): error TS1005: '=' expected.
-tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(7,32): error TS1109: Expression expected.
+tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(6,30): error TS1005: '(' expected.
+tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts(7,32): error TS1005: '(' expected.
-==== tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts (6 errors) ====
+==== tests/cases/conformance/types/specifyingTypes/typeLiterals/arrayTypeOfTypeOf.ts (2 errors) ====
// array type cannot use typeof.
var x = 1;
var xs: typeof x[]; // Not an error. This is equivalent to Array
var xs2: typeof Array;
var xs3: typeof Array;
- ~~~
-!!! error TS2322: Type 'number' is not assignable to type 'ArrayConstructor'.
- ~
-!!! error TS1005: '=' expected.
~
-!!! error TS1109: Expression expected.
+!!! error TS1005: '(' expected.
var xs4: typeof Array;
- ~~~
-!!! error TS2322: Type 'number' is not assignable to type 'ArrayConstructor'.
- ~
-!!! error TS1005: '=' expected.
~
-!!! error TS1109: Expression expected.
\ No newline at end of file
+!!! error TS1005: '(' expected.
\ No newline at end of file
diff --git a/tests/baselines/reference/arrayTypeOfTypeOf.js b/tests/baselines/reference/arrayTypeOfTypeOf.js
index f3653346be432..74a50b9cc1fc9 100644
--- a/tests/baselines/reference/arrayTypeOfTypeOf.js
+++ b/tests/baselines/reference/arrayTypeOfTypeOf.js
@@ -12,5 +12,5 @@ var xs4: typeof Array;
var x = 1;
var xs; // Not an error. This is equivalent to Array
var xs2;
-var xs3 = ;
-var xs4 = ;
+var xs3;
+var xs4;
diff --git a/tests/baselines/reference/invalidTypeOfTarget.errors.txt b/tests/baselines/reference/invalidTypeOfTarget.errors.txt
index e658ab68c81bf..569c36d1f8552 100644
--- a/tests/baselines/reference/invalidTypeOfTarget.errors.txt
+++ b/tests/baselines/reference/invalidTypeOfTarget.errors.txt
@@ -1,6 +1,8 @@
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(1,16): error TS1003: Identifier expected.
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(2,16): error TS1003: Identifier expected.
-tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(2,24): error TS1005: '=>' expected.
+tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(2,18): error TS1005: ',' expected.
+tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(2,20): error TS1134: Variable declaration expected.
+tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(2,24): error TS1109: Expression expected.
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(3,16): error TS1003: Identifier expected.
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(4,16): error TS1003: Identifier expected.
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(5,16): error TS1003: Identifier expected.
@@ -12,15 +14,19 @@ tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts
tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts(8,16): error TS1003: Identifier expected.
-==== tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts (12 errors) ====
+==== tests/cases/conformance/types/specifyingTypes/typeQueries/invalidTypeOfTarget.ts (14 errors) ====
var x1: typeof {};
~
!!! error TS1003: Identifier expected.
var x2: typeof (): void;
~
!!! error TS1003: Identifier expected.
+ ~
+!!! error TS1005: ',' expected.
+ ~~~~
+!!! error TS1134: Variable declaration expected.
~
-!!! error TS1005: '=>' expected.
+!!! error TS1109: Expression expected.
var x3: typeof 1;
~
!!! error TS1003: Identifier expected.
diff --git a/tests/baselines/reference/invalidTypeOfTarget.js b/tests/baselines/reference/invalidTypeOfTarget.js
index ebc5bb708757c..cda6f90a2f319 100644
--- a/tests/baselines/reference/invalidTypeOfTarget.js
+++ b/tests/baselines/reference/invalidTypeOfTarget.js
@@ -10,7 +10,8 @@ var x8: typeof /123/;
//// [invalidTypeOfTarget.js]
var x1 = {};
-var x2 = function () { return ; };
+var x2;
+void ;
var x3 = 1;
var x4 = '';
var x5;
diff --git a/tests/baselines/reference/overloadSelection.js b/tests/baselines/reference/overloadSelection.js
new file mode 100644
index 0000000000000..a47f65ea88ac1
--- /dev/null
+++ b/tests/baselines/reference/overloadSelection.js
@@ -0,0 +1,12 @@
+//// [overloadSelection.ts]
+interface Match {
+ (o: object): 0;
+ (o: any): 1;
+}
+type Wrap = (v: T) => Match(T);
+type A = Wrap(RegExp);
+// falls thru to 1, `object` checked not with generic val `RegExp` but with its constraint (generic `any`)
+
+
+//// [overloadSelection.js]
+// falls thru to 1, `object` checked not with generic val `RegExp` but with its constraint (generic `any`)
diff --git a/tests/baselines/reference/overloadSelection.symbols b/tests/baselines/reference/overloadSelection.symbols
new file mode 100644
index 0000000000000..fc3aa50564e30
--- /dev/null
+++ b/tests/baselines/reference/overloadSelection.symbols
@@ -0,0 +1,26 @@
+=== tests/cases/compiler/overloadSelection.ts ===
+interface Match {
+>Match : Symbol(Match, Decl(overloadSelection.ts, 0, 0))
+
+ (o: object): 0;
+>o : Symbol(o, Decl(overloadSelection.ts, 1, 3))
+
+ (o: any): 1;
+>o : Symbol(o, Decl(overloadSelection.ts, 2, 3))
+}
+type Wrap = (v: T) => Match(T);
+>Wrap : Symbol(Wrap, Decl(overloadSelection.ts, 3, 1))
+>T : Symbol(T, Decl(overloadSelection.ts, 4, 13))
+>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+>v : Symbol(v, Decl(overloadSelection.ts, 4, 25))
+>T : Symbol(T, Decl(overloadSelection.ts, 4, 13))
+>Match : Symbol(Match, Decl(overloadSelection.ts, 0, 0))
+>T : Symbol(T, Decl(overloadSelection.ts, 4, 13))
+
+type A = Wrap(RegExp);
+>A : Symbol(A, Decl(overloadSelection.ts, 4, 43))
+>Wrap : Symbol(Wrap, Decl(overloadSelection.ts, 3, 1))
+>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+
+// falls thru to 1, `object` checked not with generic val `RegExp` but with its constraint (generic `any`)
+
diff --git a/tests/baselines/reference/overloadSelection.types b/tests/baselines/reference/overloadSelection.types
new file mode 100644
index 0000000000000..29bf2c3aa7a8d
--- /dev/null
+++ b/tests/baselines/reference/overloadSelection.types
@@ -0,0 +1,26 @@
+=== tests/cases/compiler/overloadSelection.ts ===
+interface Match {
+>Match : Match
+
+ (o: object): 0;
+>o : object
+
+ (o: any): 1;
+>o : any
+}
+type Wrap = (v: T) => Match(T);
+>Wrap : Wrap
+>T : T
+>RegExp : RegExp
+>v : T
+>T : T
+>Match : Match
+>T : T
+
+type A = Wrap(RegExp);
+>A : 1
+>Wrap : Wrap
+>RegExp : RegExp
+
+// falls thru to 1, `object` checked not with generic val `RegExp` but with its constraint (generic `any`)
+
diff --git a/tests/baselines/reference/parserObjectType5.errors.txt b/tests/baselines/reference/parserObjectType5.errors.txt
index d4db1d2d85c51..2b21a42ecf243 100644
--- a/tests/baselines/reference/parserObjectType5.errors.txt
+++ b/tests/baselines/reference/parserObjectType5.errors.txt
@@ -1,13 +1,16 @@
tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts(2,7): error TS2304: Cannot find name 'B'.
+tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts(3,5): error TS2304: Cannot find name 'T'.
tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts(3,7): error TS1005: '(' expected.
-==== tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts (2 errors) ====
+==== tests/cases/conformance/parser/ecmascript5/ObjectTypes/parserObjectType5.ts (3 errors) ====
var v: {
A: B
~
!!! error TS2304: Cannot find name 'B'.
;
+ ~
+!!! error TS2304: Cannot find name 'T'.
~
!!! error TS1005: '(' expected.
};
\ No newline at end of file
diff --git a/tests/baselines/reference/parserTypeQuery8.errors.txt b/tests/baselines/reference/parserTypeQuery8.errors.txt
index 4a7098ea8fd3f..40c51093d140a 100644
--- a/tests/baselines/reference/parserTypeQuery8.errors.txt
+++ b/tests/baselines/reference/parserTypeQuery8.errors.txt
@@ -1,16 +1,13 @@
tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts(1,15): error TS2304: Cannot find name 'A'.
-tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts(1,16): error TS1005: '=' expected.
tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts(1,17): error TS2304: Cannot find name 'B'.
-tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts(1,19): error TS1109: Expression expected.
+tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts(1,19): error TS1005: '(' expected.
-==== tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts (4 errors) ====
+==== tests/cases/conformance/parser/ecmascript5/Types/parserTypeQuery8.ts (3 errors) ====
var v: typeof A
~
!!! error TS2304: Cannot find name 'A'.
- ~
-!!! error TS1005: '=' expected.
~
!!! error TS2304: Cannot find name 'B'.
-!!! error TS1109: Expression expected.
\ No newline at end of file
+!!! error TS1005: '(' expected.
\ No newline at end of file
diff --git a/tests/baselines/reference/parserTypeQuery8.js b/tests/baselines/reference/parserTypeQuery8.js
index 995ad013c1f0d..f0fd7d6212e76 100644
--- a/tests/baselines/reference/parserTypeQuery8.js
+++ b/tests/baselines/reference/parserTypeQuery8.js
@@ -2,4 +2,4 @@
var v: typeof A
//// [parserTypeQuery8.js]
-var v = ;
+var v;
diff --git a/tests/baselines/reference/tupleTypeSpread.js b/tests/baselines/reference/tupleTypeSpread.js
new file mode 100644
index 0000000000000..d7751fd4f5db2
--- /dev/null
+++ b/tests/baselines/reference/tupleTypeSpread.js
@@ -0,0 +1,7 @@
+//// [tupleTypeSpread.ts]
+type a = [1, ...[2]];
+type Combine = [Head, ...Tail];
+type b = Combine<1, [2, 3]>;
+
+
+//// [tupleTypeSpread.js]
diff --git a/tests/baselines/reference/tupleTypeSpread.symbols b/tests/baselines/reference/tupleTypeSpread.symbols
new file mode 100644
index 0000000000000..303808d580702
--- /dev/null
+++ b/tests/baselines/reference/tupleTypeSpread.symbols
@@ -0,0 +1,15 @@
+=== tests/cases/compiler/tupleTypeSpread.ts ===
+type a = [1, ...[2]];
+>a : Symbol(a, Decl(tupleTypeSpread.ts, 0, 0))
+
+type Combine = [Head, ...Tail];
+>Combine : Symbol(Combine, Decl(tupleTypeSpread.ts, 0, 21))
+>Head : Symbol(Head, Decl(tupleTypeSpread.ts, 1, 13))
+>Tail : Symbol(Tail, Decl(tupleTypeSpread.ts, 1, 18))
+>Head : Symbol(Head, Decl(tupleTypeSpread.ts, 1, 13))
+>Tail : Symbol(Tail, Decl(tupleTypeSpread.ts, 1, 18))
+
+type b = Combine<1, [2, 3]>;
+>b : Symbol(b, Decl(tupleTypeSpread.ts, 1, 57))
+>Combine : Symbol(Combine, Decl(tupleTypeSpread.ts, 0, 21))
+
diff --git a/tests/baselines/reference/tupleTypeSpread.types b/tests/baselines/reference/tupleTypeSpread.types
new file mode 100644
index 0000000000000..a804885e1a591
--- /dev/null
+++ b/tests/baselines/reference/tupleTypeSpread.types
@@ -0,0 +1,15 @@
+=== tests/cases/compiler/tupleTypeSpread.ts ===
+type a = [1, ...[2]];
+>a : [1, 2]
+
+type Combine = [Head, ...Tail];
+>Combine : [Head, ...Tail]
+>Head : Head
+>Tail : Tail
+>Head : Head
+>Tail : Tail
+
+type b = Combine<1, [2, 3]>;
+>b : [1, ...Tail]
+>Combine : [Head, ...Tail]
+
diff --git a/tests/baselines/reference/typeCall.js b/tests/baselines/reference/typeCall.js
new file mode 100644
index 0000000000000..36baf427ab212
--- /dev/null
+++ b/tests/baselines/reference/typeCall.js
@@ -0,0 +1,69 @@
+//// [typeCall.ts]
+type F1 = () => 1;
+type a = F1();
+
+type F2 = (a: string) => 1;
+type b = F2('foo');
+
+interface F3 {
+ (): 1;
+ (a: number): 2;
+ (a: string): 3;
+}
+type c = F3();
+type d = F3(123);
+type e = F3('foo');
+
+declare function f4(a: string): 1;
+let a = 'foo';
+type f = typeof f4(typeof a);
+
+type g = (() => 1)();
+
+type Id = (v: T) => T;
+type h = Id(123);
+
+type Wrap = Id(T);
+type i = Wrap<123>;
+
+type F5 = () => () => { a: () => 1; };
+type j = F5()()['a']();
+
+type k1 = Id('foo'); // `any`, `` is part of the type reference, not the function call
+type k2 = Id<>('foo'); // ok, `string`
+
+declare function id(v: T): T;
+let l = id('foo');
+
+interface IsPrimitive {
+ (o: object): '0';
+ (o: any): '1';
+}
+type stringIsPrimitive = IsPrimitive(string); // '1', ok
+type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok
+
+// explicit type arguments need to go after the type arguments of the type reference, empty `<>` if n/a
+type genericIsPrimitive = () => IsPrimitive(T);
+type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok
+type regexpIsPrimitive2 = genericIsPrimitive<>();
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+// alternative, pass as parameters
+type genericIsPrimitive3 = (v: T) => IsPrimitive(T);
+type stringIsPrimitive3 = genericIsPrimitive3(string); // '1', ok
+type regexpIsPrimitive3 = genericIsPrimitive3(RegExp)
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+type map = (fn: Fn, obj: O) => { [P in keyof O]: Fn(P) }; // Fn(O[P])
+type z = map((v: T) => [T], { a: 1, b: 2, c: 3 });
+
+// binary function composition, still fails
+type Fn1 = (v: T[]) => { [k: string]: T };
+type Fn2 = (v: { [k: string]: T }) => ReadonlyArray;
+type Fn3 = (v: T) => Fn2(Fn1(T));
+type Fn4 = Fn3(1);
+
+
+//// [typeCall.js]
+var a = 'foo';
+var l = id('foo');
diff --git a/tests/baselines/reference/typeCall.symbols b/tests/baselines/reference/typeCall.symbols
new file mode 100644
index 0000000000000..50e4cde6189a1
--- /dev/null
+++ b/tests/baselines/reference/typeCall.symbols
@@ -0,0 +1,213 @@
+=== tests/cases/compiler/typeCall.ts ===
+type F1 = () => 1;
+>F1 : Symbol(F1, Decl(typeCall.ts, 0, 0))
+
+type a = F1();
+>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
+>F1 : Symbol(F1, Decl(typeCall.ts, 0, 0))
+
+type F2 = (a: string) => 1;
+>F2 : Symbol(F2, Decl(typeCall.ts, 1, 14))
+>a : Symbol(a, Decl(typeCall.ts, 3, 11))
+
+type b = F2('foo');
+>b : Symbol(b, Decl(typeCall.ts, 3, 27))
+>F2 : Symbol(F2, Decl(typeCall.ts, 1, 14))
+
+interface F3 {
+>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
+
+ (): 1;
+ (a: number): 2;
+>a : Symbol(a, Decl(typeCall.ts, 8, 5))
+
+ (a: string): 3;
+>a : Symbol(a, Decl(typeCall.ts, 9, 5))
+}
+type c = F3();
+>c : Symbol(c, Decl(typeCall.ts, 10, 1))
+>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
+
+type d = F3(123);
+>d : Symbol(d, Decl(typeCall.ts, 11, 14))
+>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
+
+type e = F3('foo');
+>e : Symbol(e, Decl(typeCall.ts, 12, 17))
+>F3 : Symbol(F3, Decl(typeCall.ts, 4, 19))
+
+declare function f4(a: string): 1;
+>f4 : Symbol(f4, Decl(typeCall.ts, 13, 19))
+>a : Symbol(a, Decl(typeCall.ts, 15, 20))
+
+let a = 'foo';
+>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
+
+type f = typeof f4(typeof a);
+>f : Symbol(f, Decl(typeCall.ts, 16, 14))
+>f4 : Symbol(f4, Decl(typeCall.ts, 13, 19))
+>a : Symbol(a, Decl(typeCall.ts, 0, 18), Decl(typeCall.ts, 16, 3))
+
+type g = (() => 1)();
+>g : Symbol(g, Decl(typeCall.ts, 17, 29))
+
+type Id = (v: T) => T;
+>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
+>T : Symbol(T, Decl(typeCall.ts, 21, 11))
+>v : Symbol(v, Decl(typeCall.ts, 21, 14))
+>T : Symbol(T, Decl(typeCall.ts, 21, 11))
+>T : Symbol(T, Decl(typeCall.ts, 21, 11))
+
+type h = Id(123);
+>h : Symbol(h, Decl(typeCall.ts, 21, 25))
+>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
+
+type Wrap = Id(T);
+>Wrap : Symbol(Wrap, Decl(typeCall.ts, 22, 17))
+>T : Symbol(T, Decl(typeCall.ts, 24, 10))
+>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
+>T : Symbol(T, Decl(typeCall.ts, 24, 10))
+
+type i = Wrap<123>;
+>i : Symbol(i, Decl(typeCall.ts, 24, 21))
+>Wrap : Symbol(Wrap, Decl(typeCall.ts, 22, 17))
+
+type F5 = () => () => { a: () => 1; };
+>F5 : Symbol(F5, Decl(typeCall.ts, 25, 19))
+>a : Symbol(a, Decl(typeCall.ts, 27, 23))
+
+type j = F5()()['a']();
+>j : Symbol(j, Decl(typeCall.ts, 27, 38))
+>F5 : Symbol(F5, Decl(typeCall.ts, 25, 19))
+
+type k1 = Id('foo'); // `any`, `` is part of the type reference, not the function call
+>k1 : Symbol(k1, Decl(typeCall.ts, 28, 23))
+>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
+
+type k2 = Id<>('foo'); // ok, `string`
+>k2 : Symbol(k2, Decl(typeCall.ts, 30, 28))
+>Id : Symbol(Id, Decl(typeCall.ts, 19, 21))
+
+declare function id(v: T): T;
+>id : Symbol(id, Decl(typeCall.ts, 31, 30))
+>T : Symbol(T, Decl(typeCall.ts, 33, 20))
+>v : Symbol(v, Decl(typeCall.ts, 33, 23))
+>T : Symbol(T, Decl(typeCall.ts, 33, 20))
+>T : Symbol(T, Decl(typeCall.ts, 33, 20))
+
+let l = id('foo');
+>l : Symbol(l, Decl(typeCall.ts, 34, 3))
+>id : Symbol(id, Decl(typeCall.ts, 31, 30))
+
+interface IsPrimitive {
+>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26))
+
+ (o: object): '0';
+>o : Symbol(o, Decl(typeCall.ts, 37, 3))
+
+ (o: any): '1';
+>o : Symbol(o, Decl(typeCall.ts, 38, 3))
+}
+type stringIsPrimitive = IsPrimitive(string); // '1', ok
+>stringIsPrimitive : Symbol(stringIsPrimitive, Decl(typeCall.ts, 39, 1))
+>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26))
+
+type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok
+>regexpIsPrimitive : Symbol(regexpIsPrimitive, Decl(typeCall.ts, 40, 45))
+>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26))
+>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+
+// explicit type arguments need to go after the type arguments of the type reference, empty `<>` if n/a
+type genericIsPrimitive = () => IsPrimitive(T);
+>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 41, 45))
+>T : Symbol(T, Decl(typeCall.ts, 44, 27))
+>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26))
+>T : Symbol(T, Decl(typeCall.ts, 44, 27))
+
+type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok
+>stringIsPrimitive2 : Symbol(stringIsPrimitive2, Decl(typeCall.ts, 44, 50))
+>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 41, 45))
+
+type regexpIsPrimitive2 = genericIsPrimitive<>();
+>regexpIsPrimitive2 : Symbol(regexpIsPrimitive2, Decl(typeCall.ts, 45, 57))
+>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 41, 45))
+>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+// alternative, pass as parameters
+type genericIsPrimitive3 = (v: T) => IsPrimitive(T);
+>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 46, 57))
+>T : Symbol(T, Decl(typeCall.ts, 50, 28))
+>v : Symbol(v, Decl(typeCall.ts, 50, 31))
+>T : Symbol(T, Decl(typeCall.ts, 50, 28))
+>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26))
+>T : Symbol(T, Decl(typeCall.ts, 50, 28))
+
+type stringIsPrimitive3 = genericIsPrimitive3(string); // '1', ok
+>stringIsPrimitive3 : Symbol(stringIsPrimitive3, Decl(typeCall.ts, 50, 55))
+>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 46, 57))
+
+type regexpIsPrimitive3 = genericIsPrimitive3(RegExp)
+>regexpIsPrimitive3 : Symbol(regexpIsPrimitive3, Decl(typeCall.ts, 51, 54))
+>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 46, 57))
+>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+type map = (fn: Fn, obj: O) => { [P in keyof O]: Fn(P) }; // Fn(O[P])
+>map : Symbol(map, Decl(typeCall.ts, 52, 53))
+>Fn : Symbol(Fn, Decl(typeCall.ts, 55, 12))
+>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --))
+>O : Symbol(O, Decl(typeCall.ts, 55, 32))
+>fn : Symbol(fn, Decl(typeCall.ts, 55, 51))
+>Fn : Symbol(Fn, Decl(typeCall.ts, 55, 12))
+>obj : Symbol(obj, Decl(typeCall.ts, 55, 58))
+>O : Symbol(O, Decl(typeCall.ts, 55, 32))
+>P : Symbol(P, Decl(typeCall.ts, 55, 73))
+>O : Symbol(O, Decl(typeCall.ts, 55, 32))
+>Fn : Symbol(Fn, Decl(typeCall.ts, 55, 12))
+>P : Symbol(P, Decl(typeCall.ts, 55, 73))
+
+type z = map((v: T) => [T], { a: 1, b: 2, c: 3 });
+>z : Symbol(z, Decl(typeCall.ts, 55, 96))
+>map : Symbol(map, Decl(typeCall.ts, 52, 53))
+>T : Symbol(T, Decl(typeCall.ts, 56, 14))
+>v : Symbol(v, Decl(typeCall.ts, 56, 17))
+>T : Symbol(T, Decl(typeCall.ts, 56, 14))
+>T : Symbol(T, Decl(typeCall.ts, 56, 14))
+>a : Symbol(a, Decl(typeCall.ts, 56, 32))
+>b : Symbol(b, Decl(typeCall.ts, 56, 38))
+>c : Symbol(c, Decl(typeCall.ts, 56, 44))
+
+// binary function composition, still fails
+type Fn1 = (v: T[]) => { [k: string]: T };
+>Fn1 : Symbol(Fn1, Decl(typeCall.ts, 56, 53))
+>T : Symbol(T, Decl(typeCall.ts, 59, 9))
+>v : Symbol(v, Decl(typeCall.ts, 59, 30))
+>T : Symbol(T, Decl(typeCall.ts, 59, 9))
+>k : Symbol(k, Decl(typeCall.ts, 59, 44))
+>T : Symbol(T, Decl(typeCall.ts, 59, 9))
+
+type Fn2 = (v: { [k: string]: T }) => ReadonlyArray;
+>Fn2 : Symbol(Fn2, Decl(typeCall.ts, 59, 60))
+>T : Symbol(T, Decl(typeCall.ts, 60, 9))
+>v : Symbol(v, Decl(typeCall.ts, 60, 15))
+>k : Symbol(k, Decl(typeCall.ts, 60, 21))
+>T : Symbol(T, Decl(typeCall.ts, 60, 9))
+>ReadonlyArray : Symbol(ReadonlyArray, Decl(lib.d.ts, --, --))
+>T : Symbol(T, Decl(typeCall.ts, 60, 9))
+
+type Fn3 = (v: T) => Fn2(Fn1(T));
+>Fn3 : Symbol(Fn3, Decl(typeCall.ts, 60, 58))
+>T : Symbol(T, Decl(typeCall.ts, 61, 9))
+>v : Symbol(v, Decl(typeCall.ts, 61, 15))
+>T : Symbol(T, Decl(typeCall.ts, 61, 9))
+>Fn2 : Symbol(Fn2, Decl(typeCall.ts, 59, 60))
+>Fn1 : Symbol(Fn1, Decl(typeCall.ts, 56, 53))
+>T : Symbol(T, Decl(typeCall.ts, 61, 9))
+
+type Fn4 = Fn3(1);
+>Fn4 : Symbol(Fn4, Decl(typeCall.ts, 61, 36))
+>Fn3 : Symbol(Fn3, Decl(typeCall.ts, 60, 58))
+
diff --git a/tests/baselines/reference/typeCall.types b/tests/baselines/reference/typeCall.types
new file mode 100644
index 0000000000000..4c65d69645786
--- /dev/null
+++ b/tests/baselines/reference/typeCall.types
@@ -0,0 +1,216 @@
+=== tests/cases/compiler/typeCall.ts ===
+type F1 = () => 1;
+>F1 : F1
+
+type a = F1();
+>a : 1
+>F1 : F1
+
+type F2 = (a: string) => 1;
+>F2 : F2
+>a : string
+
+type b = F2('foo');
+>b : 1
+>F2 : F2
+
+interface F3 {
+>F3 : F3
+
+ (): 1;
+ (a: number): 2;
+>a : number
+
+ (a: string): 3;
+>a : string
+}
+type c = F3();
+>c : 1
+>F3 : F3
+
+type d = F3(123);
+>d : 2
+>F3 : F3
+
+type e = F3('foo');
+>e : 3
+>F3 : F3
+
+declare function f4(a: string): 1;
+>f4 : (a: string) => 1
+>a : string
+
+let a = 'foo';
+>a : string
+>'foo' : "foo"
+
+type f = typeof f4(typeof a);
+>f : 1
+>f4 : (a: string) => 1
+>a : string
+
+type g = (() => 1)();
+>g : 1
+
+type Id = (v: T) => T;
+>Id : Id
+>T : T
+>v : T
+>T : T
+>T : T
+
+type h = Id(123);
+>h : 123
+>Id : Id
+
+type Wrap = Id(T);
+>Wrap : T
+>T : T
+>Id : Id
+>T : T
+
+type i = Wrap<123>;
+>i : 123
+>Wrap : T
+
+type F5 = () => () => { a: () => 1; };
+>F5 : F5
+>a : () => 1
+
+type j = F5()()['a']();
+>j : 1
+>F5 : F5
+
+type k1 = Id('foo'); // `any`, `` is part of the type reference, not the function call
+>k1 : any
+>Id : Id
+
+type k2 = Id<>('foo'); // ok, `string`
+>k2 : string
+>Id : Id
+
+declare function id(v: T): T;
+>id : (v: T) => T
+>T : T
+>v : T
+>T : T
+>T : T
+
+let l = id('foo');
+>l : string
+>id('foo') : string
+>id : (v: T) => T
+>'foo' : "foo"
+
+interface IsPrimitive {
+>IsPrimitive : IsPrimitive
+
+ (o: object): '0';
+>o : object
+
+ (o: any): '1';
+>o : any
+}
+type stringIsPrimitive = IsPrimitive(string); // '1', ok
+>stringIsPrimitive : "1"
+>IsPrimitive : IsPrimitive
+
+type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok
+>regexpIsPrimitive : "1"
+>IsPrimitive : IsPrimitive
+>RegExp : RegExp
+
+// explicit type arguments need to go after the type arguments of the type reference, empty `<>` if n/a
+type genericIsPrimitive = () => IsPrimitive(T);
+>genericIsPrimitive : genericIsPrimitive
+>T : T
+>IsPrimitive : IsPrimitive
+>T : T
+
+type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok
+>stringIsPrimitive2 : "1"
+>genericIsPrimitive : genericIsPrimitive
+
+type regexpIsPrimitive2 = genericIsPrimitive<>();
+>regexpIsPrimitive2 : "1"
+>genericIsPrimitive : genericIsPrimitive
+>RegExp : RegExp
+
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+// alternative, pass as parameters
+type genericIsPrimitive3 = (v: T) => IsPrimitive(T);
+>genericIsPrimitive3 : genericIsPrimitive3
+>T : T
+>v : T
+>T : T
+>IsPrimitive : IsPrimitive
+>T : T
+
+type stringIsPrimitive3 = genericIsPrimitive3(string); // '1', ok
+>stringIsPrimitive3 : "1"
+>genericIsPrimitive3 : genericIsPrimitive3
+
+type regexpIsPrimitive3 = genericIsPrimitive3(RegExp)
+>regexpIsPrimitive3 : "1"
+>genericIsPrimitive3 : genericIsPrimitive3
+>RegExp : RegExp
+
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+type map = (fn: Fn, obj: O) => { [P in keyof O]: Fn(P) }; // Fn(O[P])
+>map : map
+>Fn : Fn
+>Function : Function
+>O : O
+>fn : Fn
+>Fn : Fn
+>obj : O
+>O : O
+>P : P
+>O : O
+>Fn : Fn
+>P : P
+
+type z = map((v: T) => [T], { a: 1, b: 2, c: 3 });
+>z : { a: any; b: any; c: any; }
+>map : map
+>T : T
+>v : T
+>T : T
+>T : T
+>a : 1
+>b : 2
+>c : 3
+
+// binary function composition, still fails
+type Fn1 = (v: T[]) => { [k: string]: T };
+>Fn1 : Fn1
+>T : T
+>v : T[]
+>T : T
+>k : string
+>T : T
+
+type Fn2 = (v: { [k: string]: T }) => ReadonlyArray;
+>Fn2 : Fn2
+>T : T
+>v : { [k: string]: T; }
+>k : string
+>T : T
+>ReadonlyArray : ReadonlyArray
+>T : T
+
+type Fn3 = (v: T) => Fn2(Fn1(T));
+>Fn3 : Fn3
+>T : T
+>v : T
+>T : T
+>Fn2 : Fn2
+>Fn1 : Fn1
+>T : T
+
+type Fn4 = Fn3(1);
+>Fn4 : any
+>Fn3 : Fn3
+
diff --git a/tests/baselines/reference/typeCallSpreads.errors.txt b/tests/baselines/reference/typeCallSpreads.errors.txt
new file mode 100644
index 0000000000000..78aed3b1c8f0c
--- /dev/null
+++ b/tests/baselines/reference/typeCallSpreads.errors.txt
@@ -0,0 +1,12 @@
+tests/cases/compiler/typeCallSpreads.ts(2,13): error TS1005: ')' expected.
+tests/cases/compiler/typeCallSpreads.ts(2,19): error TS1005: ';' expected.
+
+
+==== tests/cases/compiler/typeCallSpreads.ts (2 errors) ====
+ type Fn = (v: T) => T;
+ type a = Fn(...[1]);
+ ~~~
+!!! error TS1005: ')' expected.
+ ~
+!!! error TS1005: ';' expected.
+
\ No newline at end of file
diff --git a/tests/baselines/reference/typeCallSpreads.js b/tests/baselines/reference/typeCallSpreads.js
new file mode 100644
index 0000000000000..d89672c327404
--- /dev/null
+++ b/tests/baselines/reference/typeCallSpreads.js
@@ -0,0 +1,8 @@
+//// [typeCallSpreads.ts]
+type Fn = (v: T) => T;
+type a = Fn(...[1]);
+
+
+//// [typeCallSpreads.js]
+[1];
+;
diff --git a/tests/cases/compiler/overloadSelection.ts b/tests/cases/compiler/overloadSelection.ts
new file mode 100644
index 0000000000000..06b5019fd53fb
--- /dev/null
+++ b/tests/cases/compiler/overloadSelection.ts
@@ -0,0 +1,9 @@
+// @allowSyntheticDefaultImports: true
+
+interface Match {
+ (o: object): 0;
+ (o: any): 1;
+}
+type Wrap = (v: T) => Match(T);
+type A = Wrap(RegExp);
+// falls thru to 1, `object` checked not with generic val `RegExp` but with its constraint (generic `any`)
diff --git a/tests/cases/compiler/tupleTypeSpread.ts b/tests/cases/compiler/tupleTypeSpread.ts
new file mode 100644
index 0000000000000..a2693a8f9f4af
--- /dev/null
+++ b/tests/cases/compiler/tupleTypeSpread.ts
@@ -0,0 +1,4 @@
+// @allowSyntheticDefaultImports: true
+type a = [1, ...[2]];
+type Combine = [Head, ...Tail];
+type b = Combine<1, [2, 3]>;
diff --git a/tests/cases/compiler/typeCall.ts b/tests/cases/compiler/typeCall.ts
new file mode 100644
index 0000000000000..db803444ed8d6
--- /dev/null
+++ b/tests/cases/compiler/typeCall.ts
@@ -0,0 +1,65 @@
+// @allowSyntheticDefaultImports: true
+
+type F1 = () => 1;
+type a = F1();
+
+type F2 = (a: string) => 1;
+type b = F2('foo');
+
+interface F3 {
+ (): 1;
+ (a: number): 2;
+ (a: string): 3;
+}
+type c = F3();
+type d = F3(123);
+type e = F3('foo');
+
+declare function f4(a: string): 1;
+let a = 'foo';
+type f = typeof f4(typeof a);
+
+type g = (() => 1)();
+
+type Id = (v: T) => T;
+type h = Id(123);
+
+type Wrap = Id(T);
+type i = Wrap<123>;
+
+type F5 = () => () => { a: () => 1; };
+type j = F5()()['a']();
+
+type k1 = Id('foo'); // `any`, `` is part of the type reference, not the function call
+type k2 = Id<>('foo'); // ok, `string`
+
+declare function id(v: T): T;
+let l = id('foo');
+
+interface IsPrimitive {
+ (o: object): '0';
+ (o: any): '1';
+}
+type stringIsPrimitive = IsPrimitive(string); // '1', ok
+type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok
+
+// explicit type arguments need to go after the type arguments of the type reference, empty `<>` if n/a
+type genericIsPrimitive = () => IsPrimitive(T);
+type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok
+type regexpIsPrimitive2 = genericIsPrimitive<>();
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+// alternative, pass as parameters
+type genericIsPrimitive3 = (v: T) => IsPrimitive(T);
+type stringIsPrimitive3 = genericIsPrimitive3(string); // '1', ok
+type regexpIsPrimitive3 = genericIsPrimitive3(RegExp)
+// FAILS!, '1' instead of '0', should delay overload selection until type argument is known
+
+type map = (fn: Fn, obj: O) => { [P in keyof O]: Fn(P) }; // Fn(O[P])
+type z = map((v: T) => [T], { a: 1, b: 2, c: 3 });
+
+// binary function composition, still fails
+type Fn1 = (v: T[]) => { [k: string]: T };
+type Fn2 = (v: { [k: string]: T }) => ReadonlyArray;
+type Fn3 = (v: T) => Fn2(Fn1(T));
+type Fn4 = Fn3(1);
diff --git a/tests/cases/compiler/typeCallSpreads.ts b/tests/cases/compiler/typeCallSpreads.ts
new file mode 100644
index 0000000000000..c49622b419927
--- /dev/null
+++ b/tests/cases/compiler/typeCallSpreads.ts
@@ -0,0 +1,2 @@
+type Fn = (v: T) => T;
+type a = Fn(...[1]);