Defer resolution of type arguments in aliased type references

This commit is contained in:
Anders Hejlsberg 2019-08-30 07:57:55 -07:00
parent 6270ccc4b0
commit 2f0ac25a00
2 changed files with 26 additions and 26 deletions

View file

@ -6382,7 +6382,6 @@ namespace ts {
return type.resolvedBaseTypes = emptyArray;
}
const baseTypeNode = getBaseTypeNodeOfClass(type)!;
const typeArgs = typeArgumentsFromTypeReferenceNode(baseTypeNode);
let baseType: Type;
const originalBaseType = baseConstructorType.symbol ? getDeclaredTypeOfSymbol(baseConstructorType.symbol) : undefined;
if (baseConstructorType.symbol && baseConstructorType.symbol.flags & SymbolFlags.Class &&
@ -6390,7 +6389,7 @@ namespace ts {
// 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
// class and all return the instance type of the class. There is no need for further checks and we can apply the
// type arguments in the same manner as a type reference to get the same error reporting experience.
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol, typeArgs);
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol);
}
else if (baseConstructorType.flags & TypeFlags.Any) {
baseType = baseConstructorType;
@ -9115,7 +9114,7 @@ namespace ts {
return type;
}
function createDeferredTypeReference(target: GenericType, node: ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference {
function createDeferredTypeReference(target: GenericType, node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode, mapper?: TypeMapper): DeferredTypeReference {
const aliasSymbol = getAliasSymbolForTypeNode(node);
const aliasTypeArguments = getTypeArgumentsForAliasSymbol(aliasSymbol);
const type = <DeferredTypeReference>createObjectType(ObjectFlags.Reference, target.symbol);
@ -9129,7 +9128,11 @@ namespace ts {
function getTypeArguments(type: TypeReference): ReadonlyArray<Type> {
if (!type.resolvedTypeArguments) {
const typeArguments = type.node ? map(type.node.kind === SyntaxKind.ArrayType ? [type.node.elementType] : type.node.elementTypes, getTypeFromTypeNode) : emptyArray;
const node = type.node;
const typeArguments = !node ? emptyArray :
node.kind === SyntaxKind.TypeReference ? concatenate(type.target.outerTypeParameters, getEffectiveTypeArguments(node, type.target.localTypeParameters!)) :
node.kind === SyntaxKind.ArrayType ? [getTypeFromTypeNode(node.elementType)] :
map(node.elementTypes, getTypeFromTypeNode);
type.resolvedTypeArguments = type.mapper ? instantiateTypes(typeArguments, type.mapper) : typeArguments;
}
return type.resolvedTypeArguments;
@ -9139,10 +9142,11 @@ namespace ts {
return length(type.target.typeParameters);
}
/**
* Get type from type-reference that reference to class or interface
*/
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol, typeArgs: Type[] | undefined): Type {
function getTypeFromClassOrInterfaceReference(node: NodeWithTypeArguments, symbol: Symbol): Type {
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
const typeParameters = type.localTypeParameters;
if (typeParameters) {
@ -9166,10 +9170,13 @@ namespace ts {
return errorType;
}
}
if (node.kind === SyntaxKind.TypeReference && isAliasedType(node)) {
return createDeferredTypeReference(<GenericType>type, <TypeReferenceNode>node, /*mapper*/ undefined);
}
// In a type reference, the outer type parameters of the referenced class or interface are automatically
// supplied as type arguments and the type reference only specifies arguments for the local type parameters
// of the class or interface.
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, isJs));
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgumentsFromTypeReferenceNode(node), typeParameters, minTypeArgumentCount, isJs));
return createTypeReference(<GenericType>type, typeArguments);
}
return checkNoTypeArguments(node, symbol) ? type : errorType;
@ -9192,7 +9199,7 @@ namespace ts {
* references to the type parameters of the alias. We replace those with the actual type arguments by instantiating the
* declared type. Instantiations are cached using the type identities of the type arguments as the key.
*/
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type {
function getTypeFromTypeAliasReference(node: NodeWithTypeArguments, symbol: Symbol): Type {
const type = getDeclaredTypeOfSymbol(symbol);
const typeParameters = getSymbolLinks(symbol).typeParameters;
if (typeParameters) {
@ -9208,7 +9215,7 @@ namespace ts {
typeParameters.length);
return errorType;
}
return getTypeAliasInstantiation(symbol, typeArguments);
return getTypeAliasInstantiation(symbol, typeArgumentsFromTypeReferenceNode(node));
}
return checkNoTypeArguments(node, symbol) ? type : errorType;
}
@ -9239,19 +9246,16 @@ namespace ts {
}
function getTypeReferenceType(node: NodeWithTypeArguments, symbol: Symbol): Type {
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
if (symbol === unknownSymbol) {
return errorType;
}
symbol = getExpandoSymbol(symbol) || symbol;
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
return getTypeFromClassOrInterfaceReference(node, symbol);
}
if (symbol.flags & SymbolFlags.TypeAlias) {
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
return getTypeFromTypeAliasReference(node, symbol);
}
// Get type from reference to named type that cannot be generic (enum or type parameter)
const res = tryGetDeclaredTypeOfSymbol(symbol);
if (res) {
@ -9259,7 +9263,6 @@ namespace ts {
res.flags & TypeFlags.TypeParameter ? getConstrainedTypeVariable(<TypeParameter>res, node) : getRegularTypeOfLiteralType(res) :
errorType;
}
if (symbol.flags & SymbolFlags.Value && isJSDocTypeReference(node)) {
const jsdocType = getTypeFromJSAlias(node, symbol);
if (jsdocType) {
@ -9271,7 +9274,6 @@ namespace ts {
return getTypeOfSymbol(symbol);
}
}
return errorType;
}
@ -26100,16 +26102,13 @@ namespace ts {
if (node.kind === SyntaxKind.TypeReference && node.typeName.jsdocDotPos !== undefined && !isInJSFile(node) && !isInJSDoc(node)) {
grammarErrorAtPos(node, node.typeName.jsdocDotPos, 1, Diagnostics.JSDoc_types_can_only_be_used_inside_documentation_comments);
}
forEach(node.typeArguments, checkSourceElement);
const type = getTypeFromTypeReference(node);
if (type !== errorType) {
if (node.typeArguments) {
// Do type argument local checks only if referenced type is successfully resolved
forEach(node.typeArguments, checkSourceElement);
if (produceDiagnostics) {
const typeParameters = getTypeParametersForTypeReference(node);
if (typeParameters) {
checkTypeArgumentConstraints(node, typeParameters);
}
if (node.typeArguments && produceDiagnostics) {
const typeParameters = getTypeParametersForTypeReference(node);
if (typeParameters) {
checkTypeArgumentConstraints(node, typeParameters);
}
}
if (type.flags & TypeFlags.Enum && getNodeLinks(node).resolvedSymbol!.flags & SymbolFlags.EnumMember) {
@ -29333,6 +29332,7 @@ namespace ts {
const baseTypeNode = getEffectiveBaseTypeNode(node);
if (baseTypeNode) {
forEach(baseTypeNode.typeArguments, checkSourceElement);
if (languageVersion < ScriptTarget.ES2015) {
checkExternalEmitHelpers(baseTypeNode.parent, ExternalEmitHelpers.Extends);
}

View file

@ -4202,18 +4202,18 @@ namespace ts {
*/
export interface TypeReference extends ObjectType {
target: GenericType; // Type reference target
node?: ArrayTypeNode | TupleTypeNode;
node?: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
/* @internal */
mapper?: TypeMapper;
/* @internal */
resolvedTypeArguments?: ReadonlyArray<Type>; // Resolved ype reference type arguments
resolvedTypeArguments?: ReadonlyArray<Type>; // Resolved type reference type arguments
/* @internal */
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
}
export interface DeferredTypeReference extends TypeReference {
/* @internal */
node: ArrayTypeNode | TupleTypeNode;
node: TypeReferenceNode | ArrayTypeNode | TupleTypeNode;
/* @internal */
mapper?: TypeMapper;
}