Skip to content

Commit 0be6ce4

Browse files
committed
Parse & check generic instantiations
1 parent 080ba6f commit 0be6ce4

File tree

11 files changed

+532
-36
lines changed

11 files changed

+532
-36
lines changed

src/compiler/checker.ts

+31-11
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,8 @@ namespace ts {
35643564
if (ambientModuleSymbolRegex.test(rootName)) {
35653565
// module is root, must use `ImportTypeNode`
35663566
const nonRootParts = chain.length > 1 ? createEntityNameFromSymbolChain(chain, chain.length - 1, 1) : undefined;
3567-
return createImportTypeNode(createLiteralTypeNode(createLiteral(rootName.substring(1, rootName.length - 1))), nonRootParts, isTypeOf);
3567+
const typeParameterNodes = lookupTypeParameterNodes(chain, 0, context);
3568+
return createImportTypeNode(createLiteralTypeNode(createLiteral(rootName.substring(1, rootName.length - 1))), nonRootParts, typeParameterNodes as ReadonlyArray<TypeNode>, isTypeOf);
35683569
}
35693570

35703571
const entityName = createEntityNameFromSymbolChain(chain, chain.length - 1, 0);
@@ -7234,7 +7235,7 @@ namespace ts {
72347235
/**
72357236
* Get type from type-reference that reference to class or interface
72367237
*/
7237-
function getTypeFromClassOrInterfaceReference(node: TypeReferenceType, symbol: Symbol, typeArgs: Type[]): Type {
7238+
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol, typeArgs: Type[]): Type {
72387239
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
72397240
const typeParameters = type.localTypeParameters;
72407241
if (typeParameters) {
@@ -7284,7 +7285,7 @@ namespace ts {
72847285
* references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the
72857286
* declared type. Instantiations are cached using the type identities of the type arguments as the key.
72867287
*/
7287-
function getTypeFromTypeAliasReference(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type {
7288+
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type {
72887289
const type = getDeclaredTypeOfSymbol(symbol);
72897290
const typeParameters = getSymbolLinks(symbol).typeParameters;
72907291
if (typeParameters) {
@@ -7330,7 +7331,7 @@ namespace ts {
73307331
return resolveEntityName(typeReferenceName, meaning) || unknownSymbol;
73317332
}
73327333

7333-
function getTypeReferenceType(node: TypeReferenceType, symbol: Symbol) {
7334+
function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol) {
73347335
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
73357336
if (symbol === unknownSymbol) {
73367337
return unknownType;
@@ -7368,7 +7369,7 @@ namespace ts {
73687369
return valueType;
73697370
}
73707371

7371-
function getTypeReferenceTypeWorker(node: TypeReferenceType, symbol: Symbol, typeArguments: Type[]): Type | undefined {
7372+
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[]): Type | undefined {
73727373
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
73737374
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
73747375
}
@@ -7416,13 +7417,13 @@ namespace ts {
74167417
return constraints ? getSubstitutionType(typeVariable, getIntersectionType(append(constraints, typeVariable))) : typeVariable;
74177418
}
74187419

7419-
function isJSDocTypeReference(node: TypeReferenceType): node is TypeReferenceNode {
7420+
function isJSDocTypeReference(node: NodeWithTypeArguments): node is TypeReferenceNode {
74207421
return node.flags & NodeFlags.JSDoc && node.kind === SyntaxKind.TypeReference;
74217422
}
74227423

7423-
function checkNoTypeArguments(node: TypeReferenceType, symbol?: Symbol) {
7424+
function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) {
74247425
if (node.typeArguments) {
7425-
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : declarationNameToString((<TypeReferenceNode>node).typeName));
7426+
error(node, Diagnostics.Type_0_is_not_generic, symbol ? symbolToString(symbol) : (<TypeReferenceNode>node).typeName ? declarationNameToString((<TypeReferenceNode>node).typeName) : "(anonymous)");
74267427
return false;
74277428
}
74287429
return true;
@@ -7503,7 +7504,7 @@ namespace ts {
75037504
return links.resolvedType;
75047505
}
75057506

7506-
function typeArgumentsFromTypeReferenceNode(node: TypeReferenceType): Type[] {
7507+
function typeArgumentsFromTypeReferenceNode(node: NodeWithTypeArguments): Type[] {
75077508
return map(node.typeArguments, getTypeFromTypeNode);
75087509
}
75097510

@@ -8451,22 +8452,30 @@ namespace ts {
84518452
function getTypeFromImportTypeNode(node: ImportTypeNode): Type {
84528453
const links = getNodeLinks(node);
84538454
if (!links.resolvedType) {
8455+
if (node.isTypeOf && node.typeArguments) { // Only the non-typeof form can make use of type arguments
8456+
error(node, Diagnostics.type_arguments_can_only_be_used_in_a_ts_file);
8457+
links.resolvedSymbol = unknownSymbol;
8458+
return links.resolvedType = anyType;
8459+
}
84548460
const argumentType = getTypeFromTypeNode(node.argument);
84558461
const targetMeaning = node.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type;
84568462
// TODO: Future work: support unions/generics/whatever via a deferred import-type
84578463
if (!argumentType || !(argumentType.flags & TypeFlags.StringLiteral)) {
84588464
error(node.argument, Diagnostics.Import_specifier_must_be_a_string_literal_type_but_here_is_0, argumentType ? typeToString(argumentType) : "undefined");
8465+
links.resolvedSymbol = unknownSymbol;
84598466
return links.resolvedType = anyType;
84608467
}
84618468
const moduleName = (argumentType as StringLiteralType).value;
84628469
const innerModuleSymbol = resolveExternalModule(node, moduleName, Diagnostics.Cannot_find_module_0, node, /*isForAugmentation*/ false);
84638470
if (!innerModuleSymbol) {
84648471
error(node, Diagnostics.Cannot_find_module_0, moduleName);
8472+
links.resolvedSymbol = unknownSymbol;
84658473
return links.resolvedType = anyType;
84668474
}
84678475
const moduleSymbol = resolveExternalModuleSymbol(innerModuleSymbol, /*dontResolveAlias*/ false);
84688476
if (!moduleSymbol) {
84698477
error(node, Diagnostics.Cannot_find_module_0, moduleName);
8478+
links.resolvedSymbol = unknownSymbol;
84708479
return links.resolvedType = anyType;
84718480
}
84728481
if (node.qualifier) {
@@ -8492,21 +8501,32 @@ namespace ts {
84928501
}
84938502
currentNamespace = next;
84948503
}
8495-
links.resolvedType = targetMeaning === SymbolFlags.Value ? getTypeOfSymbol(currentNamespace) : getDeclaredTypeOfSymbol(currentNamespace);
8504+
resolveImportSymbolType(node, links, currentNamespace, targetMeaning);
84968505
}
84978506
else {
84988507
if (moduleSymbol.flags & targetMeaning) {
8499-
links.resolvedType = targetMeaning === SymbolFlags.Value ? getTypeOfSymbol(moduleSymbol) : getDeclaredTypeOfSymbol(moduleSymbol);
8508+
resolveImportSymbolType(node, links, moduleSymbol, targetMeaning);
85008509
}
85018510
else {
85028511
error(node, targetMeaning === SymbolFlags.Value ? Diagnostics.Module_0_does_not_refer_to_a_value_but_is_used_as_a_value_here : Diagnostics.Module_0_does_not_refer_to_a_type_but_is_used_as_a_type_here, moduleName);
8512+
links.resolvedSymbol = unknownSymbol;
85038513
links.resolvedType = anyType;
85048514
}
85058515
}
85068516
}
85078517
return links.resolvedType;
85088518
}
85098519

8520+
function resolveImportSymbolType(node: ImportTypeNode, links: NodeLinks, symbol: Symbol, meaning: SymbolFlags) {
8521+
links.resolvedSymbol = symbol;
8522+
if (meaning === SymbolFlags.Value) {
8523+
return links.resolvedType = getTypeOfSymbol(symbol);
8524+
}
8525+
else {
8526+
return links.resolvedType = getTypeReferenceType(node, symbol);
8527+
}
8528+
}
8529+
85108530
function getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node: TypeNode): Type {
85118531
const links = getNodeLinks(node);
85128532
if (!links.resolvedType) {

src/compiler/factory.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -802,19 +802,21 @@ namespace ts {
802802
: node;
803803
}
804804

805-
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, isTypeOf?: boolean) {
805+
export function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean) {
806806
const node = <ImportTypeNode>createSynthesizedNode(SyntaxKind.ImportTypeNode);
807807
node.argument = argument;
808808
node.qualifier = qualifier;
809+
node.typeArguments = asNodeArray(typeArguments);
809810
node.isTypeOf = isTypeOf;
810811
return node;
811812
}
812813

813-
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, isTypeOf?: boolean) {
814+
export function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean) {
814815
return node.argument !== argument
815816
|| node.qualifier !== qualifier
816-
|| !!node.isTypeOf !== !!isTypeOf
817-
? updateNode(createImportTypeNode(argument, qualifier, isTypeOf), node)
817+
|| node.typeArguments !== typeArguments
818+
|| node.isTypeOf !== isTypeOf
819+
? updateNode(createImportTypeNode(argument, qualifier, typeArguments, isTypeOf), node)
818820
: node;
819821
}
820822

src/compiler/parser.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,8 @@ namespace ts {
191191
return visitNode(cbNode, (<InferTypeNode>node).typeParameter);
192192
case SyntaxKind.ImportTypeNode:
193193
return visitNode(cbNode, (<ImportTypeNode>node).argument) ||
194-
visitNode(cbNode, (<ImportTypeNode>node).qualifier);
194+
visitNode(cbNode, (<ImportTypeNode>node).qualifier) ||
195+
visitNodes(cbNode, cbNodes, (<ImportTypeNode>node).typeArguments);
195196
case SyntaxKind.ParenthesizedType:
196197
case SyntaxKind.TypeOperator:
197198
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
@@ -2754,6 +2755,7 @@ namespace ts {
27542755
if (parseOptional(SyntaxKind.DotToken)) {
27552756
node.qualifier = parseEntityName(/*allowReservedWords*/ true, Diagnostics.Type_expected);
27562757
}
2758+
node.typeArguments = tryParseTypeArguments();
27572759
return finishNode(node);
27582760
}
27592761

src/compiler/types.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ namespace ts {
10671067
| SyntaxKind.NeverKeyword;
10681068
}
10691069

1070-
export interface ImportTypeNode extends TypeNode {
1070+
export interface ImportTypeNode extends NodeWithTypeArguments {
10711071
kind: SyntaxKind.ImportTypeNode;
10721072
isTypeOf?: boolean;
10731073
argument: TypeNode;
@@ -1091,12 +1091,15 @@ namespace ts {
10911091
kind: SyntaxKind.ConstructorType;
10921092
}
10931093

1094+
export interface NodeWithTypeArguments extends TypeNode {
1095+
typeArguments?: NodeArray<TypeNode>;
1096+
}
1097+
10941098
export type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
10951099

1096-
export interface TypeReferenceNode extends TypeNode {
1100+
export interface TypeReferenceNode extends NodeWithTypeArguments {
10971101
kind: SyntaxKind.TypeReference;
10981102
typeName: EntityName;
1099-
typeArguments?: NodeArray<TypeNode>;
11001103
}
11011104

11021105
export interface TypePredicateNode extends TypeNode {
@@ -1706,11 +1709,10 @@ namespace ts {
17061709
expression: ImportExpression;
17071710
}
17081711

1709-
export interface ExpressionWithTypeArguments extends TypeNode {
1712+
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
17101713
kind: SyntaxKind.ExpressionWithTypeArguments;
17111714
parent?: HeritageClause;
17121715
expression: LeftHandSideExpression;
1713-
typeArguments?: NodeArray<TypeNode>;
17141716
}
17151717

17161718
export interface NewExpression extends PrimaryExpression, Declaration {

src/compiler/visitor.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,10 @@ namespace ts {
401401
case SyntaxKind.ImportTypeNode:
402402
return updateImportTypeNode(<ImportTypeNode>node,
403403
visitNode((<ImportTypeNode>node).argument, visitor, isTypeNode),
404-
visitNode((<ImportTypeNode>node).qualifier, visitor, isEntityName));
404+
visitNode((<ImportTypeNode>node).qualifier, visitor, isEntityName),
405+
visitNodes((<ImportTypeNode>node).typeArguments, visitor, isTypeNode),
406+
(<ImportTypeNode>node).isTypeOf
407+
);
405408

406409
case SyntaxKind.ParenthesizedType:
407410
return updateParenthesizedType(<ParenthesizedTypeNode>node,

tests/baselines/reference/api/tsserverlibrary.d.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ declare namespace ts {
698698
interface KeywordTypeNode extends TypeNode {
699699
kind: SyntaxKind.AnyKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword;
700700
}
701-
interface ImportTypeNode extends TypeNode {
701+
interface ImportTypeNode extends NodeWithTypeArguments {
702702
kind: SyntaxKind.ImportTypeNode;
703703
isTypeOf?: boolean;
704704
argument: TypeNode;
@@ -714,11 +714,13 @@ declare namespace ts {
714714
interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
715715
kind: SyntaxKind.ConstructorType;
716716
}
717+
interface NodeWithTypeArguments extends TypeNode {
718+
typeArguments?: NodeArray<TypeNode>;
719+
}
717720
type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
718-
interface TypeReferenceNode extends TypeNode {
721+
interface TypeReferenceNode extends NodeWithTypeArguments {
719722
kind: SyntaxKind.TypeReference;
720723
typeName: EntityName;
721-
typeArguments?: NodeArray<TypeNode>;
722724
}
723725
interface TypePredicateNode extends TypeNode {
724726
kind: SyntaxKind.TypePredicate;
@@ -1034,11 +1036,10 @@ declare namespace ts {
10341036
interface ImportCall extends CallExpression {
10351037
expression: ImportExpression;
10361038
}
1037-
interface ExpressionWithTypeArguments extends TypeNode {
1039+
interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
10381040
kind: SyntaxKind.ExpressionWithTypeArguments;
10391041
parent?: HeritageClause;
10401042
expression: LeftHandSideExpression;
1041-
typeArguments?: NodeArray<TypeNode>;
10421043
}
10431044
interface NewExpression extends PrimaryExpression, Declaration {
10441045
kind: SyntaxKind.NewExpression;
@@ -3518,8 +3519,8 @@ declare namespace ts {
35183519
function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode;
35193520
function createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode;
35203521
function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode;
3521-
function createImportTypeNode(argument: TypeNode, qualifier?: EntityName): ImportTypeNode;
3522-
function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName): ImportTypeNode;
3522+
function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean): ImportTypeNode;
3523+
function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean): ImportTypeNode;
35233524
function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode;
35243525
function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode;
35253526
function createThisTypeNode(): ThisTypeNode;

tests/baselines/reference/api/typescript.d.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ declare namespace ts {
698698
interface KeywordTypeNode extends TypeNode {
699699
kind: SyntaxKind.AnyKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.VoidKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.NullKeyword | SyntaxKind.NeverKeyword;
700700
}
701-
interface ImportTypeNode extends TypeNode {
701+
interface ImportTypeNode extends NodeWithTypeArguments {
702702
kind: SyntaxKind.ImportTypeNode;
703703
isTypeOf?: boolean;
704704
argument: TypeNode;
@@ -714,11 +714,13 @@ declare namespace ts {
714714
interface ConstructorTypeNode extends TypeNode, SignatureDeclarationBase {
715715
kind: SyntaxKind.ConstructorType;
716716
}
717+
interface NodeWithTypeArguments extends TypeNode {
718+
typeArguments?: NodeArray<TypeNode>;
719+
}
717720
type TypeReferenceType = TypeReferenceNode | ExpressionWithTypeArguments;
718-
interface TypeReferenceNode extends TypeNode {
721+
interface TypeReferenceNode extends NodeWithTypeArguments {
719722
kind: SyntaxKind.TypeReference;
720723
typeName: EntityName;
721-
typeArguments?: NodeArray<TypeNode>;
722724
}
723725
interface TypePredicateNode extends TypeNode {
724726
kind: SyntaxKind.TypePredicate;
@@ -1034,11 +1036,10 @@ declare namespace ts {
10341036
interface ImportCall extends CallExpression {
10351037
expression: ImportExpression;
10361038
}
1037-
interface ExpressionWithTypeArguments extends TypeNode {
1039+
interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
10381040
kind: SyntaxKind.ExpressionWithTypeArguments;
10391041
parent?: HeritageClause;
10401042
expression: LeftHandSideExpression;
1041-
typeArguments?: NodeArray<TypeNode>;
10421043
}
10431044
interface NewExpression extends PrimaryExpression, Declaration {
10441045
kind: SyntaxKind.NewExpression;
@@ -3465,8 +3466,8 @@ declare namespace ts {
34653466
function updateConditionalTypeNode(node: ConditionalTypeNode, checkType: TypeNode, extendsType: TypeNode, trueType: TypeNode, falseType: TypeNode): ConditionalTypeNode;
34663467
function createInferTypeNode(typeParameter: TypeParameterDeclaration): InferTypeNode;
34673468
function updateInferTypeNode(node: InferTypeNode, typeParameter: TypeParameterDeclaration): InferTypeNode;
3468-
function createImportTypeNode(argument: TypeNode, qualifier?: EntityName): ImportTypeNode;
3469-
function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName): ImportTypeNode;
3469+
function createImportTypeNode(argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean): ImportTypeNode;
3470+
function updateImportTypeNode(node: ImportTypeNode, argument: TypeNode, qualifier?: EntityName, typeArguments?: ReadonlyArray<TypeNode>, isTypeOf?: boolean): ImportTypeNode;
34703471
function createParenthesizedType(type: TypeNode): ParenthesizedTypeNode;
34713472
function updateParenthesizedType(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode;
34723473
function createThisTypeNode(): ThisTypeNode;

0 commit comments

Comments
 (0)