[cfe] Mark combined member signatures as legacy when needed
If synthesized members have legacy signatures, mark these as
nullable-by-default even when inserted into opt-in classes.
Change-Id: I956912402cae85f6ceb28a73477d44917780a6d5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/174240
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
index f89b4e8..b1fcbcb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/combined_member_signature.dart
@@ -89,6 +89,8 @@
bool _neededNnbdTopMerge = false;
+ bool _containsNnbdTypes = false;
+
bool _needsCovarianceMerging = false;
bool _isCombinedMemberSignatureCovarianceComputed = false;
@@ -222,6 +224,43 @@
return _neededNnbdTopMerge;
}
+ /// Returns `true` if the type of combined member signature has nnbd types.
+ ///
+ /// If the combined member signature for an opt-in class is computed from
+ /// identical legacy types, that is, without the need for nnbd top merge, then
+ /// the type will be copied over directly and a member created from the
+ /// combined member signature will therefore be a legacy member, even though
+ /// it is declared in an opt in class.
+ ///
+ /// To avoid reporting errors as if the member was an opt-in member, it is
+ /// marked as nullable-by-default.
+ ///
+ /// For instance
+ ///
+ /// // opt out:
+ /// mixin Mixin {
+ /// void method({int named}) {}
+ /// }
+ /// // opt in:
+ /// class Super {
+ /// void method({required covariant int named}) {}
+ /// }
+ /// class Class extends Super with Mixin {
+ /// // A forwarding stop for Mixin.method will be inserted here:
+ /// // void method({covariant int named}) -> Mixin.method
+ /// }
+ /// class SubClass extends Class {
+ /// // This is a valid override since `Class.method` should should
+ /// // not be considered as _not_ having a required named parameter -
+ /// // it is legacy and doesn't know about required named parameters.
+ /// void method({required int named}) {}
+ /// }
+ ///
+ bool get containsNnbdTypes {
+ _ensureCombinedMemberSignatureType();
+ return _containsNnbdTypes;
+ }
+
/// Returns `true` if the covariance of the combined member signature is
/// different from the covariance of the overridden member in the superclass.
///
@@ -283,6 +322,8 @@
if (classBuilder.library.isNonNullableByDefault) {
DartType canonicalMemberType =
_combinedMemberSignatureType = getMemberType(_canonicalMemberIndex);
+ _containsNnbdTypes =
+ _getMember(_canonicalMemberIndex).isNonNullableByDefault;
if (_mutualSubtypes != null) {
_combinedMemberSignatureType =
norm(_coreTypes, _combinedMemberSignatureType);
@@ -296,6 +337,7 @@
}
_neededNnbdTopMerge =
canonicalMemberType != _combinedMemberSignatureType;
+ _containsNnbdTypes = _neededNnbdTopMerge;
}
} else {
_combinedMemberSignatureType = getMemberType(_canonicalMemberIndex);
@@ -486,8 +528,7 @@
)
..startFileOffset = startFileOffset
..fileOffset = fileOffset
- ..isNonNullableByDefault =
- enclosingClass.enclosingLibrary.isNonNullableByDefault
+ ..isNonNullableByDefault = containsNnbdTypes
..parent = enclosingClass;
}
@@ -537,8 +578,7 @@
reference: referenceFrom?.reference)
..startFileOffset = startFileOffset
..fileOffset = fileOffset
- ..isNonNullableByDefault =
- enclosingClass.enclosingLibrary.isNonNullableByDefault
+ ..isNonNullableByDefault = containsNnbdTypes
..parent = enclosingClass;
}
@@ -617,8 +657,7 @@
reference: referenceFrom?.reference)
..startFileOffset = startFileOffset
..fileOffset = fileOffset
- ..isNonNullableByDefault =
- enclosingClass.enclosingLibrary.isNonNullableByDefault
+ ..isNonNullableByDefault = containsNnbdTypes
..parent = enclosingClass;
}
diff --git a/pkg/front_end/testcases/nnbd_mixed/flutter_issue_63029/flutter_issue_63029.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/flutter_issue_63029/flutter_issue_63029.dart.weak.expect
index 2c462af..ed414cf 100644
--- a/pkg/front_end/testcases/nnbd_mixed/flutter_issue_63029/flutter_issue_63029.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/flutter_issue_63029/flutter_issue_63029.dart.weak.expect
@@ -16,7 +16,7 @@
synthetic constructor •() → self::_F&B&D
: super flu::B::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class F extends self::_F&B&D {
synthetic constructor •() → self::F
diff --git a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.expect
index 9ed16b6..dd9e9f0 100644
--- a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.expect
@@ -34,13 +34,13 @@
synthetic constructor •() → self::Class4b
: super core::Object::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class Class4c extends core::Object implements inh::GenericInterface<core::num?> {
synthetic constructor •() → self::Class4c
: super core::Object::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class Class4d extends inh::LegacyClass4 implements inh::GenericInterface<core::num> {
synthetic constructor •() → self::Class4d
diff --git a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.transformed.expect
index 0bc6430..4b67f47 100644
--- a/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/inheritance_from_opt_out.dart.weak.transformed.expect
@@ -34,13 +34,13 @@
synthetic constructor •() → self::Class4b
: super core::Object::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class Class4c extends core::Object implements inh::GenericInterface<core::num?> {
synthetic constructor •() → self::Class4c
: super core::Object::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class Class4d extends inh::LegacyClass4 implements inh::GenericInterface<core::num> {
synthetic constructor •() → self::Class4d
diff --git a/pkg/front_end/testcases/nnbd_mixed/mixin_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/mixin_from_opt_out.dart.weak.expect
index bd160a8..70ef7e5 100644
--- a/pkg/front_end/testcases/nnbd_mixed/mixin_from_opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/mixin_from_opt_out.dart.weak.expect
@@ -9,7 +9,7 @@
const synthetic constructor •() → self::_Class&Object&Mixin
: super core::Object::•()
;
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
class Class extends self::_Class&Object&Mixin {
synthetic constructor •() → self::Class
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.expect
index e2f0b61..310bd85 100644
--- a/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.expect
@@ -36,7 +36,7 @@
method test_default({required core::int? i = #C1}) → void {}
method test_nondefault({required core::int? i = #C1}) → void {}
method test_legacy({required core::int? i = #C1}) → void {}
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
static method main() → dynamic {
new self::A::•().{self::A::test_default}(i: 1);
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.transformed.expect
index e2f0b61..310bd85 100644
--- a/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd_mixed/required_name_override.dart.weak.transformed.expect
@@ -36,7 +36,7 @@
method test_default({required core::int? i = #C1}) → void {}
method test_nondefault({required core::int? i = #C1}) → void {}
method test_legacy({required core::int? i = #C1}) → void {}
- abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
}
static method main() → dynamic {
new self::A::•().{self::A::test_default}(i: 1);
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart
new file mode 100644
index 0000000..a1abf5e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2020, 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.
+
+import 'required_parameter_mixed_from_opt_out_lib.dart';
+
+class Super {
+ void method({required covariant int named}) {}
+}
+
+class Class extends Super with Mixin {}
+
+class SubClass extends Class {
+ void method({required covariant int named}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline.expect
new file mode 100644
index 0000000..ef719ee
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline.expect
@@ -0,0 +1,13 @@
+import 'required_parameter_mixed_from_opt_out_lib.dart';
+
+class Super {
+ void method({required covariant int named}) {}
+}
+
+class Class extends Super with Mixin {}
+
+class SubClass extends Class {
+ void method({required covariant int named}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..45cf3b0
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.textual_outline_modelled.expect
@@ -0,0 +1,13 @@
+import 'required_parameter_mixed_from_opt_out_lib.dart';
+
+class Class extends Super with Mixin {}
+
+class SubClass extends Class {
+ void method({required covariant int named}) {}
+}
+
+class Super {
+ void method({required covariant int named}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.expect
new file mode 100644
index 0000000..8c936d9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.expect
@@ -0,0 +1,55 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "required_parameter_mixed_from_opt_out_lib.dart" as req;
+
+import "org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart";
+
+class Super extends core::Object {
+ synthetic constructor •() → self::Super
+ : super core::Object::•()
+ ;
+ method method({required covariant core::int named = #C1}) → void {}
+}
+abstract class _Class&Super&Mixin = self::Super with req::Mixin /*isAnonymousMixin*/ {
+ synthetic constructor •() → self::_Class&Super&Mixin
+ : super self::Super::•()
+ ;
+ forwarding-stub method /*isNullableByDefault*/ method({covariant core::int* named = #C1}) → void
+ return super.{self::Super::method}(named: named);
+ abstract member-signature operator /*isNullableByDefault*/ ==(dynamic other) → core::bool*; -> core::Object::==
+}
+class Class extends self::_Class&Super&Mixin {
+ synthetic constructor •() → self::Class
+ : super self::_Class&Super&Mixin::•()
+ ;
+}
+class SubClass extends self::Class {
+ synthetic constructor •() → self::SubClass
+ : super self::Class::•()
+ ;
+ method method({required covariant core::int named = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+library;
+import self as req;
+import "dart:core" as core;
+
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+ method method({core::int* named = #C1}) → void {}
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.transformed.expect
new file mode 100644
index 0000000..5db65ce
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out.dart.weak.transformed.expect
@@ -0,0 +1,63 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "required_parameter_mixed_from_opt_out_lib.dart" as req;
+
+import "org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart";
+
+class Super extends core::Object {
+ synthetic constructor •() → self::Super
+ : super core::Object::•()
+ ;
+ method method({required covariant core::int named = #C1}) → void {}
+}
+abstract class _Class&Super&Mixin extends self::Super implements req::Mixin /*isAnonymousMixin,isEliminatedMixin*/ {
+ synthetic constructor •() → self::_Class&Super&Mixin
+ : super self::Super::•()
+ ;
+ method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ method({covariant core::int* named = #C1}) → void {}
+ abstract member-signature operator /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature get /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ toString() → core::String*; -> core::Object::toString
+ abstract member-signature method /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get /*isNullableByDefault, from org-dartlang-testcase:///required_parameter_mixed_from_opt_out_lib.dart */ runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+class Class extends self::_Class&Super&Mixin {
+ synthetic constructor •() → self::Class
+ : super self::_Class&Super&Mixin::•()
+ ;
+}
+class SubClass extends self::Class {
+ synthetic constructor •() → self::SubClass
+ : super self::Class::•()
+ ;
+ method method({required covariant core::int named = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+library;
+import self as req;
+import "dart:core" as core;
+
+abstract class Mixin extends core::Object /*isMixinDeclaration*/ {
+ method method({core::int* named = #C1}) → void {}
+ abstract member-signature get _identityHashCode() → core::int*; -> core::Object::_identityHashCode
+ abstract member-signature method _instanceOf(dynamic instantiatorTypeArguments, dynamic functionTypeArguments, dynamic type) → core::bool*; -> core::Object::_instanceOf
+ abstract member-signature method _simpleInstanceOf(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOf
+ abstract member-signature method _simpleInstanceOfTrue(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfTrue
+ abstract member-signature method _simpleInstanceOfFalse(dynamic type) → core::bool*; -> core::Object::_simpleInstanceOfFalse
+ abstract member-signature operator ==(dynamic other) → core::bool*; -> core::Object::==
+ abstract member-signature get hashCode() → core::int*; -> core::Object::hashCode
+ abstract member-signature method toString() → core::String*; -> core::Object::toString
+ abstract member-signature method noSuchMethod(core::Invocation* invocation) → dynamic; -> core::Object::noSuchMethod
+ abstract member-signature get runtimeType() → core::Type*; -> core::Object::runtimeType
+}
+
+constants {
+ #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out_lib.dart b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out_lib.dart
new file mode 100644
index 0000000..922c203
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd_mixed/required_parameter_mixed_from_opt_out_lib.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.
+
+// @dart=2.9
+
+mixin Mixin {
+ void method({int named}) {}
+}