Skip to content

Commit

Permalink
Fix comparability between type parameters related by a union constrai…
Browse files Browse the repository at this point in the history
…nt (#50978)
  • Loading branch information
andrewbranch committed Sep 28, 2022
1 parent b09e93d commit fbfe934
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Expand Up @@ -19734,7 +19734,7 @@ namespace ts {
// with another type parameter unless one extends the other. (Remember: comparability is mostly bidirectional!)
let constraint = getConstraintOfTypeParameter(source);
if (constraint && hasNonCircularBaseConstraint(source)) {
while (constraint && constraint.flags & TypeFlags.TypeParameter) {
while (constraint && someType(constraint, c => !!(c.flags & TypeFlags.TypeParameter))) {
if (result = isRelatedTo(constraint, target, RecursionFlags.Source, /*reportErrors*/ false)) {
return result;
}
Expand Down
@@ -0,0 +1,27 @@
//// [comparabilityTypeParametersRelatedByUnion.ts]
class C<T> {
constructor(readonly x: T) {}

good<U extends T>(y: U) {
if (y === this.x) {}
}

bad<U extends T | string>(y: U) {
if (y === this.x) {}
}
}


//// [comparabilityTypeParametersRelatedByUnion.js]
var C = /** @class */ (function () {
function C(x) {
this.x = x;
}
C.prototype.good = function (y) {
if (y === this.x) { }
};
C.prototype.bad = function (y) {
if (y === this.x) { }
};
return C;
}());
@@ -0,0 +1,38 @@
=== tests/cases/compiler/comparabilityTypeParametersRelatedByUnion.ts ===
class C<T> {
>C : Symbol(C, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 0))
>T : Symbol(T, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 8))

constructor(readonly x: T) {}
>x : Symbol(C.x, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 14))
>T : Symbol(T, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 8))

good<U extends T>(y: U) {
>good : Symbol(C.good, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 31))
>U : Symbol(U, Decl(comparabilityTypeParametersRelatedByUnion.ts, 3, 7))
>T : Symbol(T, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 8))
>y : Symbol(y, Decl(comparabilityTypeParametersRelatedByUnion.ts, 3, 20))
>U : Symbol(U, Decl(comparabilityTypeParametersRelatedByUnion.ts, 3, 7))

if (y === this.x) {}
>y : Symbol(y, Decl(comparabilityTypeParametersRelatedByUnion.ts, 3, 20))
>this.x : Symbol(C.x, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 14))
>this : Symbol(C, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 0))
>x : Symbol(C.x, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 14))
}

bad<U extends T | string>(y: U) {
>bad : Symbol(C.bad, Decl(comparabilityTypeParametersRelatedByUnion.ts, 5, 3))
>U : Symbol(U, Decl(comparabilityTypeParametersRelatedByUnion.ts, 7, 6))
>T : Symbol(T, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 8))
>y : Symbol(y, Decl(comparabilityTypeParametersRelatedByUnion.ts, 7, 28))
>U : Symbol(U, Decl(comparabilityTypeParametersRelatedByUnion.ts, 7, 6))

if (y === this.x) {}
>y : Symbol(y, Decl(comparabilityTypeParametersRelatedByUnion.ts, 7, 28))
>this.x : Symbol(C.x, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 14))
>this : Symbol(C, Decl(comparabilityTypeParametersRelatedByUnion.ts, 0, 0))
>x : Symbol(C.x, Decl(comparabilityTypeParametersRelatedByUnion.ts, 1, 14))
}
}

@@ -0,0 +1,32 @@
=== tests/cases/compiler/comparabilityTypeParametersRelatedByUnion.ts ===
class C<T> {
>C : C<T>

constructor(readonly x: T) {}
>x : T

good<U extends T>(y: U) {
>good : <U extends T>(y: U) => void
>y : U

if (y === this.x) {}
>y === this.x : boolean
>y : U
>this.x : T
>this : this
>x : T
}

bad<U extends T | string>(y: U) {
>bad : <U extends string | T>(y: U) => void
>y : U

if (y === this.x) {}
>y === this.x : boolean
>y : U
>this.x : T
>this : this
>x : T
}
}

11 changes: 11 additions & 0 deletions tests/cases/compiler/comparabilityTypeParametersRelatedByUnion.ts
@@ -0,0 +1,11 @@
class C<T> {
constructor(readonly x: T) {}

good<U extends T>(y: U) {
if (y === this.x) {}
}

bad<U extends T | string>(y: U) {
if (y === this.x) {}
}
}

0 comments on commit fbfe934

Please sign in to comment.