Mark type arguments as used even if used in an invalid way

This commit is contained in:
Andy Hanson
2017-05-03 08:05:40 -07:00
parent 78df75426f
commit ac7429535e
20 changed files with 534 additions and 29 deletions

View File

@@ -4714,7 +4714,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);
baseType = getTypeFromClassOrInterfaceReference(baseTypeNode, baseConstructorType.symbol, typeArgumentsFromTypeReferenceNode(baseTypeNode));
}
else if (baseConstructorType.flags & TypeFlags.Any) {
baseType = baseConstructorType;
@@ -5238,7 +5238,7 @@ namespace ts {
}
const baseTypeNode = getBaseTypeNodeOfClass(classType);
const isJavaScript = isInJavaScriptFile(baseTypeNode);
const typeArguments = map(baseTypeNode.typeArguments, getTypeFromTypeNode);
const typeArguments = typeArgumentsFromTypeReferenceNode(baseTypeNode);
const typeArgCount = length(typeArguments);
const result: Signature[] = [];
for (const baseSig of baseSignatures) {
@@ -6501,7 +6501,7 @@ namespace ts {
}
// Get type from reference to class or interface
function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
function getTypeFromClassOrInterfaceReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol, typeArgs: Type[]): Type {
const type = <InterfaceType>getDeclaredTypeOfSymbol(getMergedSymbol(symbol));
const typeParameters = type.localTypeParameters;
if (typeParameters) {
@@ -6520,7 +6520,7 @@ namespace ts {
// 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(map(node.typeArguments, getTypeFromTypeNode), typeParameters, minTypeArgumentCount, node));
const typeArguments = concatenate(type.outerTypeParameters, fillMissingTypeArguments(typeArgs, typeParameters, minTypeArgumentCount, node));
return createTypeReference(<GenericType>type, typeArguments);
}
if (node.typeArguments) {
@@ -6545,7 +6545,7 @@ namespace ts {
// Get type from reference to type alias. When a type alias is generic, the declared type of the type alias may include
// 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: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol): Type {
function getTypeFromTypeAliasReference(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol, typeArguments: Type[]): Type {
const type = getDeclaredTypeOfSymbol(symbol);
const typeParameters = getSymbolLinks(symbol).typeParameters;
if (typeParameters) {
@@ -6561,7 +6561,6 @@ namespace ts {
typeParameters.length);
return unknownType;
}
const typeArguments = map(node.typeArguments, getTypeFromTypeNode);
return getTypeAliasInstantiation(symbol, typeArguments);
}
if (node.typeArguments) {
@@ -6609,16 +6608,18 @@ namespace ts {
}
function getTypeReferenceType(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference, symbol: Symbol) {
const typeArguments = typeArgumentsFromTypeReferenceNode(node); // Do unconditionally so we mark type arguments as referenced.
if (symbol === unknownSymbol) {
return unknownType;
}
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
return getTypeFromClassOrInterfaceReference(node, symbol);
return getTypeFromClassOrInterfaceReference(node, symbol, typeArguments);
}
if (symbol.flags & SymbolFlags.TypeAlias) {
return getTypeFromTypeAliasReference(node, symbol);
return getTypeFromTypeAliasReference(node, symbol, typeArguments);
}
if (symbol.flags & SymbolFlags.Value && node.kind === SyntaxKind.JSDocTypeReference) {
@@ -6686,9 +6687,10 @@ namespace ts {
? <EntityNameExpression>(<ExpressionWithTypeArguments>node).expression
: undefined;
symbol = typeNameOrExpression && resolveEntityName(typeNameOrExpression, SymbolFlags.Type) || unknownSymbol;
const typeArguments = typeArgumentsFromTypeReferenceNode(node);
type = symbol === unknownSymbol ? unknownType :
symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol) :
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol) :
symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface) ? getTypeFromClassOrInterfaceReference(node, symbol, typeArguments) :
symbol.flags & SymbolFlags.TypeAlias ? getTypeFromTypeAliasReference(node, symbol, typeArguments) :
getTypeFromNonGenericTypeReference(node, symbol);
}
// Cache both the resolved symbol and the resolved type. The resolved symbol is needed in when we check the
@@ -6699,6 +6701,10 @@ namespace ts {
return links.resolvedType;
}
function typeArgumentsFromTypeReferenceNode(node: TypeReferenceNode | ExpressionWithTypeArguments | JSDocTypeReference): Type[] {
return map(node.typeArguments, getTypeFromTypeNode);
}
function getTypeFromTypeQueryNode(node: TypeQueryNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
@@ -14303,7 +14309,17 @@ namespace ts {
return true;
}
function callLikeExpressionMayHaveTypeArguments(node: CallLikeExpression): node is CallExpression | NewExpression {
return node.kind === SyntaxKind.CallExpression || node.kind === SyntaxKind.NewExpression;
}
function resolveUntypedCall(node: CallLikeExpression): Signature {
if (callLikeExpressionMayHaveTypeArguments(node)) {
// Check type arguments even though we will give an error that untyped calls may not accept type arguments.
// This gets us diagnostics for the type arguments and marks them as referenced.
forEach(node.typeArguments, checkSourceElement);
}
if (node.kind === SyntaxKind.TaggedTemplateExpression) {
checkExpression((<TaggedTemplateExpression>node).template);
}