Final fix verification and code formatting

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-07-15 04:04:34 +00:00
parent c3df353a8d
commit 5754edce4b
5 changed files with 621 additions and 20 deletions

View File

@@ -22143,26 +22143,26 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
(source as NumberLiteralType).value === (target as NumberLiteralType).value
) return true;
if (s & TypeFlags.BigIntLike && t & TypeFlags.BigInt) return true;
if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true;
if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true;
// For comparable relation, revert `this` type parameters back to their constrained class type
if (relation === comparableRelation) {
if (s & TypeFlags.TypeParameter && (source as TypeParameter).isThisType) {
const constraint = getConstraintOfTypeParameter(source as TypeParameter);
if (constraint && isTypeRelatedTo(constraint, target, relation)) {
return true;
}
}
if (t & TypeFlags.TypeParameter && (target as TypeParameter).isThisType) {
const constraint = getConstraintOfTypeParameter(target as TypeParameter);
if (constraint && isTypeRelatedTo(source, constraint, relation)) {
return true;
}
}
}
if (
s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName &&
isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)
if (s & TypeFlags.BooleanLike && t & TypeFlags.Boolean) return true;
if (s & TypeFlags.ESSymbolLike && t & TypeFlags.ESSymbol) return true;
// For comparable relation, revert `this` type parameters back to their constrained class type
if (relation === comparableRelation) {
if (s & TypeFlags.TypeParameter && (source as TypeParameter).isThisType) {
const constraint = getConstraintOfTypeParameter(source as TypeParameter);
if (constraint && isTypeRelatedTo(constraint, target, relation)) {
return true;
}
}
if (t & TypeFlags.TypeParameter && (target as TypeParameter).isThisType) {
const constraint = getConstraintOfTypeParameter(target as TypeParameter);
if (constraint && isTypeRelatedTo(source, constraint, relation)) {
return true;
}
}
}
if (
s & TypeFlags.Enum && t & TypeFlags.Enum && source.symbol.escapedName === target.symbol.escapedName &&
isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)
) return true;
if (s & TypeFlags.EnumLiteral && t & TypeFlags.EnumLiteral) {
if (s & TypeFlags.Union && t & TypeFlags.Union && isEnumTypeRelatedTo(source.symbol, target.symbol, errorReporter)) return true;

View File

@@ -0,0 +1,66 @@
thisTypeComparisonExtended.ts(26,13): error TS2367: This comparison appears to be unintentional because the types 'this' and 'CC' have no overlap.
==== thisTypeComparisonExtended.ts (1 errors) ====
// Test 1: Original issue - this === subclass instance should work
class AA {
do1() {
const b = dd.getB();
if (this === b) { // Should not error
console.log("this === b");
}
}
}
class BB extends AA {
getB(): BB { return this; }
}
let dd = new BB();
dd.do1();
// Test 2: this === unrelated class should still error
class CC {
value: number = 42;
}
class DD {
test() {
const c = new CC();
if (this === c) { // Should still error - no relationship
~~~~~~~~~~
!!! error TS2367: This comparison appears to be unintentional because the types 'this' and 'CC' have no overlap.
console.log("unrelated");
}
}
}
// Test 3: Multiple inheritance levels
class EE extends BB {
getE(): EE { return this; }
}
class FF extends EE {
testMultiLevel() {
const e = new EE();
if (this === e) { // Should not error - FF extends EE
console.log("multi-level inheritance");
}
}
}
// Test 4: Interface implementation
interface ITest {
getValue(): number;
}
class GG implements ITest {
getValue() { return 42; }
testInterface() {
const impl: ITest = new GG();
if (this === impl) { // Should not error
console.log("interface implementation");
}
}
}

View File

@@ -0,0 +1,155 @@
//// [tests/cases/compiler/thisTypeComparisonExtended.ts] ////
//// [thisTypeComparisonExtended.ts]
// Test 1: Original issue - this === subclass instance should work
class AA {
do1() {
const b = dd.getB();
if (this === b) { // Should not error
console.log("this === b");
}
}
}
class BB extends AA {
getB(): BB { return this; }
}
let dd = new BB();
dd.do1();
// Test 2: this === unrelated class should still error
class CC {
value: number = 42;
}
class DD {
test() {
const c = new CC();
if (this === c) { // Should still error - no relationship
console.log("unrelated");
}
}
}
// Test 3: Multiple inheritance levels
class EE extends BB {
getE(): EE { return this; }
}
class FF extends EE {
testMultiLevel() {
const e = new EE();
if (this === e) { // Should not error - FF extends EE
console.log("multi-level inheritance");
}
}
}
// Test 4: Interface implementation
interface ITest {
getValue(): number;
}
class GG implements ITest {
getValue() { return 42; }
testInterface() {
const impl: ITest = new GG();
if (this === impl) { // Should not error
console.log("interface implementation");
}
}
}
//// [thisTypeComparisonExtended.js]
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
// Test 1: Original issue - this === subclass instance should work
var AA = /** @class */ (function () {
function AA() {
}
AA.prototype.do1 = function () {
var b = dd.getB();
if (this === b) { // Should not error
console.log("this === b");
}
};
return AA;
}());
var BB = /** @class */ (function (_super) {
__extends(BB, _super);
function BB() {
return _super !== null && _super.apply(this, arguments) || this;
}
BB.prototype.getB = function () { return this; };
return BB;
}(AA));
var dd = new BB();
dd.do1();
// Test 2: this === unrelated class should still error
var CC = /** @class */ (function () {
function CC() {
this.value = 42;
}
return CC;
}());
var DD = /** @class */ (function () {
function DD() {
}
DD.prototype.test = function () {
var c = new CC();
if (this === c) { // Should still error - no relationship
console.log("unrelated");
}
};
return DD;
}());
// Test 3: Multiple inheritance levels
var EE = /** @class */ (function (_super) {
__extends(EE, _super);
function EE() {
return _super !== null && _super.apply(this, arguments) || this;
}
EE.prototype.getE = function () { return this; };
return EE;
}(BB));
var FF = /** @class */ (function (_super) {
__extends(FF, _super);
function FF() {
return _super !== null && _super.apply(this, arguments) || this;
}
FF.prototype.testMultiLevel = function () {
var e = new EE();
if (this === e) { // Should not error - FF extends EE
console.log("multi-level inheritance");
}
};
return FF;
}(EE));
var GG = /** @class */ (function () {
function GG() {
}
GG.prototype.getValue = function () { return 42; };
GG.prototype.testInterface = function () {
var impl = new GG();
if (this === impl) { // Should not error
console.log("interface implementation");
}
};
return GG;
}());

View File

@@ -0,0 +1,145 @@
//// [tests/cases/compiler/thisTypeComparisonExtended.ts] ////
=== thisTypeComparisonExtended.ts ===
// Test 1: Original issue - this === subclass instance should work
class AA {
>AA : Symbol(AA, Decl(thisTypeComparisonExtended.ts, 0, 0))
do1() {
>do1 : Symbol(AA.do1, Decl(thisTypeComparisonExtended.ts, 1, 10))
const b = dd.getB();
>b : Symbol(b, Decl(thisTypeComparisonExtended.ts, 3, 13))
>dd.getB : Symbol(BB.getB, Decl(thisTypeComparisonExtended.ts, 10, 21))
>dd : Symbol(dd, Decl(thisTypeComparisonExtended.ts, 14, 3))
>getB : Symbol(BB.getB, Decl(thisTypeComparisonExtended.ts, 10, 21))
if (this === b) { // Should not error
>this : Symbol(AA, Decl(thisTypeComparisonExtended.ts, 0, 0))
>b : Symbol(b, Decl(thisTypeComparisonExtended.ts, 3, 13))
console.log("this === b");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}
}
}
class BB extends AA {
>BB : Symbol(BB, Decl(thisTypeComparisonExtended.ts, 8, 1))
>AA : Symbol(AA, Decl(thisTypeComparisonExtended.ts, 0, 0))
getB(): BB { return this; }
>getB : Symbol(BB.getB, Decl(thisTypeComparisonExtended.ts, 10, 21))
>BB : Symbol(BB, Decl(thisTypeComparisonExtended.ts, 8, 1))
>this : Symbol(BB, Decl(thisTypeComparisonExtended.ts, 8, 1))
}
let dd = new BB();
>dd : Symbol(dd, Decl(thisTypeComparisonExtended.ts, 14, 3))
>BB : Symbol(BB, Decl(thisTypeComparisonExtended.ts, 8, 1))
dd.do1();
>dd.do1 : Symbol(AA.do1, Decl(thisTypeComparisonExtended.ts, 1, 10))
>dd : Symbol(dd, Decl(thisTypeComparisonExtended.ts, 14, 3))
>do1 : Symbol(AA.do1, Decl(thisTypeComparisonExtended.ts, 1, 10))
// Test 2: this === unrelated class should still error
class CC {
>CC : Symbol(CC, Decl(thisTypeComparisonExtended.ts, 15, 9))
value: number = 42;
>value : Symbol(CC.value, Decl(thisTypeComparisonExtended.ts, 18, 10))
}
class DD {
>DD : Symbol(DD, Decl(thisTypeComparisonExtended.ts, 20, 1))
test() {
>test : Symbol(DD.test, Decl(thisTypeComparisonExtended.ts, 22, 10))
const c = new CC();
>c : Symbol(c, Decl(thisTypeComparisonExtended.ts, 24, 13))
>CC : Symbol(CC, Decl(thisTypeComparisonExtended.ts, 15, 9))
if (this === c) { // Should still error - no relationship
>this : Symbol(DD, Decl(thisTypeComparisonExtended.ts, 20, 1))
>c : Symbol(c, Decl(thisTypeComparisonExtended.ts, 24, 13))
console.log("unrelated");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}
}
}
// Test 3: Multiple inheritance levels
class EE extends BB {
>EE : Symbol(EE, Decl(thisTypeComparisonExtended.ts, 29, 1))
>BB : Symbol(BB, Decl(thisTypeComparisonExtended.ts, 8, 1))
getE(): EE { return this; }
>getE : Symbol(EE.getE, Decl(thisTypeComparisonExtended.ts, 32, 21))
>EE : Symbol(EE, Decl(thisTypeComparisonExtended.ts, 29, 1))
>this : Symbol(EE, Decl(thisTypeComparisonExtended.ts, 29, 1))
}
class FF extends EE {
>FF : Symbol(FF, Decl(thisTypeComparisonExtended.ts, 34, 1))
>EE : Symbol(EE, Decl(thisTypeComparisonExtended.ts, 29, 1))
testMultiLevel() {
>testMultiLevel : Symbol(FF.testMultiLevel, Decl(thisTypeComparisonExtended.ts, 36, 21))
const e = new EE();
>e : Symbol(e, Decl(thisTypeComparisonExtended.ts, 38, 13))
>EE : Symbol(EE, Decl(thisTypeComparisonExtended.ts, 29, 1))
if (this === e) { // Should not error - FF extends EE
>this : Symbol(FF, Decl(thisTypeComparisonExtended.ts, 34, 1))
>e : Symbol(e, Decl(thisTypeComparisonExtended.ts, 38, 13))
console.log("multi-level inheritance");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}
}
}
// Test 4: Interface implementation
interface ITest {
>ITest : Symbol(ITest, Decl(thisTypeComparisonExtended.ts, 43, 1))
getValue(): number;
>getValue : Symbol(ITest.getValue, Decl(thisTypeComparisonExtended.ts, 46, 17))
}
class GG implements ITest {
>GG : Symbol(GG, Decl(thisTypeComparisonExtended.ts, 48, 1))
>ITest : Symbol(ITest, Decl(thisTypeComparisonExtended.ts, 43, 1))
getValue() { return 42; }
>getValue : Symbol(GG.getValue, Decl(thisTypeComparisonExtended.ts, 50, 27))
testInterface() {
>testInterface : Symbol(GG.testInterface, Decl(thisTypeComparisonExtended.ts, 51, 29))
const impl: ITest = new GG();
>impl : Symbol(impl, Decl(thisTypeComparisonExtended.ts, 54, 13))
>ITest : Symbol(ITest, Decl(thisTypeComparisonExtended.ts, 43, 1))
>GG : Symbol(GG, Decl(thisTypeComparisonExtended.ts, 48, 1))
if (this === impl) { // Should not error
>this : Symbol(GG, Decl(thisTypeComparisonExtended.ts, 48, 1))
>impl : Symbol(impl, Decl(thisTypeComparisonExtended.ts, 54, 13))
console.log("interface implementation");
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
}
}
}

View File

@@ -0,0 +1,235 @@
//// [tests/cases/compiler/thisTypeComparisonExtended.ts] ////
=== thisTypeComparisonExtended.ts ===
// Test 1: Original issue - this === subclass instance should work
class AA {
>AA : AA
> : ^^
do1() {
>do1 : () => void
> : ^^^^^^^^^^
const b = dd.getB();
>b : BB
> : ^^
>dd.getB() : BB
> : ^^
>dd.getB : () => BB
> : ^^^^^^
>dd : BB
> : ^^
>getB : () => BB
> : ^^^^^^
if (this === b) { // Should not error
>this === b : boolean
> : ^^^^^^^
>this : this
> : ^^^^
>b : BB
> : ^^
console.log("this === b");
>console.log("this === b") : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"this === b" : "this === b"
> : ^^^^^^^^^^^^
}
}
}
class BB extends AA {
>BB : BB
> : ^^
>AA : AA
> : ^^
getB(): BB { return this; }
>getB : () => BB
> : ^^^^^^
>this : this
> : ^^^^
}
let dd = new BB();
>dd : BB
> : ^^
>new BB() : BB
> : ^^
>BB : typeof BB
> : ^^^^^^^^^
dd.do1();
>dd.do1() : void
> : ^^^^
>dd.do1 : () => void
> : ^^^^^^^^^^
>dd : BB
> : ^^
>do1 : () => void
> : ^^^^^^^^^^
// Test 2: this === unrelated class should still error
class CC {
>CC : CC
> : ^^
value: number = 42;
>value : number
> : ^^^^^^
>42 : 42
> : ^^
}
class DD {
>DD : DD
> : ^^
test() {
>test : () => void
> : ^^^^^^^^^^
const c = new CC();
>c : CC
> : ^^
>new CC() : CC
> : ^^
>CC : typeof CC
> : ^^^^^^^^^
if (this === c) { // Should still error - no relationship
>this === c : boolean
> : ^^^^^^^
>this : this
> : ^^^^
>c : CC
> : ^^
console.log("unrelated");
>console.log("unrelated") : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"unrelated" : "unrelated"
> : ^^^^^^^^^^^
}
}
}
// Test 3: Multiple inheritance levels
class EE extends BB {
>EE : EE
> : ^^
>BB : BB
> : ^^
getE(): EE { return this; }
>getE : () => EE
> : ^^^^^^
>this : this
> : ^^^^
}
class FF extends EE {
>FF : FF
> : ^^
>EE : EE
> : ^^
testMultiLevel() {
>testMultiLevel : () => void
> : ^^^^^^^^^^
const e = new EE();
>e : EE
> : ^^
>new EE() : EE
> : ^^
>EE : typeof EE
> : ^^^^^^^^^
if (this === e) { // Should not error - FF extends EE
>this === e : boolean
> : ^^^^^^^
>this : this
> : ^^^^
>e : EE
> : ^^
console.log("multi-level inheritance");
>console.log("multi-level inheritance") : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"multi-level inheritance" : "multi-level inheritance"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
}
// Test 4: Interface implementation
interface ITest {
getValue(): number;
>getValue : () => number
> : ^^^^^^
}
class GG implements ITest {
>GG : GG
> : ^^
getValue() { return 42; }
>getValue : () => number
> : ^^^^^^^^^^^^
>42 : 42
> : ^^
testInterface() {
>testInterface : () => void
> : ^^^^^^^^^^
const impl: ITest = new GG();
>impl : ITest
> : ^^^^^
>new GG() : GG
> : ^^
>GG : typeof GG
> : ^^^^^^^^^
if (this === impl) { // Should not error
>this === impl : boolean
> : ^^^^^^^
>this : this
> : ^^^^
>impl : ITest
> : ^^^^^
console.log("interface implementation");
>console.log("interface implementation") : void
> : ^^^^
>console.log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>console : Console
> : ^^^^^^^
>log : (...data: any[]) => void
> : ^^^^ ^^ ^^^^^
>"interface implementation" : "interface implementation"
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^
}
}
}