[fasta] Make forwarding stubs operators if their source are operators

Change-Id: I516c0ac9ccf93770cc331b1c7569df1a1c16659c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/102160
Reviewed-by: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
index dafd56c3..5aa6fb8 100644
--- a/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/class_hierarchy_builder.dart
@@ -2313,6 +2313,9 @@
     ProcedureKind kind = ProcedureKind.Method;
     if (bestSoFar.isField || bestSoFar.isSetter || bestSoFar.isGetter) {
       kind = isSetter ? ProcedureKind.Setter : ProcedureKind.Getter;
+    } else if (bestSoFar.target is Procedure &&
+        bestSoFar.target.kind == ProcedureKind.Operator) {
+      kind = ProcedureKind.Operator;
     }
 
     if (modifyKernel) {
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart b/pkg/front_end/testcases/forwarding_stub_for_operator.dart
new file mode 100644
index 0000000..e604fe0
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2019, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+//------------------------------------------------------------------------------
+
+class A {
+  dynamic operator+(covariant int a) => null;
+}
+
+class B {
+  dynamic operator+(dynamic b) => null;
+}
+
+abstract class C implements A, B {}
+
+//------------------------------------------------------------------------------
+
+class D {
+  dynamic operator+(dynamic d) => null;
+}
+
+class E extends D {
+  dynamic operator+(covariant int e);
+}
+
+//------------------------------------------------------------------------------
+
+main() {}
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.hierarchy.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.hierarchy.expect
new file mode 100644
index 0000000..d5d1da9
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.hierarchy.expect
@@ -0,0 +1,123 @@
+Object:
+  superclasses:
+  interfaces:
+  classMembers:
+    Object._haveSameRuntimeType
+    Object.toString
+    Object.runtimeType
+    Object._toString
+    Object._simpleInstanceOf
+    Object._hashCodeRnd
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._objectHashCode
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+
+A:
+  superclasses:
+    Object
+  interfaces:
+  classMembers:
+    Object.toString
+    A.+
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+
+B:
+  superclasses:
+    Object
+  interfaces:
+  classMembers:
+    Object.toString
+    B.+
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+
+C:
+  Longest path to Object: 2
+  superclasses:
+    Object
+  interfaces: A, B
+  classMembers:
+    Object.toString
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+  interfaceMembers:
+    Object.toString
+    C.A.+%B.+
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  interfaceSetters:
+
+D:
+  superclasses:
+    Object
+  interfaces:
+  classMembers:
+    Object.toString
+    D.+
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+
+E:
+  superclasses:
+    Object
+      -> D
+  interfaces:
+  classMembers:
+    Object.toString
+    E.D.+%E.+
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.expect
new file mode 100644
index 0000000..84a1b42
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  operator +(covariant core::int a) → dynamic
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  operator +(dynamic b) → dynamic
+    return null;
+}
+abstract class C extends core::Object implements self::A, self::B {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  abstract forwarding-stub operator +(covariant dynamic b) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → self::D
+    : super core::Object::•()
+    ;
+  operator +(dynamic d) → dynamic
+    return null;
+}
+class E extends self::D {
+  synthetic constructor •() → self::E
+    : super self::D::•()
+    ;
+  forwarding-stub forwarding-semi-stub operator +(covariant core::int e) → dynamic
+    return super.{self::D::+}(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.transformed.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.transformed.expect
new file mode 100644
index 0000000..84a1b42
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.legacy.transformed.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  operator +(covariant core::int a) → dynamic
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  operator +(dynamic b) → dynamic
+    return null;
+}
+abstract class C extends core::Object implements self::A, self::B {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  abstract forwarding-stub operator +(covariant dynamic b) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → self::D
+    : super core::Object::•()
+    ;
+  operator +(dynamic d) → dynamic
+    return null;
+}
+class E extends self::D {
+  synthetic constructor •() → self::E
+    : super self::D::•()
+    ;
+  forwarding-stub forwarding-semi-stub operator +(covariant core::int e) → dynamic
+    return super.{self::D::+}(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.outline.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.outline.expect
new file mode 100644
index 0000000..14a8eef
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.outline.expect
@@ -0,0 +1,35 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  operator +(covariant core::int a) → dynamic
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    ;
+  operator +(dynamic b) → dynamic
+    ;
+}
+abstract class C extends core::Object implements self::A, self::B {
+  synthetic constructor •() → self::C
+    ;
+  abstract forwarding-stub operator +(covariant dynamic b) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → self::D
+    ;
+  operator +(dynamic d) → dynamic
+    ;
+}
+class E extends self::D {
+  synthetic constructor •() → self::E
+    ;
+  forwarding-stub forwarding-semi-stub operator +(covariant core::int e) → dynamic
+    return super.{self::D::+}(e);
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.expect
new file mode 100644
index 0000000..84a1b42
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  operator +(covariant core::int a) → dynamic
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  operator +(dynamic b) → dynamic
+    return null;
+}
+abstract class C extends core::Object implements self::A, self::B {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  abstract forwarding-stub operator +(covariant dynamic b) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → self::D
+    : super core::Object::•()
+    ;
+  operator +(dynamic d) → dynamic
+    return null;
+}
+class E extends self::D {
+  synthetic constructor •() → self::E
+    : super self::D::•()
+    ;
+  forwarding-stub forwarding-semi-stub operator +(covariant core::int e) → dynamic
+    return super.{self::D::+}(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.transformed.expect b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.transformed.expect
new file mode 100644
index 0000000..84a1b42
--- /dev/null
+++ b/pkg/front_end/testcases/forwarding_stub_for_operator.dart.strong.transformed.expect
@@ -0,0 +1,39 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  operator +(covariant core::int a) → dynamic
+    return null;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  operator +(dynamic b) → dynamic
+    return null;
+}
+abstract class C extends core::Object implements self::A, self::B {
+  synthetic constructor •() → self::C
+    : super core::Object::•()
+    ;
+  abstract forwarding-stub operator +(covariant dynamic b) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → self::D
+    : super core::Object::•()
+    ;
+  operator +(dynamic d) → dynamic
+    return null;
+}
+class E extends self::D {
+  synthetic constructor •() → self::E
+    : super self::D::•()
+    ;
+  forwarding-stub forwarding-semi-stub operator +(covariant core::int e) → dynamic
+    return super.{self::D::+}(e);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 820f52c..0147dc9 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -98,6 +98,7 @@
 fibonacci: TextSerializationFailure # Was: Pass
 for_in_scope: TextSerializationFailure # Was: Pass
 for_in_without_declaration: TextSerializationFailure
+forwarding_stub_for_operator: TextSerializationFailure
 function_in_field: TextSerializationFailure # Was: Pass
 function_type_assignments: TextSerializationFailure # Was: Pass
 function_type_default_value: TextSerializationFailure