Skip to content

Commit 2f0ac25

Browse files
committed
Defer resolution of type arguments in aliased type references
1 parent 6270ccc commit 2f0ac25

File tree

2 files changed

+26
-26
lines changed

2 files changed

+26
-26
lines changed

src/compiler/checker.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6382,15 +6382,14 @@ namespace ts {
63826382
return type.resolvedBaseTypes = emptyArray;
63836383
}
63846384
const baseTypeNode = getBaseTypeNodeOfClass(type)!;
6385-
const typeArgs = typeArgumentsFromTypeReferenceNode(baseTypeNode);
63866385
let baseType: Type;
63876386
const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined;
63886387
if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class &&
63896388
areAllOuterTypeParametersApplied(originalBaseType!)) {
63906389
// When base constructor type is a class with no captured type arguments we know that the constructors all have the same type parameters as the
63916390
// class and all return the instance type of the class. There is no need for further checks and we can apply the
63926391
// type arguments in the same manner as a type reference to get the same error reporting experience.
6393-
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol, typeArgs);
6392+
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol);
63946393
}
63956394
else if (baseConstructorType.flags & TypeFlags.Any) {
63966395
baseType = baseConstructorType;
@@ -9115,7 +9114,7 @@ namespace ts {
91159114
return type;
91169115
}
91179116

9118-
function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference {
9117+
function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference {
91199118
const aliasSymbol = getAliasSymbolForTypeNode(node);
91209119
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
91219120
const type = <DeferredTypeReference>createObjectType(ObjectFlags.Reference, target.symbol);
@@ -9129,7 +9128,11 @@ namespace ts {
91299128

91309129
function getTypeArguments(type: TypeReference): ReadonlyArray<Type> {
91319130
if (!type.resolvedTypeArguments) {
9132-
const typeArguments = type.node ? map(type.node.kind === SyntaxKind.ArrayType ? [type.node.elementType] : type.node.elementTypes, getTypeFromTypeNode) : emptyArray;
9131+
const node = type.node;
9132+
const typeArguments = !node ? emptyArray :
9133+
node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) :
9134+
node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] :
9135+
map(node.elementTypes, getTypeFromTypeNode);
91339136
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
91349137
}
91359138
return type.resolvedTypeArguments;
@@ -9139,10 +9142,11 @@ namespace ts {
91399142
return length(type.target.typeParameters);
91409143
}
91419144

9145+
91429146
/**
91439147
* Get type from type-reference that reference to class or interface
91449148
*/
9145-
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol, typeArgs: Type[] | undefined): Type {
9149+
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type {
91469150
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
91479151
const typeParameters = type.localTypeParameters;
91489152
if (typeParameters) {
@@ -9166,10 +9170,13 @@ namespace ts {
91669170
return errorType;
91679171
}
91689172
}
9173+
if (node.kind === SyntaxKind.TypeReference && isAliasedType(node)) {
9174+
return createDeferredTypeReference(<GenericType>type, <TypeReferenceNode>node, /*mapper*/ undefined);
9175+
}
91699176
// In a type reference, the outer type parameters of the referenced class or interface are automatically
91709177
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
91719178
// of the class or interface.
9172-
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
9179+
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs));
91739180
return createTypeReference(<GenericType>type, typeArguments);
91749181
}
91759182
return checkNoTypeArguments(node, symbol) ? type : errorType;
@@ -9192,7 +9199,7 @@ namespace ts {
91929199
* references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the
91939200
* declared type. Instantiations are cached using the type identities of the type arguments as the key.
91949201
*/
9195-
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type {
9202+
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol): Type {
91969203
const type = getDeclaredTypeOfSymbol(symbol);
91979204
const typeParameters = getSymbolLinks(symbol).typeParameters;
91989205
if (typeParameters) {
@@ -9208,7 +9215,7 @@ namespace ts {
92089215
typeParameters.length);
92099216
return errorType;
92109217
}
9211-
return getTypeAliasInstantiation(symbol, typeArguments);
9218+
return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node));
92129219
}
92139220
return checkNoTypeArguments(node, symbol) ? type : errorType;
92149221
}
@@ -9239,27 +9246,23 @@ namespace ts {
92399246
}
92409247

92419248
function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type {
9242-
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
92439249
if (symbol === unknownSymbol) {
92449250
return errorType;
92459251
}
92469252
symbol = getExpandoSymbol(symbol) || symbol;
9247-
92489253
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
9249-
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
9254+
return getTypeFromClassOrInterfaceReference(node, symbol);
92509255
}
92519256
if (symbol.flags & SymbolFlags.TypeAlias) {
9252-
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
9257+
return getTypeFromTypeAliasReference(node, symbol);
92539258
}
9254-
92559259
// Get type from reference to named type that cannot be generic (enum or type parameter)
92569260
const res = tryGetDeclaredTypeOfSymbol(symbol);
92579261
if (res) {
92589262
return checkNoTypeArguments(node, symbol) ?
92599263
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeVariable(<TypeParameter>res, node) : getRegularTypeOfLiteralType(res) :
92609264
errorType;
92619265
}
9262-
92639266
if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) {
92649267
const jsdocType = getTypeFromJSAlias(node, symbol);
92659268
if (jsdocType) {
@@ -9271,7 +9274,6 @@ namespace ts {
92719274
return getTypeOfSymbol(symbol);
92729275
}
92739276
}
9274-
92759277
return errorType;
92769278
}
92779279

@@ -26100,16 +26102,13 @@ namespace ts {
2610026102
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) {
2610126103
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
2610226104
}
26105+
forEach(node.typeArguments, checkSourceElement);
2610326106
const type = getTypeFromTypeReference(node);
2610426107
if (type !== errorType) {
26105-
if (node.typeArguments) {
26106-
// Do type argument local checks only if referenced type is successfully resolved
26107-
forEach(node.typeArguments, checkSourceElement);
26108-
if (produceDiagnostics) {
26109-
const typeParameters = getTypeParametersForTypeReference(node);
26110-
if (typeParameters) {
26111-
checkTypeArgumentConstraints(node, typeParameters);
26112-
}
26108+
if (node.typeArguments && produceDiagnostics) {
26109+
const typeParameters = getTypeParametersForTypeReference(node);
26110+
if (typeParameters) {
26111+
checkTypeArgumentConstraints(node, typeParameters);
2611326112
}
2611426113
}
2611526114
if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol!.flags & SymbolFlags.EnumMember) {
@@ -29333,6 +29332,7 @@ namespace ts {
2933329332

2933429333
const baseTypeNode = getEffectiveBaseTypeNode(node);
2933529334
if (baseTypeNode) {
29335+
forEach(baseTypeNode.typeArguments, checkSourceElement);
2933629336
if (languageVersion < ScriptTarget.ES2015) {
2933729337
checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends);
2933829338
}

src/compiler/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4202,18 +4202,18 @@ namespace ts {
42024202
*/
42034203
export interface TypeReference extends ObjectType {
42044204
target: GenericType; // Type reference target
4205-
node?: ArrayTypeNode | TupleTypeNode;
4205+
node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
42064206
/* @internal */
42074207
mapper?: TypeMapper;
42084208
/* @internal */
4209-
resolvedTypeArguments?: ReadonlyArray<Type>; // Resolved ype reference type arguments
4209+
resolvedTypeArguments?: ReadonlyArray<Type>; // Resolved type reference type arguments
42104210
/* @internal */
42114211
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
42124212
}
42134213

42144214
export interface DeferredTypeReference extends TypeReference {
42154215
/* @internal */
4216-
node: ArrayTypeNode | TupleTypeNode;
4216+
node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
42174217
/* @internal */
42184218
mapper?: TypeMapper;
42194219
}

0 commit comments

Comments
 (0)