Check that base constructor return types are identical
Treat class extends clause as expression position in services.ts
This commit is contained in:
parent
956d73ef5e
commit
cc81cc77f9
|
@ -2642,7 +2642,7 @@ module ts {
|
|||
return type.baseConstructorType = unknownType;
|
||||
}
|
||||
if (baseConstructorType !== unknownType && baseConstructorType !== nullType && !isConstructorType(baseConstructorType)) {
|
||||
error(baseTypeNode, Diagnostics.Base_expression_is_not_of_a_constructor_function_type);
|
||||
error(baseTypeNode.expression, Diagnostics.Base_expression_is_not_of_a_constructor_function_type);
|
||||
return type.baseConstructorType = unknownType;
|
||||
}
|
||||
type.baseConstructorType = baseConstructorType;
|
||||
|
@ -2680,7 +2680,7 @@ module ts {
|
|||
else {
|
||||
let constructors = getInstantiatedConstructorsForTypeArguments(baseContructorType, baseTypeNode.typeArguments);
|
||||
if (!constructors.length) {
|
||||
error(baseTypeNode, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
|
||||
error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
|
||||
return;
|
||||
}
|
||||
baseType = getReturnTypeOfSignature(constructors[0]);
|
||||
|
@ -2689,7 +2689,7 @@ module ts {
|
|||
return;
|
||||
}
|
||||
if (!(getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface))) {
|
||||
error(baseTypeNode, Diagnostics.Base_constructor_does_not_return_a_class_or_interface_type);
|
||||
error(baseTypeNode.expression, Diagnostics.Base_constructor_does_not_return_a_class_or_interface_type);
|
||||
return;
|
||||
}
|
||||
if (type === baseType || hasBaseType(<InterfaceType>baseType, type)) {
|
||||
|
@ -10638,7 +10638,6 @@ module ts {
|
|||
let baseTypeNode = getClassExtendsHeritageClauseElement(node);
|
||||
if (baseTypeNode) {
|
||||
emitExtends = emitExtends || !isInAmbientContext(node);
|
||||
// !!! checkExpressionWithTypeArguments(baseTypeNode);
|
||||
let baseTypes = getBaseTypes(type);
|
||||
if (baseTypes.length && produceDiagnostics) {
|
||||
let baseType = baseTypes[0];
|
||||
|
@ -10650,6 +10649,12 @@ module ts {
|
|||
checkTypeAssignableTo(type, baseType, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
|
||||
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
|
||||
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
|
||||
if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
|
||||
let constructors = getInstantiatedConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments);
|
||||
if (forEach(constructors, sig => getReturnTypeOfSignature(sig) !== baseType)) {
|
||||
error(baseTypeNode.expression, Diagnostics.Base_constructors_must_all_have_the_same_return_type);
|
||||
}
|
||||
}
|
||||
checkKindsOfPropertyMemberOverrides(type, baseType);
|
||||
}
|
||||
}
|
||||
|
@ -11997,6 +12002,10 @@ module ts {
|
|||
return unknownType;
|
||||
}
|
||||
|
||||
if (isClassExtendsExpressionWithTypeArguments(node)) {
|
||||
return getBaseTypes(<InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node.parent.parent)))[0];
|
||||
}
|
||||
|
||||
if (isTypeNode(node)) {
|
||||
return getTypeFromTypeNode(<TypeNode>node);
|
||||
}
|
||||
|
|
|
@ -383,6 +383,7 @@ module ts {
|
|||
Base_expression_is_not_of_a_constructor_function_type: { code: 2507, category: DiagnosticCategory.Error, key: "Base expression is not of a constructor function type." },
|
||||
No_base_constructor_has_the_specified_number_of_type_arguments: { code: 2508, category: DiagnosticCategory.Error, key: "No base constructor has the specified number of type arguments." },
|
||||
Base_constructor_does_not_return_a_class_or_interface_type: { code: 2509, category: DiagnosticCategory.Error, key: "Base constructor does not return a class or interface type." },
|
||||
Base_constructors_must_all_have_the_same_return_type: { code: 2510, category: DiagnosticCategory.Error, key: "Base constructors must all have the same return type." },
|
||||
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },
|
||||
Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1: { code: 4004, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported interface has or is using private name '{1}'." },
|
||||
|
|
|
@ -1521,6 +1521,10 @@
|
|||
"category": "Error",
|
||||
"code": 2509
|
||||
},
|
||||
"Base constructors must all have the same return type.": {
|
||||
"category": "Error",
|
||||
"code": 2510
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
|
|
|
@ -426,7 +426,7 @@ module ts {
|
|||
// Specialized signatures can have string literals as their parameters' type names
|
||||
return node.parent.kind === SyntaxKind.Parameter;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return true;
|
||||
return !isClassExtendsExpressionWithTypeArguments(node);
|
||||
|
||||
// Identifiers and qualified names may be type nodes, depending on their context. Climb
|
||||
// above them to find the lowest container
|
||||
|
@ -460,7 +460,7 @@ module ts {
|
|||
}
|
||||
switch (parent.kind) {
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return true;
|
||||
return !isClassExtendsExpressionWithTypeArguments(parent);
|
||||
case SyntaxKind.TypeParameter:
|
||||
return node === (<TypeParameterDeclaration>parent).constraint;
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
|
@ -872,7 +872,6 @@ module ts {
|
|||
while (node.parent.kind === SyntaxKind.QualifiedName) {
|
||||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeQuery;
|
||||
case SyntaxKind.Identifier:
|
||||
if (node.parent.kind === SyntaxKind.TypeQuery) {
|
||||
|
@ -920,6 +919,8 @@ module ts {
|
|||
return node === (<ComputedPropertyName>parent).expression;
|
||||
case SyntaxKind.Decorator:
|
||||
return true;
|
||||
case SyntaxKind.ExpressionWithTypeArguments:
|
||||
return isClassExtendsExpressionWithTypeArguments(parent);
|
||||
default:
|
||||
if (isExpression(parent)) {
|
||||
return true;
|
||||
|
@ -1878,6 +1879,12 @@ module ts {
|
|||
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
|
||||
}
|
||||
|
||||
export function isClassExtendsExpressionWithTypeArguments(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.ExpressionWithTypeArguments &&
|
||||
(<HeritageClause>node.parent).token === SyntaxKind.ExtendsKeyword &&
|
||||
node.parent.parent.kind === SyntaxKind.ClassDeclaration;
|
||||
}
|
||||
|
||||
// Returns false if this heritage clause element's expression contains something unsupported
|
||||
// (i.e. not a name or dotted name).
|
||||
export function isSupportedExpressionWithTypeArguments(node: ExpressionWithTypeArguments): boolean {
|
||||
|
|
|
@ -5811,7 +5811,8 @@ module ts {
|
|||
node = node.parent;
|
||||
}
|
||||
|
||||
return node.parent.kind === SyntaxKind.TypeReference || node.parent.kind === SyntaxKind.ExpressionWithTypeArguments;
|
||||
return node.parent.kind === SyntaxKind.TypeReference ||
|
||||
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isClassExtendsExpressionWithTypeArguments(<ExpressionWithTypeArguments>node.parent));
|
||||
}
|
||||
|
||||
function isNamespaceReference(node: Node): boolean {
|
||||
|
|
Loading…
Reference in a new issue