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();
+}