Skip to content

Commit

Permalink
fix: Type checker does not detect a signature mismatch
Browse files Browse the repository at this point in the history
Fixes: #2727
  • Loading branch information
Changqing-JING authored Oct 1, 2023
1 parent eedf306 commit 927b7cd
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 21 deletions.
11 changes: 6 additions & 5 deletions src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6609,17 +6609,18 @@ export class Compiler extends DiagnosticEmitter {
for (let i = 0, k = overrideInstances.length; i < k; ++i) {
let overrideInstance = overrideInstances[i];
if (!overrideInstance.is(CommonFlags.Compiled)) continue; // errored
let overrideType = overrideInstance.type;
let originalType = instance.type;
if (!overrideType.isAssignableTo(originalType)) {

let overrideSignature = overrideInstance.signature;
let originalSignature = instance.signature;

if (!overrideSignature.isAssignableTo(originalSignature, true)) {
this.error(
DiagnosticCode.Type_0_is_not_assignable_to_type_1,
overrideInstance.identifierNode.range, overrideType.toString(), originalType.toString()
overrideInstance.identifierNode.range, overrideSignature.toString(), originalSignature.toString()
);
continue;
}
// TODO: additional optional parameters are not permitted by `isAssignableTo` yet
let overrideSignature = overrideInstance.signature;
let overrideParameterTypes = overrideSignature.parameterTypes;
let overrideNumParameters = overrideParameterTypes.length;
let paramExprs = new Array<ExpressionRef>(1 + overrideNumParameters);
Expand Down
24 changes: 8 additions & 16 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,22 +1051,14 @@ export class Signature {
isAssignableTo(target: Signature, checkCompatibleOverride: bool = false): bool {
let thisThisType = this.thisType;
let targetThisType = target.thisType;
if (checkCompatibleOverride) {
// check kind of `this` type
if (thisThisType) {
if (!targetThisType || !thisThisType.canExtendOrImplement(targetThisType)) {
return false;
}
} else if (targetThisType) {
return false;
}
} else {
// check `this` type (invariant)
if (thisThisType) {
if (targetThisType != targetThisType) return false;
} else if (targetThisType) {
return false;
}

if (thisThisType && targetThisType) {
const compatibleThisType = checkCompatibleOverride
? thisThisType.canExtendOrImplement(targetThisType)
: targetThisType.isAssignableTo(thisThisType);
if (!compatibleThisType) return false;
} else if (thisThisType || targetThisType) {
return false;
}

// check rest parameter
Expand Down
8 changes: 8 additions & 0 deletions tests/compiler/class-member-function-as-parameter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"asc_flags": [],
"stderr": [
"TS2322: Type '() => void' is not assignable to type '(this: class-member-function-as-parameter/A) => void'.",
"TS2322: Type '(this: class-member-function-as-parameter/B) => void' is not assignable to type '(this: class-member-function-as-parameter/A) => void'.",
"EOF"
]
}
20 changes: 20 additions & 0 deletions tests/compiler/class-member-function-as-parameter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class A {
foo(): void { }
}

class B extends A {
foo(): void { }
}

function foo(): void { }

function consumeA(callback: (this: A) => void): void { }
function consumeB(callback: (this: B) => void): void { }

const a = new A();
const b = new B();

consumeB(a.foo); // shouldn't error
consumeA(foo); // should error
consumeA(b.foo); // should error
ERROR("EOF");

0 comments on commit 927b7cd

Please sign in to comment.