[fasta] Fix override-based type inference for setters

If both the getter and the setter are present in the superclass, the type should
be taken from the setter.

Change-Id: Ie0d84e45d15341151af4a688c508da0f1d7b522d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/101988
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 f433d38..dafd56c3 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
@@ -771,7 +771,7 @@
         VariableDeclaration bParameter =
             bTarget.function.positionalParameters.single;
         bType = bParameter.type;
-        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+        if (!hasExplicitlyTypedFormalParameter(b, 0)) {
           debug?.log("Giving up (type may be inferred)");
           return false;
         }
@@ -794,7 +794,7 @@
 
   bool inferSetterType(KernelProcedureBuilder a, Declaration b) {
     debug?.log(
-        "Inferring getter types for ${fullName(a)} based on ${fullName(b)}");
+        "Inferring setter types for ${fullName(a)} based on ${fullName(b)}");
     Member bTarget = b.target;
     Procedure aProcedure = a.target;
     VariableDeclaration aParameter =
@@ -810,7 +810,8 @@
             bTarget.function.positionalParameters.single;
         bType = bParameter.type;
         copyParameterCovariance(a.parent, aParameter, bParameter);
-        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+        if (!hasExplicitlyTypedFormalParameter(b, 0) ||
+            !hasExplicitlyTypedFormalParameter(a, 0)) {
           debug?.log("Giving up (type may be inferred)");
           return false;
         }
@@ -876,7 +877,7 @@
             bTarget.function.positionalParameters.single;
         // inheritedType = parameter.type;
         copyFieldCovarianceFromParameter(a.parent, a.target, parameter);
-        if (!hasExplictlyTypedFormalParameter(b, 0)) {
+        if (!hasExplicitlyTypedFormalParameter(b, 0)) {
           debug?.log("Giving up (type may be inferred)");
           return false;
         }
@@ -2012,7 +2013,7 @@
               inferReturnType(cls, a, type, a.hadTypesInferred, hierarchy);
             }
           }
-        } else if (a.isSetter && !hasExplictlyTypedFormalParameter(a, 0)) {
+        } else if (a.isSetter && !hasExplicitlyTypedFormalParameter(a, 0)) {
           DartType type;
           if (b.isGetter) {
             Procedure bTarget = b.target;
@@ -2448,11 +2449,14 @@
 }
 
 String fullName(Declaration declaration) {
-  if (declaration is DelayedMember) return declaration.fullNameForErrors;
+  String suffix = declaration.isSetter ? "=" : "";
+  if (declaration is DelayedMember) {
+    return "${declaration.fullNameForErrors}$suffix";
+  }
   Declaration parent = declaration.parent;
   return parent == null
-      ? declaration.fullNameForErrors
-      : "${parent.fullNameForErrors}.${declaration.fullNameForErrors}";
+      ? "${declaration.fullNameForErrors}$suffix"
+      : "${parent.fullNameForErrors}.${declaration.fullNameForErrors}$suffix";
 }
 
 int compareNamedParameters(VariableDeclaration a, VariableDeclaration b) {
@@ -2594,7 +2598,7 @@
       : true;
 }
 
-bool hasExplictlyTypedFormalParameter(Declaration declaration, int index) {
+bool hasExplicitlyTypedFormalParameter(Declaration declaration, int index) {
   assert(
       declaration is KernelProcedureBuilder || declaration is DillMemberBuilder,
       "${declaration.runtimeType}");
diff --git a/pkg/front_end/testcases/issue129167943.dart.hierarchy.expect b/pkg/front_end/testcases/issue129167943.dart.hierarchy.expect
index 5b7b04e..a8b24514 100644
--- a/pkg/front_end/testcases/issue129167943.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/issue129167943.dart.hierarchy.expect
@@ -387,7 +387,7 @@
     Object._simpleInstanceOfTrue
     Object.==
   interfaceSetters:
-    H3.E.foo%G.foo
+    H3.E.foo=%G.foo=
 
 H4:
   Longest path to Object: 3
diff --git a/pkg/front_end/testcases/mixin_application_override.dart.hierarchy.expect b/pkg/front_end/testcases/mixin_application_override.dart.hierarchy.expect
index 426ba18..2d41275 100644
--- a/pkg/front_end/testcases/mixin_application_override.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/mixin_application_override.dart.hierarchy.expect
@@ -115,7 +115,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    A0.M.foo%S.foo%M.foo
+    A0.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -128,7 +128,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    A0.M.foo%S.foo%M.foo
+    A0.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -311,7 +311,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -324,7 +324,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -344,7 +344,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -357,7 +357,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -609,7 +609,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -622,7 +622,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -642,7 +642,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -655,7 +655,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -907,7 +907,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -920,7 +920,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -940,7 +940,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -953,7 +953,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -974,7 +974,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
@@ -987,7 +987,7 @@
     Object.runtimeType
     Object._simpleInstanceOf
     Object._instanceOf
-    S with M.M.foo%S.foo%M.foo
+    S with M.M.foo%S.foo
     Object.noSuchMethod
     Object._identityHashCode
     Object.hashCode
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart b/pkg/front_end/testcases/override_inference_for_setters.dart
new file mode 100644
index 0000000..0da2cf9
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart
@@ -0,0 +1,14 @@
+// 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 B {
+  num get foo => null;
+  set foo(dynamic newFoo) {}
+}
+
+class A extends B {
+  set foo(newFoo) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.hierarchy.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.hierarchy.expect
new file mode 100644
index 0000000..b1e3c8a
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.hierarchy.expect
@@ -0,0 +1,58 @@
+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:
+
+B:
+  superclasses:
+    Object
+  interfaces:
+  classMembers:
+    Object.toString
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    B.foo
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+    B.foo
+
+A:
+  superclasses:
+    Object
+      -> B
+  interfaces:
+  classMembers:
+    Object.toString
+    Object.runtimeType
+    Object._simpleInstanceOf
+    Object._instanceOf
+    B.foo
+    Object.noSuchMethod
+    Object._identityHashCode
+    Object.hashCode
+    Object._simpleInstanceOfFalse
+    Object._simpleInstanceOfTrue
+    Object.==
+  classSetters:
+    A.foo
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.expect
new file mode 100644
index 0000000..fd832da
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get foo() → core::num
+    return null;
+  set foo(dynamic newFoo) → void {}
+}
+class A extends self::B {
+  synthetic constructor •() → self::A
+    : super self::B::•()
+    ;
+  set foo(dynamic newFoo) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.transformed.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.transformed.expect
new file mode 100644
index 0000000..fd832da
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.legacy.transformed.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get foo() → core::num
+    return null;
+  set foo(dynamic newFoo) → void {}
+}
+class A extends self::B {
+  synthetic constructor •() → self::A
+    : super self::B::•()
+    ;
+  set foo(dynamic newFoo) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.outline.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.outline.expect
new file mode 100644
index 0000000..1c22d1f
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.outline.expect
@@ -0,0 +1,20 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    ;
+  get foo() → core::num
+    ;
+  set foo(dynamic newFoo) → void
+    ;
+}
+class A extends self::B {
+  synthetic constructor •() → self::A
+    ;
+  set foo(dynamic newFoo) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.strong.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.strong.expect
new file mode 100644
index 0000000..fd832da
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.strong.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get foo() → core::num
+    return null;
+  set foo(dynamic newFoo) → void {}
+}
+class A extends self::B {
+  synthetic constructor •() → self::A
+    : super self::B::•()
+    ;
+  set foo(dynamic newFoo) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/override_inference_for_setters.dart.strong.transformed.expect b/pkg/front_end/testcases/override_inference_for_setters.dart.strong.transformed.expect
new file mode 100644
index 0000000..fd832da
--- /dev/null
+++ b/pkg/front_end/testcases/override_inference_for_setters.dart.strong.transformed.expect
@@ -0,0 +1,19 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  get foo() → core::num
+    return null;
+  set foo(dynamic newFoo) → void {}
+}
+class A extends self::B {
+  synthetic constructor •() → self::A
+    : super self::B::•()
+    ;
+  set foo(dynamic newFoo) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/rasta/issue_000048.dart.hierarchy.expect b/pkg/front_end/testcases/rasta/issue_000048.dart.hierarchy.expect
index 7b077f3..953dad2 100644
--- a/pkg/front_end/testcases/rasta/issue_000048.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/rasta/issue_000048.dart.hierarchy.expect
@@ -67,7 +67,7 @@
     Object.toString
     Object.runtimeType
     Object._simpleInstanceOf
-    C.M1.v2%A.v2%M1.v2
+    C.M1.v2%A.v2
     Object._instanceOf
     Object.noSuchMethod
     Object._identityHashCode
@@ -77,13 +77,13 @@
     Object._simpleInstanceOfTrue
     Object.==
   classSetters:
-    C.M1.v2%A.v2%M1.v2
+    C.M1.v2%A.v2
     A.v1
   interfaceMembers:
     Object.toString
     Object.runtimeType
     Object._simpleInstanceOf
-    C.M1.v2%A.v2%M1.v2
+    C.M1.v2%A.v2
     Object._instanceOf
     Object.noSuchMethod
     Object._identityHashCode
@@ -93,5 +93,5 @@
     Object._simpleInstanceOfTrue
     Object.==
   interfaceSetters:
-    C.M1.v2%A.v2%M1.v2
+    C.M1.v2%A.v2
     A.v1
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.hierarchy.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.hierarchy.expect
index edbfd6d..9a9e066 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_field.dart.hierarchy.expect
@@ -100,8 +100,8 @@
     Object._simpleInstanceOfTrue
     Object.==
   classSetters:
-    C.M.y%B.y%I.y
-    C.M.x%B.x%I.x
+    C.M.y%B.y=%I.y=
+    C.M.x%B.x=%I.x=
   interfaceMembers:
     C.M.y%B.y%I.y
     Object.toString
@@ -116,8 +116,8 @@
     Object._simpleInstanceOfTrue
     Object.==
   interfaceSetters:
-    C.M.y%B.y%I.y
-    C.M.x%B.x%I.x
+    C.M.y%B.y=%I.y=
+    C.M.x%B.x=%I.x=
 
 Comparable:
   superclasses:
diff --git a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_setter.dart.hierarchy.expect b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_setter.dart.hierarchy.expect
index df047dc..e23589d 100644
--- a/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_setter.dart.hierarchy.expect
+++ b/pkg/front_end/testcases/runtime_checks_new/mixin_forwarding_stub_setter.dart.hierarchy.expect
@@ -116,8 +116,8 @@
     Object._simpleInstanceOfTrue
     Object.==
   interfaceSetters:
-    C.M.y%I.y
-    C.M.x%I.x
+    C.M.y=%I.y=
+    C.M.x=%I.x=
 
 Comparable:
   superclasses:
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 1e7266a..820f52c 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -753,6 +753,7 @@
 override_check_generic_method_f_bounded: TextSerializationFailure # Was: Pass
 override_check_two_substitutions: TextSerializationFailure # Was: Pass
 override_check_with_covariant_modifier: TypeCheckError # Issue #31620
+override_inference_for_setters: TextSerializationFailure
 part_as_entry_point: TextSerializationFailure # Was: Pass
 part_as_entry_point_lib: TextSerializationFailure # Was: Pass
 part_not_part_of: TextSerializationFailure