Better context message on SyntheticForwarder in MissingImplementation

Previously we could get something like this:
```
regress_32660_test_06.dart:9:7: Context: 'foo' is defined here.
class I extends G implements H {
      ^^^
```

because a SyntheticForwarder was added with a file location of the
class.

It now instead goes to the forwarding stub target and says
```
regress_32660_test_06.dart:6:3: Context: 'foo' is defined here.
  foo(int x, {int y}) => y;
  ^^^
```

Change-Id: I6fb1b958f58635c9afffa8e58cd49eb69df28afd
Reviewed-on: https://dart-review.googlesource.com/72680
Reviewed-by: Peter von der Ahé <ahe@google.com>
Commit-Queue: Jens Johansen <jensj@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
index 5463069..e277db1 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_class_builder.dart
@@ -529,6 +529,11 @@
           if (hasProblem) {
             Name name = interfaceMember.name;
             String displayName = name.name + (setters ? "=" : "");
+            if (interfaceMember is Procedure &&
+                interfaceMember.isSyntheticForwarder) {
+              Procedure forwarder = interfaceMember;
+              interfaceMember = forwarder.forwardingStubInterfaceTarget;
+            }
             context ??= <LocatedMessage>[];
             context.add(templateMissingImplementationCause
                 .withArguments(displayName)
diff --git a/pkg/front_end/testcases/regress/issue_32660.dart b/pkg/front_end/testcases/regress/issue_32660.dart
new file mode 100644
index 0000000..ec799be
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_32660.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2018, 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 {
+  foo(int x) => x;
+}
+
+class B {
+  foo(int x, {int y}) => y;
+}
+
+class C extends A implements B {
+  noSuchMethod(i) {
+    print("No such method!");
+    return 42;
+  }
+}
+
+class D {
+  foo(int x) => x;
+}
+
+class E extends D {
+  foo(int x, {int y});
+
+  noSuchMethod(i) {
+    print(i.namedArguments);
+    return 42;
+  }
+}
+
+main() {
+  C c = new C();
+  E e = new E();
+}
diff --git a/pkg/front_end/testcases/regress/issue_32660.dart.direct.expect b/pkg/front_end/testcases/regress/issue_32660.dart.direct.expect
new file mode 100644
index 0000000..7f42fe5
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_32660.dart.direct.expect
@@ -0,0 +1,48 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class B extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x, {core::int y = null}) → dynamic
+    return y;
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → void
+    : super self::A::•()
+    ;
+  method noSuchMethod(dynamic i) → dynamic {
+    core::print("No such method!");
+    return 42;
+  }
+}
+class D extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class E extends self::D {
+  synthetic constructor •() → void
+    : super self::D::•()
+    ;
+  abstract method foo(core::int x, {core::int y = null}) → dynamic;
+  method noSuchMethod(dynamic i) → dynamic {
+    core::print(i.namedArguments);
+    return 42;
+  }
+}
+static method main() → dynamic {
+  self::C c = new self::C::•();
+  self::E e = new self::E::•();
+}
diff --git a/pkg/front_end/testcases/regress/issue_32660.dart.direct.transformed.expect b/pkg/front_end/testcases/regress/issue_32660.dart.direct.transformed.expect
new file mode 100644
index 0000000..7f42fe5
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_32660.dart.direct.transformed.expect
@@ -0,0 +1,48 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class B extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x, {core::int y = null}) → dynamic
+    return y;
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → void
+    : super self::A::•()
+    ;
+  method noSuchMethod(dynamic i) → dynamic {
+    core::print("No such method!");
+    return 42;
+  }
+}
+class D extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class E extends self::D {
+  synthetic constructor •() → void
+    : super self::D::•()
+    ;
+  abstract method foo(core::int x, {core::int y = null}) → dynamic;
+  method noSuchMethod(dynamic i) → dynamic {
+    core::print(i.namedArguments);
+    return 42;
+  }
+}
+static method main() → dynamic {
+  self::C c = new self::C::•();
+  self::E e = new self::E::•();
+}
diff --git a/pkg/front_end/testcases/regress/issue_32660.dart.outline.expect b/pkg/front_end/testcases/regress/issue_32660.dart.outline.expect
new file mode 100644
index 0000000..e77621d
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_32660.dart.outline.expect
@@ -0,0 +1,37 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → void
+    ;
+  method foo(core::int x) → dynamic
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → void
+    ;
+  method foo(core::int x, {core::int y}) → dynamic
+    ;
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → void
+    ;
+  method noSuchMethod(dynamic i) → dynamic
+    ;
+}
+class D extends core::Object {
+  synthetic constructor •() → void
+    ;
+  method foo(core::int x) → dynamic
+    ;
+}
+class E extends self::D {
+  synthetic constructor •() → void
+    ;
+  abstract method foo(core::int x, {core::int y}) → dynamic;
+  method noSuchMethod(dynamic i) → dynamic
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/regress/issue_32660.dart.strong.expect b/pkg/front_end/testcases/regress/issue_32660.dart.strong.expect
new file mode 100644
index 0000000..057aa3f
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_32660.dart.strong.expect
@@ -0,0 +1,73 @@
+// Errors:
+//
+// pkg/front_end/testcases/regress/issue_32660.dart:13:7: Error: The non-abstract class 'C' is missing implementations for these members:
+//   'foo'.
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+// 
+// class C extends A implements B {
+//       ^
+//
+// pkg/front_end/testcases/regress/issue_32660.dart:24:7: Error: The non-abstract class 'E' is missing implementations for these members:
+//   'foo'.
+// Try to either
+//  - provide an implementation,
+//  - inherit an implementation from a superclass or mixin,
+//  - mark the class as abstract, or
+//  - provide a 'noSuchMethod' implementation.
+// 
+// class E extends D {
+//       ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class B extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x, {core::int y = null}) → dynamic
+    return y;
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → void
+    : super self::A::•()
+    ;
+  method noSuchMethod(core::Invocation i) → dynamic {
+    core::print("No such method!");
+    return 42;
+  }
+  abstract forwarding-stub method foo(core::int x, {core::int y = null}) → dynamic;
+}
+class D extends core::Object {
+  synthetic constructor •() → void
+    : super core::Object::•()
+    ;
+  method foo(core::int x) → dynamic
+    return x;
+}
+class E extends self::D {
+  synthetic constructor •() → void
+    : super self::D::•()
+    ;
+  abstract method foo(core::int x, {core::int y = null}) → dynamic;
+  method noSuchMethod(core::Invocation i) → dynamic {
+    core::print(i.{core::Invocation::namedArguments});
+    return 42;
+  }
+}
+static method main() → dynamic {
+  self::C c = new self::C::•();
+  self::E e = new self::E::•();
+}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index ec7d1bd..3545194 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -201,6 +201,7 @@
 regress/issue_31299: TypeCheckError
 regress/issue_32972: TypeCheckError
 regress/issue_33452: RuntimeError # Test has an intentional error
+regress/issue_32660: TypeCheckError # Test has an intentional error
 
 runtime_checks_new/contravariant_generic_return_with_compound_assign_implicit_downcast: RuntimeError
 runtime_checks_new/mixin_forwarding_stub_field: TypeCheckError