[cfe] Pass on guard in if-case statement

Change-Id: Ic7c201bd90b2cf67a2b7526fc4ac035b21f34cc6
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/265720
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
This commit is contained in:
Johnni Winther 2022-10-26 10:19:58 +00:00 committed by Commit Queue
parent 7e87efd2e7
commit 142bf69440
40 changed files with 331 additions and 8 deletions

View file

@ -2317,7 +2317,7 @@ class BodyBuilder extends StackListenerImpl
libraryFeatures.patterns, case_.charOffset, case_.charCount);
Matcher matcher = toMatcher(pop());
Expression expression = popForValue();
push(new Condition(expression, matcher));
push(new Condition(expression, matcher, guard));
} else {
assert(checkState(token, [
unionOfKinds([
@ -3495,11 +3495,12 @@ class BodyBuilder extends StackListenerImpl
Statement thenPart = popStatement();
Condition condition = pop() as Condition;
Matcher? matcher = condition.matcher;
Expression? guard = condition.guard;
Expression expression = condition.expression;
Statement node;
if (matcher != null) {
node = new IfCaseStatement(
expression, matcher, thenPart, elsePart, ifToken.charOffset);
expression, matcher, guard, thenPart, elsePart, ifToken.charOffset);
} else {
node = forest.createIfStatement(
offsetForToken(ifToken), expression, thenPart, elsePart);
@ -8809,10 +8810,14 @@ class _FindChildVisitor extends Visitor<void> with VisitorVoidMixin {
class Condition {
final Expression expression;
final Matcher? matcher;
final Expression? guard;
Condition(this.expression, [this.matcher]);
Condition(this.expression, [this.matcher, this.guard])
: assert(guard == null || matcher != null,
"Unexpected guard without matcher.");
@override
String toString() =>
'Condition($expression${matcher != null ? ',$matcher' : ''})';
String toString() => 'Condition($expression'
'${matcher != null ? ',$matcher' : ''}'
'${guard != null ? ',$guard' : ''})';
}

View file

@ -5461,17 +5461,26 @@ class PatternVariableDeclaration extends Statement {
final Matcher dummyMatcher = new ExpressionMatcher(dummyExpression);
/// Internal statement for a if-case statements:
///
/// if (expression case matcher) then
/// if (expression case matcher) then else otherwise
/// if (expression case matcher when guard) then
/// if (expression case matcher when guard) then else otherwise
///
class IfCaseStatement extends InternalStatement {
Expression expression;
Matcher matcher;
Expression? guard;
Statement then;
Statement? otherwise;
IfCaseStatement(this.expression, this.matcher, this.then, this.otherwise,
int fileOffset) {
IfCaseStatement(this.expression, this.matcher, this.guard, this.then,
this.otherwise, int fileOffset) {
this.fileOffset = fileOffset;
expression.parent = this;
matcher.parent = this;
guard?.parent = this;
then.parent = this;
otherwise?.parent = this;
}
@ -5487,6 +5496,10 @@ class IfCaseStatement extends InternalStatement {
printer.writeExpression(expression);
printer.write(' case ');
matcher.toTextInternal(printer);
if (guard != null) {
printer.write(' when ');
printer.writeExpression(guard!);
}
printer.write(') ');
printer.writeStatement(then);
if (otherwise != null) {

View file

@ -1802,7 +1802,7 @@ class InferenceVisitorImpl extends InferenceVisitorBase
}
StatementInferenceResult visitIfCaseStatement(IfCaseStatement node) {
// TODO(cstefantsova): Handle if-case statements.
// TODO(cstefantsova): Handle if-case-when statements.
return new StatementInferenceResult.single(
new EmptyStatement()..fileOffset = node.fileOffset);
}

View file

@ -1144,6 +1144,7 @@ void _testIfCaseStatement() {
new IfCaseStatement(
new IntLiteral(0),
new ExpressionMatcher(new IntLiteral(1)),
null,
new ReturnStatement(),
null,
TreeNode.noOffset),
@ -1154,9 +1155,32 @@ if (0 case 1) return;''');
new IfCaseStatement(
new IntLiteral(0),
new ExpressionMatcher(new IntLiteral(1)),
null,
new ReturnStatement(new IntLiteral(2)),
new ReturnStatement(new IntLiteral(3)),
TreeNode.noOffset),
'''
if (0 case 1) return 2; else return 3;''');
testStatement(
new IfCaseStatement(
new IntLiteral(0),
new ExpressionMatcher(new IntLiteral(1)),
new IntLiteral(2),
new ReturnStatement(),
null,
TreeNode.noOffset),
'''
if (0 case 1 when 2) return;''');
testStatement(
new IfCaseStatement(
new IntLiteral(0),
new ExpressionMatcher(new IntLiteral(1)),
new IntLiteral(2),
new ReturnStatement(new IntLiteral(3)),
new ReturnStatement(new IntLiteral(4)),
TreeNode.noOffset),
'''
if (0 case 1 when 2) return 3; else return 4;''');
}

View file

@ -0,0 +1,3 @@
void f(x) {
if (x case 0 when true) {}
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,5 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void
;

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
void f(x) {
switch (x) {
case 0 when true:
break;
}
}

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = 0
}

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = 0
}

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = 0
}

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = 0
}

View file

@ -0,0 +1,5 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void
;

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
import "dart:core" as core;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = 0
}

View file

@ -0,0 +1,3 @@
void f(x) {
if (x case 0 as int when true) {}
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,5 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void
;

View file

@ -0,0 +1,6 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
;
}

View file

@ -0,0 +1,6 @@
void f(x) {
switch (x) {
case 0 as int when true:
break;
}
}

View file

@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = null
}

View file

@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = null
}

View file

@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = null
}

View file

@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = null
}

View file

@ -0,0 +1,5 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void
;

View file

@ -0,0 +1,17 @@
library /*isNonNullableByDefault*/;
import self as self;
static method f(dynamic x) → void {
#L1:
switch(x) {
#L2:
case #C1:
{
break #L1;
}
}
}
constants {
#C1 = null
}