[cfe] Handle required parameters in combined member signature creation

Change-Id: I4ee6a6f1f404a65e7abc926adaa08178698838e9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/170880
Reviewed-by: Jens Johansen <jensj@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 ea003a5..f89b4e8 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
@@ -582,18 +582,22 @@
       NamedType namedType = functionType.namedParameters.first;
       VariableDeclaration parameter = function.namedParameters.first;
       namedParameters.add(new VariableDeclaration(parameter.name,
-          type: namedType.type, isCovariant: parameter.isCovariant)
+          type: namedType.type,
+          isRequired: namedType.isRequired,
+          isCovariant: parameter.isCovariant)
         ..isGenericCovariantImpl = parameter.isGenericCovariantImpl);
     } else if (namedParameterCount > 1) {
-      Map<String, DartType> namedTypes = {};
+      Map<String, NamedType> namedTypes = {};
       for (NamedType namedType in functionType.namedParameters) {
-        namedTypes[namedType.name] = namedType.type;
+        namedTypes[namedType.name] = namedType;
       }
       for (int i = 0; i < namedParameterCount; i++) {
         VariableDeclaration parameter = function.namedParameters[i];
-        DartType parameterType = namedTypes[parameter.name];
+        NamedType namedParameterType = namedTypes[parameter.name];
         namedParameters.add(new VariableDeclaration(parameter.name,
-            type: parameterType, isCovariant: parameter.isCovariant)
+            type: namedParameterType.type,
+            isRequired: namedParameterType.isRequired,
+            isCovariant: parameter.isCovariant)
           ..isGenericCovariantImpl = parameter.isGenericCovariantImpl);
       }
     }
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart b/pkg/front_end/testcases/nnbd/combined_required.dart
new file mode 100644
index 0000000..9584091
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart
@@ -0,0 +1,18 @@
+class A {
+  void method1({required int a}) {}
+  void method2({int? a, required int b}) {}
+}
+
+class B {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+class C extends A implements B {}
+
+class D extends C {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.outline.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.outline.expect
new file mode 100644
index 0000000..f39bdf2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.outline.expect
@@ -0,0 +1,38 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    ;
+  method method1({required core::int a}) → void
+    ;
+  method method2({core::int? a, required core::int b}) → void
+    ;
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    ;
+  method method1({required covariant core::int a}) → void
+    ;
+  method method2({covariant core::int? a, required core::int b}) → void
+    ;
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → self::C
+    ;
+  forwarding-stub method method1({required covariant core::int a}) → void
+    return super.{self::A::method1}(a: a);
+  forwarding-stub method method2({covariant core::int? a, required core::int b}) → void
+    return super.{self::A::method2}(a: a, b: b);
+}
+class D extends self::C {
+  synthetic constructor •() → self::D
+    ;
+  method method1({required covariant core::int a}) → void
+    ;
+  method method2({covariant core::int? a, required core::int b}) → void
+    ;
+}
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.strong.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.strong.expect
new file mode 100644
index 0000000..34958ef
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.strong.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method method1({required core::int a = #C1}) → void {}
+  method method2({core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → self::C
+    : super self::A::•()
+    ;
+  forwarding-stub method method1({required covariant core::int a = #C1}) → void
+    return super.{self::A::method1}(a: a);
+  forwarding-stub method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void
+    return super.{self::A::method2}(a: a, b: b);
+}
+class D extends self::C {
+  synthetic constructor •() → self::D
+    : super self::C::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.strong.transformed.expect
new file mode 100644
index 0000000..34958ef
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.strong.transformed.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method method1({required core::int a = #C1}) → void {}
+  method method2({core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → self::C
+    : super self::A::•()
+    ;
+  forwarding-stub method method1({required covariant core::int a = #C1}) → void
+    return super.{self::A::method1}(a: a);
+  forwarding-stub method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void
+    return super.{self::A::method2}(a: a, b: b);
+}
+class D extends self::C {
+  synthetic constructor •() → self::D
+    : super self::C::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline.expect
new file mode 100644
index 0000000..9584091
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline.expect
@@ -0,0 +1,18 @@
+class A {
+  void method1({required int a}) {}
+  void method2({int? a, required int b}) {}
+}
+
+class B {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+class C extends A implements B {}
+
+class D extends C {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..9584091
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.textual_outline_modelled.expect
@@ -0,0 +1,18 @@
+class A {
+  void method1({required int a}) {}
+  void method2({int? a, required int b}) {}
+}
+
+class B {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+class C extends A implements B {}
+
+class D extends C {
+  void method1({required covariant int a}) {}
+  void method2({covariant int? a, required int b}) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.weak.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.weak.expect
new file mode 100644
index 0000000..34958ef
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.weak.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method method1({required core::int a = #C1}) → void {}
+  method method2({core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → self::C
+    : super self::A::•()
+    ;
+  forwarding-stub method method1({required covariant core::int a = #C1}) → void
+    return super.{self::A::method1}(a: a);
+  forwarding-stub method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void
+    return super.{self::A::method2}(a: a, b: b);
+}
+class D extends self::C {
+  synthetic constructor •() → self::D
+    : super self::C::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/combined_required.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/combined_required.dart.weak.transformed.expect
new file mode 100644
index 0000000..34958ef
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/combined_required.dart.weak.transformed.expect
@@ -0,0 +1,39 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+  synthetic constructor •() → self::A
+    : super core::Object::•()
+    ;
+  method method1({required core::int a = #C1}) → void {}
+  method method2({core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class B extends core::Object {
+  synthetic constructor •() → self::B
+    : super core::Object::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+class C extends self::A implements self::B {
+  synthetic constructor •() → self::C
+    : super self::A::•()
+    ;
+  forwarding-stub method method1({required covariant core::int a = #C1}) → void
+    return super.{self::A::method1}(a: a);
+  forwarding-stub method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void
+    return super.{self::A::method2}(a: a, b: b);
+}
+class D extends self::C {
+  synthetic constructor •() → self::D
+    : super self::C::•()
+    ;
+  method method1({required covariant core::int a = #C1}) → void {}
+  method method2({covariant core::int? a = #C1, required core::int b = #C1}) → void {}
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}