[cfe] If statements for const functions.
Change-Id: If4449eb6613c7a2b53119ed2e8d3f3042624ccd1
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/190800
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
diff --git a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
index 1089515..ec0a9bb 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -3340,6 +3340,29 @@
}
@override
+ ExecutionStatus visitIfStatement(IfStatement node) {
+ Constant condition = evaluate(node.condition);
+ if (condition is AbortConstant) return new ReturnStatus(condition);
+ if (condition is BoolConstant) {
+ if (condition.value) {
+ return node.then.accept(this);
+ } else if (node.otherwise != null) {
+ return node.otherwise.accept(this);
+ } else {
+ return const ProceedStatus();
+ }
+ } else {
+ return new ReturnStatus(exprEvaluator.createErrorConstant(
+ node.condition,
+ templateConstEvalInvalidType.withArguments(
+ condition,
+ exprEvaluator.typeEnvironment.coreTypes.boolLegacyRawType,
+ condition.getType(exprEvaluator._staticTypeContext),
+ exprEvaluator.isNonNullableByDefault)));
+ }
+ }
+
+ @override
ExecutionStatus visitExpressionStatement(ExpressionStatement node) {
Constant value = evaluate(node.expression);
if (value is AbortConstant) return new ReturnStatus(value);
@@ -3436,7 +3459,12 @@
EvaluationEnvironment.withParent(this._parent);
/// Whether the current environment is empty.
- bool get isEmpty => _typeVariables.isEmpty && _variables.isEmpty;
+ bool get isEmpty {
+ // Since we look up variables in enclosing environment, the environment
+ // is not empty if its parent is not empty.
+ if (_parent != null && !_parent.isEmpty) return false;
+ return _typeVariables.isEmpty && _variables.isEmpty;
+ }
void addTypeParameterValue(TypeParameter parameter, DartType value) {
assert(!_typeVariables.containsKey(parameter));
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart
new file mode 100644
index 0000000..a4118a3
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart
@@ -0,0 +1,75 @@
+// 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 if statements for const functions.
+
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+int ifTest(int a) {
+ if (a == 1) {
+ return 100;
+ } else if (a == 2) {
+ return 200;
+ } else {
+ return 300;
+ }
+}
+
+const one = 1;
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+int ifTest2(int a) {
+ if (a == one) {
+ return 100;
+ } else {
+ return 200;
+ }
+}
+
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+int ifTest3(int a) {
+ if (a > 0) {
+ if (a == 1) return 100;
+ return 200;
+ }
+ return 300;
+}
+
+const var7 = ifTest4(1);
+int ifTest4(int a) {
+ int b = a;
+ if (a == 1) {
+ b += a;
+ if (a % 2 == 1) {
+ b += a;
+ }
+ } else if (a == 2) {
+ b -= a;
+ }
+
+ return b;
+}
+
+const var8 = ifTest5();
+int ifTest5() {
+ var x = 10;
+ if (true) var x = 20;
+ return x;
+}
+
+void main() {
+ Expect.equals(var1, 100);
+ Expect.equals(var2, 200);
+ Expect.equals(var3, 300);
+ Expect.equals(var4, 100);
+ Expect.equals(var5, 200);
+ Expect.equals(var6, 100);
+ Expect.equals(var7, 3);
+ Expect.equals(var8, 10);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.expect
@@ -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 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+ if(a.{core::num::==}(1)) {
+ return 100;
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ return 200;
+ }
+ else {
+ return 300;
+ }
+}
+static method ifTest2(core::int a) → core::int {
+ if(a.{core::num::==}(#C4)) {
+ return 100;
+ }
+ else {
+ return 200;
+ }
+}
+static method ifTest3(core::int a) → core::int {
+ if(a.{core::num::>}(0)) {
+ if(a.{core::num::==}(1))
+ return 100;
+ return 200;
+ }
+ return 300;
+}
+static method ifTest4(core::int a) → core::int {
+ core::int b = a;
+ if(a.{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ if(a.{core::num::%}(2).{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ }
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ b = b.{core::num::-}(a);
+ }
+ return b;
+}
+static method ifTest5() → core::int {
+ core::int x = 10;
+ if(true) {
+ core::int x = 20;
+ }
+ return x;
+}
+static method main() → void {
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C3, 300);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C5, 3);
+ exp::Expect::equals(#C6, 10);
+}
+
+constants {
+ #C1 = 100
+ #C2 = 200
+ #C3 = 300
+ #C4 = 1
+ #C5 = 3
+ #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.strong.transformed.expect
@@ -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 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+ if(a.{core::num::==}(1)) {
+ return 100;
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ return 200;
+ }
+ else {
+ return 300;
+ }
+}
+static method ifTest2(core::int a) → core::int {
+ if(a.{core::num::==}(#C4)) {
+ return 100;
+ }
+ else {
+ return 200;
+ }
+}
+static method ifTest3(core::int a) → core::int {
+ if(a.{core::num::>}(0)) {
+ if(a.{core::num::==}(1))
+ return 100;
+ return 200;
+ }
+ return 300;
+}
+static method ifTest4(core::int a) → core::int {
+ core::int b = a;
+ if(a.{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ if(a.{core::num::%}(2).{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ }
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ b = b.{core::num::-}(a);
+ }
+ return b;
+}
+static method ifTest5() → core::int {
+ core::int x = 10;
+ if(true) {
+ core::int x = 20;
+ }
+ return x;
+}
+static method main() → void {
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C3, 300);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C5, 3);
+ exp::Expect::equals(#C6, 10);
+}
+
+constants {
+ #C1 = 100
+ #C2 = 200
+ #C3 = 300
+ #C4 = 1
+ #C5 = 3
+ #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect
new file mode 100644
index 0000000..0af1a72
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline.expect
@@ -0,0 +1,19 @@
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+int ifTest(int a) {}
+const one = 1;
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+int ifTest2(int a) {}
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+int ifTest3(int a) {}
+const var7 = ifTest4(1);
+int ifTest4(int a) {}
+const var8 = ifTest5();
+int ifTest5() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..5f5b560
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.textual_outline_modelled.expect
@@ -0,0 +1,19 @@
+import "package:expect/expect.dart";
+
+const one = 1;
+const var1 = ifTest(1);
+const var2 = ifTest(2);
+const var3 = ifTest(3);
+const var4 = ifTest2(1);
+const var5 = ifTest2(2);
+const var6 = ifTest3(1);
+const var6_1 = ifTest3(2);
+const var6_2 = ifTest3(0);
+const var7 = ifTest4(1);
+const var8 = ifTest5();
+int ifTest(int a) {}
+int ifTest2(int a) {}
+int ifTest3(int a) {}
+int ifTest4(int a) {}
+int ifTest5() {}
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.expect
@@ -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 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+ if(a.{core::num::==}(1)) {
+ return 100;
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ return 200;
+ }
+ else {
+ return 300;
+ }
+}
+static method ifTest2(core::int a) → core::int {
+ if(a.{core::num::==}(#C4)) {
+ return 100;
+ }
+ else {
+ return 200;
+ }
+}
+static method ifTest3(core::int a) → core::int {
+ if(a.{core::num::>}(0)) {
+ if(a.{core::num::==}(1))
+ return 100;
+ return 200;
+ }
+ return 300;
+}
+static method ifTest4(core::int a) → core::int {
+ core::int b = a;
+ if(a.{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ if(a.{core::num::%}(2).{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ }
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ b = b.{core::num::-}(a);
+ }
+ return b;
+}
+static method ifTest5() → core::int {
+ core::int x = 10;
+ if(true) {
+ core::int x = 20;
+ }
+ return x;
+}
+static method main() → void {
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C3, 300);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C5, 3);
+ exp::Expect::equals(#C6, 10);
+}
+
+constants {
+ #C1 = 100
+ #C2 = 200
+ #C3 = 300
+ #C4 = 1
+ #C5 = 3
+ #C6 = 10
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect
new file mode 100644
index 0000000..ee08b4b
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.outline.expect
@@ -0,0 +1,29 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+static const field core::int var1 = self::ifTest(1);
+static const field core::int var2 = self::ifTest(2);
+static const field core::int var3 = self::ifTest(3);
+static const field core::int one = 1;
+static const field core::int var4 = self::ifTest2(1);
+static const field core::int var5 = self::ifTest2(2);
+static const field core::int var6 = self::ifTest3(1);
+static const field core::int var6_1 = self::ifTest3(2);
+static const field core::int var6_2 = self::ifTest3(0);
+static const field core::int var7 = self::ifTest4(1);
+static const field core::int var8 = self::ifTest5();
+static method ifTest(core::int a) → core::int
+ ;
+static method ifTest2(core::int a) → core::int
+ ;
+static method ifTest3(core::int a) → core::int
+ ;
+static method ifTest4(core::int a) → core::int
+ ;
+static method ifTest5() → core::int
+ ;
+static method main() → void
+ ;
diff --git a/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect
new file mode 100644
index 0000000..8d0f813
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_if_statements.dart.weak.transformed.expect
@@ -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 = #C2;
+static const field core::int var3 = #C3;
+static const field core::int one = #C4;
+static const field core::int var4 = #C1;
+static const field core::int var5 = #C2;
+static const field core::int var6 = #C1;
+static const field core::int var6_1 = #C2;
+static const field core::int var6_2 = #C3;
+static const field core::int var7 = #C5;
+static const field core::int var8 = #C6;
+static method ifTest(core::int a) → core::int {
+ if(a.{core::num::==}(1)) {
+ return 100;
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ return 200;
+ }
+ else {
+ return 300;
+ }
+}
+static method ifTest2(core::int a) → core::int {
+ if(a.{core::num::==}(#C4)) {
+ return 100;
+ }
+ else {
+ return 200;
+ }
+}
+static method ifTest3(core::int a) → core::int {
+ if(a.{core::num::>}(0)) {
+ if(a.{core::num::==}(1))
+ return 100;
+ return 200;
+ }
+ return 300;
+}
+static method ifTest4(core::int a) → core::int {
+ core::int b = a;
+ if(a.{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ if(a.{core::num::%}(2).{core::num::==}(1)) {
+ b = b.{core::num::+}(a);
+ }
+ }
+ else
+ if(a.{core::num::==}(2)) {
+ b = b.{core::num::-}(a);
+ }
+ return b;
+}
+static method ifTest5() → core::int {
+ core::int x = 10;
+ if(true) {
+ core::int x = 20;
+ }
+ return x;
+}
+static method main() → void {
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C3, 300);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C2, 200);
+ exp::Expect::equals(#C1, 100);
+ exp::Expect::equals(#C5, 3);
+ exp::Expect::equals(#C6, 10);
+}
+
+constants {
+ #C1 = 100
+ #C2 = 200
+ #C3 = 300
+ #C4 = 1
+ #C5 = 3
+ #C6 = 10
+}
diff --git a/tests/language/const_functions/const_functions_if_statements_test.dart b/tests/language/const_functions/const_functions_if_statements_test.dart
new file mode 100644
index 0000000..e4998ee
--- /dev/null
+++ b/tests/language/const_functions/const_functions_if_statements_test.dart
@@ -0,0 +1,97 @@
+// 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 if statements for const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+const var1 = ifTest(1);
+// ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var2 = ifTest(2);
+// ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var3 = ifTest(3);
+// ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest(int a) {
+ if (a == 1) {
+ return 100;
+ } else if (a == 2) {
+ return 200;
+ } else {
+ return 300;
+ }
+}
+
+const one = 1;
+const var4 = ifTest2(1);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var5 = ifTest2(2);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest2(int a) {
+ if (a == one) {
+ return 100;
+ } else {
+ return 200;
+ }
+}
+
+const var6 = ifTest3(1);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var6_1 = ifTest3(2);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+const var6_2 = ifTest3(0);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest3(int a) {
+ if (a > 0) {
+ if (a == 1) return 100;
+ return 200;
+ }
+ return 300;
+}
+
+const var7 = ifTest4(1);
+// ^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest4(int a) {
+ int b = a;
+ if (a == 1) {
+ b += a;
+ if (a % 2 == 1) {
+ b += a;
+ }
+ } else if (a == 2) {
+ b -= a;
+ }
+
+ return b;
+}
+
+const var8 = ifTest5();
+// ^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int ifTest5() {
+ var x = 10;
+ if (true) var x = 20;
+ return x;
+}
+
+void main() {
+ Expect.equals(var1, 100);
+ Expect.equals(var2, 200);
+ Expect.equals(var3, 300);
+ Expect.equals(var4, 100);
+ Expect.equals(var5, 200);
+ Expect.equals(var6, 100);
+ Expect.equals(var7, 3);
+ Expect.equals(var8, 10);
+}