[cfe] Closures and environment changes for const functions.
Change-Id: If844a28192c1eef4dcbb62075ae07e86297f2c92 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/193920 Reviewed-by: Dmitry Stefantsov <dmitryas@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com> Reviewed-by: Jake Macdonald <jakemac@google.com> Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
40441c9685
commit
6f90c5531e
@@ -1352,6 +1352,28 @@ Message _withArgumentsConstEvalFailedAssertionWithMessage(
|
||||
arguments: {'stringOKEmpty': stringOKEmpty});
|
||||
}
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Template<Message Function(String nameOKEmpty)>
|
||||
templateConstEvalGetterNotFound =
|
||||
const Template<Message Function(String nameOKEmpty)>(
|
||||
messageTemplate: r"""Variable get not found: '#nameOKEmpty'""",
|
||||
withArguments: _withArgumentsConstEvalGetterNotFound);
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Code<Message Function(String nameOKEmpty)> codeConstEvalGetterNotFound =
|
||||
const Code<Message Function(String nameOKEmpty)>(
|
||||
"ConstEvalGetterNotFound",
|
||||
);
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
Message _withArgumentsConstEvalGetterNotFound(String nameOKEmpty) {
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (nameOKEmpty == null || nameOKEmpty.isEmpty) nameOKEmpty = '(unnamed)';
|
||||
return new Message(codeConstEvalGetterNotFound,
|
||||
message: """Variable get not found: '${nameOKEmpty}'""",
|
||||
arguments: {'nameOKEmpty': nameOKEmpty});
|
||||
}
|
||||
|
||||
// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
|
||||
const Template<Message Function(String nameOKEmpty)>
|
||||
templateConstEvalInvalidStaticInvocation =
|
||||
|
||||
@@ -59,6 +59,7 @@ import '../fasta_codes.dart'
|
||||
templateConstEvalElementImplementsEqual,
|
||||
templateConstEvalFailedAssertionWithMessage,
|
||||
templateConstEvalFreeTypeParameter,
|
||||
templateConstEvalGetterNotFound,
|
||||
templateConstEvalInvalidType,
|
||||
templateConstEvalInvalidBinaryOperandType,
|
||||
templateConstEvalInvalidEqualsOperandType,
|
||||
@@ -559,7 +560,7 @@ class ConstantsTransformer extends RemovingTransformer {
|
||||
node.function = transform(node.function)..parent = node;
|
||||
}
|
||||
constantEvaluator.env.addVariableValue(
|
||||
node.variable, new IntermediateValue(node.function));
|
||||
node.variable, new FunctionValue(node.function, null));
|
||||
} else {
|
||||
return super.visitFunctionDeclaration(node, removalSentinel);
|
||||
}
|
||||
@@ -1394,6 +1395,9 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
|
||||
@override
|
||||
Constant visitFunctionExpression(FunctionExpression node) {
|
||||
if (enableConstFunctions) {
|
||||
return new FunctionValue(node.function, env);
|
||||
}
|
||||
return createInvalidExpressionConstant(node, "Function literal");
|
||||
}
|
||||
|
||||
@@ -2165,6 +2169,9 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
node, "method invocation with named arguments");
|
||||
}
|
||||
|
||||
final Constant receiver = _evaluateSubexpression(node.receiver);
|
||||
if (receiver is AbortConstant) return receiver;
|
||||
|
||||
final List<Constant> arguments =
|
||||
_evaluatePositionalArguments(node.arguments);
|
||||
|
||||
@@ -2176,12 +2183,7 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
assert(_gotError == null);
|
||||
assert(arguments != null);
|
||||
|
||||
final Constant receiver = _evaluateSubexpression(node.receiver);
|
||||
if (receiver is AbortConstant) {
|
||||
return receiver;
|
||||
} else if (enableConstFunctions &&
|
||||
receiver is IntermediateValue &&
|
||||
receiver.value is FunctionNode) {
|
||||
if (enableConstFunctions && receiver is FunctionValue) {
|
||||
// Evaluate type arguments of the method invoked.
|
||||
List<DartType> types = _evaluateTypeArguments(node, node.arguments);
|
||||
if (types == null && _gotError != null) {
|
||||
@@ -2203,7 +2205,9 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
assert(_gotError == null);
|
||||
assert(named != null);
|
||||
|
||||
return _handleFunctionInvocation(receiver.value, types, arguments, named);
|
||||
return _handleFunctionInvocation(
|
||||
receiver.function, types, arguments, named,
|
||||
functionEnvironment: receiver.environment);
|
||||
}
|
||||
|
||||
if (shouldBeUnevaluated) {
|
||||
@@ -2465,8 +2469,8 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
final VariableDeclaration variable = node.variable;
|
||||
if (enableConstFunctions) {
|
||||
return env.lookupVariable(variable) ??
|
||||
createInvalidExpressionConstant(
|
||||
node, 'Variable get of an unknown value.');
|
||||
createErrorConstant(node,
|
||||
templateConstEvalGetterNotFound.withArguments(variable.name));
|
||||
} else {
|
||||
if (variable.parent is Let || _isFormalParameter(variable)) {
|
||||
return env.lookupVariable(node.variable) ??
|
||||
@@ -2815,8 +2819,9 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
FunctionNode function,
|
||||
List<DartType> typeArguments,
|
||||
List<Constant> positionalArguments,
|
||||
Map<String, Constant> namedArguments) {
|
||||
return withNewEnvironment(() {
|
||||
Map<String, Constant> namedArguments,
|
||||
{EvaluationEnvironment functionEnvironment}) {
|
||||
Constant executeFunction() {
|
||||
// Map arguments from caller to callee.
|
||||
for (int i = 0; i < function.typeParameters.length; i++) {
|
||||
env.addTypeParameterValue(function.typeParameters[i], typeArguments[i]);
|
||||
@@ -2838,7 +2843,12 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
env.addVariableValue(parameter, value);
|
||||
}
|
||||
return execute(function.body);
|
||||
});
|
||||
}
|
||||
|
||||
if (functionEnvironment != null) {
|
||||
return withEnvironment(functionEnvironment, executeFunction);
|
||||
}
|
||||
return withNewEnvironment(executeFunction);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -3264,6 +3274,14 @@ class ConstantEvaluator implements ExpressionVisitor<Constant> {
|
||||
return result;
|
||||
}
|
||||
|
||||
T withEnvironment<T>(EvaluationEnvironment newEnv, T fn()) {
|
||||
final EvaluationEnvironment oldEnv = env;
|
||||
env = newEnv;
|
||||
T result = fn();
|
||||
env = oldEnv;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Binary operation between two operands, at least one of which is a double.
|
||||
Constant evaluateBinaryNumericOperation(
|
||||
String op, num a, num b, TreeNode node) {
|
||||
@@ -3423,6 +3441,17 @@ class StatementConstantEvaluator extends StatementVisitor<ExecutionStatus> {
|
||||
return const ProceedStatus();
|
||||
}
|
||||
|
||||
@override
|
||||
ExecutionStatus visitFunctionDeclaration(FunctionDeclaration node) {
|
||||
final EvaluationEnvironment newEnv =
|
||||
new EvaluationEnvironment.withParent(exprEvaluator.env);
|
||||
newEnv.addVariableValue(
|
||||
node.variable, new FunctionValue(node.function, null));
|
||||
final FunctionValue function = new FunctionValue(node.function, newEnv);
|
||||
exprEvaluator.env.addVariableValue(node.variable, function);
|
||||
return const ProceedStatus();
|
||||
}
|
||||
|
||||
@override
|
||||
ExecutionStatus visitIfStatement(IfStatement node) {
|
||||
Constant condition = evaluate(node.condition);
|
||||
@@ -3740,11 +3769,13 @@ class BreakStatus extends ExecutionStatus {
|
||||
BreakStatus(this.target);
|
||||
}
|
||||
|
||||
/// An intermediate result that is used within the [ConstantEvaluator].
|
||||
class IntermediateValue implements Constant {
|
||||
dynamic value;
|
||||
/// An intermediate result that is used for invoking function nodes with their
|
||||
/// respective environment within the [ConstantEvaluator].
|
||||
class FunctionValue implements Constant {
|
||||
final FunctionNode function;
|
||||
final EvaluationEnvironment environment;
|
||||
|
||||
IntermediateValue(this.value);
|
||||
FunctionValue(this.function, this.environment);
|
||||
|
||||
@override
|
||||
R accept<R>(ConstantVisitor<R> v) {
|
||||
|
||||
@@ -106,6 +106,8 @@ ConstEvalFailedAssertion/example: Fail
|
||||
ConstEvalFailedAssertionWithMessage/example: Fail
|
||||
ConstEvalFreeTypeParameter/analyzerCode: Fail
|
||||
ConstEvalFreeTypeParameter/example: Fail
|
||||
ConstEvalGetterNotFound/analyzerCode: Fail
|
||||
ConstEvalGetterNotFound/example: Fail
|
||||
ConstEvalInvalidBinaryOperandType/analyzerCode: Fail # CONST_EVAL_TYPE_NUM / CONST_EVAL_TYPE_BOOL
|
||||
ConstEvalInvalidBinaryOperandType/example: Fail
|
||||
ConstEvalInvalidEqualsOperandType/analyzerCode: Fail
|
||||
|
||||
@@ -150,6 +150,9 @@ ConstEvalTruncateError:
|
||||
ConstEvalNonNull:
|
||||
template: "Constant expression must be non-null."
|
||||
|
||||
ConstEvalGetterNotFound:
|
||||
template: "Variable get not found: '#nameOKEmpty'"
|
||||
|
||||
ConstEvalInvalidMethodInvocation:
|
||||
template: "The method '#stringOKEmpty' can't be invoked on '#constant' in a constant expression."
|
||||
analyzerCode: UNDEFINED_OPERATOR
|
||||
|
||||
@@ -13,6 +13,17 @@ int fn() {
|
||||
return x;
|
||||
}
|
||||
|
||||
const var2 = fn2();
|
||||
int fn2() {
|
||||
int x = 0;
|
||||
assert(() {
|
||||
var y = x + 1;
|
||||
return y == 1;
|
||||
}());
|
||||
return x;
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 0);
|
||||
Expect.equals(var2, 0);
|
||||
}
|
||||
|
||||
+10
@@ -6,13 +6,23 @@ import "package:expect/expect.dart" as exp;
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static method fn() → core::int {
|
||||
core::int x = 0;
|
||||
assert(x.{core::num::==}(0), "fail");
|
||||
return x;
|
||||
}
|
||||
static method fn2() → core::int {
|
||||
core::int x = 0;
|
||||
assert((() → core::bool {
|
||||
core::int y = x.{core::num::+}(1);
|
||||
return y.{core::num::==}(1);
|
||||
}).call());
|
||||
return x;
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
}
|
||||
|
||||
constants {
|
||||
|
||||
+10
@@ -6,13 +6,23 @@ import "package:expect/expect.dart" as exp;
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static method fn() → core::int {
|
||||
core::int x = 0;
|
||||
assert(x.{core::num::==}(0), "fail");
|
||||
return x;
|
||||
}
|
||||
static method fn2() → core::int {
|
||||
core::int x = 0;
|
||||
assert((() → core::bool {
|
||||
core::int y = x.{core::num::+}(1);
|
||||
return y.{core::num::==}(1);
|
||||
}).call());
|
||||
return x;
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
}
|
||||
|
||||
constants {
|
||||
|
||||
+2
@@ -2,4 +2,6 @@ import "package:expect/expect.dart";
|
||||
|
||||
const var1 = fn();
|
||||
int fn() {}
|
||||
const var2 = fn2();
|
||||
int fn2() {}
|
||||
void main() {}
|
||||
|
||||
+2
@@ -1,5 +1,7 @@
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = fn();
|
||||
const var2 = fn2();
|
||||
int fn() {}
|
||||
int fn2() {}
|
||||
void main() {}
|
||||
|
||||
+10
@@ -6,13 +6,23 @@ import "package:expect/expect.dart" as exp;
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static method fn() → core::int {
|
||||
core::int x = 0;
|
||||
assert(x.{core::num::==}(0), "fail");
|
||||
return x;
|
||||
}
|
||||
static method fn2() → core::int {
|
||||
core::int x = 0;
|
||||
assert((() → core::bool {
|
||||
core::int y = x.{core::num::+}(1);
|
||||
return y.{core::num::==}(1);
|
||||
}).call());
|
||||
return x;
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
}
|
||||
|
||||
constants {
|
||||
|
||||
+3
@@ -5,7 +5,10 @@ import "dart:core" as core;
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = self::fn();
|
||||
static const field core::int var2 = self::fn2();
|
||||
static method fn() → core::int
|
||||
;
|
||||
static method fn2() → core::int
|
||||
;
|
||||
static method main() → void
|
||||
;
|
||||
|
||||
+10
@@ -6,13 +6,23 @@ import "package:expect/expect.dart" as exp;
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static method fn() → core::int {
|
||||
core::int x = 0;
|
||||
assert(x.{core::num::==}(0), "fail");
|
||||
return x;
|
||||
}
|
||||
static method fn2() → core::int {
|
||||
core::int x = 0;
|
||||
assert((() → core::bool {
|
||||
core::int y = x.{core::num::+}(1);
|
||||
return y.{core::num::==}(1);
|
||||
}).call());
|
||||
return x;
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
}
|
||||
|
||||
constants {
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests closures with const functions.
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = foo();
|
||||
int foo() {
|
||||
var f = () {
|
||||
int count = 0;
|
||||
int baz() {
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
return baz;
|
||||
};
|
||||
var c1 = f();
|
||||
var c2 = f();
|
||||
|
||||
var c1_val1 = c1();
|
||||
assert(c1_val1 == 1);
|
||||
var c1_val2 = c1();
|
||||
assert(c1_val2 == 2);
|
||||
var c1_val3 = c1();
|
||||
assert(c1_val3 == 3);
|
||||
|
||||
var c2_val1 = c2();
|
||||
assert(c1_val1 == 1);
|
||||
var c2_val2 = c2();
|
||||
assert(c1_val2 == 2);
|
||||
var c2_val3 = c2();
|
||||
assert(c1_val3 == 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const var2 = fn();
|
||||
int fn() {
|
||||
return (() => 0)();
|
||||
}
|
||||
|
||||
const y = 1;
|
||||
const var3 = fn3();
|
||||
int fn3() {
|
||||
int y = 2;
|
||||
return y;
|
||||
}
|
||||
|
||||
const var4 = fn4();
|
||||
int fn4() {
|
||||
var x = 0;
|
||||
int innerFn() {
|
||||
return x;
|
||||
}
|
||||
|
||||
return innerFn();
|
||||
}
|
||||
|
||||
const var5 = fn5(3);
|
||||
int fn5(int a) {
|
||||
int recurse(int b) {
|
||||
if (b == 1) return 1;
|
||||
int result = recurse(b - 1);
|
||||
return b * result;
|
||||
}
|
||||
|
||||
return recurse(a);
|
||||
}
|
||||
|
||||
const var6 = fn6(4);
|
||||
int fn6(int a) {
|
||||
int recurse() {
|
||||
a--;
|
||||
if (a == 1) return 1;
|
||||
return a * recurse();
|
||||
}
|
||||
|
||||
return recurse();
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 0);
|
||||
Expect.equals(var2, 0);
|
||||
Expect.equals(var3, 2);
|
||||
Expect.equals(var4, 0);
|
||||
Expect.equals(var5, 6);
|
||||
Expect.equals(var6, 6);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static const field core::int y = #C2;
|
||||
static const field core::int var3 = #C3;
|
||||
static const field core::int var4 = #C1;
|
||||
static const field core::int var5 = #C4;
|
||||
static const field core::int var6 = #C4;
|
||||
static method foo() → core::int {
|
||||
() → () → core::int f = () → () → core::int {
|
||||
core::int count = 0;
|
||||
function baz() → core::int {
|
||||
count = count.{core::num::+}(1);
|
||||
return count;
|
||||
}
|
||||
return baz;
|
||||
};
|
||||
() → core::int c1 = f.call();
|
||||
() → core::int c2 = f.call();
|
||||
core::int c1_val1 = c1.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c1_val2 = c1.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c1_val3 = c1.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
core::int c2_val1 = c2.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c2_val2 = c2.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c2_val3 = c2.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
return 0;
|
||||
}
|
||||
static method fn() → core::int {
|
||||
return (() → core::int => 0).call();
|
||||
}
|
||||
static method fn3() → core::int {
|
||||
core::int y = 2;
|
||||
return y;
|
||||
}
|
||||
static method fn4() → core::int {
|
||||
core::int x = 0;
|
||||
function innerFn() → core::int {
|
||||
return x;
|
||||
}
|
||||
return innerFn.call();
|
||||
}
|
||||
static method fn5(core::int a) → core::int {
|
||||
function recurse(core::int b) → core::int {
|
||||
if(b.{core::num::==}(1))
|
||||
return 1;
|
||||
core::int result = recurse.call(b.{core::num::-}(1));
|
||||
return b.{core::num::*}(result);
|
||||
}
|
||||
return recurse.call(a);
|
||||
}
|
||||
static method fn6(core::int a) → core::int {
|
||||
function recurse() → core::int {
|
||||
a = a.{core::num::-}(1);
|
||||
if(a.{core::num::==}(1))
|
||||
return 1;
|
||||
return a.{core::num::*}(recurse.call());
|
||||
}
|
||||
return recurse.call();
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C3, 2);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 0
|
||||
#C2 = 1
|
||||
#C3 = 2
|
||||
#C4 = 6
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static const field core::int y = #C2;
|
||||
static const field core::int var3 = #C3;
|
||||
static const field core::int var4 = #C1;
|
||||
static const field core::int var5 = #C4;
|
||||
static const field core::int var6 = #C4;
|
||||
static method foo() → core::int {
|
||||
() → () → core::int f = () → () → core::int {
|
||||
core::int count = 0;
|
||||
function baz() → core::int {
|
||||
count = count.{core::num::+}(1);
|
||||
return count;
|
||||
}
|
||||
return baz;
|
||||
};
|
||||
() → core::int c1 = f.call();
|
||||
() → core::int c2 = f.call();
|
||||
core::int c1_val1 = c1.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c1_val2 = c1.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c1_val3 = c1.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
core::int c2_val1 = c2.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c2_val2 = c2.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c2_val3 = c2.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
return 0;
|
||||
}
|
||||
static method fn() → core::int {
|
||||
return (() → core::int => 0).call();
|
||||
}
|
||||
static method fn3() → core::int {
|
||||
core::int y = 2;
|
||||
return y;
|
||||
}
|
||||
static method fn4() → core::int {
|
||||
core::int x = 0;
|
||||
function innerFn() → core::int {
|
||||
return x;
|
||||
}
|
||||
return innerFn.call();
|
||||
}
|
||||
static method fn5(core::int a) → core::int {
|
||||
function recurse(core::int b) → core::int {
|
||||
if(b.{core::num::==}(1))
|
||||
return 1;
|
||||
core::int result = recurse.call(b.{core::num::-}(1));
|
||||
return b.{core::num::*}(result);
|
||||
}
|
||||
return recurse.call(a);
|
||||
}
|
||||
static method fn6(core::int a) → core::int {
|
||||
function recurse() → core::int {
|
||||
a = a.{core::num::-}(1);
|
||||
if(a.{core::num::==}(1))
|
||||
return 1;
|
||||
return a.{core::num::*}(recurse.call());
|
||||
}
|
||||
return recurse.call();
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C3, 2);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 0
|
||||
#C2 = 1
|
||||
#C3 = 2
|
||||
#C4 = 6
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = foo();
|
||||
int foo() {}
|
||||
const var2 = fn();
|
||||
int fn() {}
|
||||
const y = 1;
|
||||
const var3 = fn3();
|
||||
int fn3() {}
|
||||
const var4 = fn4();
|
||||
int fn4() {}
|
||||
const var5 = fn5(3);
|
||||
int fn5(int a) {}
|
||||
const var6 = fn6(4);
|
||||
int fn6(int a) {}
|
||||
void main() {}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = foo();
|
||||
const var2 = fn();
|
||||
const var3 = fn3();
|
||||
const var4 = fn4();
|
||||
const var5 = fn5(3);
|
||||
const var6 = fn6(4);
|
||||
const y = 1;
|
||||
int fn() {}
|
||||
int fn3() {}
|
||||
int fn4() {}
|
||||
int fn5(int a) {}
|
||||
int fn6(int a) {}
|
||||
int foo() {}
|
||||
void main() {}
|
||||
@@ -0,0 +1,86 @@
|
||||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static const field core::int y = #C2;
|
||||
static const field core::int var3 = #C3;
|
||||
static const field core::int var4 = #C1;
|
||||
static const field core::int var5 = #C4;
|
||||
static const field core::int var6 = #C4;
|
||||
static method foo() → core::int {
|
||||
() → () → core::int f = () → () → core::int {
|
||||
core::int count = 0;
|
||||
function baz() → core::int {
|
||||
count = count.{core::num::+}(1);
|
||||
return count;
|
||||
}
|
||||
return baz;
|
||||
};
|
||||
() → core::int c1 = f.call();
|
||||
() → core::int c2 = f.call();
|
||||
core::int c1_val1 = c1.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c1_val2 = c1.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c1_val3 = c1.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
core::int c2_val1 = c2.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c2_val2 = c2.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c2_val3 = c2.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
return 0;
|
||||
}
|
||||
static method fn() → core::int {
|
||||
return (() → core::int => 0).call();
|
||||
}
|
||||
static method fn3() → core::int {
|
||||
core::int y = 2;
|
||||
return y;
|
||||
}
|
||||
static method fn4() → core::int {
|
||||
core::int x = 0;
|
||||
function innerFn() → core::int {
|
||||
return x;
|
||||
}
|
||||
return innerFn.call();
|
||||
}
|
||||
static method fn5(core::int a) → core::int {
|
||||
function recurse(core::int b) → core::int {
|
||||
if(b.{core::num::==}(1))
|
||||
return 1;
|
||||
core::int result = recurse.call(b.{core::num::-}(1));
|
||||
return b.{core::num::*}(result);
|
||||
}
|
||||
return recurse.call(a);
|
||||
}
|
||||
static method fn6(core::int a) → core::int {
|
||||
function recurse() → core::int {
|
||||
a = a.{core::num::-}(1);
|
||||
if(a.{core::num::==}(1))
|
||||
return 1;
|
||||
return a.{core::num::*}(recurse.call());
|
||||
}
|
||||
return recurse.call();
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C3, 2);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 0
|
||||
#C2 = 1
|
||||
#C3 = 2
|
||||
#C4 = 6
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = self::foo();
|
||||
static const field core::int var2 = self::fn();
|
||||
static const field core::int y = 1;
|
||||
static const field core::int var3 = self::fn3();
|
||||
static const field core::int var4 = self::fn4();
|
||||
static const field core::int var5 = self::fn5(3);
|
||||
static const field core::int var6 = self::fn6(4);
|
||||
static method foo() → core::int
|
||||
;
|
||||
static method fn() → core::int
|
||||
;
|
||||
static method fn3() → core::int
|
||||
;
|
||||
static method fn4() → core::int
|
||||
;
|
||||
static method fn5(core::int a) → core::int
|
||||
;
|
||||
static method fn6(core::int a) → core::int
|
||||
;
|
||||
static method main() → void
|
||||
;
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
library /*isNonNullableByDefault*/;
|
||||
import self as self;
|
||||
import "dart:core" as core;
|
||||
import "package:expect/expect.dart" as exp;
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
static const field core::int var1 = #C1;
|
||||
static const field core::int var2 = #C1;
|
||||
static const field core::int y = #C2;
|
||||
static const field core::int var3 = #C3;
|
||||
static const field core::int var4 = #C1;
|
||||
static const field core::int var5 = #C4;
|
||||
static const field core::int var6 = #C4;
|
||||
static method foo() → core::int {
|
||||
() → () → core::int f = () → () → core::int {
|
||||
core::int count = 0;
|
||||
function baz() → core::int {
|
||||
count = count.{core::num::+}(1);
|
||||
return count;
|
||||
}
|
||||
return baz;
|
||||
};
|
||||
() → core::int c1 = f.call();
|
||||
() → core::int c2 = f.call();
|
||||
core::int c1_val1 = c1.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c1_val2 = c1.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c1_val3 = c1.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
core::int c2_val1 = c2.call();
|
||||
assert(c1_val1.{core::num::==}(1));
|
||||
core::int c2_val2 = c2.call();
|
||||
assert(c1_val2.{core::num::==}(2));
|
||||
core::int c2_val3 = c2.call();
|
||||
assert(c1_val3.{core::num::==}(3));
|
||||
return 0;
|
||||
}
|
||||
static method fn() → core::int {
|
||||
return (() → core::int => 0).call();
|
||||
}
|
||||
static method fn3() → core::int {
|
||||
core::int y = 2;
|
||||
return y;
|
||||
}
|
||||
static method fn4() → core::int {
|
||||
core::int x = 0;
|
||||
function innerFn() → core::int {
|
||||
return x;
|
||||
}
|
||||
return innerFn.call();
|
||||
}
|
||||
static method fn5(core::int a) → core::int {
|
||||
function recurse(core::int b) → core::int {
|
||||
if(b.{core::num::==}(1))
|
||||
return 1;
|
||||
core::int result = recurse.call(b.{core::num::-}(1));
|
||||
return b.{core::num::*}(result);
|
||||
}
|
||||
return recurse.call(a);
|
||||
}
|
||||
static method fn6(core::int a) → core::int {
|
||||
function recurse() → core::int {
|
||||
a = a.{core::num::-}(1);
|
||||
if(a.{core::num::==}(1))
|
||||
return 1;
|
||||
return a.{core::num::*}(recurse.call());
|
||||
}
|
||||
return recurse.call();
|
||||
}
|
||||
static method main() → void {
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C3, 2);
|
||||
exp::Expect::equals(#C1, 0);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
exp::Expect::equals(#C4, 6);
|
||||
}
|
||||
|
||||
constants {
|
||||
#C1 = 0
|
||||
#C2 = 1
|
||||
#C3 = 2
|
||||
#C4 = 6
|
||||
}
|
||||
@@ -17,6 +17,19 @@ int fn() {
|
||||
return x;
|
||||
}
|
||||
|
||||
const var2 = fn2();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn2() {
|
||||
int x = 0;
|
||||
assert(() {
|
||||
var y = x + 1;
|
||||
return y == 1;
|
||||
}());
|
||||
return x;
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 0);
|
||||
Expect.equals(var2, 0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests erroneous closure situations with const functions.
|
||||
|
||||
// SharedOptions=--enable-experiment=const-functions
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
var varVariable = 1;
|
||||
const var1 = fn();
|
||||
// ^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [cfe] Constant evaluation error:
|
||||
int fn() {
|
||||
return varVariable;
|
||||
}
|
||||
|
||||
final finalVariable = 1;
|
||||
const var2 = fn2();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// [cfe] Constant evaluation error:
|
||||
int fn2() {
|
||||
return finalVariable;
|
||||
}
|
||||
|
||||
const var3 = fn3();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn3() {
|
||||
int innerFn() {
|
||||
return x;
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
|
||||
}
|
||||
|
||||
const x = 0;
|
||||
// ^
|
||||
// [cfe] Can't declare 'x' because it was already used in this scope.
|
||||
return innerFn();
|
||||
}
|
||||
|
||||
const var4 = fn4();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn4() {
|
||||
var a = () {
|
||||
return x;
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
|
||||
};
|
||||
var x = 1;
|
||||
// ^
|
||||
// [cfe] Can't declare 'x' because it was already used in this scope.
|
||||
return a();
|
||||
}
|
||||
|
||||
const var5 = fn5(1);
|
||||
// ^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
fn5(a) {
|
||||
var a = () => a;
|
||||
// ^
|
||||
// [cfe] Can't declare 'a' because it was already used in this scope.
|
||||
// ^
|
||||
// [analyzer] COMPILE_TIME_ERROR.REFERENCED_BEFORE_DECLARATION
|
||||
return a();
|
||||
}
|
||||
|
||||
const x = 0;
|
||||
void fn6() {
|
||||
var x = 1;
|
||||
int a() => x;
|
||||
const z = a();
|
||||
// ^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
// ^
|
||||
// [cfe] Constant evaluation error:
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
|
||||
// for details. All rights reserved. Use of this source code is governed by a
|
||||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
// Tests closures with const functions.
|
||||
|
||||
// SharedOptions=--enable-experiment=const-functions
|
||||
|
||||
import "package:expect/expect.dart";
|
||||
|
||||
const var1 = foo();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int foo() {
|
||||
var f = () {
|
||||
int count = 0;
|
||||
int baz() {
|
||||
++count;
|
||||
return count;
|
||||
}
|
||||
|
||||
return baz;
|
||||
};
|
||||
var c1 = f();
|
||||
var c2 = f();
|
||||
|
||||
var c1_val1 = c1();
|
||||
assert(c1_val1 == 1);
|
||||
var c1_val2 = c1();
|
||||
assert(c1_val2 == 2);
|
||||
var c1_val3 = c1();
|
||||
assert(c1_val3 == 3);
|
||||
|
||||
var c2_val1 = c2();
|
||||
assert(c1_val1 == 1);
|
||||
var c2_val2 = c2();
|
||||
assert(c1_val2 == 2);
|
||||
var c2_val3 = c2();
|
||||
assert(c1_val3 == 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const var2 = fn();
|
||||
// ^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn() {
|
||||
return (() => 0)();
|
||||
}
|
||||
|
||||
const y = 1;
|
||||
const var3 = fn3();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn3() {
|
||||
int y = 2;
|
||||
return y;
|
||||
}
|
||||
|
||||
const var4 = fn4();
|
||||
// ^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn4() {
|
||||
var x = 0;
|
||||
int innerFn() {
|
||||
return x;
|
||||
}
|
||||
|
||||
return innerFn();
|
||||
}
|
||||
|
||||
const var5 = fn5(3);
|
||||
// ^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn5(int a) {
|
||||
int recurse(int b) {
|
||||
if (b == 1) return 1;
|
||||
int result = recurse(b - 1);
|
||||
return b * result;
|
||||
}
|
||||
|
||||
return recurse(a);
|
||||
}
|
||||
|
||||
const var6 = fn6(4);
|
||||
// ^^^^^^
|
||||
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
|
||||
int fn6(int a) {
|
||||
int recurse() {
|
||||
a--;
|
||||
if (a == 1) return 1;
|
||||
return a * recurse();
|
||||
}
|
||||
|
||||
return recurse();
|
||||
}
|
||||
|
||||
void main() {
|
||||
Expect.equals(var1, 0);
|
||||
Expect.equals(var2, 0);
|
||||
Expect.equals(var3, 2);
|
||||
Expect.equals(var4, 0);
|
||||
Expect.equals(var5, 6);
|
||||
Expect.equals(var6, 6);
|
||||
}
|
||||
Reference in New Issue
Block a user