Skip to content

Commit 459010f

Browse files
chloestefantsovaCommit Queue
authored and
Commit Queue
committed
[cfe] Ajust scoping for pattern variables in pattern-for statements
Part of #49749 Change-Id: Ia5551f14b73b6ce50e8e7390f3b7995aaf5fda3b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/284140 Reviewed-by: Johnni Winther <[email protected]> Commit-Queue: Chloe Stefantsova <[email protected]>
1 parent 93e73bf commit 459010f

15 files changed

+512
-8
lines changed

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

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4081,6 +4081,23 @@ class BodyBuilder extends StackListenerImpl
40814081
declareVariable(variable, scope);
40824082
typeInferrer.assignedVariables.declare(variable);
40834083
}
4084+
Scope forScope = scope.createNestedScope(
4085+
debugName: "pattern-for internal variables",
4086+
kind: ScopeKind.forStatement);
4087+
exitLocalScope();
4088+
enterLocalScope(forScope);
4089+
List<VariableDeclaration> internalVariables = [];
4090+
for (VariableDeclaration variable in pattern.declaredVariables) {
4091+
VariableDeclaration internalVariable = forest.createVariableDeclaration(
4092+
variable.fileOffset, variable.name,
4093+
initializer:
4094+
forest.createVariableGet(variable.fileOffset, variable),
4095+
type: variable.type);
4096+
internalVariables.add(internalVariable);
4097+
declareVariable(internalVariable, scope);
4098+
typeInferrer.assignedVariables.declare(internalVariable);
4099+
}
4100+
push(internalVariables);
40844101
push(new PatternVariableDeclaration(pattern, toValue(expression),
40854102
fileOffset: offsetForToken(keyword),
40864103
isFinal: keyword.lexeme == "final"));
@@ -4131,10 +4148,14 @@ class BodyBuilder extends StackListenerImpl
41314148
typeInferrer.assignedVariables.popNode();
41324149

41334150
Object? variableOrExpression = pop();
4151+
List<VariableDeclaration>? variables;
4152+
if (variableOrExpression is PatternVariableDeclaration) {
4153+
variables = pop() as List<VariableDeclaration>; // Internal variables.
4154+
} else {
4155+
variables = _buildForLoopVariableDeclarations(variableOrExpression)!;
4156+
}
41344157
exitLocalScope();
41354158

4136-
List<VariableDeclaration> variables =
4137-
_buildForLoopVariableDeclarations(variableOrExpression)!;
41384159
typeInferrer.assignedVariables.pushNode(assignedVariablesNodeInfo);
41394160
Expression? condition;
41404161
if (conditionStatement is ExpressionStatement) {
@@ -4199,7 +4220,9 @@ class BodyBuilder extends StackListenerImpl
41994220

42004221
Object? variableOrExpression = pop();
42014222
List<VariableDeclaration>? variables =
4202-
_buildForLoopVariableDeclarations(variableOrExpression);
4223+
variableOrExpression is PatternVariableDeclaration
4224+
? pop() as List<VariableDeclaration>
4225+
: _buildForLoopVariableDeclarations(variableOrExpression);
42034226
exitLocalScope();
42044227
JumpTarget continueTarget = exitContinueTarget() as JumpTarget;
42054228
JumpTarget breakTarget = exitBreakTarget() as JumpTarget;

pkg/front_end/testcases/patterns/simple_pattern_for_statements.dart.strong.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static method test1(dynamic x) → dynamic {
1212
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))))
1313
throw new _in::ReachabilityError::•();
1414
}
15-
for (; true; ) {
15+
for (core::int i = i; true; ) {
1616
return i;
1717
}
1818
}

pkg/front_end/testcases/patterns/simple_pattern_for_statements.dart.strong.transformed.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static method test1(dynamic x) → dynamic {
1414
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))))
1515
throw new _in::ReachabilityError::•();
1616
}
17-
for (; true; ) {
17+
for (core::int i = i; true; ) {
1818
return i;
1919
}
2020
}

pkg/front_end/testcases/patterns/simple_pattern_for_statements.dart.weak.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static method test1(dynamic x) → dynamic {
1212
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))))
1313
throw new _in::ReachabilityError::•();
1414
}
15-
for (; true; ) {
15+
for (core::int i = i; true; ) {
1616
return i;
1717
}
1818
}

pkg/front_end/testcases/patterns/simple_pattern_for_statements.dart.weak.modular.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ static method test1(dynamic x) → dynamic {
1212
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))))
1313
throw new _in::ReachabilityError::•();
1414
}
15-
for (; true; ) {
15+
for (core::int i = i; true; ) {
1616
return i;
1717
}
1818
}

pkg/front_end/testcases/patterns/simple_pattern_for_statements.dart.weak.transformed.expect

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static method test1(dynamic x) → dynamic {
1414
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))))
1515
throw new _in::ReachabilityError::•();
1616
}
17-
for (; true; ) {
17+
for (core::int i = i; true; ) {
1818
return i;
1919
}
2020
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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+
int i;
7+
for (var [i] = x; true;) {
8+
return i;
9+
}
10+
}
11+
12+
test2(dynamic x) {
13+
for (var [int i] = x; i < 3; i++) {
14+
int i = -1;
15+
return i;
16+
}
17+
}
18+
19+
test3(dynamic x) {
20+
List<int Function()> functions = [];
21+
for (var [int i] = x; i < 5; i++) {
22+
functions.add(() => i);
23+
}
24+
return functions.map((f) => f()).fold(0, (a, x) => a + x);
25+
}
26+
27+
main() {
28+
expectEquals(test1([0]), 0);
29+
expectThrows(() => test1("foo"));
30+
31+
expectEquals(test2([0]), -1);
32+
33+
expectEquals(test3([0]), 10);
34+
}
35+
36+
expectEquals(x, y) {
37+
if (x != y) {
38+
throw "Expected '${x}' to be equal to '${y}'.";
39+
}
40+
}
41+
42+
expectThrows(void Function() f) {
43+
bool hasThrown = true;
44+
try {
45+
f();
46+
hasThrown = false;
47+
} catch (e) {}
48+
if (!hasThrown) {
49+
throw "Expected the function to throw.";
50+
}
51+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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+
core::int i;
8+
{
9+
dynamic i;
10+
{
11+
final dynamic #0#0 = x;
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 && (let final dynamic #t1 = i = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic} in true)))
13+
throw new _in::ReachabilityError::•();
14+
}
15+
for (dynamic i = i; true; ) {
16+
return i;
17+
}
18+
}
19+
}
20+
static method test2(dynamic x) → dynamic {
21+
{
22+
core::int i;
23+
{
24+
final dynamic #0#0 = x;
25+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
26+
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 #t2 = i = #0#6{core::int} in true))))
27+
throw new _in::ReachabilityError::•();
28+
}
29+
for (core::int i = i; i.{core::num::<}(3){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
30+
core::int i = 1.{core::int::unary-}(){() → core::int};
31+
return i;
32+
}
33+
}
34+
}
35+
static method test3(dynamic x) → dynamic {
36+
core::List<() → core::int> functions = <() → core::int>[];
37+
{
38+
core::int i;
39+
{
40+
final dynamic #0#0 = x;
41+
late final dynamic #0#6 = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
42+
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 #t3 = i = #0#6{core::int} in true))))
43+
throw new _in::ReachabilityError::•();
44+
}
45+
for (core::int i = i; i.{core::num::<}(5){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
46+
functions.{core::List::add}(() → core::int => i){(() → core::int) → void};
47+
}
48+
}
49+
return functions.{core::Iterable::map}<core::int>((() → core::int f) → core::int => f(){() → core::int}){((() → core::int) → core::int) → core::Iterable<core::int>}.{core::Iterable::fold}<core::int>(0, (core::int a, core::int x) → core::int => a.{core::num::+}(x){(core::num) → core::int}){(core::int, (core::int, core::int) → core::int) → core::int};
50+
}
51+
static method main() → dynamic {
52+
self::expectEquals(self::test1(<core::int>[0]), 0);
53+
self::expectThrows(() → void => self::test1("foo"));
54+
self::expectEquals(self::test2(<core::int>[0]), 1.{core::int::unary-}(){() → core::int});
55+
self::expectEquals(self::test3(<core::int>[0]), 10);
56+
}
57+
static method expectEquals(dynamic x, dynamic y) → dynamic {
58+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
59+
throw "Expected '${x}' to be equal to '${y}'.";
60+
}
61+
}
62+
static method expectThrows(() → void f) → dynamic {
63+
core::bool hasThrown = true;
64+
try {
65+
f(){() → void};
66+
hasThrown = false;
67+
}
68+
on core::Object catch(final core::Object e) {
69+
}
70+
if(!hasThrown) {
71+
throw "Expected the function to throw.";
72+
}
73+
}
74+
75+
constants {
76+
#C1 = 1
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
core::int i;
8+
{
9+
dynamic i;
10+
{
11+
final dynamic #0#0 = x;
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 && (let final dynamic #t1 = i = #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic} in true)))
13+
throw new _in::ReachabilityError::•();
14+
}
15+
for (dynamic i = i; true; ) {
16+
return i;
17+
}
18+
}
19+
}
20+
static method test2(dynamic x) → dynamic {
21+
{
22+
core::int i;
23+
{
24+
final dynamic #0#0 = x;
25+
function ##0#6#initializer() → dynamic
26+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
27+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
28+
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 #t2 = i = #0#6{core::int} in true))))
29+
throw new _in::ReachabilityError::•();
30+
}
31+
for (core::int i = i; i.{core::num::<}(3){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
32+
core::int i = 1.{core::int::unary-}(){() → core::int};
33+
return i;
34+
}
35+
}
36+
}
37+
static method test3(dynamic x) → dynamic {
38+
core::List<() → core::int> functions = core::_GrowableList::•<() → core::int>(0);
39+
{
40+
core::int i;
41+
{
42+
final dynamic #0#0 = x;
43+
function ##0#6#initializer() → dynamic
44+
return #0#0{core::List<dynamic>}.{core::List::[]}(0){(core::int) → dynamic};
45+
late final dynamic #0#6 = ##0#6#initializer(){() → dynamic};
46+
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 #t3 = i = #0#6{core::int} in true))))
47+
throw new _in::ReachabilityError::•();
48+
}
49+
for (core::int i = i; i.{core::num::<}(5){(core::num) → core::bool}; i = i.{core::num::+}(1){(core::num) → core::int}) {
50+
functions.{core::List::add}(() → core::int => i){(() → core::int) → void};
51+
}
52+
}
53+
return functions.{core::Iterable::map}<core::int>((() → core::int f) → core::int => f(){() → core::int}){((() → core::int) → core::int) → core::Iterable<core::int>}.{core::Iterable::fold}<core::int>(0, (core::int a, core::int x) → core::int => a.{core::num::+}(x){(core::num) → core::int}){(core::int, (core::int, core::int) → core::int) → core::int};
54+
}
55+
static method main() → dynamic {
56+
self::expectEquals(self::test1(core::_GrowableList::_literal1<core::int>(0)), 0);
57+
self::expectThrows(() → void => self::test1("foo"));
58+
self::expectEquals(self::test2(core::_GrowableList::_literal1<core::int>(0)), 1.{core::int::unary-}(){() → core::int});
59+
self::expectEquals(self::test3(core::_GrowableList::_literal1<core::int>(0)), 10);
60+
}
61+
static method expectEquals(dynamic x, dynamic y) → dynamic {
62+
if(!(x =={core::Object::==}{(core::Object) → core::bool} y)) {
63+
throw "Expected '${x}' to be equal to '${y}'.";
64+
}
65+
}
66+
static method expectThrows(() → void f) → dynamic {
67+
core::bool hasThrown = true;
68+
try {
69+
f(){() → void};
70+
hasThrown = false;
71+
}
72+
on core::Object catch(final core::Object e) {
73+
}
74+
if(!hasThrown) {
75+
throw "Expected the function to throw.";
76+
}
77+
}
78+
79+
constants {
80+
#C1 = 1
81+
}
82+
83+
Extra constant evaluation status:
84+
Evaluated: InstanceInvocation @ org-dartlang-testcase:///variable_scoping_in_pattern_for_statements.dart:14:13 -> IntConstant(-1)
85+
Evaluated: InstanceInvocation @ org-dartlang-testcase:///variable_scoping_in_pattern_for_statements.dart:31:28 -> IntConstant(-1)
86+
Extra constant evaluation: evaluated: 113, effectively constant: 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
test1(dynamic x) {}
2+
test2(dynamic x) {}
3+
test3(dynamic x) {}
4+
main() {}
5+
expectEquals(x, y) {}
6+
expectThrows(void Function() f) {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
expectEquals(x, y) {}
2+
expectThrows(void Function() f) {}
3+
main() {}
4+
test1(dynamic x) {}
5+
test2(dynamic x) {}
6+
test3(dynamic x) {}

0 commit comments

Comments
 (0)