[cfe] Do-while statements for const functions.

Change-Id: I881fb535ef76e564ab76c5fc661d3adbbe5aed0f
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/192401
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
This commit is contained in:
Kallen Tu 2021-03-22 22:19:45 +00:00 committed by commit-bot@chromium.org
parent 86c5085565
commit 9e5a6c1568
11 changed files with 434 additions and 0 deletions

View file

@ -3362,6 +3362,29 @@ class StatementConstantEvaluator extends StatementVisitor<ExecutionStatus> {
ExecutionStatus visitBreakStatement(BreakStatement node) =>
new BreakStatus(node.target);
@override
ExecutionStatus visitDoStatement(DoStatement node) {
Constant condition;
do {
ExecutionStatus status = node.body.accept(this);
if (status is! ProceedStatus) return status;
condition = evaluate(node.condition);
} while (condition is BoolConstant && condition.value);
if (condition is AbortConstant) {
return new AbortStatus(condition);
} else if (condition is! BoolConstant) {
return new AbortStatus(exprEvaluator.createErrorConstant(
node.condition,
templateConstEvalInvalidType.withArguments(
condition,
exprEvaluator.typeEnvironment.coreTypes.boolLegacyRawType,
condition.getType(exprEvaluator._staticTypeContext),
exprEvaluator.isNonNullableByDefault)));
}
return const ProceedStatus();
}
@override
ExecutionStatus visitIfStatement(IfStatement node) {
Constant condition = evaluate(node.condition);

View file

@ -0,0 +1,46 @@
// 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 do-while statements for const functions.
import "package:expect/expect.dart";
const var1 = fn();
int fn() {
int x = 0;
do {
x++;
} while (x < 2);
return x;
}
const var2 = fn2(2);
const var3 = fn2(10);
int fn2(int a) {
int x = 0, b = 0;
do {
if (x > 5) break;
x += a;
b++;
} while (b < 2);
return x;
}
const var4 = fn3();
int fn3() {
int x = 0, b = 0;
do {
x += 1;
if (x % 2 == 1) continue;
b += x;
} while (x < 5);
return b;
}
void main() {
Expect.equals(var1, 2);
Expect.equals(var2, 4);
Expect.equals(var3, 10);
Expect.equals(var4, 6);
}

View file

@ -0,0 +1,59 @@
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 = #C2;
static const field core::int var3 = #C3;
static const field core::int var4 = #C4;
static method fn() → core::int {
core::int x = 0;
do {
x = x.{core::num::+}(1);
}
while (x.{core::num::<}(2))
return x;
}
static method fn2(core::int a) → core::int {
core::int x = 0;
core::int b = 0;
#L1:
do {
if(x.{core::num::>}(5))
break #L1;
x = x.{core::num::+}(a);
b = b.{core::num::+}(1);
}
while (b.{core::num::<}(2))
return x;
}
static method fn3() → core::int {
core::int x = 0;
core::int b = 0;
do
#L2:
{
x = x.{core::num::+}(1);
if(x.{core::num::%}(2).{core::num::==}(1))
break #L2;
b = b.{core::num::+}(x);
}
while (x.{core::num::<}(5))
return b;
}
static method main() → void {
exp::Expect::equals(#C1, 2);
exp::Expect::equals(#C2, 4);
exp::Expect::equals(#C3, 10);
exp::Expect::equals(#C4, 6);
}
constants {
#C1 = 2
#C2 = 4
#C3 = 10
#C4 = 6
}

View file

@ -0,0 +1,59 @@
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 = #C2;
static const field core::int var3 = #C3;
static const field core::int var4 = #C4;
static method fn() → core::int {
core::int x = 0;
do {
x = x.{core::num::+}(1);
}
while (x.{core::num::<}(2))
return x;
}
static method fn2(core::int a) → core::int {
core::int x = 0;
core::int b = 0;
#L1:
do {
if(x.{core::num::>}(5))
break #L1;
x = x.{core::num::+}(a);
b = b.{core::num::+}(1);
}
while (b.{core::num::<}(2))
return x;
}
static method fn3() → core::int {
core::int x = 0;
core::int b = 0;
do
#L2:
{
x = x.{core::num::+}(1);
if(x.{core::num::%}(2).{core::num::==}(1))
break #L2;
b = b.{core::num::+}(x);
}
while (x.{core::num::<}(5))
return b;
}
static method main() → void {
exp::Expect::equals(#C1, 2);
exp::Expect::equals(#C2, 4);
exp::Expect::equals(#C3, 10);
exp::Expect::equals(#C4, 6);
}
constants {
#C1 = 2
#C2 = 4
#C3 = 10
#C4 = 6
}

View file

@ -0,0 +1,10 @@
import "package:expect/expect.dart";
const var1 = fn();
int fn() {}
const var2 = fn2(2);
const var3 = fn2(10);
int fn2(int a) {}
const var4 = fn3();
int fn3() {}
void main() {}

View file

@ -0,0 +1,10 @@
import "package:expect/expect.dart";
const var1 = fn();
const var2 = fn2(2);
const var3 = fn2(10);
const var4 = fn3();
int fn() {}
int fn2(int a) {}
int fn3() {}
void main() {}

View file

@ -0,0 +1,59 @@
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 = #C2;
static const field core::int var3 = #C3;
static const field core::int var4 = #C4;
static method fn() → core::int {
core::int x = 0;
do {
x = x.{core::num::+}(1);
}
while (x.{core::num::<}(2))
return x;
}
static method fn2(core::int a) → core::int {
core::int x = 0;
core::int b = 0;
#L1:
do {
if(x.{core::num::>}(5))
break #L1;
x = x.{core::num::+}(a);
b = b.{core::num::+}(1);
}
while (b.{core::num::<}(2))
return x;
}
static method fn3() → core::int {
core::int x = 0;
core::int b = 0;
do
#L2:
{
x = x.{core::num::+}(1);
if(x.{core::num::%}(2).{core::num::==}(1))
break #L2;
b = b.{core::num::+}(x);
}
while (x.{core::num::<}(5))
return b;
}
static method main() → void {
exp::Expect::equals(#C1, 2);
exp::Expect::equals(#C2, 4);
exp::Expect::equals(#C3, 10);
exp::Expect::equals(#C4, 6);
}
constants {
#C1 = 2
#C2 = 4
#C3 = 10
#C4 = 6
}

View file

@ -0,0 +1,18 @@
library /*isNonNullableByDefault*/;
import self as self;
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(2);
static const field core::int var3 = self::fn2(10);
static const field core::int var4 = self::fn3();
static method fn() → core::int
;
static method fn2(core::int a) → core::int
;
static method fn3() → core::int
;
static method main() → void
;

View file

@ -0,0 +1,59 @@
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 = #C2;
static const field core::int var3 = #C3;
static const field core::int var4 = #C4;
static method fn() → core::int {
core::int x = 0;
do {
x = x.{core::num::+}(1);
}
while (x.{core::num::<}(2))
return x;
}
static method fn2(core::int a) → core::int {
core::int x = 0;
core::int b = 0;
#L1:
do {
if(x.{core::num::>}(5))
break #L1;
x = x.{core::num::+}(a);
b = b.{core::num::+}(1);
}
while (b.{core::num::<}(2))
return x;
}
static method fn3() → core::int {
core::int x = 0;
core::int b = 0;
do
#L2:
{
x = x.{core::num::+}(1);
if(x.{core::num::%}(2).{core::num::==}(1))
break #L2;
b = b.{core::num::+}(x);
}
while (x.{core::num::<}(5))
return b;
}
static method main() → void {
exp::Expect::equals(#C1, 2);
exp::Expect::equals(#C2, 4);
exp::Expect::equals(#C3, 10);
exp::Expect::equals(#C4, 6);
}
constants {
#C1 = 2
#C2 = 4
#C3 = 10
#C4 = 6
}

View file

@ -0,0 +1,35 @@
// 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 do-while statements for const functions.
// SharedOptions=--enable-experiment=const-functions
import "package:expect/expect.dart";
const var1 = fn();
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn() {
int x = 0;
do {
x++;
} while (x);
// ^
// [analyzer] COMPILE_TIME_ERROR.NON_BOOL_CONDITION
// [cfe] A value of type 'int' can't be assigned to a variable of type 'bool'.
return 2;
}
const var2 = fn2();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
// [cfe] Constant evaluation error:
int fn2() {
int x = 0;
do {
x++;
} while (x as dynamic);
return 2;
}

View file

@ -0,0 +1,56 @@
// 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 do-while statements for const functions.
// SharedOptions=--enable-experiment=const-functions
import "package:expect/expect.dart";
const var1 = fn();
// ^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn() {
int x = 0;
do {
x++;
} while (x < 2);
return x;
}
const var2 = fn2(2);
// ^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
const var3 = fn2(10);
// ^^^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn2(int a) {
int x = 0, b = 0;
do {
if (x > 5) break;
x += a;
b++;
} while (b < 2);
return x;
}
const var4 = fn3();
// ^^^^^
// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
int fn3() {
int x = 0, b = 0;
do {
x += 1;
if (x % 2 == 1) continue;
b += x;
} while (x < 5);
return b;
}
void main() {
Expect.equals(var1, 2);
Expect.equals(var2, 4);
Expect.equals(var3, 10);
Expect.equals(var4, 6);
}