Skip to content

Commit a183ba9

Browse files
author
Arthur Ozga
committed
added flag as argument to checkTypeRelatedTo
1 parent 52e8b6c commit a183ba9

2 files changed

Lines changed: 56 additions & 31 deletions

File tree

src/compiler/checker.ts

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4263,27 +4263,27 @@ namespace ts {
42634263
// TYPE CHECKING
42644264

42654265
function isTypeIdenticalTo(source: Type, target: Type): boolean {
4266-
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined);
4266+
return checkTypeRelatedTo(source, target, identityRelation, RelationComparisonFlags.None, /*errorNode*/ undefined);
42674267
}
42684268

42694269
function compareTypes(source: Type, target: Type): Ternary {
4270-
return checkTypeRelatedTo(source, target, identityRelation, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
4270+
return checkTypeRelatedTo(source, target, identityRelation, RelationComparisonFlags.None, /*errorNode*/ undefined) ? Ternary.True : Ternary.False;
42714271
}
42724272

42734273
function isTypeSubtypeOf(source: Type, target: Type): boolean {
42744274
return checkTypeSubtypeOf(source, target, /*errorNode*/ undefined);
42754275
}
42764276

42774277
function isTypeAssignableTo(source: Type, target: Type): boolean {
4278-
return checkTypeAssignableTo(source, target, /*errorNode*/ undefined);
4278+
return checkTypeAssignableTo(source, target, RelationComparisonFlags.None, /*errorNode*/ undefined);
42794279
}
42804280

42814281
function checkTypeSubtypeOf(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
4282-
return checkTypeRelatedTo(source, target, subtypeRelation, errorNode, headMessage, containingMessageChain);
4282+
return checkTypeRelatedTo(source, target, subtypeRelation, RelationComparisonFlags.None, errorNode, headMessage, containingMessageChain);
42834283
}
42844284

4285-
function checkTypeAssignableTo(source: Type, target: Type, errorNode: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
4286-
return checkTypeRelatedTo(source, target, assignableRelation, errorNode, headMessage, containingMessageChain);
4285+
function checkTypeAssignableTo(source: Type, target: Type, relationFlags: RelationComparisonFlags, errorNode?: Node, headMessage?: DiagnosticMessage, containingMessageChain?: DiagnosticMessageChain): boolean {
4286+
return checkTypeRelatedTo(source, target, assignableRelation, relationFlags, errorNode, headMessage, containingMessageChain);
42874287
}
42884288

42894289
function isSignatureAssignableTo(source: Signature, target: Signature): boolean {
@@ -4292,13 +4292,30 @@ namespace ts {
42924292
return checkTypeRelatedTo(sourceType, targetType, assignableRelation, /*errorNode*/ undefined);
42934293
}
42944294

4295+
/**
4296+
* Checks if 'source' is related to 'target' (e.g.: is a assignable to).
4297+
* @param source The left-hand-side of the relation.
4298+
* @param target The right-hand-side of the relation.
4299+
* @param relation The relation considered. One of 'identityRelation', 'assignableRelation', or 'subTypeRelation'.
4300+
* Used as both to determine which checks are performed and as a cache of previously computed results.
4301+
* @param relationFlags Additional information affecting whether the relation holds. Currently used only for distinguishing
4302+
* between a type comparison when extending classes from other comparisons of the constructor types.
4303+
*
4304+
* Caution: checks triggered by these flags should NOT affect the result re
4305+
* @param errorNode The node upon which all errors will be reported, if defined.
4306+
* @param headMessage If the error chain should be prepended by a head message, then headMessage will be used.
4307+
* @param containingMessageChain A chain of errors to prepend any new errors found.
4308+
4309+
*/
42954310
function checkTypeRelatedTo(
42964311
source: Type,
42974312
target: Type,
42984313
relation: Map<RelationComparisonResult>,
4299-
errorNode: Node,
4314+
relationFlags: RelationComparisonFlags,
4315+
errorNode?: Node,
43004316
headMessage?: DiagnosticMessage,
4301-
containingMessageChain?: DiagnosticMessageChain): boolean {
4317+
containingMessageChain?: DiagnosticMessageChain
4318+
): boolean {
43024319

43034320
let errorInfo: DiagnosticMessageChain;
43044321
let sourceStack: ObjectType[];
@@ -7212,6 +7229,7 @@ namespace ts {
72127229
typeArgumentsAreAssignable = checkTypeAssignableTo(
72137230
typeArgument,
72147231
constraint,
7232+
RelationComparisonFlags.None,
72157233
reportErrors ? typeArgNode : undefined,
72167234
typeArgumentHeadMessage,
72177235
errorInfo);
@@ -7243,7 +7261,7 @@ namespace ts {
72437261
// Use argument expression as error location when reporting errors
72447262
let errorNode = reportErrors ? getEffectiveArgumentErrorNode(node, i, arg) : undefined;
72457263
let headMessage = Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1;
7246-
if (!checkTypeRelatedTo(argType, paramType, relation, errorNode, headMessage)) {
7264+
if (!checkTypeRelatedTo(argType, paramType, relation, RelationComparisonFlags.None, errorNode, headMessage)) {
72477265
return false;
72487266
}
72497267
}
@@ -8040,7 +8058,7 @@ namespace ts {
80408058
if (produceDiagnostics && targetType !== unknownType) {
80418059
let widenedType = getWidenedType(exprType);
80428060
if (!(isTypeAssignableTo(targetType, widenedType))) {
8043-
checkTypeAssignableTo(exprType, targetType, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
8061+
checkTypeAssignableTo(exprType, targetType, RelationComparisonFlags.None, node, Diagnostics.Neither_type_0_nor_type_1_is_assignable_to_the_other);
80448062
}
80458063
}
80468064
return targetType;
@@ -8274,7 +8292,7 @@ namespace ts {
82748292
else {
82758293
let exprType = checkExpression(<Expression>node.body);
82768294
if (node.type) {
8277-
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), node.body, /*headMessage*/ undefined);
8295+
checkTypeAssignableTo(exprType, getTypeFromTypeNode(node.type), RelationComparisonFlags.None, node.body, /*headMessage*/ undefined);
82788296
}
82798297
checkFunctionAndClassExpressionBodies(node.body);
82808298
}
@@ -8582,7 +8600,7 @@ namespace ts {
85828600
function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
85838601
let targetType = checkExpression(target, contextualMapper);
85848602
if (checkReferenceExpression(target, Diagnostics.Invalid_left_hand_side_of_assignment_expression, Diagnostics.Left_hand_side_of_assignment_expression_cannot_be_a_constant)) {
8585-
checkTypeAssignableTo(sourceType, targetType, target, /*headMessage*/ undefined);
8603+
checkTypeAssignableTo(sourceType, targetType, RelationComparisonFlags.None, target, /*headMessage*/ undefined);
85868604
}
85878605
return sourceType;
85888606
}
@@ -8757,7 +8775,7 @@ namespace ts {
87578775
// Use default messages
87588776
if (ok) {
87598777
// to avoid cascading errors check assignability only if 'isReference' check succeeded and no errors were reported
8760-
checkTypeAssignableTo(valueType, leftType, node.left, /*headMessage*/ undefined);
8778+
checkTypeAssignableTo(valueType, leftType, RelationComparisonFlags.None, node.left, /*headMessage*/ undefined);
87618779
}
87628780
}
87638781
}
@@ -8808,10 +8826,10 @@ namespace ts {
88088826
if (func.type) {
88098827
let signatureElementType = getElementTypeOfIterableIterator(getTypeFromTypeNode(func.type)) || anyType;
88108828
if (nodeIsYieldStar) {
8811-
checkTypeAssignableTo(expressionElementType, signatureElementType, node.expression, /*headMessage*/ undefined);
8829+
checkTypeAssignableTo(expressionElementType, signatureElementType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
88128830
}
88138831
else {
8814-
checkTypeAssignableTo(expressionType, signatureElementType, node.expression, /*headMessage*/ undefined);
8832+
checkTypeAssignableTo(expressionType, signatureElementType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
88158833
}
88168834
}
88178835
}
@@ -9119,7 +9137,7 @@ namespace ts {
91199137
else {
91209138
checkTypeAssignableTo(typePredicate.type,
91219139
getTypeAtLocation(node.parameters[typePredicate.parameterIndex]),
9122-
typePredicateNode.type);
9140+
RelationComparisonFlags.None, typePredicateNode.type);
91239141
}
91249142
}
91259143
else if (typePredicateNode.parameterName) {
@@ -9197,7 +9215,7 @@ namespace ts {
91979215
// interface BadGenerator extends Iterable<number>, Iterator<string> { }
91989216
// function* g(): BadGenerator { } // Iterable and Iterator have different types!
91999217
//
9200-
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, node.type);
9218+
checkTypeAssignableTo(iterableIteratorInstantiation, returnType, RelationComparisonFlags.None, node.type);
92019219
}
92029220
}
92039221
}
@@ -9399,7 +9417,7 @@ namespace ts {
93999417
let constraint = getConstraintOfTypeParameter(typeParameters[i]);
94009418
if (constraint) {
94019419
let typeArgument = typeArguments[i];
9402-
result = result && checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
9420+
result = result && checkTypeAssignableTo(getTypeFromTypeNode(typeArgument), constraint, RelationComparisonFlags.None, typeArgument, Diagnostics.Type_0_does_not_satisfy_the_constraint_1);
94039421
}
94049422
}
94059423
return result;
@@ -9836,6 +9854,7 @@ namespace ts {
98369854
checkTypeAssignableTo(
98379855
returnType,
98389856
expectedReturnType,
9857+
RelationComparisonFlags.None,
98399858
node,
98409859
headMessage,
98419860
errorInfo);
@@ -10257,7 +10276,7 @@ namespace ts {
1025710276
// For a binding pattern, validate the initializer and exit
1025810277
if (isBindingPattern(node.name)) {
1025910278
if (node.initializer) {
10260-
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
10279+
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), RelationComparisonFlags.None, node, /*headMessage*/ undefined);
1026110280
checkParameterInitializer(node);
1026210281
}
1026310282
return;
@@ -10267,7 +10286,7 @@ namespace ts {
1026710286
if (node === symbol.valueDeclaration) {
1026810287
// Node is the primary declaration of the symbol, just validate the initializer
1026910288
if (node.initializer) {
10270-
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
10289+
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, RelationComparisonFlags.None, node, /*headMessage*/ undefined);
1027110290
checkParameterInitializer(node);
1027210291
}
1027310292
}
@@ -10279,7 +10298,7 @@ namespace ts {
1027910298
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));
1028010299
}
1028110300
if (node.initializer) {
10282-
checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, node, /*headMessage*/ undefined);
10301+
checkTypeAssignableTo(checkExpressionCached(node.initializer), declarationType, RelationComparisonFlags.None, node, /*headMessage*/ undefined);
1028310302
}
1028410303
}
1028510304
if (node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.PropertySignature) {
@@ -10331,7 +10350,7 @@ namespace ts {
1033110350

1033210351
function checkExpressionStatement(node: ExpressionStatement) {
1033310352
// Grammar checking
10334-
checkGrammarStatementInAmbientContext(node)
10353+
checkGrammarStatementInAmbientContext(node);
1033510354

1033610355
checkExpression(node.expression);
1033710356
}
@@ -10415,7 +10434,7 @@ namespace ts {
1041510434
// because we accessed properties from anyType, or it may have led to an error inside
1041610435
// getElementTypeOfIterable.
1041710436
if (iteratedType) {
10418-
checkTypeAssignableTo(iteratedType, leftType, varExpr, /*headMessage*/ undefined);
10437+
checkTypeAssignableTo(iteratedType, leftType, RelationComparisonFlags.None, varExpr, /*headMessage*/ undefined);
1041910438
}
1042010439
}
1042110440
}
@@ -10515,7 +10534,7 @@ namespace ts {
1051510534
// Now even though we have extracted the iteratedType, we will have to validate that the type
1051610535
// passed in is actually an Iterable.
1051710536
if (errorNode && elementType) {
10518-
checkTypeAssignableTo(iterable, createIterableType(elementType), errorNode);
10537+
checkTypeAssignableTo(iterable, createIterableType(elementType), RelationComparisonFlags.None, errorNode);
1051910538
}
1052010539

1052110540
return elementType || anyType;
@@ -10759,7 +10778,7 @@ namespace ts {
1075910778
}
1076010779
}
1076110780
else if (func.type || isGetAccessorWithAnnotatatedSetAccessor(func) || signature.typePredicate) {
10762-
checkTypeAssignableTo(exprType, returnType, node.expression, /*headMessage*/ undefined);
10781+
checkTypeAssignableTo(exprType, returnType, RelationComparisonFlags.None, node.expression, /*headMessage*/ undefined);
1076310782
}
1076410783
}
1076510784
}
@@ -10802,7 +10821,7 @@ namespace ts {
1080210821
let caseType = checkExpression(caseClause.expression);
1080310822
if (!isTypeAssignableTo(expressionType, caseType)) {
1080410823
// check 'expressionType isAssignableTo caseType' failed, try the reversed check and report errors if it fails
10805-
checkTypeAssignableTo(caseType, expressionType, caseClause.expression, /*headMessage*/ undefined);
10824+
checkTypeAssignableTo(caseType, expressionType, RelationComparisonFlags.None, caseClause.expression, /*headMessage*/ undefined);
1080610825
}
1080710826
}
1080810827
forEach(clause.statements, checkSourceElement);
@@ -11043,8 +11062,8 @@ namespace ts {
1104311062
}
1104411063
}
1104511064
}
11046-
checkTypeAssignableTo(type, baseType, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
11047-
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), node.name || node,
11065+
checkTypeAssignableTo(type, baseType, RelationComparisonFlags.None, node.name || node, Diagnostics.Class_0_incorrectly_extends_base_class_1);
11066+
checkTypeAssignableTo(staticType, getTypeWithoutSignatures(staticBaseType), RelationComparisonFlags.ExtendingClass, node.name || node,
1104811067
Diagnostics.Class_static_side_0_incorrectly_extends_base_class_static_side_1);
1104911068
if (!(staticBaseType.symbol && staticBaseType.symbol.flags & SymbolFlags.Class)) {
1105011069
// When the static base type is a "class-like" constructor function (but not actually a class), we verify
@@ -11072,7 +11091,7 @@ namespace ts {
1107211091
if (t !== unknownType) {
1107311092
let declaredType = (t.flags & TypeFlags.Reference) ? (<TypeReference>t).target : t;
1107411093
if (declaredType.flags & (TypeFlags.Class | TypeFlags.Interface)) {
11075-
checkTypeAssignableTo(type, t, node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
11094+
checkTypeAssignableTo(type, t, RelationComparisonFlags.None, node.name || node, Diagnostics.Class_0_incorrectly_implements_interface_1);
1107611095
}
1107711096
else {
1107811097
error(typeRefNode, Diagnostics.A_class_may_only_implement_another_class_or_interface);
@@ -11255,7 +11274,7 @@ namespace ts {
1125511274
// run subsequent checks only if first set succeeded
1125611275
if (checkInheritedPropertiesAreIdentical(type, node.name)) {
1125711276
forEach(getBaseTypes(type), baseType => {
11258-
checkTypeAssignableTo(type, baseType, node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1);
11277+
checkTypeAssignableTo(type, baseType, RelationComparisonFlags.None, node.name, Diagnostics.Interface_0_incorrectly_extends_interface_1);
1125911278
});
1126011279
checkIndexConstraints(type);
1126111280
}
@@ -11308,7 +11327,7 @@ namespace ts {
1130811327
// If it is a constant value (not undefined), it is syntactically constrained to be a number.
1130911328
// Also, we do not need to check this for ambients because there is already
1131011329
// a syntax error if it is not a constant.
11311-
checkTypeAssignableTo(checkExpression(initializer), enumType, initializer, /*headMessage*/ undefined);
11330+
checkTypeAssignableTo(checkExpression(initializer), enumType, RelationComparisonFlags.None, initializer, /*headMessage*/ undefined);
1131211331
}
1131311332
}
1131411333
else if (enumIsConst) {

src/compiler/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,12 @@ namespace ts {
403403
FailedAndReported = 3
404404
}
405405

406+
/* @internal */
407+
export const enum RelationComparisonFlags {
408+
None = 0,
409+
ExtendingClass = 0x00000001
410+
}
411+
406412
export interface Node extends TextRange {
407413
kind: SyntaxKind;
408414
flags: NodeFlags;

0 commit comments

Comments
 (0)