From cbe74d63cf9243803f36c820747a1e8cc77be25e Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Mon, 31 Jul 2023 14:10:09 +0800 Subject: [PATCH] bug fix 2727: class member function type is assigned to a normal function type --- src/compiler.ts | 4 +- src/types.ts | 28 +++++----- .../class-member-function-as-parameter.json | 8 +++ .../class-member-function-as-parameter.ts | 52 +++++++++++++++++++ 4 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 tests/compiler/class-member-function-as-parameter.json create mode 100644 tests/compiler/class-member-function-as-parameter.ts diff --git a/src/compiler.ts b/src/compiler.ts index a2b313603b..43ffd7ba72 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -6611,7 +6611,9 @@ export class Compiler extends DiagnosticEmitter { if (!overrideInstance.is(CommonFlags.Compiled)) continue; // errored let overrideType = overrideInstance.type; let originalType = instance.type; - if (!overrideType.isAssignableTo(originalType)) { + + assert(originalType.getSignature() != null && overrideType.getSignature() != null); + if (!(overrideType.getSignature() as Signature).isAssignableTo(originalType.getSignature() as Signature, true)) { this.error( DiagnosticCode.Type_0_is_not_assignable_to_type_1, overrideInstance.identifierNode.range, overrideType.toString(), originalType.toString() diff --git a/src/types.ts b/src/types.ts index 4aef00a5b2..5ebf847829 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1051,21 +1051,23 @@ 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)) { + + if ( + (thisThisType == null && targetThisType != null) || + (thisThisType != null && targetThisType == null) + ) { + return false; + }else if(thisThisType != null && targetThisType != null){ + if(checkCompatibleOverride){ + // check kind of `this` type + if(!thisThisType.canExtendOrImplement(targetThisType)){ + return false; + } + }else{ + // check `this` type (invariant) + if(targetThisType.isAssignableTo(thisThisType)){ return false; } - } else if (targetThisType) { - return false; - } - } else { - // check `this` type (invariant) - if (thisThisType) { - if (targetThisType != targetThisType) return false; - } else if (targetThisType) { - return false; } } diff --git a/tests/compiler/class-member-function-as-parameter.json b/tests/compiler/class-member-function-as-parameter.json new file mode 100644 index 0000000000..60bb912d81 --- /dev/null +++ b/tests/compiler/class-member-function-as-parameter.json @@ -0,0 +1,8 @@ +{ + "asc_flags": [], + "stderr": [ + "TS2322: Type '(this: class-member-function-as-parameter/C, i32) => i32' is not assignable to type '(i32) => i32'.", + "TS2322: Type '() => void' is not assignable to type '(this: class-member-function-as-parameter/B) => void'.", + "EOF" + ] +} diff --git a/tests/compiler/class-member-function-as-parameter.ts b/tests/compiler/class-member-function-as-parameter.ts new file mode 100644 index 0000000000..2bbce497bf --- /dev/null +++ b/tests/compiler/class-member-function-as-parameter.ts @@ -0,0 +1,52 @@ +class C { + aa: i32 = 1; + callback(a: i32): i32 { + return this.aa + a + 3; + } +} + +function expectCallback(c1: (arg0: i32) => i32): i32 { + return c1(4); +} + +export function fut(): i32 { + const c1 = new C(); + return expectCallback(c1.callback); +} + +fut(); + +class A { + foo(): void { + console.log("A"); + } +} + +class B extends A { + foo(): void { + console.log("B"); + } +} + +function foo(): void { + console.log("nothing"); +} + +function consume(callback: (this: B) => void): void { + const b = new B(); + callback.call(b); +} + +export function testNull(): void { + consume(foo); // This should (and does) error; this is fine. +} + +export function testA(): void { + const a = new A(); + consume(a.foo); // This shouldn't error +} + +testNull(); +testA(); + +ERROR("EOF"); \ No newline at end of file