Skip to content

Commit 521fee6

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Add basic support for pattern-for statements
Part of #49749 Change-Id: I0c25e96cb52d34397057f65554ceae35732b9537 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283822 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent f9abd48 commit 521fee6

10 files changed

+317
-0
lines changed

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4010,6 +4010,8 @@ class BodyBuilder extends StackListenerImpl
40104010
variables.addAll(_buildForLoopVariableDeclarations(v)!);
40114011
}
40124012
return variables;
4013+
} else if (variableOrExpression is PatternVariableDeclaration) {
4014+
return <VariableDeclaration>[];
40134015
} else if (variableOrExpression == null) {
40144016
return <VariableDeclaration>[];
40154017
}
@@ -4052,6 +4054,42 @@ class BodyBuilder extends StackListenerImpl
40524054
}
40534055
}
40544056

4057+
@override
4058+
void handleForInitializerPatternVariableAssignment(
4059+
Token keyword, Token equals) {
4060+
debugEvent("handleForInitializerPatternVariableAssignment");
4061+
assert(checkState(keyword, [
4062+
unionOfKinds([
4063+
ValueKinds.Expression,
4064+
ValueKinds.Generator,
4065+
ValueKinds.ProblemBuilder,
4066+
]),
4067+
unionOfKinds([
4068+
ValueKinds.Expression,
4069+
ValueKinds.Generator,
4070+
ValueKinds.ProblemBuilder,
4071+
ValueKinds.Pattern,
4072+
]),
4073+
]));
4074+
4075+
Object expression = pop() as Object;
4076+
Object pattern = pop() as Object;
4077+
4078+
if (pattern is Pattern) {
4079+
pop(); // Metadata.
4080+
for (VariableDeclaration variable in pattern.declaredVariables) {
4081+
declareVariable(variable, scope);
4082+
typeInferrer.assignedVariables.declare(variable);
4083+
}
4084+
push(new PatternVariableDeclaration(pattern, toValue(expression),
4085+
fileOffset: offsetForToken(keyword),
4086+
isFinal: keyword.lexeme == "final"));
4087+
}
4088+
4089+
// This is matched by the call to [deferNode] in [endForStatement].
4090+
typeInferrer.assignedVariables.beginNode();
4091+
}
4092+
40554093
@override
40564094
void handleForLoopParts(Token forKeyword, Token leftParen,
40574095
Token leftSeparator, int updateExpressionCount) {
@@ -4153,6 +4191,7 @@ class BodyBuilder extends StackListenerImpl
41534191
Statement conditionStatement = popStatement();
41544192
// This is matched by the call to [beginNode] in
41554193
// [handleForInitializerEmptyStatement],
4194+
// [handleForInitializerPatternVariableAssignment],
41564195
// [handleForInitializerExpressionStatement], and
41574196
// [handleForInitializerLocalVariableDeclaration].
41584197
AssignedVariablesNodeInfo assignedVariablesNodeInfo =
@@ -4192,6 +4231,10 @@ class BodyBuilder extends StackListenerImpl
41924231
breakTarget.resolveBreaks(forest, labeledStatement, forStatement);
41934232
result = labeledStatement;
41944233
}
4234+
if (variableOrExpression is PatternVariableDeclaration) {
4235+
result = forest.createBlock(result.fileOffset, result.fileOffset,
4236+
<Statement>[variableOrExpression, result]);
4237+
}
41954238
if (variableOrExpression is ParserRecovery) {
41964239
problemInLoopOrSwitch ??= buildProblemStatement(
41974240
fasta.messageSyntheticToken, variableOrExpression.charOffset,
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2023, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
test1(dynamic x) {
6+
for (var [int i] = x; true;) {
7+
return i;
8+
}
9+
}
10+
11+
main() {
12+
expectEquals(test1([0]), 0);
13+
expectThrows(() => test1([]));
14+
}
15+
16+
expectEquals(x, y) {
17+
if (x != y) {
18+
throw "Expected '${x}' to be equal to '${y}'.";
19+
}
20+
}
21+
22+
expectThrows(void Function() f) {
23+
bool hasThrown = true;
24+
try {
25+
f();
26+
hasThrown = false;
27+
} catch (e) {}
28+
if (!hasThrown) {
29+
throw "Expected function to throw.";
30+
}
31+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
static method test1(dynamic x) → dynamic {
7+
{
8+
core::int i;
9+
{
10+
final dynamic #0#0 = x;
11+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
12+
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = i = #0#6{core::int} in true))))
13+
throw new _in::ReachabilityError::•();
14+
}
15+
for (; true; ) {
16+
return i;
17+
}
18+
}
19+
}
20+
static method main() → dynamic {
21+
self::expectEquals(self::test1(<core::int>[0]), 0);
22+
self::expectThrows(() → void => self::test1(<dynamic>[]));
23+
}
24+
static method expectEquals(dynamic x, dynamic y) → dynamic {
25+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
26+
throw "Expected '${x}' to be equal to '${y}'.";
27+
}
28+
}
29+
static method expectThrows(() → void f) → dynamic {
30+
core::bool hasThrown = true;
31+
try {
32+
f(){() → void};
33+
hasThrown = false;
34+
}
35+
on core::Object catch(final core::Object e) {
36+
}
37+
if(!hasThrown) {
38+
throw "Expected function to throw.";
39+
}
40+
}
41+
42+
constants {
43+
#C1 = 1
44+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
static method test1(dynamic x) → dynamic {
7+
{
8+
core::int i;
9+
{
10+
final dynamic #0#0 = x;
11+
function ##0#6#initializer() → dynamic
12+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
13+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
14+
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t1 = i = #0#6{core::int} in true))))
15+
throw new _in::ReachabilityError::•();
16+
}
17+
for (; true; ) {
18+
return i;
19+
}
20+
}
21+
}
22+
static method main() → dynamic {
23+
self::expectEquals(self::test1(core::_GrowableList::_literal1<core::int>(0)), 0);
24+
self::expectThrows(() → void => self::test1(core::_GrowableList::•<dynamic>(0)));
25+
}
26+
static method expectEquals(dynamic x, dynamic y) → dynamic {
27+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
28+
throw "Expected '${x}' to be equal to '${y}'.";
29+
}
30+
}
31+
static method expectThrows(() → void f) → dynamic {
32+
core::bool hasThrown = true;
33+
try {
34+
f(){() → void};
35+
hasThrown = false;
36+
}
37+
on core::Object catch(final core::Object e) {
38+
}
39+
if(!hasThrown) {
40+
throw "Expected function to throw.";
41+
}
42+
}
43+
44+
constants {
45+
#C1 = 1
46+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
test1(dynamic x) {}
2+
main() {}
3+
expectEquals(x, y) {}
4+
expectThrows(void Function() f) {}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
expectEquals(x, y) {}
2+
expectThrows(void Function() f) {}
3+
main() {}
4+
test1(dynamic x) {}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
static method test1(dynamic x) → dynamic {
7+
{
8+
core::int i;
9+
{
10+
final dynamic #0#0 = x;
11+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
12+
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = i = #0#6{core::int} in true))))
13+
throw new _in::ReachabilityError::•();
14+
}
15+
for (; true; ) {
16+
return i;
17+
}
18+
}
19+
}
20+
static method main() → dynamic {
21+
self::expectEquals(self::test1(<core::int>[0]), 0);
22+
self::expectThrows(() → void => self::test1(<dynamic>[]));
23+
}
24+
static method expectEquals(dynamic x, dynamic y) → dynamic {
25+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
26+
throw "Expected '${x}' to be equal to '${y}'.";
27+
}
28+
}
29+
static method expectThrows(() → void f) → dynamic {
30+
core::bool hasThrown = true;
31+
try {
32+
f(){() → void};
33+
hasThrown = false;
34+
}
35+
on core::Object catch(final core::Object e) {
36+
}
37+
if(!hasThrown) {
38+
throw "Expected function to throw.";
39+
}
40+
}
41+
42+
constants {
43+
#C1 = 1
44+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
static method test1(dynamic x) → dynamic {
7+
{
8+
core::int i;
9+
{
10+
final dynamic #0#0 = x;
11+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
12+
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final dynamic #t1 = i = #0#6{core::int} in true))))
13+
throw new _in::ReachabilityError::•();
14+
}
15+
for (; true; ) {
16+
return i;
17+
}
18+
}
19+
}
20+
static method main() → dynamic {
21+
self::expectEquals(self::test1(<core::int>[0]), 0);
22+
self::expectThrows(() → void => self::test1(<dynamic>[]));
23+
}
24+
static method expectEquals(dynamic x, dynamic y) → dynamic {
25+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
26+
throw "Expected '${x}' to be equal to '${y}'.";
27+
}
28+
}
29+
static method expectThrows(() → void f) → dynamic {
30+
core::bool hasThrown = true;
31+
try {
32+
f(){() → void};
33+
hasThrown = false;
34+
}
35+
on core::Object catch(final core::Object e) {
36+
}
37+
if(!hasThrown) {
38+
throw "Expected function to throw.";
39+
}
40+
}
41+
42+
constants {
43+
#C1 = 1
44+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
4+
static method test1(dynamic x) → dynamic
5+
;
6+
static method main() → dynamic
7+
;
8+
static method expectEquals(dynamic x, dynamic y) → dynamic
9+
;
10+
static method expectThrows(() → void f) → dynamic
11+
;
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "dart:_internal" as _in;
5+
6+
static method test1(dynamic x) → dynamic {
7+
{
8+
core::int i;
9+
{
10+
final dynamic #0#0 = x;
11+
function ##0#6#initializer() → dynamic
12+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
13+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
14+
if(!(#0#0 is{ForNonNullableByDefault} core::List<dynamic> && #0#0{core::List<dynamic>}.{core::List::length}{core::int} =={core::num::==}{(core::Object) → core::bool} #C1 && (#0#6 is{ForNonNullableByDefault} core::int && (let final core::int #t1 = i = #0#6{core::int} in true))))
15+
throw new _in::ReachabilityError::•();
16+
}
17+
for (; true; ) {
18+
return i;
19+
}
20+
}
21+
}
22+
static method main() → dynamic {
23+
self::expectEquals(self::test1(core::_GrowableList::_literal1<core::int>(0)), 0);
24+
self::expectThrows(() → void => self::test1(core::_GrowableList::•<dynamic>(0)));
25+
}
26+
static method expectEquals(dynamic x, dynamic y) → dynamic {
27+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
28+
throw "Expected '${x}' to be equal to '${y}'.";
29+
}
30+
}
31+
static method expectThrows(() → void f) → dynamic {
32+
core::bool hasThrown = true;
33+
try {
34+
f(){() → void};
35+
hasThrown = false;
36+
}
37+
on core::Object catch(final core::Object e) {
38+
}
39+
if(!hasThrown) {
40+
throw "Expected function to throw.";
41+
}
42+
}
43+
44+
constants {
45+
#C1 = 1
46+
}

0 commit comments

Comments
 (0)