added flag as argument to checkTypeRelatedTo

This commit is contained in:
Arthur Ozga 2015-06-29 14:02:01 -07:00
parent 52e8b6cbbc
commit a183ba9020
2 changed files with 56 additions and 31 deletions

View File

@ -4263,11 +4263,11 @@ namespace ts {
// TYPE CHECKING
function isTypeIdenticalTo(source: Type, target: Type): boolean {
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
return checkTypeRelatedTo(source, target, identityRelation, RelationComparisonFlags.None, /*errorNode*/ undefined);
}
function compareTypes(source: Type, target: Type): Ternary {
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
return checkTypeRelatedTo(source, target, identityRelation, RelationComparisonFlags.None, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
}
function isTypeSubtypeOf(source: Type, target: Type): boolean {
@ -4275,15 +4275,15 @@ namespace ts {
}
function isTypeAssignableTo(source: Type, target: Type): boolean {
return checkTypeAssignableTo(source, target, /*errorNode*/ undefined);
return checkTypeAssignableTo(source, target, RelationComparisonFlags.None, /*errorNode*/ undefined);
}
function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain);
return checkTypeRelatedTo(source, target, subtypeRelation, RelationComparisonFlags.None, errorNode, headMessage, containingMessageChain);
}
function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
function checkTypeAssignableTo(source: Type, target: Type, relationFlags: RelationComparisonFlags, errorNode?: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
return checkTypeRelatedTo(source, target, assignableRelation, relationFlags, errorNode, headMessage, containingMessageChain);
}
function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
@ -4292,13 +4292,30 @@ namespace ts {
return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
}
/**
* Checks if 'source' is related to 'target' (e.g.: is a assignable to).
* @param source The left-hand-side of the relation.
* @param target The right-hand-side of the relation.
* @param relation The relation considered. One of 'identityRelation', 'assignableRelation', or 'subTypeRelation'.
* Used as both to determine which checks are performed and as a cache of previously computed results.
* @param relationFlags Additional information affecting whether the relation holds. Currently used only for distinguishing
* between a type comparison when extending classes from other comparisons of the constructor types.
*
* Caution: checks triggered by these flags should NOT affect the result re
* @param errorNode The node upon which all errors will be reported, if defined.
* @param headMessage If the error chain should be prepended by a head message, then headMessage will be used.
* @param containingMessageChain A chain of errors to prepend any new errors found.
*/
function checkTypeRelatedTo(
source: Type,
target: Type,
relation: Map<RelationComparisonResult>,
errorNode: Node,
relationFlags: RelationComparisonFlags,
errorNode?: Node,
headMessage?: DiagnosticMessage,
containingMessageChain?: DiagnosticMessageChain): boolean {
containingMessageChain?: DiagnosticMessageChain
): boolean {
let errorInfo: DiagnosticMessageChain;
let sourceStack: ObjectType[];
@ -7212,6 +7229,7 @@ namespace ts {
typeArgumentsAreAssignable = checkTypeAssignableTo(
typeArgument,
constraint,
RelationComparisonFlags.None,
reportErrors ? typeArgNode : undefined,
typeArgumentHeadMessage,
errorInfo);
@ -7243,7 +7261,7 @@ namespace ts {
// Use argument expression as error location when reporting errors
let errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined;
let headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1;
if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage)) {
if (!checkTypeRelatedTo(argType, paramType, relation, RelationComparisonFlags.None, errorNode, headMessage)) {
return false;
}
}
@ -8040,7 +8058,7 @@ namespace ts {
if (produceDiagnostics && targetType !== unknownType) {
let widenedType = getWidenedType(exprType);
if (!(isTypeAssignableTo(targetType, widenedType))) {
checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
checkTypeAssignableTo(exprType, targetType, RelationComparisonFlags.None, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
}
}
return targetType;
@ -8274,7 +8292,7 @@ namespace ts {
else {
let exprType = checkExpression(<Expression>node.body);
if (node.type) {
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, /*headMessage*/ undefined);
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), RelationComparisonFlags.None, node.body, /*headMessage*/ undefined);
}
checkFunctionAndClassExpressionBodies(node.body);
}
@ -8582,7 +8600,7 @@ namespace ts {
function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
let targetType = checkExpression(target, contextualMapper);
if (checkReferenceExpression(target, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) {
checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined);
checkTypeAssignableTo(sourceType, targetType, RelationComparisonFlags.None, target, /*headMessage*/ undefined);
}
return sourceType;
}
@ -8757,7 +8775,7 @@ namespace ts {
// Use default messages
if (ok) {
// to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported
checkTypeAssignableTo(valueType, leftType, node.left, /*headMessage*/ undefined);
checkTypeAssignableTo(valueType, leftType, RelationComparisonFlags.None, node.left, /*headMessage*/ undefined);
}
}
}
@ -8808,10 +8826,10 @@ namespace ts {
if (func.type) {
let signatureElementType = getElementTypeOfIterableIterator(getTypeFromTypeNode(func.type)) || anyType;
if (nodeIsYieldStar) {
checkTypeAssignableTo(expressionElementType, signatureElementType, node.expression, /*headMessage*/ undefined);
checkTypeAssignableTo(expressionElementType, signatureElementType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
}
else {
checkTypeAssignableTo(expressionType, signatureElementType, node.expression, /*headMessage*/ undefined);
checkTypeAssignableTo(expressionType, signatureElementType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
}
}
}
@ -9119,7 +9137,7 @@ namespace ts {
else {
checkTypeAssignableTo(typePredicate.type,
getTypeAtLocation(node.parameters[typePredicate.parameterIndex]),
typePredicateNode.type);
RelationComparisonFlags.None, typePredicateNode.type);
}
}
else if (typePredicateNode.parameterName) {
@ -9197,7 +9215,7 @@ namespace ts {
// interface BadGenerator extends Iterable<number>, Iterator<string> { }
// function* g(): BadGenerator { } // Iterable and Iterator have different types!
//
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, RelationComparisonFlags.None, node.type);
}
}
}
@ -9399,7 +9417,7 @@ namespace ts {
let constraint = getConstraintOfTypeParameter(typeParameters[i]);
if (constraint) {
let typeArgument = typeArguments[i];
result = result && checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
result = result && checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, RelationComparisonFlags.None, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
}
}
return result;
@ -9836,6 +9854,7 @@ namespace ts {
checkTypeAssignableTo(
returnType,
expectedReturnType,
RelationComparisonFlags.None,
node,
headMessage,
errorInfo);
@ -10257,7 +10276,7 @@ namespace ts {
// For a binding pattern, validate the initializer and exit
if (isBindingPattern(node.name)) {
if (node.initializer) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), RelationComparisonFlags.None, node, /*headMessage*/ undefined);
checkParameterInitializer(node);
}
return;
@ -10267,7 +10286,7 @@ namespace ts {
if (node === symbol.valueDeclaration) {
// Node is the primary declaration of the symbol, just validate the initializer
if (node.initializer) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, RelationComparisonFlags.None, node, /*headMessage*/ undefined);
checkParameterInitializer(node);
}
}
@ -10279,7 +10298,7 @@ namespace ts {
error(node.name, Diagnostics.Subsequent_variable_declarations_must_have_the_same_type_Variable_0_must_be_of_type_1_but_here_has_type_2, declarationNameToString(node.name), typeToString(type), typeToString(declarationType));
}
if (node.initializer) {
checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, /*headMessage*/ undefined);
checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, RelationComparisonFlags.None, node, /*headMessage*/ undefined);
}
}
if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) {
@ -10331,7 +10350,7 @@ namespace ts {
function checkExpressionStatement(node: ExpressionStatement) {
// Grammar checking
checkGrammarStatementInAmbientContext(node)
checkGrammarStatementInAmbientContext(node);
checkExpression(node.expression);
}
@ -10415,7 +10434,7 @@ namespace ts {
// because we accessed properties from anyType, or it may have led to an error inside
// getElementTypeOfIterable.
if (iteratedType) {
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
checkTypeAssignableTo(iteratedType, leftType, RelationComparisonFlags.None, varExpr, /*headMessage*/ undefined);
}
}
}
@ -10515,7 +10534,7 @@ namespace ts {
// Now even though we have extracted the iteratedType, we will have to validate that the type
// passed in is actually an Iterable.
if (errorNode && elementType) {
checkTypeAssignableTo(iterable, createIterableType(elementType), errorNode);
checkTypeAssignableTo(iterable, createIterableType(elementType), RelationComparisonFlags.None, errorNode);
}
return elementType || anyType;
@ -10759,7 +10778,7 @@ namespace ts {
}
}
else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) {
checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined);
checkTypeAssignableTo(exprType, returnType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
}
}
}
@ -10802,7 +10821,7 @@ namespace ts {
let caseType = checkExpression(caseClause.expression);
if (!isTypeAssignableTo(expressionType, caseType)) {
// check 'expressionType isAssignableTo caseType' failed, try the reversed check and report errors if it fails
checkTypeAssignableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined);
checkTypeAssignableTo(caseType, expressionType, RelationComparisonFlags.None, caseClause.expression, /*headMessage*/ undefined);
}
}
forEach(clause.statements, checkSourceElement);
@ -11043,8 +11062,8 @@ namespace ts {
}
}
}
checkTypeAssignableTo(type, baseType, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
checkTypeAssignableTo(type, baseType, RelationComparisonFlags.None, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), RelationComparisonFlags.ExtendingClass, 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
@ -11072,7 +11091,7 @@ namespace ts {
if (t !== unknownType) {
let declaredType = (t.flags & TypeFlags.Reference) ? (<TypeReference>t).target : t;
if (declaredType.flags & (TypeFlags.Class | TypeFlags.Interface)) {
checkTypeAssignableTo(type, t, node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
checkTypeAssignableTo(type, t, RelationComparisonFlags.None, node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
}
else {
error(typeRefNode, Diagnostics.A_class_may_only_implement_another_class_or_interface);
@ -11255,7 +11274,7 @@ namespace ts {
// run subsequent checks only if first set succeeded
if (checkInheritedPropertiesAreIdentical(type, node.name)) {
forEach(getBaseTypes(type), baseType => {
checkTypeAssignableTo(type, baseType, node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1);
checkTypeAssignableTo(type, baseType, RelationComparisonFlags.None, node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1);
});
checkIndexConstraints(type);
}
@ -11308,7 +11327,7 @@ namespace ts {
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
// Also, we do not need to check this for ambients because there is already
// a syntax error if it is not a constant.
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
checkTypeAssignableTo(checkExpression(initializer), enumType, RelationComparisonFlags.None, initializer, /*headMessage*/ undefined);
}
}
else if (enumIsConst) {

View File

@ -403,6 +403,12 @@ namespace ts {
FailedAndReported = 3
}
/* @internal */
export const enum RelationComparisonFlags {
None = 0,
ExtendingClass = 0x00000001
}
export interface Node extends TextRange {
kind: SyntaxKind;
flags: NodeFlags;