Addressing CR feedback

This commit is contained in:
Anders Hejlsberg 2015-06-17 13:28:39 -07:00
parent f6bcf7074c
commit d71af8a3fb
6 changed files with 35 additions and 26 deletions

View file

@ -2639,7 +2639,8 @@ namespace ts {
}
let baseConstructorType = checkExpression(baseTypeNode.expression);
if (baseConstructorType.flags & TypeFlags.ObjectType) {
// Force resolution of members such that we catch circularities
// Resolving the members of a class requires us to resolve the base class of that class.
// We force resolution here such that we catch circularities now.
resolveObjectOrUnionTypeMembers(baseConstructorType);
}
if (!popTypeResolution()) {
@ -2647,7 +2648,7 @@ namespace ts {
return type.resolvedBaseConstructorType = unknownType;
}
if (baseConstructorType !== unknownType && baseConstructorType !== nullType && !isConstructorType(baseConstructorType)) {
error(baseTypeNode.expression, Diagnostics.Base_expression_is_not_of_a_constructor_function_type);
error(baseTypeNode.expression, Diagnostics.Type_0_is_not_a_constructor_function_type, typeToString(baseConstructorType));
return type.resolvedBaseConstructorType = unknownType;
}
type.resolvedBaseConstructorType = baseConstructorType;
@ -2699,7 +2700,7 @@ namespace ts {
return;
}
if (!(getTargetType(baseType).flags & (TypeFlags.Class | TypeFlags.Interface))) {
error(baseTypeNode.expression, Diagnostics.Base_constructor_does_not_return_a_class_or_interface_type);
error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType));
return;
}
if (type === baseType || hasBaseType(<InterfaceType>baseType, type)) {
@ -5962,7 +5963,9 @@ namespace ts {
let baseClassType = classType && getBaseTypes(classType)[0];
if (!baseClassType) {
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
if (!classDeclaration || !getClassExtendsHeritageClauseElement(classDeclaration)) {
error(node, Diagnostics.super_can_only_be_referenced_in_a_derived_class);
}
return unknownType;
}
@ -8970,13 +8973,14 @@ namespace ts {
checkDecorators(node);
}
function checkTypeArgumentsAndConstraints(typeParameters: TypeParameter[], typeArguments: TypeNode[]) {
for (let i = 0; i < typeArguments.length; i++) {
let typeArgument = typeArguments[i];
checkSourceElement(typeArgument);
let constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (produceDiagnostics && constraint) {
checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
function checkTypeArgumentConstraints(typeParameters: TypeParameter[], typeArguments: TypeNode[]) {
if (produceDiagnostics) {
for (let i = 0; i < typeParameters.length; i++) {
let constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (constraint) {
let typeArgument = typeArguments[i];
checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
}
}
}
@ -8986,9 +8990,10 @@ namespace ts {
let type = getTypeFromTypeReference(node);
if (type !== unknownType && node.typeArguments) {
// Do type argument local checks only if referenced type is successfully resolved
forEach(node.typeArguments, checkSourceElement);
let symbol = getNodeLinks(node).resolvedSymbol;
let typeParameters = symbol.flags & SymbolFlags.TypeAlias ? getSymbolLinks(symbol).typeParameters : (<TypeReference>type).target.localTypeParameters;
checkTypeArgumentsAndConstraints(typeParameters, node.typeArguments);
checkTypeArgumentConstraints(typeParameters, node.typeArguments);
}
}
@ -10588,15 +10593,19 @@ namespace ts {
let baseType = baseTypes[0];
let staticBaseType = getBaseConstructorTypeOfClass(type);
if (baseTypeNode.typeArguments) {
let constructors = getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments);
checkTypeArgumentsAndConstraints(constructors[0].typeParameters, baseTypeNode.typeArguments);
forEach(baseTypeNode.typeArguments, checkSourceElement);
for (let constructor of getConstructorsForTypeArguments(staticBaseType, baseTypeNode.typeArguments)) {
checkTypeArgumentConstraints(constructor.typeParameters, baseTypeNode.typeArguments);
}
}
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)) {
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
// that all instantiated base constructor signatures return the same type.
// that all instantiated base constructor signatures return the same type. We can simply compare the type
// references (as opposed to checking the structure of the types) because elsewhere we have already checked
// that the base type is a class or interface type (and not, for example, an anonymous object type).
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);
@ -11997,7 +12006,7 @@ namespace ts {
return getTypeOfExpression(<Expression>node);
}
if (isClassExtendsExpressionWithTypeArguments(node)) {
if (isExpressionWithTypeArgumentsInClassExtendsClause(node)) {
// A SyntaxKind.ExpressionWithTypeArguments is considered a type node, except when it occurs in the
// extends clause of a class. We handle that case here.
return getBaseTypes(<InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(node.parent.parent)))[0];

View file

@ -385,9 +385,9 @@ namespace ts {
No_best_common_type_exists_among_yield_expressions: { code: 2504, category: DiagnosticCategory.Error, key: "No best common type exists among yield expressions." },
A_generator_cannot_have_a_void_type_annotation: { code: 2505, category: DiagnosticCategory.Error, key: "A generator cannot have a 'void' type annotation." },
_0_is_referenced_directly_or_indirectly_in_its_own_base_expression: { code: 2506, category: DiagnosticCategory.Error, key: "'{0}' is referenced directly or indirectly in its own base expression." },
Base_expression_is_not_of_a_constructor_function_type: { code: 2507, category: DiagnosticCategory.Error, key: "Base expression is not of a constructor function type." },
Type_0_is_not_a_constructor_function_type: { code: 2507, category: DiagnosticCategory.Error, key: "Type '{0}' is not 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_constructor_return_type_0_is_not_a_class_or_interface_type: { code: 2509, category: DiagnosticCategory.Error, key: "Base constructor return type '{0}' is not 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}'." },

View file

@ -1529,7 +1529,7 @@
"category": "Error",
"code": 2506
},
"Base expression is not of a constructor function type.": {
"Type '{0}' is not a constructor function type.": {
"category": "Error",
"code": 2507
},
@ -1537,7 +1537,7 @@
"category": "Error",
"code": 2508
},
"Base constructor does not return a class or interface type.": {
"Base constructor return type '{0}' is not a class or interface type.": {
"category": "Error",
"code": 2509
},

View file

@ -426,7 +426,7 @@ namespace ts {
// Specialized signatures can have string literals as their parameters' type names
return node.parent.kind === SyntaxKind.Parameter;
case SyntaxKind.ExpressionWithTypeArguments:
return !isClassExtendsExpressionWithTypeArguments(node);
return !isExpressionWithTypeArgumentsInClassExtendsClause(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 @@ namespace ts {
}
switch (parent.kind) {
case SyntaxKind.ExpressionWithTypeArguments:
return !isClassExtendsExpressionWithTypeArguments(parent);
return !isExpressionWithTypeArgumentsInClassExtendsClause(parent);
case SyntaxKind.TypeParameter:
return node === (<TypeParameterDeclaration>parent).constraint;
case SyntaxKind.PropertyDeclaration:
@ -920,7 +920,7 @@ namespace ts {
case SyntaxKind.Decorator:
return true;
case SyntaxKind.ExpressionWithTypeArguments:
return isClassExtendsExpressionWithTypeArguments(parent);
return (<ExpressionWithTypeArguments>parent).expression === node && isExpressionWithTypeArgumentsInClassExtendsClause(parent);
default:
if (isExpression(parent)) {
return true;
@ -1914,7 +1914,7 @@ namespace ts {
return token >= SyntaxKind.FirstAssignment && token <= SyntaxKind.LastAssignment;
}
export function isClassExtendsExpressionWithTypeArguments(node: Node): boolean {
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
return node.kind === SyntaxKind.ExpressionWithTypeArguments &&
(<HeritageClause>node.parent).token === SyntaxKind.ExtendsKeyword &&
node.parent.parent.kind === SyntaxKind.ClassDeclaration;

View file

@ -43,7 +43,7 @@ class TypeWriterWalker {
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
// var type = this.checker.getTypeAtLocation(node);
var type = node.parent && ts.isClassExtendsExpressionWithTypeArguments(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
var type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
ts.Debug.assert(type !== undefined, "type doesn't exist");
var symbol = this.checker.getSymbolAtLocation(node);

View file

@ -5812,7 +5812,7 @@ namespace ts {
}
return node.parent.kind === SyntaxKind.TypeReference ||
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isClassExtendsExpressionWithTypeArguments(<ExpressionWithTypeArguments>node.parent));
(node.parent.kind === SyntaxKind.ExpressionWithTypeArguments && !isExpressionWithTypeArgumentsInClassExtendsClause(<ExpressionWithTypeArguments>node.parent));
}
function isNamespaceReference(node: Node): boolean {