Skip to content

Commit 494aaaa

Browse files
kallentucommit-bot@chromium.org
authored andcommitted
[cfe] Variable assignments (VariableSet) for const functions.
Change-Id: Iab23493fc09b8fdad78968d905ac8f28e1236aa4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190620 Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Dmitry Stefantsov <[email protected]> Reviewed-by: Jake Macdonald <[email protected]>
1 parent 4e027fa commit 494aaaa

10 files changed

+317
-18
lines changed

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

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ class ConstantsTransformer extends RemovingTransformer {
543543
if (node.function != null) {
544544
node.function = transform(node.function)..parent = node;
545545
}
546-
constantEvaluator.env.updateVariableValue(
546+
constantEvaluator.env.addVariableValue(
547547
node.variable, new IntermediateValue(node.function));
548548
} else {
549549
return super.visitFunctionDeclaration(node, removalSentinel);
@@ -559,7 +559,7 @@ class ConstantsTransformer extends RemovingTransformer {
559559
if (node.initializer != null) {
560560
if (node.isConst) {
561561
final Constant constant = evaluateWithContext(node, node.initializer);
562-
constantEvaluator.env.updateVariableValue(node, constant);
562+
constantEvaluator.env.addVariableValue(node, constant);
563563
node.initializer = makeConstantExpression(constant, node.initializer)
564564
..parent = node;
565565

@@ -1669,14 +1669,14 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
16691669
// TODO(johnniwinther): This should call [_evaluateSubexpression].
16701670
: _evaluateNullableSubexpression(parameter.initializer);
16711671
if (value is AbortConstant) return value;
1672-
env.updateVariableValue(parameter, value);
1672+
env.addVariableValue(parameter, value);
16731673
}
16741674
for (final VariableDeclaration parameter in function.namedParameters) {
16751675
final Constant value = namedArguments[parameter.name] ??
16761676
// TODO(johnniwinther): This should call [_evaluateSubexpression].
16771677
_evaluateNullableSubexpression(parameter.initializer);
16781678
if (value is AbortConstant) return value;
1679-
env.updateVariableValue(parameter, value);
1679+
env.addVariableValue(parameter, value);
16801680
}
16811681

16821682
// Step 2) Run all initializers (including super calls) with environment
@@ -1697,7 +1697,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
16971697
final VariableDeclaration variable = init.variable;
16981698
Constant constant = _evaluateSubexpression(variable.initializer);
16991699
if (constant is AbortConstant) return constant;
1700-
env.updateVariableValue(variable, constant);
1700+
env.addVariableValue(variable, constant);
17011701
} else if (init is SuperInitializer) {
17021702
AbortConstant error = checkConstructorConst(init, constructor);
17031703
if (error != null) return error;
@@ -2412,7 +2412,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
24122412
Constant visitLet(Let node) {
24132413
Constant value = _evaluateSubexpression(node.variable.initializer);
24142414
if (value is AbortConstant) return value;
2415-
env.updateVariableValue(node.variable, value);
2415+
env.addVariableValue(node.variable, value);
24162416
return _evaluateSubexpression(node.body);
24172417
}
24182418

@@ -2445,6 +2445,19 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
24452445
node, 'Variable get of a non-const variable.');
24462446
}
24472447

2448+
@override
2449+
Constant visitVariableSet(VariableSet node) {
2450+
if (enableConstFunctions) {
2451+
final VariableDeclaration variable = node.variable;
2452+
Constant value = _evaluateSubexpression(node.value);
2453+
if (value is AbortConstant) return value;
2454+
return env.updateVariableValue(variable, value) ??
2455+
createInvalidExpressionConstant(
2456+
node, 'Variable set of an unknown value.');
2457+
}
2458+
return defaultExpression(node);
2459+
}
2460+
24482461
/// Computes the constant for [expression] defined in the context of [member].
24492462
///
24502463
/// This compute the constant as seen in the current evaluation mode even when
@@ -2772,14 +2785,14 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
27722785
// TODO(johnniwinther): This should call [_evaluateSubexpression].
27732786
: _evaluateNullableSubexpression(parameter.initializer);
27742787
if (value is AbortConstant) return value;
2775-
env.updateVariableValue(parameter, value);
2788+
env.addVariableValue(parameter, value);
27762789
}
27772790
for (final VariableDeclaration parameter in function.namedParameters) {
27782791
final Constant value = namedArguments[parameter.name] ??
27792792
// TODO(johnniwinther): This should call [_evaluateSubexpression].
27802793
_evaluateNullableSubexpression(parameter.initializer);
27812794
if (value is AbortConstant) return value;
2782-
env.updateVariableValue(parameter, value);
2795+
env.addVariableValue(parameter, value);
27832796
}
27842797
return execute(function.body);
27852798
});
@@ -3295,9 +3308,6 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
32953308

32963309
@override
32973310
Constant visitThrow(Throw node) => defaultExpression(node);
3298-
3299-
@override
3300-
Constant visitVariableSet(VariableSet node) => defaultExpression(node);
33013311
}
33023312

33033313
class StatementConstantEvaluator extends StatementVisitor<ExecutionStatus> {
@@ -3329,6 +3339,13 @@ class StatementConstantEvaluator extends StatementVisitor<ExecutionStatus> {
33293339
});
33303340
}
33313341

3342+
@override
3343+
ExecutionStatus visitExpressionStatement(ExpressionStatement node) {
3344+
Constant value = evaluate(node.expression);
3345+
if (value is AbortConstant) return new ReturnStatus(value);
3346+
return const ProceedStatus();
3347+
}
3348+
33323349
@override
33333350
ExecutionStatus visitReturnStatement(ReturnStatement node) =>
33343351
new ReturnStatus(evaluate(node.expression));
@@ -3337,7 +3354,7 @@ class StatementConstantEvaluator extends StatementVisitor<ExecutionStatus> {
33373354
ExecutionStatus visitVariableDeclaration(VariableDeclaration node) {
33383355
Constant value = evaluate(node.initializer);
33393356
if (value is AbortConstant) return new ReturnStatus(value);
3340-
exprEvaluator.env.updateVariableValue(node, value);
3357+
exprEvaluator.env.addVariableValue(node, value);
33413358
return const ProceedStatus();
33423359
}
33433360
}
@@ -3426,17 +3443,21 @@ class EvaluationEnvironment {
34263443
_typeVariables[parameter] = value;
34273444
}
34283445

3429-
void updateVariableValue(VariableDeclaration variable, Constant value) {
3430-
if (!_variables.containsKey(variable)) {
3431-
_variables[variable] = new EvaluationReference(value);
3432-
} else {
3433-
_variables[variable].value = value;
3434-
}
3446+
void addVariableValue(VariableDeclaration variable, Constant value) {
3447+
_variables[variable] = new EvaluationReference(value);
34353448
if (value is UnevaluatedConstant) {
34363449
_unreadUnevaluatedVariables.add(variable);
34373450
}
34383451
}
34393452

3453+
Constant updateVariableValue(VariableDeclaration variable, Constant value) {
3454+
if (_variables.containsKey(variable)) {
3455+
_variables[variable].value = value;
3456+
return value;
3457+
}
3458+
return _parent?.updateVariableValue(variable, value);
3459+
}
3460+
34403461
Constant lookupVariable(VariableDeclaration variable) {
34413462
Constant value = _variables[variable]?.value;
34423463
if (value is UnevaluatedConstant) {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) 2021, 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+
// Tests variable assignments for const functions.
6+
7+
// SharedOptions=--enable-experiment=const-functions
8+
9+
import "package:expect/expect.dart";
10+
11+
const var1 = varAssignmentTest(1);
12+
int varAssignmentTest(int a) {
13+
int x = 4;
14+
{
15+
x = 3;
16+
}
17+
return x;
18+
}
19+
20+
int function() {
21+
int varAssignmentTest2() {
22+
int x = 2;
23+
x += 1;
24+
return x;
25+
}
26+
27+
const var2 = varAssignmentTest2();
28+
return var2;
29+
}
30+
31+
const var3 = varAssignmentTest3(1);
32+
int varAssignmentTest3(int a) {
33+
int x = 4;
34+
x = a + 1;
35+
return x;
36+
}
37+
38+
void main() {
39+
Expect.equals(var1, 3);
40+
Expect.equals(function(), 3);
41+
Expect.equals(var3, 2);
42+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "package:expect/expect.dart" as exp;
5+
6+
import "package:expect/expect.dart";
7+
8+
static const field core::int var1 = #C1;
9+
static const field core::int var3 = #C2;
10+
static method varAssignmentTest(core::int a) → core::int {
11+
core::int x = 4;
12+
{
13+
x = 3;
14+
}
15+
return x;
16+
}
17+
static method function() → core::int {
18+
function varAssignmentTest2() → core::int {
19+
core::int x = 2;
20+
x = x.{core::num::+}(1);
21+
return x;
22+
}
23+
return #C1;
24+
}
25+
static method varAssignmentTest3(core::int a) → core::int {
26+
core::int x = 4;
27+
x = a.{core::num::+}(1);
28+
return x;
29+
}
30+
static method main() → void {
31+
exp::Expect::equals(#C1, 3);
32+
exp::Expect::equals(self::function(), 3);
33+
exp::Expect::equals(#C2, 2);
34+
}
35+
36+
constants {
37+
#C1 = 3
38+
#C2 = 2
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "package:expect/expect.dart" as exp;
5+
6+
import "package:expect/expect.dart";
7+
8+
static const field core::int var1 = #C1;
9+
static const field core::int var3 = #C2;
10+
static method varAssignmentTest(core::int a) → core::int {
11+
core::int x = 4;
12+
{
13+
x = 3;
14+
}
15+
return x;
16+
}
17+
static method function() → core::int {
18+
function varAssignmentTest2() → core::int {
19+
core::int x = 2;
20+
x = x.{core::num::+}(1);
21+
return x;
22+
}
23+
return #C1;
24+
}
25+
static method varAssignmentTest3(core::int a) → core::int {
26+
core::int x = 4;
27+
x = a.{core::num::+}(1);
28+
return x;
29+
}
30+
static method main() → void {
31+
exp::Expect::equals(#C1, 3);
32+
exp::Expect::equals(self::function(), 3);
33+
exp::Expect::equals(#C2, 2);
34+
}
35+
36+
constants {
37+
#C1 = 3
38+
#C2 = 2
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import "package:expect/expect.dart";
2+
3+
const var1 = varAssignmentTest(1);
4+
int varAssignmentTest(int a) {}
5+
int function() {}
6+
const var3 = varAssignmentTest3(1);
7+
int varAssignmentTest3(int a) {}
8+
void main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import "package:expect/expect.dart";
2+
3+
const var1 = varAssignmentTest(1);
4+
const var3 = varAssignmentTest3(1);
5+
int function() {}
6+
int varAssignmentTest(int a) {}
7+
int varAssignmentTest3(int a) {}
8+
void main() {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "package:expect/expect.dart" as exp;
5+
6+
import "package:expect/expect.dart";
7+
8+
static const field core::int var1 = #C1;
9+
static const field core::int var3 = #C2;
10+
static method varAssignmentTest(core::int a) → core::int {
11+
core::int x = 4;
12+
{
13+
x = 3;
14+
}
15+
return x;
16+
}
17+
static method function() → core::int {
18+
function varAssignmentTest2() → core::int {
19+
core::int x = 2;
20+
x = x.{core::num::+}(1);
21+
return x;
22+
}
23+
return #C1;
24+
}
25+
static method varAssignmentTest3(core::int a) → core::int {
26+
core::int x = 4;
27+
x = a.{core::num::+}(1);
28+
return x;
29+
}
30+
static method main() → void {
31+
exp::Expect::equals(#C1, 3);
32+
exp::Expect::equals(self::function(), 3);
33+
exp::Expect::equals(#C2, 2);
34+
}
35+
36+
constants {
37+
#C1 = 3
38+
#C2 = 2
39+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
5+
import "package:expect/expect.dart";
6+
7+
static const field core::int var1 = self::varAssignmentTest(1);
8+
static const field core::int var3 = self::varAssignmentTest3(1);
9+
static method varAssignmentTest(core::int a) → core::int
10+
;
11+
static method function() → core::int
12+
;
13+
static method varAssignmentTest3(core::int a) → core::int
14+
;
15+
static method main() → void
16+
;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
library /*isNonNullableByDefault*/;
2+
import self as self;
3+
import "dart:core" as core;
4+
import "package:expect/expect.dart" as exp;
5+
6+
import "package:expect/expect.dart";
7+
8+
static const field core::int var1 = #C1;
9+
static const field core::int var3 = #C2;
10+
static method varAssignmentTest(core::int a) → core::int {
11+
core::int x = 4;
12+
{
13+
x = 3;
14+
}
15+
return x;
16+
}
17+
static method function() → core::int {
18+
function varAssignmentTest2() → core::int {
19+
core::int x = 2;
20+
x = x.{core::num::+}(1);
21+
return x;
22+
}
23+
return #C1;
24+
}
25+
static method varAssignmentTest3(core::int a) → core::int {
26+
core::int x = 4;
27+
x = a.{core::num::+}(1);
28+
return x;
29+
}
30+
static method main() → void {
31+
exp::Expect::equals(#C1, 3);
32+
exp::Expect::equals(self::function(), 3);
33+
exp::Expect::equals(#C2, 2);
34+
}
35+
36+
constants {
37+
#C1 = 3
38+
#C2 = 2
39+
}

0 commit comments

Comments
 (0)