From 6fce518f482fac4c18c0b2b24089ad5bccd985db Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Fri, 3 Apr 2026 16:42:28 +0800 Subject: [PATCH 1/4] fix: report error when generic method attempts to implement non-generic interface method --- src/resolver.ts | 23 ++++++++++++++++++- .../compiler/override-typeparam-mismatch.json | 6 +++++ tests/compiler/override-typeparam-mismatch.ts | 12 ++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 tests/compiler/override-typeparam-mismatch.json create mode 100644 tests/compiler/override-typeparam-mismatch.ts diff --git a/src/resolver.ts b/src/resolver.ts index 456aefd6f8..ce158fee58 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -3063,7 +3063,14 @@ export class Resolver extends DiagnosticEmitter { let boundPrototype = classInstance.getMember(unboundOverridePrototype.name); if (boundPrototype) { // might have errored earlier and wasn't added assert(boundPrototype.kind == ElementKind.FunctionPrototype); - overrideInstance = this.resolveFunction(boundPrototype, instance.typeArguments); + let boundFuncPrototype = boundPrototype; + let overrideTypeParams = boundFuncPrototype.typeParameterNodes; + let numOverrideTypeParams = overrideTypeParams ? overrideTypeParams.length : 0; + let baseTypeArgs = instance.typeArguments; + let numBaseTypeArgs = baseTypeArgs ? baseTypeArgs.length : 0; + if (numOverrideTypeParams == numBaseTypeArgs) { + overrideInstance = this.resolveFunction(boundFuncPrototype, baseTypeArgs); + } } } if (overrideInstance) overrides.add(overrideInstance); @@ -3439,6 +3446,20 @@ export class Resolver extends DiagnosticEmitter { default: assert(false); } if (!member.is(CommonFlags.Abstract)) { + // A generic method cannot implement a non-generic interface method + // because monomorphization requires a concrete type to generate code, + // but virtual dispatch through the interface has no type arguments. + let ifaceMember = unimplemented.get(memberName); + if (ifaceMember + && member.kind == ElementKind.FunctionPrototype + && ifaceMember.kind == ElementKind.FunctionPrototype + ) { + let memberTypeParams = (member).typeParameterNodes; + let ifaceTypeParams = (ifaceMember).typeParameterNodes; + let numMemberTypeParams = memberTypeParams ? memberTypeParams.length : 0; + let numIfaceTypeParams = ifaceTypeParams ? ifaceTypeParams.length : 0; + if (numMemberTypeParams != numIfaceTypeParams) continue; + } unimplemented.delete(memberName); } } diff --git a/tests/compiler/override-typeparam-mismatch.json b/tests/compiler/override-typeparam-mismatch.json new file mode 100644 index 0000000000..416bb21b57 --- /dev/null +++ b/tests/compiler/override-typeparam-mismatch.json @@ -0,0 +1,6 @@ +{ + "asc_flags": [], + "stderr": [ + "TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'." + ] +} diff --git a/tests/compiler/override-typeparam-mismatch.ts b/tests/compiler/override-typeparam-mismatch.ts new file mode 100644 index 0000000000..0b271f2b6f --- /dev/null +++ b/tests/compiler/override-typeparam-mismatch.ts @@ -0,0 +1,12 @@ +interface I { + foo(x: i32): i32; +} + +class CC implements I { + foo(x: i32): i32 { + return x; + } +} + +let c:I = new CC(); +c.foo(1); From c1f84f8138147935c80bb4044eb2e1cc4219a133 Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Fri, 3 Apr 2026 17:08:26 +0800 Subject: [PATCH 2/4] Fix --- src/resolver.ts | 7 +++---- tests/compiler/override-typeparam-mismatch.json | 3 ++- tests/compiler/override-typeparam-mismatch.ts | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/resolver.ts b/src/resolver.ts index ce158fee58..ba10bd0a34 100644 --- a/src/resolver.ts +++ b/src/resolver.ts @@ -3449,13 +3449,12 @@ export class Resolver extends DiagnosticEmitter { // A generic method cannot implement a non-generic interface method // because monomorphization requires a concrete type to generate code, // but virtual dispatch through the interface has no type arguments. - let ifaceMember = unimplemented.get(memberName); - if (ifaceMember + if (unimplemented.has(memberName) && member.kind == ElementKind.FunctionPrototype - && ifaceMember.kind == ElementKind.FunctionPrototype + && unimplemented.get(memberName)!.kind == ElementKind.FunctionPrototype ) { let memberTypeParams = (member).typeParameterNodes; - let ifaceTypeParams = (ifaceMember).typeParameterNodes; + let ifaceTypeParams = (unimplemented.get(memberName)).typeParameterNodes; let numMemberTypeParams = memberTypeParams ? memberTypeParams.length : 0; let numIfaceTypeParams = ifaceTypeParams ? ifaceTypeParams.length : 0; if (numMemberTypeParams != numIfaceTypeParams) continue; diff --git a/tests/compiler/override-typeparam-mismatch.json b/tests/compiler/override-typeparam-mismatch.json index 416bb21b57..1ccf848ce0 100644 --- a/tests/compiler/override-typeparam-mismatch.json +++ b/tests/compiler/override-typeparam-mismatch.json @@ -1,6 +1,7 @@ { "asc_flags": [], "stderr": [ - "TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'." + "TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'.", + "EOF" ] } diff --git a/tests/compiler/override-typeparam-mismatch.ts b/tests/compiler/override-typeparam-mismatch.ts index 0b271f2b6f..3e87478b9e 100644 --- a/tests/compiler/override-typeparam-mismatch.ts +++ b/tests/compiler/override-typeparam-mismatch.ts @@ -10,3 +10,5 @@ class CC implements I { let c:I = new CC(); c.foo(1); + +ERROR("EOF"); From fae279c56a8dbdbf0f50d69adb49bc11e2115b6b Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Fri, 3 Apr 2026 17:25:37 +0800 Subject: [PATCH 3/4] Add test --- tests/compiler/override-typeparam-mismatch.json | 1 + tests/compiler/override-typeparam-mismatch.ts | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/tests/compiler/override-typeparam-mismatch.json b/tests/compiler/override-typeparam-mismatch.json index 1ccf848ce0..a80012ff88 100644 --- a/tests/compiler/override-typeparam-mismatch.json +++ b/tests/compiler/override-typeparam-mismatch.json @@ -2,6 +2,7 @@ "asc_flags": [], "stderr": [ "TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'.", + "TS2515: Non-abstract class 'override-typeparam-mismatch/DD' does not implement inherited abstract member 'bar' from 'override-typeparam-mismatch/J'.", "EOF" ] } diff --git a/tests/compiler/override-typeparam-mismatch.ts b/tests/compiler/override-typeparam-mismatch.ts index 3e87478b9e..cc46b89cdc 100644 --- a/tests/compiler/override-typeparam-mismatch.ts +++ b/tests/compiler/override-typeparam-mismatch.ts @@ -11,4 +11,17 @@ class CC implements I { let c:I = new CC(); c.foo(1); +interface J { + bar(x: i32): i32; +} + +class DD implements J { + bar(x: i32): i32 { + return x; + } +} + +let dd:DD = new DD(); +dd.bar(1); + ERROR("EOF"); From dda9bbc93c912b6f3ea7264006f406c969b15005 Mon Sep 17 00:00:00 2001 From: Changqing Jing Date: Fri, 3 Apr 2026 17:31:58 +0800 Subject: [PATCH 4/4] add testcase --- tests/compiler/override-typeparam-mismatch.json | 1 + tests/compiler/override-typeparam-mismatch.ts | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/tests/compiler/override-typeparam-mismatch.json b/tests/compiler/override-typeparam-mismatch.json index a80012ff88..4751c70a92 100644 --- a/tests/compiler/override-typeparam-mismatch.json +++ b/tests/compiler/override-typeparam-mismatch.json @@ -3,6 +3,7 @@ "stderr": [ "TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'.", "TS2515: Non-abstract class 'override-typeparam-mismatch/DD' does not implement inherited abstract member 'bar' from 'override-typeparam-mismatch/J'.", + "TS2515: Non-abstract class 'override-typeparam-mismatch/C2' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I2'.", "EOF" ] } diff --git a/tests/compiler/override-typeparam-mismatch.ts b/tests/compiler/override-typeparam-mismatch.ts index cc46b89cdc..d37bd6d542 100644 --- a/tests/compiler/override-typeparam-mismatch.ts +++ b/tests/compiler/override-typeparam-mismatch.ts @@ -24,4 +24,16 @@ class DD implements J { let dd:DD = new DD(); dd.bar(1); +interface I2 { + foo(x: i32): i32; +} + +class C2 implements I2 { + foo(x: i32): i32 { + return x; + } +} + +new C2().foo(1); + ERROR("EOF");