Skip to content

Commit 459099c

Browse files
sandersntypescript-bot
authored andcommitted
Cherry-pick PR microsoft#34789 into release-3.7
Component commits: 2e0b451 Add isIntersectionConstituent to relation key isIntersectionConstituent controls whether relation checking performs excess property and common property checks. It is possible to fail a relation check with excess property checks turned on, cache the result, and then skip a relation check with excess property checks that would have succeeded. microsoft#33133 provides an example of such a program. Fixes microsoft#33133 the right way, so I reverted the fix at microsoft#33213 Fixes microsoft#34762 (by reverting microsoft#33213) Fixes microsoft#33944 -- I added the test from microsoft#34646 14d7a44 Merge branch 'master' into add-isIntersectionConstituent-to-relation-key ea80362 Update comments in test 0764275 Merge branch 'master' into add-isIntersectionConstituent-to-relation-key
1 parent 787ff34 commit 459099c

14 files changed

+209
-45
lines changed

src/compiler/checker.ts

+10-9
Original file line numberDiff line numberDiff line change
@@ -14157,7 +14157,7 @@ namespace ts {
1415714157
return true;
1415814158
}
1415914159
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
14160-
const related = relation.get(getRelationKey(source, target, relation));
14160+
const related = relation.get(getRelationKey(source, target, /*isIntersectionConstituent*/ false, relation));
1416114161
if (related !== undefined) {
1416214162
return !!(related & RelationComparisonResult.Succeeded);
1416314163
}
@@ -14563,7 +14563,7 @@ namespace ts {
1456314563
// and we need to handle "each" relations before "some" relations for the same kind of type.
1456414564
if (source.flags & TypeFlags.Union) {
1456514565
result = relation === comparableRelation ?
14566-
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), isIntersectionConstituent) :
14566+
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) :
1456714567
eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
1456814568
}
1456914569
else {
@@ -14601,7 +14601,7 @@ namespace ts {
1460114601
//
1460214602
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
1460314603
// breaking the intersection apart.
14604-
result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false, /*isIntersectionConstituent*/ true);
14604+
result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false);
1460514605
}
1460614606
if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) {
1460714607
if (result = recursiveTypeRelatedTo(source, target, reportErrors, isIntersectionConstituent)) {
@@ -14895,14 +14895,14 @@ namespace ts {
1489514895
return result;
1489614896
}
1489714897

14898-
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
14898+
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
1489914899
const sourceTypes = source.types;
1490014900
if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) {
1490114901
return Ternary.True;
1490214902
}
1490314903
const len = sourceTypes.length;
1490414904
for (let i = 0; i < len; i++) {
14905-
const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1, /*headMessage*/ undefined, isIntersectionConstituent);
14905+
const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1);
1490614906
if (related) {
1490714907
return related;
1490814908
}
@@ -14989,7 +14989,7 @@ namespace ts {
1498914989
if (overflow) {
1499014990
return Ternary.False;
1499114991
}
14992-
const id = getRelationKey(source, target, relation);
14992+
const id = getRelationKey(source, target, isIntersectionConstituent, relation);
1499314993
const entry = relation.get(id);
1499414994
if (entry !== undefined) {
1499514995
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
@@ -16203,17 +16203,18 @@ namespace ts {
1620316203
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
1620416204
* For other cases, the types ids are used.
1620516205
*/
16206-
function getRelationKey(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
16206+
function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, relation: Map<RelationComparisonResult>) {
1620716207
if (relation === identityRelation && source.id > target.id) {
1620816208
const temp = source;
1620916209
source = target;
1621016210
target = temp;
1621116211
}
16212+
const intersection = isIntersectionConstituent ? "&" : "";
1621216213
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
1621316214
const typeParameters: Type[] = [];
16214-
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters);
16215+
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters) + intersection;
1621516216
}
16216-
return source.id + "," + target.id;
16217+
return source.id + "," + target.id + intersection;
1621716218
}
1621816219

1621916220
// Invoke the callback for each underlying property symbol of the given symbol and return the first
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
tests/cases/conformance/types/intersection/commonTypeIntersection.ts(2,5): error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; } & { a: boolean; }'.
2+
Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; }'.
3+
Types of property '__typename' are incompatible.
4+
Type '"TypeTwo"' is not assignable to type '"TypeOne"'.
5+
tests/cases/conformance/types/intersection/commonTypeIntersection.ts(4,5): error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; } & string'.
6+
Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; }'.
7+
Types of property '__typename' are incompatible.
8+
Type '"TypeTwo"' is not assignable to type '"TypeOne"'.
9+
10+
11+
==== tests/cases/conformance/types/intersection/commonTypeIntersection.ts (2 errors) ====
12+
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
13+
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here
14+
~~
15+
!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; } & { a: boolean; }'.
16+
!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & { a: boolean; }' is not assignable to type '{ __typename?: "TypeOne"; }'.
17+
!!! error TS2322: Types of property '__typename' are incompatible.
18+
!!! error TS2322: Type '"TypeTwo"' is not assignable to type '"TypeOne"'.
19+
declare let x2: { __typename?: 'TypeTwo' } & string;
20+
let y2: { __typename?: 'TypeOne' } & string = x2; // should error here
21+
~~
22+
!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; } & string'.
23+
!!! error TS2322: Type '{ __typename?: "TypeTwo"; } & string' is not assignable to type '{ __typename?: "TypeOne"; }'.
24+
!!! error TS2322: Types of property '__typename' are incompatible.
25+
!!! error TS2322: Type '"TypeTwo"' is not assignable to type '"TypeOne"'.
26+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//// [commonTypeIntersection.ts]
2+
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
3+
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here
4+
declare let x2: { __typename?: 'TypeTwo' } & string;
5+
let y2: { __typename?: 'TypeOne' } & string = x2; // should error here
6+
7+
8+
//// [commonTypeIntersection.js]
9+
var y1 = x1; // should error here
10+
var y2 = x2; // should error here
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/conformance/types/intersection/commonTypeIntersection.ts ===
2+
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
3+
>x1 : Symbol(x1, Decl(commonTypeIntersection.ts, 0, 11))
4+
>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 0, 17))
5+
>a : Symbol(a, Decl(commonTypeIntersection.ts, 0, 46))
6+
7+
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here
8+
>y1 : Symbol(y1, Decl(commonTypeIntersection.ts, 1, 3))
9+
>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 1, 9))
10+
>a : Symbol(a, Decl(commonTypeIntersection.ts, 1, 38))
11+
>x1 : Symbol(x1, Decl(commonTypeIntersection.ts, 0, 11))
12+
13+
declare let x2: { __typename?: 'TypeTwo' } & string;
14+
>x2 : Symbol(x2, Decl(commonTypeIntersection.ts, 2, 11))
15+
>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 2, 17))
16+
17+
let y2: { __typename?: 'TypeOne' } & string = x2; // should error here
18+
>y2 : Symbol(y2, Decl(commonTypeIntersection.ts, 3, 3))
19+
>__typename : Symbol(__typename, Decl(commonTypeIntersection.ts, 3, 9))
20+
>x2 : Symbol(x2, Decl(commonTypeIntersection.ts, 2, 11))
21+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
=== tests/cases/conformance/types/intersection/commonTypeIntersection.ts ===
2+
declare let x1: { __typename?: 'TypeTwo' } & { a: boolean };
3+
>x1 : { __typename?: "TypeTwo"; } & { a: boolean; }
4+
>__typename : "TypeTwo"
5+
>a : boolean
6+
7+
let y1: { __typename?: 'TypeOne' } & { a: boolean} = x1; // should error here
8+
>y1 : { __typename?: "TypeOne"; } & { a: boolean; }
9+
>__typename : "TypeOne"
10+
>a : boolean
11+
>x1 : { __typename?: "TypeTwo"; } & { a: boolean; }
12+
13+
declare let x2: { __typename?: 'TypeTwo' } & string;
14+
>x2 : { __typename?: "TypeTwo"; } & string
15+
>__typename : "TypeTwo"
16+
17+
let y2: { __typename?: 'TypeOne' } & string = x2; // should error here
18+
>y2 : { __typename?: "TypeOne"; } & string
19+
>__typename : "TypeOne"
20+
>x2 : { __typename?: "TypeTwo"; } & string
21+

tests/baselines/reference/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.errors.txt

+34-28
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,23 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t
55
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
66
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
77
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
8-
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
9-
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
10-
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
11-
Type '"text"' is not assignable to type 'T & "text"'.
12-
Type '"text"' is not assignable to type 'T'.
13-
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
14-
Type 'T' is not assignable to type 'T & "text"'.
15-
Type '"text" | "email"' is not assignable to type 'T & "text"'.
16-
Type '"text"' is not assignable to type 'T & "text"'.
17-
Type '"text"' is not assignable to type 'T'.
18-
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
19-
Type 'T' is not assignable to type '"text"'.
20-
Type '"text" | "email"' is not assignable to type '"text"'.
21-
Type '"email"' is not assignable to type '"text"'.
8+
Type '"text"' is not assignable to type 'T & "text"'.
9+
Type '"text"' is not assignable to type 'T'.
10+
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
11+
Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
12+
Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
13+
Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
14+
Type '"text"' is not assignable to type 'T & "text"'.
15+
Type '"text"' is not assignable to type 'T'.
16+
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
17+
Type 'T' is not assignable to type 'T & "text"'.
18+
Type '"text" | "email"' is not assignable to type 'T & "text"'.
19+
Type '"text"' is not assignable to type 'T & "text"'.
20+
Type '"text"' is not assignable to type 'T'.
21+
'"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
22+
Type 'T' is not assignable to type '"text"'.
23+
Type '"text" | "email"' is not assignable to type '"text"'.
24+
Type '"email"' is not assignable to type '"text"'.
2225

2326

2427
==== tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.ts (1 errors) ====
@@ -63,20 +66,23 @@ tests/cases/compiler/complicatedIndexedAccessKeyofReliesOnKeyofNeverUpperBound.t
6366
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
6467
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"] & ChannelOfType<T, EmailChannel>["type"]'.
6568
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
66-
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
67-
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
68-
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
69-
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
70-
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
71-
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
72-
!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'.
73-
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'.
74-
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
75-
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
76-
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
77-
!!! error TS2322: Type 'T' is not assignable to type '"text"'.
78-
!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'.
79-
!!! error TS2322: Type '"email"' is not assignable to type '"text"'.
69+
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
70+
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
71+
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
72+
!!! error TS2322: Type 'T' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
73+
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
74+
!!! error TS2322: Type '"text"' is not assignable to type 'ChannelOfType<T, TextChannel>["type"]'.
75+
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
76+
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
77+
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
78+
!!! error TS2322: Type 'T' is not assignable to type 'T & "text"'.
79+
!!! error TS2322: Type '"text" | "email"' is not assignable to type 'T & "text"'.
80+
!!! error TS2322: Type '"text"' is not assignable to type 'T & "text"'.
81+
!!! error TS2322: Type '"text"' is not assignable to type 'T'.
82+
!!! error TS2322: '"text"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint '"text" | "email"'.
83+
!!! error TS2322: Type 'T' is not assignable to type '"text"'.
84+
!!! error TS2322: Type '"text" | "email"' is not assignable to type '"text"'.
85+
!!! error TS2322: Type '"email"' is not assignable to type '"text"'.
8086
}
8187

8288
const newTextChannel = makeNewChannel('text');

0 commit comments

Comments
 (0)