[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
}