Handle AmbiguousBuilder in computeRedirecteeType

We get an AmbiguousBuilder if there are more than one redirecting
factory with the same name. We shouldn't crash though.

Fixes #35266.

Bug: 35266
Change-Id: I1ac0babdde49c4ca3966e6af5c580191baac0873
Reviewed-on: https://dart-review.googlesource.com/c/85390
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Peter von der Ahé <ahe@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 ad101b7..873aa85 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
@@ -64,6 +64,7 @@
         messagePatchDeclarationMismatch,
         messagePatchDeclarationOrigin,
         noLength,
+        templateDuplicatedDeclarationUse,
         templateFactoryRedirecteeHasTooFewPositionalParameters,
         templateFactoryRedirecteeInvalidReturnType,
         templateGenericFunctionTypeInferredAsActualTypeArgument,
@@ -100,6 +101,8 @@
 
 import '../problems.dart' show unexpected, unhandled, unimplemented;
 
+import '../scope.dart' show AmbiguousBuilder;
+
 import '../type_inference/type_schema.dart' show UnknownType;
 
 import 'kernel_builder.dart'
@@ -460,6 +463,18 @@
                 }
                 declaration.setRedirectingFactoryBody(
                     targetBuilder.member, typeArguments);
+              } else if (targetBuilder is AmbiguousBuilder) {
+                Message message = templateDuplicatedDeclarationUse
+                    .withArguments(redirectionTarget.fullNameForErrors);
+                if (declaration.isConst) {
+                  addProblem(message, declaration.charOffset, noLength);
+                } else {
+                  addProblem(message, declaration.charOffset, noLength);
+                }
+                // CoreTypes aren't computed yet, and this is the outline
+                // phase. So we can't and shouldn't create a method body.
+                declaration.body = new RedirectingFactoryBody.unresolved(
+                    redirectionTarget.fullNameForErrors);
               } else {
                 Message message = templateRedirectionTargetNotFound
                     .withArguments(redirectionTarget.fullNameForErrors);
@@ -1495,6 +1510,12 @@
       //   class B implements A {}
       //
       target = targetBuilder.member.function;
+    } else if (redirectionTarget.target is AmbiguousBuilder) {
+      // Multiple definitions with the same name: An error has already been
+      // issued.
+      // TODO(http://dartbug.com/35294): Unfortunate error; see also
+      // https://dart-review.googlesource.com/c/sdk/+/85390/.
+      return null;
     } else {
       unhandled("${redirectionTarget.target}", "computeRedirecteeType",
           charOffset, fileUri);
diff --git a/pkg/front_end/testcases/legacy.status b/pkg/front_end/testcases/legacy.status
index c4c996e..9832553 100644
--- a/pkg/front_end/testcases/legacy.status
+++ b/pkg/front_end/testcases/legacy.status
@@ -110,6 +110,7 @@
 regress/issue_35258: RuntimeError # Expected
 regress/issue_35259: RuntimeError # Expected
 regress/issue_35260: RuntimeError # Expected
+regress/issue_35266: RuntimeError # Expected
 runtime_checks/implicit_downcast_constructor_initializer: RuntimeError # Test exercises strong mode semantics
 runtime_checks/implicit_downcast_do: RuntimeError # Test exercises strong mode semantics
 runtime_checks/implicit_downcast_for_condition: RuntimeError # Test exercises strong mode semantics
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart b/pkg/front_end/testcases/regress/issue_35266.dart
new file mode 100644
index 0000000..8564b50
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart
@@ -0,0 +1,18 @@
+// 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 B<T> extends C<T> {
+  B();
+  factory B.foo() = B<T>;
+  factory B.foo() = B<T>;
+}
+
+class C<K> {
+  C();
+  factory C.bar() = B<K>.foo;
+}
+
+main() {
+  new C.bar();
+}
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.legacy.expect b/pkg/front_end/testcases/regress/issue_35266.dart.legacy.expect
new file mode 100644
index 0000000..247942c
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.legacy.expect
@@ -0,0 +1,50 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+// pkg/front_end/testcases/regress/issue_35266.dart:7:11: Context: Previous declaration of 'B.foo'.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Warning: Method not found: 'B.foo'.
+//   factory C.bar() = B<K>.foo;
+//           ^^^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class B<T extends core::Object = dynamic> extends self::C<self::B::T> {
+  static field dynamic _redirecting# = <dynamic>[self::B::foo];
+  constructor •() → self::B<self::B::T>
+    : super self::C::•()
+    ;
+  static factory foo<T extends core::Object = dynamic>() → self::B<self::B::foo::T>
+    let dynamic #redirecting_factory = self::B::• in let self::B::foo::T #typeArg0 = null in invalid-expression;
+}
+class C<K extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::C::bar];
+  constructor •() → self::C<self::C::K>
+    : super core::Object::•()
+    ;
+  static factory bar<K extends core::Object = dynamic>() → self::C<self::C::bar::K>
+    let dynamic #redirecting_factory = "B.foo" in invalid-expression;
+}
+static method main() → dynamic {
+  let dynamic _ = null in let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#B.foo, 32, core::List::unmodifiable<dynamic>(<core::Type>[dynamic]), const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.legacy.transformed.expect b/pkg/front_end/testcases/regress/issue_35266.dart.legacy.transformed.expect
new file mode 100644
index 0000000..c538a3d
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.legacy.transformed.expect
@@ -0,0 +1,33 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class B<T extends core::Object = dynamic> extends self::C<self::B::T> {
+  static field dynamic _redirecting# = <dynamic>[self::B::foo];
+  constructor •() → self::B<self::B::T>
+    : super self::C::•()
+    ;
+  static factory foo<T extends core::Object = dynamic>() → self::B<self::B::foo::T>
+    let dynamic #redirecting_factory = self::B::• in let self::B::foo::T #typeArg0 = null in invalid-expression;
+}
+class C<K extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::C::bar];
+  constructor •() → self::C<self::C::K>
+    : super core::Object::•()
+    ;
+  static factory bar<K extends core::Object = dynamic>() → self::C<self::C::bar::K>
+    let dynamic #redirecting_factory = "B.foo" in invalid-expression;
+}
+static method main() → dynamic {
+  let dynamic _ = null in let dynamic _ = null in throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#B.foo, 32, core::List::unmodifiable<dynamic>(<core::Type>[dynamic]), const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{})));
+}
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect b/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect
new file mode 100644
index 0000000..c7faea7
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.outline.expect
@@ -0,0 +1,33 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+// pkg/front_end/testcases/regress/issue_35266.dart:7:11: Context: Previous declaration of 'B.foo'.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class B<T extends core::Object = dynamic> extends self::C<self::B::T> {
+  static field dynamic _redirecting# = <dynamic>[self::B::foo];
+  constructor •() → self::B<self::B::T>
+    ;
+  static factory foo<T extends core::Object = dynamic>() → self::B<self::B::foo::T>
+    let dynamic #redirecting_factory = self::B::• in let self::B::foo::T #typeArg0 = null in invalid-expression;
+}
+class C<K extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::C::bar];
+  constructor •() → self::C<self::C::K>
+    ;
+  static factory bar<K extends core::Object = dynamic>() → self::C<self::C::bar::K>
+    let dynamic #redirecting_factory = "B.foo" in invalid-expression;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect b/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect
new file mode 100644
index 0000000..52afc68
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.strong.expect
@@ -0,0 +1,52 @@
+// Formatted problems:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+// pkg/front_end/testcases/regress/issue_35266.dart:7:11: Context: Previous declaration of 'B.foo'.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
+//   factory C.bar() = B<K>.foo;
+//           ^^^
+
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class B<T extends core::Object = dynamic> extends self::C<self::B::T> {
+  static field dynamic _redirecting# = <dynamic>[self::B::foo];
+  constructor •() → self::B<self::B::T>
+    : super self::C::•()
+    ;
+  static factory foo<T extends core::Object = dynamic>() → self::B<self::B::foo::T>
+    let dynamic #redirecting_factory = self::B::• in let self::B::foo::T #typeArg0 = null in invalid-expression;
+}
+class C<K extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::C::bar];
+  constructor •() → self::C<self::C::K>
+    : super core::Object::•()
+    ;
+  static factory bar<K extends core::Object = dynamic>() → self::C<self::C::bar::K>
+    let dynamic #redirecting_factory = "B.foo" in invalid-expression;
+}
+static method main() → dynamic {
+  let dynamic _ = null in invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
+  factory C.bar() = B<K>.foo;
+          ^^^";
+}
diff --git a/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect b/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect
new file mode 100644
index 0000000..c97d4b6
--- /dev/null
+++ b/pkg/front_end/testcases/regress/issue_35266.dart.strong.transformed.expect
@@ -0,0 +1,35 @@
+// Unhandled errors:
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:8:11: Error: 'B.foo' is already declared in this scope.
+//   factory B.foo() = B<T>;
+//           ^^^^^
+//
+// pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Can't use 'B.foo' because it is declared more than once.
+//   factory C.bar() = B<K>.foo;
+//           ^
+
+library;
+import self as self;
+import "dart:core" as core;
+
+class B<T extends core::Object = dynamic> extends self::C<self::B::T> {
+  static field dynamic _redirecting# = <dynamic>[self::B::foo];
+  constructor •() → self::B<self::B::T>
+    : super self::C::•()
+    ;
+  static factory foo<T extends core::Object = dynamic>() → self::B<self::B::foo::T>
+    let<BottomType> #redirecting_factory = self::B::• in let self::B::foo::T #typeArg0 = null in invalid-expression;
+}
+class C<K extends core::Object = dynamic> extends core::Object {
+  static field dynamic _redirecting# = <dynamic>[self::C::bar];
+  constructor •() → self::C<self::C::K>
+    : super core::Object::•()
+    ;
+  static factory bar<K extends core::Object = dynamic>() → self::C<self::C::bar::K>
+    let core::String #redirecting_factory = "B.foo" in invalid-expression;
+}
+static method main() → dynamic {
+  let<BottomType> _ = null in invalid-expression "pkg/front_end/testcases/regress/issue_35266.dart:13:11: Error: Method not found: 'B.foo'.
+  factory C.bar() = B<K>.foo;
+          ^^^";
+}
diff --git a/pkg/front_end/testcases/strong.status b/pkg/front_end/testcases/strong.status
index 4efd9ed..ce39537 100644
--- a/pkg/front_end/testcases/strong.status
+++ b/pkg/front_end/testcases/strong.status
@@ -136,6 +136,7 @@
 regress/issue_35258: RuntimeError # Expected
 regress/issue_35259: RuntimeError # Expected
 regress/issue_35260: RuntimeError # Expected
+regress/issue_35266: RuntimeError # Expected
 runtime_checks_new/contravariant_generic_return_with_compound_assign_implicit_downcast: RuntimeError
 runtime_checks_new/mixin_forwarding_stub_field: TypeCheckError
 runtime_checks_new/mixin_forwarding_stub_getter: TypeCheckError
diff --git a/tests/language_2/regress_35266_test.dart b/tests/language_2/regress_35266_test.dart
new file mode 100644
index 0000000..3d82833
--- /dev/null
+++ b/tests/language_2/regress_35266_test.dart
@@ -0,0 +1,18 @@
+// 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 B<T> extends C<T> {
+  B();
+  factory B.foo() = B<T>;
+  factory B.foo() = B<T>; //# 01: compile-time error
+}
+
+class C<K> {
+  C();
+  factory C.bar() = B<K>.foo;
+}
+
+main() {
+  new C.bar();
+}