[cfe] Implement the desugaring for NullAssertPattern
Part of https://github.com/dart-lang/sdk/issues/49749
Change-Id: I56ac79a98eb4306daabec05d95f09bb18d248825
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/268961
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
index 34e4a62..3cef561 100644
--- a/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/internal_ast.dart
@@ -5417,15 +5417,56 @@
@override
Expression? makeCondition(VariableDeclaration matchedExpressionVariable,
InferenceVisitorBase inferenceVisitor) {
- return new InvalidExpression(
- "Unimplemented NullAssertPattern.makeCondition");
+ // nullCheckCondition: `matchedExpressionVariable`!
+ Expression nullCheckExpression = inferenceVisitor.engine.forest
+ .createNullCheck(
+ fileOffset,
+ inferenceVisitor.engine.forest
+ .createVariableGet(fileOffset, matchedExpressionVariable));
+
+ DartType typeWithoutNullabilityMarkers =
+ matchedExpressionVariable.type.toNonNull();
+
+ // intermediateVariable: `typeWithoutNullabilityMarkers` VAR =
+ // `nullCheckExpression`;
+ // ==> `typeWithoutNullabilityMarkers` VAR = `matchedExpressionVariable`!;
+ VariableDeclaration intermediateVariable = inferenceVisitor.engine.forest
+ .createVariableDeclarationForValue(nullCheckExpression,
+ type: typeWithoutNullabilityMarkers);
+
+ Expression? patternCondition =
+ pattern.makeCondition(intermediateVariable, inferenceVisitor);
+ if (patternCondition == null) {
+ // TODO(cstefantsova): As an optimization of the generated code size and
+ // the number of runtime checks, the null check in this case can be
+ // removed if any variable is initialized via this pattern, and therefore
+ // will have the cast in its initializer expression.
+
+ // return: let `intermediateVariable` in true
+ // ==> let `typeWithoutNullabilityMarkers` VAR =
+ // `matchedExpressionVariable`! in
+ // true
+ return inferenceVisitor.engine.forest.createLet(intermediateVariable,
+ inferenceVisitor.engine.forest.createBoolLiteral(fileOffset, true));
+ } else {
+ // return: let `intermediateVariable` in `patternCondition`
+ // ==> let `typeWithoutNullabilityMarkers` VAR =
+ // `matchedExpressionVariable`! in
+ // `patternCondition`
+ return inferenceVisitor.engine.forest
+ .createLet(intermediateVariable, patternCondition);
+ }
}
@override
void createDeclaredVariableInitializers(Expression matchedExpression,
DartType matchedType, InferenceVisitorBase inferenceVisitor) {
+ DartType matchedTypeWithoutNullabilityMarkers = matchedType.toNonNull();
pattern.createDeclaredVariableInitializers(
- matchedExpression, matchedType, inferenceVisitor);
+ inferenceVisitor.engine.forest
+ .createNullCheck(fileOffset, matchedExpression),
+ matchedTypeWithoutNullabilityMarkers,
+ inferenceVisitor);
}
@override
diff --git a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.expect b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.expect
index 897435b..758e485 100644
--- a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.expect
+++ b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.expect
@@ -3,8 +3,8 @@
static method test(dynamic x) → dynamic {
final dynamic #t1 = x;
- if(invalid-expression "Unimplemented NullAssertPattern.makeCondition") {
- dynamic y = #t1;
+ if(let final dynamic #t2 = #t1! in true) {
+ dynamic y = #t1!;
{}
}
}
diff --git a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.transformed.expect b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.transformed.expect
index 897435b..758e485 100644
--- a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.strong.transformed.expect
@@ -3,8 +3,8 @@
static method test(dynamic x) → dynamic {
final dynamic #t1 = x;
- if(invalid-expression "Unimplemented NullAssertPattern.makeCondition") {
- dynamic y = #t1;
+ if(let final dynamic #t2 = #t1! in true) {
+ dynamic y = #t1!;
{}
}
}
diff --git a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.expect b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.expect
index 897435b..758e485 100644
--- a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.expect
+++ b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.expect
@@ -3,8 +3,8 @@
static method test(dynamic x) → dynamic {
final dynamic #t1 = x;
- if(invalid-expression "Unimplemented NullAssertPattern.makeCondition") {
- dynamic y = #t1;
+ if(let final dynamic #t2 = #t1! in true) {
+ dynamic y = #t1!;
{}
}
}
diff --git a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.modular.expect b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.modular.expect
index 897435b..758e485 100644
--- a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.modular.expect
@@ -3,8 +3,8 @@
static method test(dynamic x) → dynamic {
final dynamic #t1 = x;
- if(invalid-expression "Unimplemented NullAssertPattern.makeCondition") {
- dynamic y = #t1;
+ if(let final dynamic #t2 = #t1! in true) {
+ dynamic y = #t1!;
{}
}
}
diff --git a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.transformed.expect b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.transformed.expect
index 897435b..758e485 100644
--- a/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/patterns/null_assert_inside_if_case.dart.weak.transformed.expect
@@ -3,8 +3,8 @@
static method test(dynamic x) → dynamic {
final dynamic #t1 = x;
- if(invalid-expression "Unimplemented NullAssertPattern.makeCondition") {
- dynamic y = #t1;
+ if(let final dynamic #t2 = #t1! in true) {
+ dynamic y = #t1!;
{}
}
}