[fasta] Fix an issue with override inference and type parameters
The CL fixes how override-based inference works in the cases when the
type of a parameter in the overriding method is omitted, and the type
of this parameter in the overridden method contains a type parameter
of the class. Basically, the type should be substituted in this case.
Change-Id: I36d6c614d47e5cd68dc14eae1a2bbe4cd19d842b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104784
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 040d468..597ce11 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
@@ -737,7 +737,13 @@
VariableDeclaration bParameter = bNamed[bCount];
copyParameterCovariance(a.parent, aParameter, bParameter);
DartType aType = aParameter.type;
+ if (aSubstitution != null) {
+ aType = aSubstitution.substituteType(aType);
+ }
DartType bType = bParameter.type;
+ if (bSubstitution != null) {
+ bType = bSubstitution.substituteType(bType);
+ }
if (substitution != null) {
bType = substitution.substituteType(bType);
}
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart
new file mode 100644
index 0000000..f905aee
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart
@@ -0,0 +1,13 @@
+// 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.
+
+abstract class A<X> {
+ void foo({Iterable<X> x});
+}
+
+class B<Y> implements A<Y> {
+ void foo({x}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.hierarchy.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.hierarchy.expect
new file mode 100644
index 0000000..c985c1b
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.hierarchy.expect
@@ -0,0 +1,69 @@
+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
+ Object.runtimeType
+ Object._simpleInstanceOf
+ Object._instanceOf
+ A.foo
+ Object.noSuchMethod
+ Object._identityHashCode
+ Object.hashCode
+ Object._simpleInstanceOfFalse
+ Object._simpleInstanceOfTrue
+ Object.==
+ classSetters:
+
+B:
+ Longest path to Object: 2
+ superclasses:
+ Object
+ interfaces: A<Y>
+ classMembers:
+ Object.toString
+ Object.runtimeType
+ Object._simpleInstanceOf
+ Object._instanceOf
+ B.foo
+ Object.noSuchMethod
+ Object._identityHashCode
+ Object.hashCode
+ Object._simpleInstanceOfFalse
+ Object._simpleInstanceOfTrue
+ Object.==
+ classSetters:
+ interfaceMembers:
+ Object.toString
+ Object.runtimeType
+ Object._simpleInstanceOf
+ Object._instanceOf
+ B.foo
+ Object.noSuchMethod
+ Object._identityHashCode
+ Object.hashCode
+ Object._simpleInstanceOfFalse
+ Object._simpleInstanceOfTrue
+ Object.==
+ interfaceSetters:
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.expect
new file mode 100644
index 0000000..a036a98
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+ abstract method foo({generic-covariant-impl core::Iterable<self::A::X> x = null}) → void;
+}
+class B<Y extends core::Object = dynamic> extends core::Object implements self::A<self::B::Y> {
+ synthetic constructor •() → self::B<self::B::Y>
+ : super core::Object::•()
+ ;
+ method foo({generic-covariant-impl core::Iterable<self::B::Y> x = null}) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.transformed.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.transformed.expect
new file mode 100644
index 0000000..a036a98
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.legacy.transformed.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+ abstract method foo({generic-covariant-impl core::Iterable<self::A::X> x = null}) → void;
+}
+class B<Y extends core::Object = dynamic> extends core::Object implements self::A<self::B::Y> {
+ synthetic constructor •() → self::B<self::B::Y>
+ : super core::Object::•()
+ ;
+ method foo({generic-covariant-impl core::Iterable<self::B::Y> x = null}) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.outline.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.outline.expect
new file mode 100644
index 0000000..986c56b
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.outline.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ ;
+ abstract method foo({generic-covariant-impl core::Iterable<self::A::X> x}) → void;
+}
+class B<Y extends core::Object = dynamic> extends core::Object implements self::A<self::B::Y> {
+ synthetic constructor •() → self::B<self::B::Y>
+ ;
+ method foo({generic-covariant-impl core::Iterable<self::B::Y> x}) → void
+ ;
+}
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.expect
new file mode 100644
index 0000000..a036a98
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+ abstract method foo({generic-covariant-impl core::Iterable<self::A::X> x = null}) → void;
+}
+class B<Y extends core::Object = dynamic> extends core::Object implements self::A<self::B::Y> {
+ synthetic constructor •() → self::B<self::B::Y>
+ : super core::Object::•()
+ ;
+ method foo({generic-covariant-impl core::Iterable<self::B::Y> x = null}) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.transformed.expect b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.transformed.expect
new file mode 100644
index 0000000..a036a98
--- /dev/null
+++ b/pkg/front_end/testcases/inference/override_inference_with_type_parameters.dart.strong.transformed.expect
@@ -0,0 +1,17 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+abstract class A<X extends core::Object = dynamic> extends core::Object {
+ synthetic constructor •() → self::A<self::A::X>
+ : super core::Object::•()
+ ;
+ abstract method foo({generic-covariant-impl core::Iterable<self::A::X> x = null}) → void;
+}
+class B<Y extends core::Object = dynamic> extends core::Object implements self::A<self::B::Y> {
+ synthetic constructor •() → self::B<self::B::Y>
+ : super core::Object::•()
+ ;
+ method foo({generic-covariant-impl core::Iterable<self::B::Y> x = null}) → void {}
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/text_serialization.status b/pkg/front_end/testcases/text_serialization.status
index 43c0eb4..ef897a2 100644
--- a/pkg/front_end/testcases/text_serialization.status
+++ b/pkg/front_end/testcases/text_serialization.status
@@ -475,6 +475,7 @@
inference/overloaded_int_operators: TextSerializationFailure # Was: Pass
inference/override_equals: TextSerializationFailure # Was: RuntimeError
inference/override_inference_depends_on_field_inference: TextSerializationFailure
+inference/override_inference_with_type_parameters: TextSerializationFailure
inference/parameter_defaults_downwards: TextSerializationFailure # Was: Pass
inference/parameter_defaults_upwards: TextSerializationFailure # Was: Pass
inference/promote_bounds: TextSerializationFailure # Was: Pass