Skip to content

Commit c11d12b

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Add basic support for if-case elements in lists
Part of #49749 Change-Id: Ib5dd6d1159c09856971ed5b39b2499971044160a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/282860 Commit-Queue: Chloe Stefantsova <[email protected]> Reviewed-by: Johnni Winther <[email protected]>
1 parent ae408d3 commit c11d12b

14 files changed

+704
-17
lines changed

pkg/front_end/lib/src/fasta/kernel/body_builder.dart

+60-11
Original file line numberDiff line numberDiff line change
@@ -3590,7 +3590,7 @@ class BodyBuilder extends StackListenerImpl
35903590
assert(checkState(token, [ValueKinds.Scope]));
35913591
Scope thenScope = scope.createNestedScope(
35923592
debugName: "then body", kind: ScopeKind.statementLocalScope);
3593-
exitLocalScope();
3593+
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
35943594
push(condition);
35953595
enterLocalScope(thenScope);
35963596
} else {
@@ -6473,10 +6473,39 @@ class BodyBuilder extends StackListenerImpl
64736473

64746474
@override
64756475
void handleThenControlFlow(Token token) {
6476+
assert(checkState(token, [ValueKinds.Condition]));
64766477
// This is matched by the call to [deferNode] in
64776478
// [handleElseControlFlow] and by the call to [endNode] in
64786479
// [endIfControlFlow].
64796480
typeInferrer.assignedVariables.beginNode();
6481+
6482+
Condition condition = pop() as Condition;
6483+
PatternGuard? patternGuard = condition.patternGuard;
6484+
if (patternGuard != null) {
6485+
if (patternGuard.guard != null) {
6486+
Scope thenScope = scope.createNestedScope(
6487+
debugName: "then-control-flow", kind: ScopeKind.ifElement);
6488+
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
6489+
enterLocalScope(thenScope);
6490+
} else {
6491+
createAndEnterLocalScope(
6492+
debugName: "if-case-head", kind: ScopeKind.ifCaseHead);
6493+
for (VariableDeclaration variable
6494+
in patternGuard.pattern.declaredVariables) {
6495+
declareVariable(variable, scope);
6496+
typeInferrer.assignedVariables.declare(variable);
6497+
}
6498+
Scope thenScope = scope.createNestedScope(
6499+
debugName: "then-control-flow", kind: ScopeKind.ifElement);
6500+
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifCaseHead]);
6501+
enterLocalScope(thenScope);
6502+
}
6503+
} else {
6504+
createAndEnterLocalScope(
6505+
debugName: "then-control-flow", kind: ScopeKind.ifElement);
6506+
}
6507+
push(condition);
6508+
64806509
super.handleThenControlFlow(token);
64816510
}
64826511

@@ -6504,22 +6533,33 @@ class BodyBuilder extends StackListenerImpl
65046533
ValueKinds.MapLiteralEntry,
65056534
]),
65066535
ValueKinds.Condition,
6536+
ValueKinds.Scope,
65076537
ValueKinds.Token,
65086538
]));
65096539

65106540
Object? entry = pop();
65116541
Condition condition = pop() as Condition;
6512-
assert(condition.patternGuard == null,
6513-
"Unexpected pattern in control flow if: ${condition.patternGuard}.");
6542+
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifElement]);
65146543
Token ifToken = pop() as Token;
65156544

6545+
PatternGuard? patternGuard = condition.patternGuard;
65166546
TreeNode node;
65176547
if (entry is MapLiteralEntry) {
6518-
node = forest.createIfMapEntry(
6519-
offsetForToken(ifToken), condition.expression, entry);
6548+
if (patternGuard == null) {
6549+
node = forest.createIfMapEntry(
6550+
offsetForToken(ifToken), condition.expression, entry);
6551+
} else {
6552+
node = forest.createIfCaseMapEntry(
6553+
offsetForToken(ifToken), condition.expression, patternGuard, entry);
6554+
}
65206555
} else {
6521-
node = forest.createIfElement(
6522-
offsetForToken(ifToken), condition.expression, toValue(entry));
6556+
if (patternGuard == null) {
6557+
node = forest.createIfElement(
6558+
offsetForToken(ifToken), condition.expression, toValue(entry));
6559+
} else {
6560+
node = forest.createIfCaseElement(offsetForToken(ifToken),
6561+
condition.expression, patternGuard, toValue(entry));
6562+
}
65236563
}
65246564
push(node);
65256565
// This is matched by the call to [beginNode] in
@@ -6545,6 +6585,7 @@ class BodyBuilder extends StackListenerImpl
65456585
]),
65466586
ValueKinds.AssignedVariablesNodeInfo,
65476587
ValueKinds.Condition,
6588+
ValueKinds.Scope,
65486589
ValueKinds.Token,
65496590
]));
65506591

@@ -6553,8 +6594,7 @@ class BodyBuilder extends StackListenerImpl
65536594
AssignedVariablesNodeInfo assignedVariablesInfo =
65546595
pop() as AssignedVariablesNodeInfo;
65556596
Condition condition = pop() as Condition; // parenthesized expression
6556-
assert(condition.patternGuard == null,
6557-
"Unexpected pattern in control flow if: ${condition.patternGuard}.");
6597+
exitLocalScope(expectedScopeKinds: const [ScopeKind.ifElement]);
65586598
Token ifToken = pop() as Token;
65596599

65606600
TreeNode node;
@@ -6612,8 +6652,17 @@ class BodyBuilder extends StackListenerImpl
66126652
..fileOffset = offsetForToken(ifToken);
66136653
}
66146654
} else {
6615-
node = forest.createIfElement(offsetForToken(ifToken),
6616-
condition.expression, toValue(thenEntry), toValue(elseEntry));
6655+
if (condition.patternGuard == null) {
6656+
node = forest.createIfElement(offsetForToken(ifToken),
6657+
condition.expression, toValue(thenEntry), toValue(elseEntry));
6658+
} else {
6659+
node = forest.createIfCaseElement(
6660+
offsetForToken(ifToken),
6661+
condition.expression,
6662+
condition.patternGuard!,
6663+
toValue(thenEntry),
6664+
toValue(elseEntry));
6665+
}
66176666
}
66186667
push(node);
66196668
// This is matched by the call to [deferNode] in

pkg/front_end/lib/src/fasta/kernel/forest.dart

+18
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,15 @@ class Forest {
272272
return new IfElement(condition, then, otherwise)..fileOffset = fileOffset;
273273
}
274274

275+
Expression createIfCaseElement(int fileOffset, Expression expression,
276+
PatternGuard patternGuard, Expression then,
277+
[Expression? otherwise]) {
278+
// ignore: unnecessary_null_comparison
279+
assert(fileOffset != null);
280+
return new IfCaseElement(expression, patternGuard, then, otherwise)
281+
..fileOffset = fileOffset;
282+
}
283+
275284
MapLiteralEntry createIfMapEntry(
276285
int fileOffset, Expression condition, MapLiteralEntry then,
277286
[MapLiteralEntry? otherwise]) {
@@ -280,6 +289,15 @@ class Forest {
280289
return new IfMapEntry(condition, then, otherwise)..fileOffset = fileOffset;
281290
}
282291

292+
MapLiteralEntry createIfCaseMapEntry(int fileOffset, Expression expression,
293+
PatternGuard patternGuard, MapLiteralEntry then,
294+
[MapLiteralEntry? otherwise]) {
295+
// ignore: unnecessary_null_comparison
296+
assert(fileOffset != null);
297+
return new IfCaseMapEntry(expression, patternGuard, then, otherwise)
298+
..fileOffset = fileOffset;
299+
}
300+
283301
ForElement createForElement(
284302
int fileOffset,
285303
List<VariableDeclaration> variables,

pkg/front_end/lib/src/fasta/kernel/internal_ast.dart

+89
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import '../type_inference/inference_visitor.dart';
3232
import '../type_inference/inference_results.dart';
3333
import '../type_inference/type_schema.dart' show UnknownType;
3434

35+
import 'collections.dart';
36+
3537
typedef SharedMatchContext = shared
3638
.MatchContext<TreeNode, Expression, Pattern, DartType, VariableDeclaration>;
3739

@@ -4805,3 +4807,90 @@ enum ObjectAccessKind {
48054807
/// Erroneous property access.
48064808
Error,
48074809
}
4810+
4811+
class IfCaseElement extends InternalExpression with ControlFlowElement {
4812+
Expression expression;
4813+
PatternGuard patternGuard;
4814+
Expression then;
4815+
Expression? otherwise;
4816+
late List<Statement> replacement;
4817+
4818+
IfCaseElement(this.expression, this.patternGuard, this.then, this.otherwise) {
4819+
expression.parent = this;
4820+
patternGuard.parent = this;
4821+
then.parent = this;
4822+
otherwise?.parent = this;
4823+
}
4824+
4825+
@override
4826+
ExpressionInferenceResult acceptInference(
4827+
InferenceVisitorImpl visitor, DartType typeContext) {
4828+
throw new UnsupportedError("IfCaseElement.acceptInference");
4829+
}
4830+
4831+
@override
4832+
void toTextInternal(AstPrinter printer) {
4833+
printer.write('if (');
4834+
printer.writeExpression(expression);
4835+
printer.write(' case ');
4836+
patternGuard.toTextInternal(printer);
4837+
printer.write(') ');
4838+
printer.writeExpression(then);
4839+
if (otherwise != null) {
4840+
printer.write(' else ');
4841+
printer.writeExpression(otherwise!);
4842+
}
4843+
}
4844+
4845+
@override
4846+
MapLiteralEntry? toMapLiteralEntry(
4847+
void Function(TreeNode from, TreeNode to) onConvertElement) {
4848+
// TODO(cstefantsova): implement toMapLiteralEntry
4849+
throw new UnimplementedError();
4850+
}
4851+
4852+
@override
4853+
String toString() {
4854+
return "IfCaseElement(${toStringInternal()})";
4855+
}
4856+
}
4857+
4858+
class IfCaseMapEntry extends TreeNode
4859+
with InternalTreeNode, ControlFlowMapEntry {
4860+
Expression expression;
4861+
PatternGuard patternGuard;
4862+
MapLiteralEntry then;
4863+
MapLiteralEntry? otherwise;
4864+
4865+
IfCaseMapEntry(
4866+
this.expression, this.patternGuard, this.then, this.otherwise) {
4867+
expression.parent = this;
4868+
patternGuard.parent = this;
4869+
then.parent = this;
4870+
otherwise?.parent = this;
4871+
}
4872+
4873+
ExpressionInferenceResult acceptInference(
4874+
InferenceVisitorImpl visitor, DartType typeContext) {
4875+
throw new UnsupportedError("IfCaseMapEntry.acceptInference");
4876+
}
4877+
4878+
@override
4879+
void toTextInternal(AstPrinter printer) {
4880+
printer.write('if (');
4881+
expression.toTextInternal(printer);
4882+
printer.write(' case ');
4883+
patternGuard.toTextInternal(printer);
4884+
printer.write(') ');
4885+
then.toTextInternal(printer);
4886+
if (otherwise != null) {
4887+
printer.write(' else ');
4888+
otherwise!.toTextInternal(printer);
4889+
}
4890+
}
4891+
4892+
@override
4893+
String toString() {
4894+
return "IfCaseMapEntry(${toStringInternal()})";
4895+
}
4896+
}

pkg/front_end/lib/src/fasta/scope.dart

+4-1
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ enum ScopeKind {
5151
/// Scope of the head of the if-case statement
5252
ifCaseHead,
5353

54+
/// Scope of an if-element in a collection
55+
ifElement,
56+
5457
/// Scope for the initializers of generative constructors
5558
initializers,
5659

@@ -137,7 +140,7 @@ class MutableScope {
137140
Scope? get parent => _parent;
138141

139142
@override
140-
String toString() => "Scope($classNameOrDebugName, ${_local.keys})";
143+
String toString() => "Scope(${kind}, $classNameOrDebugName, ${_local.keys})";
141144
}
142145

143146
class Scope extends MutableScope {

0 commit comments

Comments
 (0)