Skip to content

Commit 0314372

Browse files
authored
Make type comparison error elaboration consistent (#58859)
1 parent 6d3be98 commit 0314372

File tree

84 files changed

+1183
-246
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+1183
-246
lines changed

src/compiler/checker.ts

+18-20
Original file line numberDiff line numberDiff line change
@@ -21464,7 +21464,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2146421464
}
2146521465
const id = getSymbolId(sourceSymbol) + "," + getSymbolId(targetSymbol);
2146621466
const entry = enumRelation.get(id);
21467-
if (entry !== undefined && !(!(entry & RelationComparisonResult.Reported) && entry & RelationComparisonResult.Failed && errorReporter)) {
21467+
if (entry !== undefined && !(entry & RelationComparisonResult.Failed && errorReporter)) {
2146821468
return !!(entry & RelationComparisonResult.Succeeded);
2146921469
}
2147021470
const targetEnumType = getTypeOfSymbol(targetSymbol);
@@ -21474,11 +21474,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2147421474
if (!targetProperty || !(targetProperty.flags & SymbolFlags.EnumMember)) {
2147521475
if (errorReporter) {
2147621476
errorReporter(Diagnostics.Property_0_is_missing_in_type_1, symbolName(sourceProperty), typeToString(getDeclaredTypeOfSymbol(targetSymbol), /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType));
21477-
enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported);
21478-
}
21479-
else {
21480-
enumRelation.set(id, RelationComparisonResult.Failed);
2148121477
}
21478+
enumRelation.set(id, RelationComparisonResult.Failed);
2148221479
return false;
2148321480
}
2148421481
const sourceValue = getEnumMemberValue(getDeclarationOfKind(sourceProperty, SyntaxKind.EnumMember)!).value;
@@ -21489,15 +21486,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2148921486

2149021487
// If we have 2 enums with *known* values that differ, they are incompatible.
2149121488
if (sourceValue !== undefined && targetValue !== undefined) {
21492-
if (!errorReporter) {
21493-
enumRelation.set(id, RelationComparisonResult.Failed);
21494-
}
21495-
else {
21489+
if (errorReporter) {
2149621490
const escapedSource = sourceIsString ? `"${escapeString(sourceValue)}"` : sourceValue;
2149721491
const escapedTarget = targetIsString ? `"${escapeString(targetValue)}"` : targetValue;
2149821492
errorReporter(Diagnostics.Each_declaration_of_0_1_differs_in_its_value_where_2_was_expected_but_3_was_given, symbolName(targetSymbol), symbolName(targetProperty), escapedTarget, escapedSource);
21499-
enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported);
2150021493
}
21494+
enumRelation.set(id, RelationComparisonResult.Failed);
2150121495
return false;
2150221496
}
2150321497

@@ -21508,16 +21502,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2150821502
// Either way, we can assume that it's numeric.
2150921503
// If the other is a string, we have a mismatch in types.
2151021504
if (sourceIsString || targetIsString) {
21511-
if (!errorReporter) {
21512-
enumRelation.set(id, RelationComparisonResult.Failed);
21513-
}
21514-
else {
21505+
if (errorReporter) {
2151521506
const knownStringValue = sourceValue ?? targetValue;
2151621507
Debug.assert(typeof knownStringValue === "string");
2151721508
const escapedValue = `"${escapeString(knownStringValue)}"`;
2151821509
errorReporter(Diagnostics.One_value_of_0_1_is_the_string_2_and_the_other_is_assumed_to_be_an_unknown_numeric_value, symbolName(targetSymbol), symbolName(targetProperty), escapedValue);
21519-
enumRelation.set(id, RelationComparisonResult.Failed | RelationComparisonResult.Reported);
2152021510
}
21511+
enumRelation.set(id, RelationComparisonResult.Failed);
2152121512
return false;
2152221513
}
2152321514
}
@@ -21716,7 +21707,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2171621707
if (overflow) {
2171721708
// Record this relation as having failed such that we don't attempt the overflowing operation again.
2171821709
const id = getRelationKey(source, target, /*intersectionState*/ IntersectionState.None, relation, /*ignoreConstraints*/ false);
21719-
relation.set(id, RelationComparisonResult.Reported | RelationComparisonResult.Failed);
21710+
relation.set(id, RelationComparisonResult.Failed | (relationCount <= 0 ? RelationComparisonResult.ComplexityOverflow : RelationComparisonResult.StackDepthOverflow));
2172021711
tracing?.instant(tracing.Phase.CheckTypes, "checkTypeRelatedTo_DepthLimit", { sourceId: source.id, targetId: target.id, depth: sourceDepth, targetDepth });
2172121712
const message = relationCount <= 0 ?
2172221713
Diagnostics.Excessive_complexity_comparing_types_0_and_1 :
@@ -22617,9 +22608,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2261722608
const id = getRelationKey(source, target, intersectionState, relation, /*ignoreConstraints*/ false);
2261822609
const entry = relation.get(id);
2261922610
if (entry !== undefined) {
22620-
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
22621-
// We are elaborating errors and the cached result is an unreported failure. The result will be reported
22622-
// as a failure, and should be updated as a reported failure by the bottom of this function.
22611+
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Overflow)) {
22612+
// We are elaborating errors and the cached result is a failure not due to a comparison overflow,
22613+
// so we will do the comparison again to generate an error message.
2262322614
}
2262422615
else {
2262522616
if (outofbandVarianceMarkerHandler) {
@@ -22632,6 +22623,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2263222623
instantiateType(source, reportUnreliableMapper);
2263322624
}
2263422625
}
22626+
if (reportErrors && entry & RelationComparisonResult.Overflow) {
22627+
const message = entry & RelationComparisonResult.ComplexityOverflow ?
22628+
Diagnostics.Excessive_complexity_comparing_types_0_and_1 :
22629+
Diagnostics.Excessive_stack_depth_comparing_types_0_and_1;
22630+
reportError(message, typeToString(source), typeToString(target));
22631+
overrideNextErrorInfo++;
22632+
}
2263522633
return entry & RelationComparisonResult.Succeeded ? Ternary.True : Ternary.False;
2263622634
}
2263722635
}
@@ -22735,7 +22733,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
2273522733
else {
2273622734
// A false result goes straight into global cache (when something is false under
2273722735
// assumptions it will also be false without assumptions)
22738-
relation.set(id, (reportErrors ? RelationComparisonResult.Reported : 0) | RelationComparisonResult.Failed | propagatingVarianceFlags);
22736+
relation.set(id, RelationComparisonResult.Failed | propagatingVarianceFlags);
2273922737
relationCount--;
2274022738
resetMaybeStack(/*markAllAsSucceeded*/ false);
2274122739
}

src/compiler/types.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -913,11 +913,14 @@ export const enum RelationComparisonResult {
913913
None = 0,
914914
Succeeded = 1 << 0, // Should be truthy
915915
Failed = 1 << 1,
916-
Reported = 1 << 2,
917916

918917
ReportsUnmeasurable = 1 << 3,
919918
ReportsUnreliable = 1 << 4,
920919
ReportsMask = ReportsUnmeasurable | ReportsUnreliable,
920+
921+
ComplexityOverflow = 1 << 5,
922+
StackDepthOverflow = 1 << 6,
923+
Overflow = ComplexityOverflow | StackDepthOverflow,
921924
}
922925

923926
/** @internal */

tests/baselines/reference/arrayFrom.errors.txt

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
arrayFrom.ts(20,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'.
22
Property 'b' is missing in type 'A' but required in type 'B'.
33
arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'.
4+
Property 'b' is missing in type 'A' but required in type 'B'.
45

56

67
==== arrayFrom.ts (2 errors) ====
@@ -33,6 +34,8 @@ arrayFrom.ts(23,7): error TS2322: Type 'A[]' is not assignable to type 'B[]'.
3334
const result6: B[] = Array.from(inputALike); // expect error
3435
~~~~~~~
3536
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
37+
!!! error TS2322: Property 'b' is missing in type 'A' but required in type 'B'.
38+
!!! related TS2728 arrayFrom.ts:9:3: 'b' is declared here.
3639
const result7: B[] = Array.from(inputALike, ({ a }): B => ({ b: a }));
3740
const result8: A[] = Array.from(inputARand);
3841
const result9: B[] = Array.from(inputARand, ({ a }): B => ({ b: a }));

tests/baselines/reference/arrayOfSubtypeIsAssignableToReadonlyArray.errors.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ arrayOfSubtypeIsAssignableToReadonlyArray.ts(13,1): error TS2322: Type 'A[]' is
33
arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
44
The types returned by 'concat(...)' are incompatible between these types.
55
Type 'A[]' is not assignable to type 'B[]'.
6-
Type 'A' is not assignable to type 'B'.
6+
Property 'b' is missing in type 'A' but required in type 'B'.
77

88

99
==== arrayOfSubtypeIsAssignableToReadonlyArray.ts (2 errors) ====
@@ -33,5 +33,6 @@ arrayOfSubtypeIsAssignableToReadonlyArray.ts(18,1): error TS2322: Type 'C<A>' is
3333
!!! error TS2322: Type 'C<A>' is not assignable to type 'readonly B[]'.
3434
!!! error TS2322: The types returned by 'concat(...)' are incompatible between these types.
3535
!!! error TS2322: Type 'A[]' is not assignable to type 'B[]'.
36-
!!! error TS2322: Type 'A' is not assignable to type 'B'.
36+
!!! error TS2322: Property 'b' is missing in type 'A' but required in type 'B'.
37+
!!! related TS2728 arrayOfSubtypeIsAssignableToReadonlyArray.ts:2:21: 'b' is declared here.
3738

tests/baselines/reference/assignmentCompatWithNumericIndexer.errors.txt

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ assignmentCompatWithNumericIndexer.ts(32,9): error TS2322: Type '{ [x: number]:
1111
assignmentCompatWithNumericIndexer.ts(33,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived; }'.
1212
'number' index signatures are incompatible.
1313
Type 'T' is not assignable to type 'Derived'.
14-
Type 'Base' is not assignable to type 'Derived'.
14+
Property 'bar' is missing in type 'Base' but required in type 'Derived'.
1515
assignmentCompatWithNumericIndexer.ts(36,9): error TS2322: Type '{ [x: number]: Derived2; }' is not assignable to type 'A<T>'.
1616
'number' index signatures are incompatible.
1717
Type 'Derived2' is not assignable to type 'T'.
1818
'Derived2' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Base'.
1919
assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
2020
'number' index signatures are incompatible.
2121
Type 'T' is not assignable to type 'Derived2'.
22-
Type 'Base' is not assignable to type 'Derived2'.
22+
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
2323

2424

2525
==== assignmentCompatWithNumericIndexer.ts (6 errors) ====
@@ -74,7 +74,8 @@ assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not as
7474
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived; }'.
7575
!!! error TS2322: 'number' index signatures are incompatible.
7676
!!! error TS2322: Type 'T' is not assignable to type 'Derived'.
77-
!!! error TS2322: Type 'Base' is not assignable to type 'Derived'.
77+
!!! error TS2322: Property 'bar' is missing in type 'Base' but required in type 'Derived'.
78+
!!! related TS2728 assignmentCompatWithNumericIndexer.ts:4:34: 'bar' is declared here.
7879

7980
var b2: { [x: number]: Derived2; }
8081
a = b2; // error
@@ -88,7 +89,7 @@ assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not as
8889
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
8990
!!! error TS2322: 'number' index signatures are incompatible.
9091
!!! error TS2322: Type 'T' is not assignable to type 'Derived2'.
91-
!!! error TS2322: Type 'Base' is not assignable to type 'Derived2'.
92+
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar
9293

9394
var b3: { [x: number]: T; }
9495
a = b3; // ok

tests/baselines/reference/assignmentCompatWithNumericIndexer2.errors.txt

+5-4
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ assignmentCompatWithNumericIndexer2.ts(32,9): error TS2322: Type '{ [x: number]:
1111
assignmentCompatWithNumericIndexer2.ts(33,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived; }'.
1212
'number' index signatures are incompatible.
1313
Type 'T' is not assignable to type 'Derived'.
14-
Type 'Base' is not assignable to type 'Derived'.
14+
Property 'bar' is missing in type 'Base' but required in type 'Derived'.
1515
assignmentCompatWithNumericIndexer2.ts(36,9): error TS2322: Type '{ [x: number]: Derived2; }' is not assignable to type 'A<T>'.
1616
'number' index signatures are incompatible.
1717
Type 'Derived2' is not assignable to type 'T'.
1818
'Derived2' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Base'.
1919
assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
2020
'number' index signatures are incompatible.
2121
Type 'T' is not assignable to type 'Derived2'.
22-
Type 'Base' is not assignable to type 'Derived2'.
22+
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
2323

2424

2525
==== assignmentCompatWithNumericIndexer2.ts (6 errors) ====
@@ -74,7 +74,8 @@ assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not a
7474
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived; }'.
7575
!!! error TS2322: 'number' index signatures are incompatible.
7676
!!! error TS2322: Type 'T' is not assignable to type 'Derived'.
77-
!!! error TS2322: Type 'Base' is not assignable to type 'Derived'.
77+
!!! error TS2322: Property 'bar' is missing in type 'Base' but required in type 'Derived'.
78+
!!! related TS2728 assignmentCompatWithNumericIndexer2.ts:4:34: 'bar' is declared here.
7879

7980
var b2: { [x: number]: Derived2; }
8081
a = b2; // error
@@ -88,7 +89,7 @@ assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not a
8889
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
8990
!!! error TS2322: 'number' index signatures are incompatible.
9091
!!! error TS2322: Type 'T' is not assignable to type 'Derived2'.
91-
!!! error TS2322: Type 'Base' is not assignable to type 'Derived2'.
92+
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar
9293

9394
var b3: { [x: number]: T; }
9495
a = b3; // ok

0 commit comments

Comments
 (0)