From 481e88bdbd641ac7b876090ba6ffb505577f1dc0 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Fri, 18 Aug 2017 18:07:07 +0800 Subject: [PATCH 01/11] tuple type spread attempt, resolves too early for generics :( new node reusable for Fn(...Args) --- src/compiler/binder.ts | 1 + src/compiler/checker.ts | 30 ++++++++++++++++++- src/compiler/diagnosticMessages.json | 4 +++ src/compiler/emitter.ts | 9 ++++++ src/compiler/factory.ts | 12 ++++++++ src/compiler/parser.ts | 20 +++++++++++-- src/compiler/types.ts | 8 ++++- src/compiler/utilities.ts | 4 +++ src/compiler/visitor.ts | 8 +++++ .../reference/tupleTypeSpread.errors.txt | 10 +++++++ tests/baselines/reference/tupleTypeSpread.js | 7 +++++ .../reference/tupleTypeSpread.symbols | 4 +++ .../baselines/reference/tupleTypeSpread.types | 4 +++ tests/cases/compiler/tupleTypeSpread.ts | 4 +++ 14 files changed, 121 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/tupleTypeSpread.errors.txt create mode 100644 tests/baselines/reference/tupleTypeSpread.js create mode 100644 tests/baselines/reference/tupleTypeSpread.symbols create mode 100644 tests/baselines/reference/tupleTypeSpread.types create mode 100644 tests/cases/compiler/tupleTypeSpread.ts 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 ce5f5a4f1c522..2a53c68ec0838 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7202,11 +7202,39 @@ 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 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 typeNode: TypeNode = (node as TypeSpreadTypeNode).type; + const type = getApparentType(getTypeFromTypeNode( typeNode)); + if (isTupleLikeType(type)) { + return getTupleTypeElementTypes(type); + } + else { + error(typeNode, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types); + return []; + } + } + else { + return getTypeFromTypeNode(node as TypeNode); + } + } + interface TypeSet extends Array { containsAny?: boolean; containsUndefined?: boolean; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 77e7f7e7b6246..a35f95d5b82c1 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2200,6 +2200,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..3aa43f219deb9 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: @@ -2193,6 +2195,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..23866ac865001 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2185,6 +2185,18 @@ namespace ts { : node; } + export function createTypeSpread(type: TypeNode) { + 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 a2fe752ad18e9..83fd2092ac679 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: @@ -1378,8 +1380,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 +2588,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); } @@ -5160,6 +5163,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 efcf747e88c4c..c3511ab384bc8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -343,6 +343,7 @@ namespace ts { PropertyAssignment, ShorthandPropertyAssignment, SpreadAssignment, + TypeSpread, // Enum EnumMember, @@ -950,7 +951,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; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index c77d267471a06..740ce56a097ff 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..356bce73cfe33 100644 --- a/src/compiler/visitor.ts +++ b/src/compiler/visitor.ts @@ -869,6 +869,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 +1395,10 @@ namespace ts { result = reduceNode((node).expression, 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/tupleTypeSpread.errors.txt b/tests/baselines/reference/tupleTypeSpread.errors.txt new file mode 100644 index 0000000000000..a17035a8c3965 --- /dev/null +++ b/tests/baselines/reference/tupleTypeSpread.errors.txt @@ -0,0 +1,10 @@ +tests/cases/compiler/tupleTypeSpread.ts(2,52): error TS2714: Tuple type spreads may only be created from tuple types. + + +==== tests/cases/compiler/tupleTypeSpread.ts (1 errors) ==== + type a = [1, ...[2]]; + type Combine = [Head, ...Tail]; + ~~~~ +!!! error TS2714: Tuple type spreads may only be created from tuple types. + type b = Combine<1, [2, 3]>; + \ No newline at end of file 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..f176363ab75cb --- /dev/null +++ b/tests/baselines/reference/tupleTypeSpread.symbols @@ -0,0 +1,4 @@ +=== tests/cases/compiler/tupleTypeSpread.ts === +type a = [1, ...[2]]; +>a : Symbol(a, Decl(tupleTypeSpread.ts, 0, 0)) + diff --git a/tests/baselines/reference/tupleTypeSpread.types b/tests/baselines/reference/tupleTypeSpread.types new file mode 100644 index 0000000000000..4fcd58b203ccf --- /dev/null +++ b/tests/baselines/reference/tupleTypeSpread.types @@ -0,0 +1,4 @@ +=== tests/cases/compiler/tupleTypeSpread.ts === +type a = [1, ...[2]]; +>a : [1, 2] + 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]>; From dd42eb3faef05863bb65b5d47a8d1dffbd3082b8 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Sat, 19 Aug 2017 00:38:07 +0800 Subject: [PATCH 02/11] tslint warning --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 2a53c68ec0838..03d90f2d28be8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7221,7 +7221,7 @@ namespace ts { function getTypeFromTupleElement(node: TypeNode | TypeSpreadTypeNode): Type | Type[] { if (node.kind === SyntaxKind.TypeSpread) { const typeNode: TypeNode = (node as TypeSpreadTypeNode).type; - const type = getApparentType(getTypeFromTypeNode( typeNode)); + const type = getApparentType(getTypeFromTypeNode(typeNode as TypeNode)); if (isTupleLikeType(type)) { return getTupleTypeElementTypes(type); } From 17310a878ece83a54018d27066c9bbf371669b67 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Sat, 19 Aug 2017 01:06:56 +0800 Subject: [PATCH 03/11] logging crap --- src/compiler/checker.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 03d90f2d28be8..ac74cfa2f2fe3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,5 +1,8 @@ /// /// +// /// + +// declare var console: Console; /* @internal */ namespace ts { @@ -5380,6 +5383,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[]; @@ -7222,7 +7226,16 @@ namespace ts { if (node.kind === SyntaxKind.TypeSpread) { const typeNode: TypeNode = (node as TypeSpreadTypeNode).type; const type = getApparentType(getTypeFromTypeNode(typeNode as TypeNode)); + // const nodeType = getTypeFromTypeNode(typeNode as TypeNode); + // const type = getApparentType(nodeType); + if (allowSyntheticDefaultImports) { + // console.log("nodeType", typeToString(nodeType)); + // console.log("type", typeToString(type)); + // console.log("isTupleLikeType(nodeType)", isTupleLikeType(nodeType)); + // console.log("isTupleLikeType(type)", isTupleLikeType(type)); + } if (isTupleLikeType(type)) { + // return map(getPropertiesOfType(type), getTypeOfSymbol); return getTupleTypeElementTypes(type); } else { From e89096db17817e869a25664e362b94ad636ebec4 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Sat, 19 Aug 2017 18:50:14 +0800 Subject: [PATCH 04/11] progress, now it evaluates too slow for b! --- src/compiler/checker.ts | 87 ++++++++++++++----- src/compiler/types.ts | 6 ++ .../reference/tupleTypeSpread.errors.txt | 10 --- .../reference/tupleTypeSpread.symbols | 11 +++ .../baselines/reference/tupleTypeSpread.types | 11 +++ 5 files changed, 95 insertions(+), 30 deletions(-) delete mode 100644 tests/baselines/reference/tupleTypeSpread.errors.txt diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index ac74cfa2f2fe3..284c17708f880 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1,8 +1,8 @@ /// /// -// /// +/// -// declare var console: Console; +declare var console: Console; /* @internal */ namespace ts { @@ -240,6 +240,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); @@ -2528,6 +2529,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."); @@ -3291,6 +3296,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 // { ... } @@ -5383,7 +5392,7 @@ namespace ts { } function resolveObjectTypeMembers(type: ObjectType, source: InterfaceTypeWithDeclaredMembers, typeParameters: TypeParameter[], typeArguments: Type[]) { - // if (allowSyntheticDefaultImports) console.log("resolveObjectTypeMembers", typeToString(type)); + if (allowSyntheticDefaultImports) console.log("resolveObjectTypeMembers", typeToString(type)); let mapper: TypeMapper; let members: SymbolTable; let callSignatures: Signature[]; @@ -7211,6 +7220,39 @@ namespace ts { 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 = []; @@ -7224,24 +7266,11 @@ namespace ts { function getTypeFromTupleElement(node: TypeNode | TypeSpreadTypeNode): Type | Type[] { if (node.kind === SyntaxKind.TypeSpread) { - const typeNode: TypeNode = (node as TypeSpreadTypeNode).type; - const type = getApparentType(getTypeFromTypeNode(typeNode as TypeNode)); - // const nodeType = getTypeFromTypeNode(typeNode as TypeNode); - // const type = getApparentType(nodeType); - if (allowSyntheticDefaultImports) { - // console.log("nodeType", typeToString(nodeType)); - // console.log("type", typeToString(type)); - // console.log("isTupleLikeType(nodeType)", isTupleLikeType(nodeType)); - // console.log("isTupleLikeType(type)", isTupleLikeType(type)); - } - if (isTupleLikeType(type)) { - // return map(getPropertiesOfType(type), getTypeOfSymbol); - return getTupleTypeElementTypes(type); - } - else { - error(typeNode, Diagnostics.Tuple_type_spreads_may_only_be_created_from_tuple_types); - return []; + const links = getNodeLinks(node); + if (!links.resolvedType) { + links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type) } + return getTypeSpreadTypes(links.resolvedType); } else { return getTypeFromTypeNode(node as TypeNode); @@ -7585,6 +7614,12 @@ namespace ts { return type; } + function createTypeSpreadType(tuple: Type) { + 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 ? @@ -8400,6 +8435,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; } @@ -18799,6 +18837,13 @@ namespace ts { forEach(node.elementTypes, checkSourceElement); } + function checkTypeSpread(node: TypeSpreadTypeNode) { + const type = getApparentType(getTypeFromTypeNode(node.type as TypeNode)); + 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); } @@ -22334,6 +22379,8 @@ namespace ts { return checkArrayType(node); case SyntaxKind.TupleType: return checkTupleType(node); + case SyntaxKind.TypeSpread: + return checkTypeSpread(node); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: return checkUnionOrIntersectionType(node); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index c3511ab384bc8..e85e5e1227253 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -3146,6 +3146,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, @@ -3393,6 +3394,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/tests/baselines/reference/tupleTypeSpread.errors.txt b/tests/baselines/reference/tupleTypeSpread.errors.txt deleted file mode 100644 index a17035a8c3965..0000000000000 --- a/tests/baselines/reference/tupleTypeSpread.errors.txt +++ /dev/null @@ -1,10 +0,0 @@ -tests/cases/compiler/tupleTypeSpread.ts(2,52): error TS2714: Tuple type spreads may only be created from tuple types. - - -==== tests/cases/compiler/tupleTypeSpread.ts (1 errors) ==== - type a = [1, ...[2]]; - type Combine = [Head, ...Tail]; - ~~~~ -!!! error TS2714: Tuple type spreads may only be created from tuple types. - type b = Combine<1, [2, 3]>; - \ No newline at end of file diff --git a/tests/baselines/reference/tupleTypeSpread.symbols b/tests/baselines/reference/tupleTypeSpread.symbols index f176363ab75cb..303808d580702 100644 --- a/tests/baselines/reference/tupleTypeSpread.symbols +++ b/tests/baselines/reference/tupleTypeSpread.symbols @@ -2,3 +2,14 @@ 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 index 4fcd58b203ccf..a804885e1a591 100644 --- a/tests/baselines/reference/tupleTypeSpread.types +++ b/tests/baselines/reference/tupleTypeSpread.types @@ -2,3 +2,14 @@ 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] + From 568b8996bd08591cc2d20b1d224845d63790776c Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Sat, 19 Aug 2017 19:16:14 +0800 Subject: [PATCH 05/11] fix check --- src/compiler/checker.ts | 21 ++++++++++++++++----- src/compiler/factory.ts | 1 + 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 284c17708f880..664742d4a62f4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7229,7 +7229,8 @@ namespace ts { spreadTypes.set(id, type = createTypeSpreadType(tuple)); } return [type]; - } else { + } + else { // const type = getApparentType(nodeType); if (allowSyntheticDefaultImports) { console.log("type", typeToString(tuple)); @@ -7268,7 +7269,7 @@ namespace ts { if (node.kind === SyntaxKind.TypeSpread) { const links = getNodeLinks(node); if (!links.resolvedType) { - links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type) + links.resolvedType = getTypeFromTypeNode((node as TypeSpreadTypeNode).type); } return getTypeSpreadTypes(links.resolvedType); } @@ -7615,6 +7616,7 @@ namespace ts { } function createTypeSpreadType(tuple: Type) { + console.log("createTypeSpreadType"); const type = createType(TypeFlags.TypeSpread); type.type = tuple; return type; @@ -18837,13 +18839,22 @@ namespace ts { forEach(node.elementTypes, checkSourceElement); } - function checkTypeSpread(node: TypeSpreadTypeNode) { - const type = getApparentType(getTypeFromTypeNode(node.type as TypeNode)); + 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); } @@ -22380,7 +22391,7 @@ namespace ts { case SyntaxKind.TupleType: return checkTupleType(node); case SyntaxKind.TypeSpread: - return checkTypeSpread(node); + return checkTypeSpreadTypeNode(node); case SyntaxKind.UnionType: case SyntaxKind.IntersectionType: return checkUnionOrIntersectionType(node); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 23866ac865001..25fe218f6f107 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -2186,6 +2186,7 @@ namespace ts { } export function createTypeSpread(type: TypeNode) { + console.log("createTypeSpread"); const node = createSynthesizedNode(SyntaxKind.TypeSpread); node.type = type !== undefined ? parenthesizeElementTypeMember(type) : undefined; return node; From 080b3911e78153e897583597469b2ade3adead9c Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Tue, 22 Aug 2017 23:56:03 +0800 Subject: [PATCH 06/11] add type-level function application --- src/compiler/checker.ts | 16 +++- src/compiler/emitter.ts | 8 ++ src/compiler/factory.ts | 16 ++++ src/compiler/parser.ts | 54 ++++++++++-- src/compiler/types.ts | 10 ++- src/compiler/visitor.ts | 10 +++ .../reference/arrayTypeOfTypeOf.errors.txt | 22 ++--- .../baselines/reference/arrayTypeOfTypeOf.js | 4 +- .../reference/invalidTypeOfTarget.errors.txt | 12 ++- .../reference/invalidTypeOfTarget.js | 3 +- .../reference/parserObjectType5.errors.txt | 5 +- .../reference/parserTypeQuery8.errors.txt | 9 +- tests/baselines/reference/parserTypeQuery8.js | 2 +- tests/baselines/reference/typeCall.js | 36 ++++++++ tests/baselines/reference/typeCall.symbols | 86 ++++++++++++++++++ tests/baselines/reference/typeCall.types | 87 +++++++++++++++++++ tests/cases/compiler/typeCall.ts | 31 +++++++ 17 files changed, 373 insertions(+), 38 deletions(-) create mode 100644 tests/baselines/reference/typeCall.js create mode 100644 tests/baselines/reference/typeCall.symbols create mode 100644 tests/baselines/reference/typeCall.types create mode 100644 tests/cases/compiler/typeCall.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d2d3697f175c6..d79ab58473159 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7546,6 +7546,18 @@ namespace ts { return links.resolvedType; } + function getTypeFromTypeCallNode(node: TypeCallTypeNode): Type { + const fn = typeToExpression(node.type); + const args = map(node.arguments, typeToExpression); + const callExpr = createCall(fn, node.typeArguments, args); + return checkExpression(callExpr); + } + + // null! as type + function typeToExpression(type: TypeNode): Expression { + return createAsExpression(createNonNullExpression(createNull()), type); + } + function createIndexedAccessType(objectType: Type, indexType: Type) { const type = createType(TypeFlags.IndexedAccess); type.objectType = objectType; @@ -8003,6 +8015,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: @@ -13179,7 +13193,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: diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 5444c618353bd..641f4dbc833d3 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -753,6 +753,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 +1242,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); diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index daec1bce1e8b5..be310b80cedcf 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); diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index a2fe752ad18e9..261a54045bb75 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -170,6 +170,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) || @@ -2738,8 +2742,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(); @@ -2761,8 +2765,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); @@ -2794,7 +2798,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 { @@ -4240,6 +4244,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, parseType); + parseExpected(SyntaxKind.CloseParenToken); + return result; + } + function parseCallExpressionRest(expression: LeftHandSideExpression): LeftHandSideExpression { while (true) { expression = parseMemberExpressionRest(expression); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 608bc779042df..df9cc5b01c483 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, @@ -398,7 +399,7 @@ namespace ts { FirstFutureReservedWord = ImplementsKeyword, LastFutureReservedWord = YieldKeyword, FirstTypeNode = TypePredicate, - LastTypeNode = LiteralType, + LastTypeNode = TypeCall, FirstPunctuation = OpenBraceToken, LastPunctuation = CaretEqualsToken, FirstToken = Unknown, @@ -1495,6 +1496,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; diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts index 1ce42199372d8..0592b84a50f03 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), @@ -1391,6 +1397,10 @@ namespace ts { result = reduceNode((node).expression, cbNode, result); break; + case SyntaxKind.TypeCall: + 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/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/typeCall.js b/tests/baselines/reference/typeCall.js new file mode 100644 index 0000000000000..7d10ac980ce25 --- /dev/null +++ b/tests/baselines/reference/typeCall.js @@ -0,0 +1,36 @@ +//// [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 k = Id('foo'); + + +//// [typeCall.js] +var a = 'foo'; diff --git a/tests/baselines/reference/typeCall.symbols b/tests/baselines/reference/typeCall.symbols new file mode 100644 index 0000000000000..cd34250a4f482 --- /dev/null +++ b/tests/baselines/reference/typeCall.symbols @@ -0,0 +1,86 @@ +=== 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 k = Id('foo'); +>k : Symbol(k, Decl(typeCall.ts, 28, 23)) +>Id : Symbol(Id, Decl(typeCall.ts, 19, 21)) + diff --git a/tests/baselines/reference/typeCall.types b/tests/baselines/reference/typeCall.types new file mode 100644 index 0000000000000..f0398b1cb6dff --- /dev/null +++ b/tests/baselines/reference/typeCall.types @@ -0,0 +1,87 @@ +=== 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 k = Id('foo'); +>k : any +>Id : Id + diff --git a/tests/cases/compiler/typeCall.ts b/tests/cases/compiler/typeCall.ts new file mode 100644 index 0000000000000..1a867d71c66ff --- /dev/null +++ b/tests/cases/compiler/typeCall.ts @@ -0,0 +1,31 @@ +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 k = Id('foo'); From 312b69e8b76c7266180593af04a19e51cdf2dc99 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Wed, 23 Aug 2017 00:31:49 +0800 Subject: [PATCH 07/11] type calls: add failing test --- tests/baselines/reference/typeCall.js | 21 +++++++- tests/baselines/reference/typeCall.symbols | 60 +++++++++++++++++++++- tests/baselines/reference/typeCall.types | 60 +++++++++++++++++++++- tests/cases/compiler/typeCall.ts | 20 +++++++- 4 files changed, 157 insertions(+), 4 deletions(-) diff --git a/tests/baselines/reference/typeCall.js b/tests/baselines/reference/typeCall.js index 7d10ac980ce25..1be051d960c20 100644 --- a/tests/baselines/reference/typeCall.js +++ b/tests/baselines/reference/typeCall.js @@ -29,8 +29,27 @@ type i = Wrap<123>; type F5 = () => () => { a: () => 1; }; type j = F5()()['a'](); -type k = Id('foo'); +type k = Id('foo'); // `any`, explicit type argument fails + +interface IsPrimitive { + (o: T): '0'; + (o: T): '1'; +} +type stringIsPrimitive = IsPrimitive(string); // '1', ok +type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok + +// explicit type arguments still fail +type genericIsPrimitive = () => IsPrimitive(T); +type stringIsPrimitive2 = genericIsPrimitive(); +type regexpIsPrimitive2 = genericIsPrimitive(); + +// workaround, 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 //// [typeCall.js] var a = 'foo'; +// FAILS!, '1' instead of '0', should delay overload selection until type argument is known diff --git a/tests/baselines/reference/typeCall.symbols b/tests/baselines/reference/typeCall.symbols index cd34250a4f482..593e4b2892338 100644 --- a/tests/baselines/reference/typeCall.symbols +++ b/tests/baselines/reference/typeCall.symbols @@ -80,7 +80,65 @@ type j = F5()()['a'](); >j : Symbol(j, Decl(typeCall.ts, 27, 38)) >F5 : Symbol(F5, Decl(typeCall.ts, 25, 19)) -type k = Id('foo'); +type k = Id('foo'); // `any`, explicit type argument fails >k : Symbol(k, Decl(typeCall.ts, 28, 23)) >Id : Symbol(Id, Decl(typeCall.ts, 19, 21)) +interface IsPrimitive { +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) + + (o: T): '0'; +>T : Symbol(T, Decl(typeCall.ts, 33, 3)) +>o : Symbol(o, Decl(typeCall.ts, 33, 21)) +>T : Symbol(T, Decl(typeCall.ts, 33, 3)) + + (o: T): '1'; +>T : Symbol(T, Decl(typeCall.ts, 34, 3)) +>o : Symbol(o, Decl(typeCall.ts, 34, 6)) +>T : Symbol(T, Decl(typeCall.ts, 34, 3)) +} +type stringIsPrimitive = IsPrimitive(string); // '1', ok +>stringIsPrimitive : Symbol(stringIsPrimitive, Decl(typeCall.ts, 35, 1)) +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) + +type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok +>regexpIsPrimitive : Symbol(regexpIsPrimitive, Decl(typeCall.ts, 36, 45)) +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +// explicit type arguments still fail +type genericIsPrimitive = () => IsPrimitive(T); +>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 37, 45)) +>T : Symbol(T, Decl(typeCall.ts, 40, 27)) +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) +>T : Symbol(T, Decl(typeCall.ts, 40, 27)) + +type stringIsPrimitive2 = genericIsPrimitive(); +>stringIsPrimitive2 : Symbol(stringIsPrimitive2, Decl(typeCall.ts, 40, 50)) +>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 37, 45)) + +type regexpIsPrimitive2 = genericIsPrimitive(); +>regexpIsPrimitive2 : Symbol(regexpIsPrimitive2, Decl(typeCall.ts, 41, 55)) +>genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 37, 45)) +>RegExp : Symbol(RegExp, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +// workaround, pass as parameters +type genericIsPrimitive3 = (v: T) => IsPrimitive(T); +>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 42, 55)) +>T : Symbol(T, Decl(typeCall.ts, 45, 28)) +>v : Symbol(v, Decl(typeCall.ts, 45, 31)) +>T : Symbol(T, Decl(typeCall.ts, 45, 28)) +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) +>T : Symbol(T, Decl(typeCall.ts, 45, 28)) + +type stringIsPrimitive3 = genericIsPrimitive3(string); // '1', ok +>stringIsPrimitive3 : Symbol(stringIsPrimitive3, Decl(typeCall.ts, 45, 55)) +>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 42, 55)) + +type regexpIsPrimitive3 = genericIsPrimitive3(RegExp) +>regexpIsPrimitive3 : Symbol(regexpIsPrimitive3, Decl(typeCall.ts, 46, 54)) +>genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 42, 55)) +>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 + diff --git a/tests/baselines/reference/typeCall.types b/tests/baselines/reference/typeCall.types index f0398b1cb6dff..2ffe3492eb4c1 100644 --- a/tests/baselines/reference/typeCall.types +++ b/tests/baselines/reference/typeCall.types @@ -81,7 +81,65 @@ type j = F5()()['a'](); >j : 1 >F5 : F5 -type k = Id('foo'); +type k = Id('foo'); // `any`, explicit type argument fails >k : any >Id : Id +interface IsPrimitive { +>IsPrimitive : IsPrimitive + + (o: T): '0'; +>T : T +>o : T +>T : T + + (o: T): '1'; +>T : T +>o : T +>T : T +} +type stringIsPrimitive = IsPrimitive(string); // '1', ok +>stringIsPrimitive : "1" +>IsPrimitive : IsPrimitive + +type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok +>regexpIsPrimitive : "0" +>IsPrimitive : IsPrimitive +>RegExp : RegExp + +// explicit type arguments still fail +type genericIsPrimitive = () => IsPrimitive(T); +>genericIsPrimitive : genericIsPrimitive +>T : T +>IsPrimitive : IsPrimitive +>T : T + +type stringIsPrimitive2 = genericIsPrimitive(); +>stringIsPrimitive2 : any +>genericIsPrimitive : genericIsPrimitive + +type regexpIsPrimitive2 = genericIsPrimitive(); +>regexpIsPrimitive2 : any +>genericIsPrimitive : genericIsPrimitive +>RegExp : RegExp + +// workaround, 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 + diff --git a/tests/cases/compiler/typeCall.ts b/tests/cases/compiler/typeCall.ts index 1a867d71c66ff..27761d1389173 100644 --- a/tests/cases/compiler/typeCall.ts +++ b/tests/cases/compiler/typeCall.ts @@ -28,4 +28,22 @@ type i = Wrap<123>; type F5 = () => () => { a: () => 1; }; type j = F5()()['a'](); -type k = Id('foo'); +type k = Id('foo'); // `any`, explicit type argument fails + +interface IsPrimitive { + (o: T): '0'; + (o: T): '1'; +} +type stringIsPrimitive = IsPrimitive(string); // '1', ok +type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok + +// explicit type arguments still fail +type genericIsPrimitive = () => IsPrimitive(T); +type stringIsPrimitive2 = genericIsPrimitive(); +type regexpIsPrimitive2 = genericIsPrimitive(); + +// workaround, 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 From c98fe7930546bf93a737cbe774046af3cf2a0d29 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Wed, 23 Aug 2017 15:32:53 +0800 Subject: [PATCH 08/11] disambiguate type argument lists with empty <> --- src/compiler/checker.ts | 10 +- tests/baselines/reference/typeCall.js | 24 +++-- tests/baselines/reference/typeCall.symbols | 116 ++++++++++++++------- tests/baselines/reference/typeCall.types | 72 ++++++++++--- tests/cases/compiler/typeCall.ts | 24 +++-- 5 files changed, 171 insertions(+), 75 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d79ab58473159..4605282da1bcb 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6792,7 +6792,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; } @@ -6834,7 +6834,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; } @@ -6845,7 +6845,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; } @@ -18728,7 +18728,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) { @@ -24284,7 +24284,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/tests/baselines/reference/typeCall.js b/tests/baselines/reference/typeCall.js index 1be051d960c20..618847b55522a 100644 --- a/tests/baselines/reference/typeCall.js +++ b/tests/baselines/reference/typeCall.js @@ -29,27 +29,35 @@ type i = Wrap<123>; type F5 = () => () => { a: () => 1; }; type j = F5()()['a'](); -type k = Id('foo'); // `any`, explicit type argument fails +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: T): '0'; - (o: T): '1'; + (o: object): '0'; + (o: any): '1'; } type stringIsPrimitive = IsPrimitive(string); // '1', ok type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok -// explicit type arguments still fail +// 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(); -type regexpIsPrimitive2 = genericIsPrimitive(); +type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok +type regexpIsPrimitive2 = genericIsPrimitive<>(); +// FAILS!, '1' instead of '0', should delay overload selection until type argument is known -// workaround, pass as parameters +// 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 }); //// [typeCall.js] var a = 'foo'; -// FAILS!, '1' instead of '0', should delay overload selection until type argument is known +var l = id('foo'); diff --git a/tests/baselines/reference/typeCall.symbols b/tests/baselines/reference/typeCall.symbols index 593e4b2892338..feac9667aa446 100644 --- a/tests/baselines/reference/typeCall.symbols +++ b/tests/baselines/reference/typeCall.symbols @@ -80,65 +80,103 @@ type j = F5()()['a'](); >j : Symbol(j, Decl(typeCall.ts, 27, 38)) >F5 : Symbol(F5, Decl(typeCall.ts, 25, 19)) -type k = Id('foo'); // `any`, explicit type argument fails ->k : Symbol(k, Decl(typeCall.ts, 28, 23)) +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, 30, 27)) +>IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 34, 26)) - (o: T): '0'; ->T : Symbol(T, Decl(typeCall.ts, 33, 3)) ->o : Symbol(o, Decl(typeCall.ts, 33, 21)) ->T : Symbol(T, Decl(typeCall.ts, 33, 3)) + (o: object): '0'; +>o : Symbol(o, Decl(typeCall.ts, 37, 3)) - (o: T): '1'; ->T : Symbol(T, Decl(typeCall.ts, 34, 3)) ->o : Symbol(o, Decl(typeCall.ts, 34, 6)) ->T : Symbol(T, Decl(typeCall.ts, 34, 3)) + (o: any): '1'; +>o : Symbol(o, Decl(typeCall.ts, 38, 3)) } type stringIsPrimitive = IsPrimitive(string); // '1', ok ->stringIsPrimitive : Symbol(stringIsPrimitive, Decl(typeCall.ts, 35, 1)) ->IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) +>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, 36, 45)) ->IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) +>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 still fail +// 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, 37, 45)) ->T : Symbol(T, Decl(typeCall.ts, 40, 27)) ->IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) ->T : Symbol(T, Decl(typeCall.ts, 40, 27)) - -type stringIsPrimitive2 = genericIsPrimitive(); ->stringIsPrimitive2 : Symbol(stringIsPrimitive2, Decl(typeCall.ts, 40, 50)) ->genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 37, 45)) - -type regexpIsPrimitive2 = genericIsPrimitive(); ->regexpIsPrimitive2 : Symbol(regexpIsPrimitive2, Decl(typeCall.ts, 41, 55)) ->genericIsPrimitive : Symbol(genericIsPrimitive, Decl(typeCall.ts, 37, 45)) +>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, --, --)) -// workaround, pass as parameters +// 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, 42, 55)) ->T : Symbol(T, Decl(typeCall.ts, 45, 28)) ->v : Symbol(v, Decl(typeCall.ts, 45, 31)) ->T : Symbol(T, Decl(typeCall.ts, 45, 28)) ->IsPrimitive : Symbol(IsPrimitive, Decl(typeCall.ts, 30, 27)) ->T : Symbol(T, Decl(typeCall.ts, 45, 28)) +>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, 45, 55)) ->genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 42, 55)) +>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, 46, 54)) ->genericIsPrimitive3 : Symbol(genericIsPrimitive3, Decl(typeCall.ts, 42, 55)) +>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)) + diff --git a/tests/baselines/reference/typeCall.types b/tests/baselines/reference/typeCall.types index 2ffe3492eb4c1..b0d3b06102a87 100644 --- a/tests/baselines/reference/typeCall.types +++ b/tests/baselines/reference/typeCall.types @@ -81,22 +81,35 @@ type j = F5()()['a'](); >j : 1 >F5 : F5 -type k = Id('foo'); // `any`, explicit type argument fails ->k : any +type k1 = Id('foo'); // `any`, `` is part of the type reference, not the function call +>k1 : any >Id : Id -interface IsPrimitive { ->IsPrimitive : IsPrimitive +type k2 = Id<>('foo'); // ok, `string` +>k2 : string +>Id : Id - (o: T): '0'; +declare function id(v: T): T; +>id : (v: T) => T >T : T ->o : T ->T : T - - (o: T): '1'; +>v : T >T : T ->o : 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" @@ -107,23 +120,25 @@ type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok >IsPrimitive : IsPrimitive >RegExp : RegExp -// explicit type arguments still fail +// 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(); ->stringIsPrimitive2 : any +type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok +>stringIsPrimitive2 : "1" >genericIsPrimitive : genericIsPrimitive -type regexpIsPrimitive2 = genericIsPrimitive(); ->regexpIsPrimitive2 : any +type regexpIsPrimitive2 = genericIsPrimitive<>(); +>regexpIsPrimitive2 : "1" >genericIsPrimitive : genericIsPrimitive >RegExp : RegExp -// workaround, pass as parameters +// 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 @@ -143,3 +158,28 @@ 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]) +>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 + diff --git a/tests/cases/compiler/typeCall.ts b/tests/cases/compiler/typeCall.ts index 27761d1389173..8591e8b14a33d 100644 --- a/tests/cases/compiler/typeCall.ts +++ b/tests/cases/compiler/typeCall.ts @@ -1,3 +1,5 @@ +// @allowSyntheticDefaultImports: true + type F1 = () => 1; type a = F1(); @@ -28,22 +30,30 @@ type i = Wrap<123>; type F5 = () => () => { a: () => 1; }; type j = F5()()['a'](); -type k = Id('foo'); // `any`, explicit type argument fails +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: T): '0'; - (o: T): '1'; + (o: object): '0'; + (o: any): '1'; } type stringIsPrimitive = IsPrimitive(string); // '1', ok type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok -// explicit type arguments still fail +// 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(); -type regexpIsPrimitive2 = genericIsPrimitive(); +type stringIsPrimitive2 = genericIsPrimitive<>(); // '1', ok +type regexpIsPrimitive2 = genericIsPrimitive<>(); +// FAILS!, '1' instead of '0', should delay overload selection until type argument is known -// workaround, pass as parameters +// 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 }); From 636b4acae895e6011f1637512213158d95c1f5a2 Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Wed, 23 Aug 2017 15:36:00 +0800 Subject: [PATCH 09/11] fix function name --- src/compiler/checker.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 4605282da1bcb..ea92d0c57bc0b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7547,14 +7547,14 @@ namespace ts { } function getTypeFromTypeCallNode(node: TypeCallTypeNode): Type { - const fn = typeToExpression(node.type); - const args = map(node.arguments, typeToExpression); + const fn = typeNodeToExpression(node.type); + const args = map(node.arguments, typeNodeToExpression); const callExpr = createCall(fn, node.typeArguments, args); return checkExpression(callExpr); } // null! as type - function typeToExpression(type: TypeNode): Expression { + function typeNodeToExpression(type: TypeNode): Expression { return createAsExpression(createNonNullExpression(createNull()), type); } From a76ba3838de96da7d4ba8bba220f74b5ad751bbb Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Thu, 24 Aug 2017 15:56:32 +0800 Subject: [PATCH 10/11] show issues: overload selection (#17471), composition --- .../baselines/reference/overloadSelection.js | 12 +++++++ .../reference/overloadSelection.symbols | 26 +++++++++++++++ .../reference/overloadSelection.types | 26 +++++++++++++++ tests/baselines/reference/typeCall.js | 6 ++++ tests/baselines/reference/typeCall.symbols | 31 +++++++++++++++++ tests/baselines/reference/typeCall.types | 33 ++++++++++++++++++- tests/cases/compiler/overloadSelection.ts | 9 +++++ tests/cases/compiler/typeCall.ts | 6 ++++ 8 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/overloadSelection.js create mode 100644 tests/baselines/reference/overloadSelection.symbols create mode 100644 tests/baselines/reference/overloadSelection.types create mode 100644 tests/cases/compiler/overloadSelection.ts 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/typeCall.js b/tests/baselines/reference/typeCall.js index 618847b55522a..36baf427ab212 100644 --- a/tests/baselines/reference/typeCall.js +++ b/tests/baselines/reference/typeCall.js @@ -56,6 +56,12 @@ type regexpIsPrimitive3 = genericIsPrimitive3(RegExp) 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] diff --git a/tests/baselines/reference/typeCall.symbols b/tests/baselines/reference/typeCall.symbols index feac9667aa446..50e4cde6189a1 100644 --- a/tests/baselines/reference/typeCall.symbols +++ b/tests/baselines/reference/typeCall.symbols @@ -180,3 +180,34 @@ type z = map((v: T) => [T], { a: 1, b: 2, c: 3 }); >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 index b0d3b06102a87..4c65d69645786 100644 --- a/tests/baselines/reference/typeCall.types +++ b/tests/baselines/reference/typeCall.types @@ -116,7 +116,7 @@ type stringIsPrimitive = IsPrimitive(string); // '1', ok >IsPrimitive : IsPrimitive type regexpIsPrimitive = IsPrimitive(RegExp); // '0', ok ->regexpIsPrimitive : "0" +>regexpIsPrimitive : "1" >IsPrimitive : IsPrimitive >RegExp : RegExp @@ -183,3 +183,34 @@ type z = map((v: T) => [T], { a: 1, b: 2, c: 3 }); >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/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/typeCall.ts b/tests/cases/compiler/typeCall.ts index 8591e8b14a33d..db803444ed8d6 100644 --- a/tests/cases/compiler/typeCall.ts +++ b/tests/cases/compiler/typeCall.ts @@ -57,3 +57,9 @@ type regexpIsPrimitive3 = genericIsPrimitive3(RegExp) 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); From bbcd11ea7f67d67aefc34cd74c5bebc7b57fd60c Mon Sep 17 00:00:00 2001 From: Tycho Grouwstra Date: Thu, 24 Aug 2017 20:40:06 +0800 Subject: [PATCH 11/11] WIP: allow spreads in type calls Fixes the third part of #5453, needed to effectively type `bind` (Function.prototype), `curry` and `compose`. Depends on #17961 type calls, #17884 type spread and #18004 tuple spread. The first 2/3 are included, so changes will look more cluttered here though new changes just span 10 lines over 2 functions. Will properly test this when those are ready -- now still broken. --- src/compiler/checker.ts | 8 +++++++- src/compiler/parser.ts | 2 +- tests/baselines/reference/typeCallSpreads.errors.txt | 12 ++++++++++++ tests/baselines/reference/typeCallSpreads.js | 8 ++++++++ tests/cases/compiler/typeCallSpreads.ts | 2 ++ 5 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/typeCallSpreads.errors.txt create mode 100644 tests/baselines/reference/typeCallSpreads.js create mode 100644 tests/cases/compiler/typeCallSpreads.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0b79a32f337d3..c6d43db5d24db 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7626,7 +7626,13 @@ namespace ts { function getTypeFromTypeCallNode(node: TypeCallTypeNode): Type { const fn = typeNodeToExpression(node.type); - const args = map(node.arguments, typeNodeToExpression); + 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); } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 12bc3c3796c9b..7c819727de264 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -4283,7 +4283,7 @@ namespace ts { function parseTypeArgumentList() { parseExpected(SyntaxKind.OpenParenToken); - const result = parseDelimitedList(ParsingContext.TypeArguments, parseType); + const result = parseDelimitedList(ParsingContext.TypeArguments, parseTupleElement); parseExpected(SyntaxKind.CloseParenToken); return result; } 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/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]);