Skip to content

Commit 54dd10a

Browse files
forbidden interface function and generic function to be generic
1 parent dda9bbc commit 54dd10a

5 files changed

Lines changed: 61 additions & 20 deletions

File tree

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"Initializer, definitive assignment or nullable type expected.": 238,
5353
"Definitive assignment has no effect on local variables.": 239,
5454
"Ambiguous operator overload '{0}' (conflicting overloads '{1}' and '{2}').": 240,
55+
"An interface or abstract method '{0}' cannot have type parameters.": 241,
5556

5657
"Importing the table disables some indirect call optimizations.": 901,
5758
"Exporting the table disables some indirect call optimizations.": 902,

src/program.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2079,6 +2079,13 @@ export class Program extends DiagnosticEmitter {
20792079
}
20802080
case NodeKind.MethodDeclaration: {
20812081
let methodDeclaration = <MethodDeclaration>memberDeclaration;
2082+
if (methodDeclaration.is(CommonFlags.Abstract) && methodDeclaration.is(CommonFlags.Generic)) {
2083+
this.error(
2084+
DiagnosticCode.An_interface_or_abstract_method_0_cannot_have_type_parameters,
2085+
methodDeclaration.name.range,
2086+
methodDeclaration.name.text
2087+
);
2088+
}
20822089
if (memberDeclaration.isAny(CommonFlags.Get | CommonFlags.Set)) {
20832090
this.initializeProperty(methodDeclaration, element);
20842091
} else {
@@ -2653,6 +2660,13 @@ export class Program extends DiagnosticEmitter {
26532660
}
26542661
case NodeKind.MethodDeclaration: {
26552662
let methodDeclaration = <MethodDeclaration>memberDeclaration;
2663+
if (methodDeclaration.is(CommonFlags.Generic)) {
2664+
this.error(
2665+
DiagnosticCode.An_interface_or_abstract_method_0_cannot_have_type_parameters,
2666+
methodDeclaration.name.range,
2667+
methodDeclaration.name.text
2668+
);
2669+
}
26562670
if (memberDeclaration.isAny(CommonFlags.Get | CommonFlags.Set)) {
26572671
this.initializeProperty(methodDeclaration, element);
26582672
} else {

src/resolver.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,12 +3064,17 @@ export class Resolver extends DiagnosticEmitter {
30643064
if (boundPrototype) { // might have errored earlier and wasn't added
30653065
assert(boundPrototype.kind == ElementKind.FunctionPrototype);
30663066
let boundFuncPrototype = <FunctionPrototype>boundPrototype;
3067-
let overrideTypeParams = boundFuncPrototype.typeParameterNodes;
3068-
let numOverrideTypeParams = overrideTypeParams ? overrideTypeParams.length : 0;
3069-
let baseTypeArgs = instance.typeArguments;
3070-
let numBaseTypeArgs = baseTypeArgs ? baseTypeArgs.length : 0;
3071-
if (numOverrideTypeParams == numBaseTypeArgs) {
3072-
overrideInstance = this.resolveFunction(boundFuncPrototype, baseTypeArgs);
3067+
// Only resolve the override when the generic-ness matches the base method.
3068+
// - generic child → non-generic base: skip; vtable dispatch site has no type
3069+
// arguments to forward to the monomorphized child.
3070+
// - generic child → generic base: OK; type args come from the base call site.
3071+
// - non-generic child → non-generic base: OK; plain vtable override.
3072+
// FIXME: non-generic child → generic base is also mismatched (resolveFunction
3073+
// would assert on typeArguments/typeParameterNodes length mismatch) but that
3074+
// case is not yet guarded here. The correct fix is to replace this condition
3075+
// with `boundFuncPrototype.is(Generic) == instance.is(Generic)`.
3076+
if (!boundFuncPrototype.is(CommonFlags.Generic) || instance.is(CommonFlags.Generic)) {
3077+
overrideInstance = this.resolveFunction(boundFuncPrototype, instance.typeArguments);
30733078
}
30743079
}
30753080
}
@@ -3445,20 +3450,10 @@ export class Resolver extends DiagnosticEmitter {
34453450
}
34463451
default: assert(false);
34473452
}
3448-
if (!member.is(CommonFlags.Abstract)) {
3449-
// A generic method cannot implement a non-generic interface method
3450-
// because monomorphization requires a concrete type to generate code,
3451-
// but virtual dispatch through the interface has no type arguments.
3452-
if (unimplemented.has(memberName)
3453-
&& member.kind == ElementKind.FunctionPrototype
3454-
&& unimplemented.get(memberName)!.kind == ElementKind.FunctionPrototype
3455-
) {
3456-
let memberTypeParams = (<FunctionPrototype>member).typeParameterNodes;
3457-
let ifaceTypeParams = (<FunctionPrototype>unimplemented.get(memberName)).typeParameterNodes;
3458-
let numMemberTypeParams = memberTypeParams ? memberTypeParams.length : 0;
3459-
let numIfaceTypeParams = ifaceTypeParams ? ifaceTypeParams.length : 0;
3460-
if (numMemberTypeParams != numIfaceTypeParams) continue;
3461-
}
3453+
if (!member.is(CommonFlags.Abstract) && !member.is(CommonFlags.Generic)) {
3454+
// A generic method cannot satisfy a non-generic interface/abstract
3455+
// requirement: interface methods cannot be generic (AS241), and
3456+
// virtual dispatch cannot supply type arguments for monomorphization.
34623457
unimplemented.delete(memberName);
34633458
}
34643459
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
{
22
"asc_flags": [],
33
"stderr": [
4+
"AS241: An interface or abstract method 'foo' cannot have type parameters.",
5+
"AS241: An interface or abstract method 'baz' cannot have type parameters.",
46
"TS2515: Non-abstract class 'override-typeparam-mismatch/CC' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I'.",
57
"TS2515: Non-abstract class 'override-typeparam-mismatch/DD' does not implement inherited abstract member 'bar' from 'override-typeparam-mismatch/J'.",
68
"TS2515: Non-abstract class 'override-typeparam-mismatch/C2' does not implement inherited abstract member 'foo' from 'override-typeparam-mismatch/I2'.",
9+
"TS2515: Non-abstract class 'override-typeparam-mismatch/FF' does not implement inherited abstract member 'baz' from 'override-typeparam-mismatch/A1'.",
10+
"TS2515: Non-abstract class 'override-typeparam-mismatch/GG' does not implement inherited abstract member 'qux' from 'override-typeparam-mismatch/A2'.",
711
"EOF"
812
]
913
}

tests/compiler/override-typeparam-mismatch.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,31 @@ class C2 implements I2 {
3636

3737
new C2().foo<i32>(1);
3838

39+
// abstract method cannot be generic (AS241)
40+
abstract class A1 {
41+
abstract baz<T>(x: i32): i32;
42+
}
43+
44+
class FF extends A1 {
45+
baz<T>(x: i32): i32 {
46+
return x;
47+
}
48+
}
49+
50+
new FF().baz<i32>(1);
51+
52+
// generic method cannot implement non-generic abstract method (TS2515)
53+
abstract class A2 {
54+
abstract qux(x: i32): i32;
55+
}
56+
57+
class GG extends A2 {
58+
qux<T>(x: i32): i32 {
59+
return x;
60+
}
61+
}
62+
63+
let a: A2 = new GG();
64+
a.qux(1);
65+
3966
ERROR("EOF");

0 commit comments

Comments
 (0)