Skip to content

Commit dfc8a65

Browse files
authored
fix: strictly check operator overload ambiguity (#2762)
Operator overload is an internal mechanism, it can support to compare user-defined class, but it need to be limited. a == b and b == a should run the same function and get the same result in semantic level. Allowing ambiguity is bug prone.
1 parent 1847c8f commit dfc8a65

10 files changed

+4549
-233
lines changed

‎src/compiler.ts‎

Lines changed: 185 additions & 230 deletions
Large diffs are not rendered by default.

‎src/diagnosticMessages.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"Index signature accessors in type '{0}' differ in types.": 237,
5252
"Initializer, definitive assignment or nullable type expected.": 238,
5353
"Definitive assignment has no effect on local variables.": 239,
54+
"Ambiguous operator overload '{0}' (conflicting overloads '{1}' and '{2}').": 240,
5455

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

‎src/program.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,10 @@ export namespace OperatorKind{
390390
caseToken.GreaterThan_GreaterThan_Equals: returnOperatorKind.BitwiseShr;
391391
caseToken.GreaterThan_GreaterThan_GreaterThan:
392392
caseToken.GreaterThan_GreaterThan_GreaterThan_Equals: returnOperatorKind.BitwiseShrU;
393-
caseToken.Equals_Equals: returnOperatorKind.Eq;
394-
caseToken.Exclamation_Equals: returnOperatorKind.Ne;
393+
caseToken.Equals_Equals:
394+
caseToken.Equals_Equals_Equals: returnOperatorKind.Eq;
395+
caseToken.Exclamation_Equals:
396+
caseToken.Exclamation_Equals_Equals: returnOperatorKind.Ne;
395397
caseToken.GreaterThan: returnOperatorKind.Gt;
396398
caseToken.GreaterThan_Equals: returnOperatorKind.Ge;
397399
caseToken.LessThan: returnOperatorKind.Lt;

‎src/types.ts‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import{
1010
import{
1111
Class,
1212
Program,
13-
DecoratorFlags
13+
DecoratorFlags,
14+
OperatorKind,
15+
Function
1416
}from"./program";
1517

1618
import{
@@ -320,6 +322,14 @@ export class Type{
320322
returnnull;
321323
}
322324

325+
lookupOverload(kind: OperatorKind,program: Program): Function|null{
326+
letclassReference=this.getClassOrWrapper(program);
327+
if(classReference){
328+
returnclassReference.lookupOverload(kind);
329+
}
330+
returnnull;
331+
}
332+
323333
/** Gets the underlying function signature of this type, if any. */
324334
getSignature(): Signature|null{
325335
returnthis.isInternalReference
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"asc_flags": [],
3+
"stderr": [
4+
"AS240: Ambiguous operator overload '==' (conflicting overloads 'operator-overload-ambiguity/A#__eq' and 'operator-overload-ambiguity/B#__eq').",
5+
"compare_nonnull_a == compare_nonnull_b;",
6+
"AS240: Ambiguous operator overload '==' (conflicting overloads 'operator-overload-ambiguity/B#__eq' and 'operator-overload-ambiguity/A#__eq').",
7+
"compare_nonnull_b == compare_nonnull_a;",
8+
"AS240: Ambiguous operator overload '==' (conflicting overloads 'operator-overload-ambiguity/C.__eq' and 'operator-overload-ambiguity/D#__eq').",
9+
"compare_nonnull_c == compare_nonnull_d;",
10+
"AS240: Ambiguous operator overload '==' (conflicting overloads 'operator-overload-ambiguity/A#__eq' and 'operator-overload-ambiguity/B#__eq').",
11+
"compare_extend_1 == compare_extend_2;",
12+
"EOF"
13+
]
14+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
classA{
2+
@operator("==")__eq(other: B): bool{
3+
returntrue;
4+
}
5+
}
6+
classB{
7+
@operator("==")__eq(other: A): bool{
8+
returntrue;
9+
}
10+
}
11+
exportfunctioncompare_nonnull(compare_nonnull_a: A,compare_nonnull_b: B): void{
12+
compare_nonnull_a==compare_nonnull_b;
13+
compare_nonnull_b==compare_nonnull_a;
14+
}
15+
16+
classC{
17+
@operator("==")static__eq(self: C|null,other: D|null): bool{
18+
returntrue;
19+
}
20+
}
21+
classD{
22+
@operator("==")__eq(other: i32): bool{
23+
returntrue;
24+
}
25+
}
26+
exportfunctioncompare_null(compare_nonnull_c: C|null,compare_nonnull_d: D|null): void{
27+
compare_nonnull_c==compare_nonnull_d;
28+
}
29+
30+
classPAextendsA{}
31+
classPBextendsB{}
32+
exportfunctioncompare_extend(compare_extend_1: PA,compare_extend_2: PB): void{
33+
compare_extend_1==compare_extend_2;
34+
}
35+
36+
exportfunctionend(): void{
37+
ERROR("EOF");
38+
}

0 commit comments

Comments
(0)