[cfe] Synthesize null initializer for required named parameters

The initializer is required for weak mode and won't affect the strong
mode.

Change-Id: I719fad1ee73e4e7b01c6608f931c37d038db01b8
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/130700
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
index 4b2ba9b..26f3db3 100644
--- a/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
+++ b/pkg/front_end/lib/src/fasta/builder/formal_parameter_builder.dart
@@ -70,6 +70,9 @@
 
   bool initializerWasInferred = false;
 
+  /// True if the initializer was declared by the programmer.
+  bool hasDeclaredInitializer = false;
+
   FormalParameterBuilder(this.metadata, this.modifiers, this.type, this.name,
       LibraryBuilder compilationUnit, int charOffset,
       [Uri fileUri])
@@ -180,8 +183,8 @@
       assert(!initializerWasInferred);
       Expression initializer =
           bodyBuilder.parseFieldInitializer(initializerToken);
-      initializer = bodyBuilder.typeInferrer
-          ?.inferParameterInitializer(bodyBuilder, initializer, variable.type);
+      initializer = bodyBuilder.typeInferrer?.inferParameterInitializer(
+          bodyBuilder, initializer, variable.type, hasDeclaredInitializer);
       variable.initializer = initializer..parent = variable;
       if (library.loader is SourceLoader) {
         SourceLoader loader = library.loader;
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
index 31c1e1a..210998e 100644
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart
@@ -888,7 +888,10 @@
             }
             VariableDeclaration originParameter = builder.getFormalParameter(i);
             initializer = typeInferrer?.inferParameterInitializer(
-                this, initializer, originParameter.type);
+                this,
+                initializer,
+                originParameter.type,
+                parameter.hasDeclaredInitializer);
             originParameter.initializer = initializer..parent = originParameter;
             libraryBuilder.loader.transformPostInference(
                 originParameter,
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index 9a7bf3a..4213637 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -2200,8 +2200,9 @@
       modifiers |= initializingFormalMask;
     }
     FormalParameterBuilder formal = new FormalParameterBuilder(
-        metadata, modifiers, type, name, this, charOffset, uri);
-    formal.initializerToken = initializerToken;
+        metadata, modifiers, type, name, this, charOffset, uri)
+      ..initializerToken = initializerToken
+      ..hasDeclaredInitializer = (initializerToken != null);
     return formal;
   }
 
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
index 0757cdd..c6ef570 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inferrer.dart
@@ -439,7 +439,10 @@
   /// Performs type inference on the given function parameter initializer
   /// expression.
   Expression inferParameterInitializer(
-      InferenceHelper helper, Expression initializer, DartType declaredType);
+      InferenceHelper helper,
+      Expression initializer,
+      DartType declaredType,
+      bool hasDeclaredInitializer);
 
   /// Ensures that all parameter types of [constructor] have been inferred.
   // TODO(johnniwinther): We are still parameters on synthesized mixin
@@ -2840,13 +2843,18 @@
 
   @override
   Expression inferParameterInitializer(
-      InferenceHelper helper, Expression initializer, DartType declaredType) {
+      InferenceHelper helper,
+      Expression initializer,
+      DartType declaredType,
+      bool hasDeclaredInitializer) {
     assert(closureContext == null);
     this.helper = helper;
     assert(declaredType != null);
     ExpressionInferenceResult result =
         inferExpression(initializer, declaredType, true);
-    initializer = ensureAssignableResult(declaredType, result);
+    if (hasDeclaredInitializer) {
+      initializer = ensureAssignableResult(declaredType, result);
+    }
     this.helper = null;
     return initializer;
   }
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
index 7eff55e..5f1bfd7 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/opt_out.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
@@ -25,7 +20,7 @@
 static field core::String? s = null;
 static field core::String t = self::s!;
 late static field core::int field = 42;
-static method method(() →? void f, {required core::int a = invalid-expression "pkg/front_end/testcases/nnbd/opt_out.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → void {}
+static method method(() →? void f, {required core::int a = #C1}) → void {}
 static method main() → dynamic {}
 static method noErrors() → dynamic {
   late core::int local = 42;
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
index 7eff55e..5f1bfd7 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.strong.transformed.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/opt_out.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
@@ -25,7 +20,7 @@
 static field core::String? s = null;
 static field core::String t = self::s!;
 late static field core::int field = 42;
-static method method(() →? void f, {required core::int a = invalid-expression "pkg/front_end/testcases/nnbd/opt_out.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → void {}
+static method method(() →? void f, {required core::int a = #C1}) → void {}
 static method main() → dynamic {}
 static method noErrors() → dynamic {
   late core::int local = 42;
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
index 16ef433..5f1bfd7 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/opt_out.dart: Warning: Assigning value of type 'Null?' to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
index 16ef433..5f1bfd7 100644
--- a/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/opt_out.dart.weak.transformed.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/opt_out.dart: Warning: Assigning value of type 'Null?' to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
index b906bf8..0347610 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
@@ -13,12 +8,13 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-  method method({core::int a = #C1, required core::int b = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required final core::int c = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required covariant final core::int d = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → dynamic {}
+  method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2, required covariant final core::int d = #C2}) → dynamic {}
 }
 static field ({a: core::int, required b: core::int}) → dynamic field;
-static method method({core::int a = #C1, required core::int b = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required final core::int c = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → dynamic {}
+static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }
diff --git a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
index b906bf8..0347610 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.strong.transformed.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
@@ -13,12 +8,13 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-  method method({core::int a = #C1, required core::int b = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required final core::int c = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required covariant final core::int d = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → dynamic {}
+  method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2, required covariant final core::int d = #C2}) → dynamic {}
 }
 static field ({a: core::int, required b: core::int}) → dynamic field;
-static method method({core::int a = #C1, required core::int b = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'.", required final core::int c = invalid-expression "pkg/front_end/testcases/nnbd/required.dart: Error: A value of type 'Null?' can't be assigned to a variable of type 'int'."}) → dynamic {}
+static method method({core::int a = #C1, required core::int b = #C2, required final core::int c = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }
diff --git a/pkg/front_end/testcases/nnbd/required.dart.weak.expect b/pkg/front_end/testcases/nnbd/required.dart.weak.expect
index cc4fcef..0347610 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.weak.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/required.dart: Warning: Assigning value of type 'Null?' to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
index cc4fcef..0347610 100644
--- a/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required.dart.weak.transformed.expect
@@ -1,9 +1,4 @@
 library;
-//
-// Problems in library:
-//
-// pkg/front_end/testcases/nnbd/required.dart: Warning: Assigning value of type 'Null?' to a variable of type 'int'.
-//
 import self as self;
 import "dart:core" as core;
 
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart b/pkg/front_end/testcases/nnbd/required_named_parameter.dart
index 301c32f..49a509e 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart
@@ -2,6 +2,10 @@
 // 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.
 
+// Should be a compile-time error / warning.
 foo({required int parameter = 42}) {}
 
+// Should be ok.
+bar({required int parameter}) {}
+
 main() {}
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
index a594396..385108f 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.outline.expect
@@ -2,7 +2,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/required_named_parameter.dart:5:19: Error: Required named parameter 'parameter' can't have a default value.
+// pkg/front_end/testcases/nnbd/required_named_parameter.dart:6:19: Error: Required named parameter 'parameter' can't have a default value.
 // foo({required int parameter = 42}) {}
 //                   ^^^^^^^^^
 //
@@ -11,5 +11,7 @@
 
 static method foo({required core::int parameter}) → dynamic
   ;
+static method bar({required core::int parameter}) → dynamic
+  ;
 static method main() → dynamic
   ;
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
index a34d591..b865c67 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.expect
@@ -2,7 +2,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/required_named_parameter.dart:5:19: Error: Required named parameter 'parameter' can't have a default value.
+// pkg/front_end/testcases/nnbd/required_named_parameter.dart:6:19: Error: Required named parameter 'parameter' can't have a default value.
 // foo({required int parameter = 42}) {}
 //                   ^^^^^^^^^
 //
@@ -10,8 +10,10 @@
 import "dart:core" as core;
 
 static method foo({required core::int parameter = #C1}) → dynamic {}
+static method bar({required core::int parameter = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
index a34d591..b865c67 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/required_named_parameter.dart:5:19: Error: Required named parameter 'parameter' can't have a default value.
+// pkg/front_end/testcases/nnbd/required_named_parameter.dart:6:19: Error: Required named parameter 'parameter' can't have a default value.
 // foo({required int parameter = 42}) {}
 //                   ^^^^^^^^^
 //
@@ -10,8 +10,10 @@
 import "dart:core" as core;
 
 static method foo({required core::int parameter = #C1}) → dynamic {}
+static method bar({required core::int parameter = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
index 21278e2..0ccf7a2d 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.expect
@@ -2,7 +2,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/required_named_parameter.dart:5:19: Warning: Required named parameter 'parameter' has a default value.
+// pkg/front_end/testcases/nnbd/required_named_parameter.dart:6:19: Warning: Required named parameter 'parameter' has a default value.
 // foo({required int parameter = 42}) {}
 //                   ^^^^^^^^^
 //
@@ -10,8 +10,10 @@
 import "dart:core" as core;
 
 static method foo({required core::int parameter = #C1}) → dynamic {}
+static method bar({required core::int parameter = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }
diff --git a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
index 21278e2..0ccf7a2d 100644
--- a/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/required_named_parameter.dart.weak.transformed.expect
@@ -2,7 +2,7 @@
 //
 // Problems in library:
 //
-// pkg/front_end/testcases/nnbd/required_named_parameter.dart:5:19: Warning: Required named parameter 'parameter' has a default value.
+// pkg/front_end/testcases/nnbd/required_named_parameter.dart:6:19: Warning: Required named parameter 'parameter' has a default value.
 // foo({required int parameter = 42}) {}
 //                   ^^^^^^^^^
 //
@@ -10,8 +10,10 @@
 import "dart:core" as core;
 
 static method foo({required core::int parameter = #C1}) → dynamic {}
+static method bar({required core::int parameter = #C2}) → dynamic {}
 static method main() → dynamic {}
 
 constants  {
   #C1 = 42
+  #C2 = null
 }