[cfe] Instance field get for const functions.
Change-Id: Ie090cbf47d1e5be82e59a3f782dea8b4c1c75c91
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/196380
Reviewed-by: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Jake Macdonald <jakemac@google.com>
Reviewed-by: Bob Nystrom <rnystrom@google.com>
Commit-Queue: Kallen Tu <kallentu@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 57ba7b1..d6e8775 100644
--- a/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/constant_evaluator.dart
@@ -2475,6 +2475,13 @@
interfaceTarget: node.interfaceTarget));
} else if (receiver is NullConstant) {
return createErrorConstant(node, messageConstEvalNullValue);
+ } else if (receiver is InstanceConstant && enableConstFunctions) {
+ for (final Reference fieldRef in receiver.fieldValues.keys) {
+ final Field field = fieldRef.asField;
+ if (field.name == node.name) {
+ return receiver.fieldValues[fieldRef];
+ }
+ }
}
return createErrorConstant(
node,
@@ -2588,6 +2595,13 @@
}
return receiver.entries.single;
}
+ } else if (receiver is InstanceConstant && enableConstFunctions) {
+ for (final Reference fieldRef in receiver.fieldValues.keys) {
+ final Field field = fieldRef.asField;
+ if (field.name == node.name) {
+ return receiver.fieldValues[fieldRef];
+ }
+ }
}
return createErrorConstant(
node,
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart
new file mode 100644
index 0000000..10e2d24
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart
@@ -0,0 +1,49 @@
+// 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 instance field usage with const functions.
+
+import "package:expect/expect.dart";
+
+class A {
+ final int y;
+
+ const A(this.y);
+}
+
+const var1 = fn();
+int fn() => const A(1).y;
+
+const var2 = fn2();
+int fn2() {
+ var x = const A(1);
+ return x.y;
+}
+
+const var3 = const A(1).y;
+
+class B extends A {
+ const B(int x) : super(x);
+}
+
+const var4 = fn4();
+int fn4() => const B(1).y;
+
+class C extends A {
+ @override
+ final int y = 2;
+
+ const C() : super(100);
+}
+
+const var5 = fn5();
+int fn5() => const C().y;
+
+void main() {
+ Expect.equals(var1, 1);
+ Expect.equals(var2, 1);
+ Expect.equals(var3, 1);
+ Expect.equals(var4, 1);
+ Expect.equals(var5, 2);
+}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.expect
new file mode 100644
index 0000000..265d81d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class A extends core::Object /*hasConstConstructor*/ {
+ final field core::int y;
+ const constructor •(core::int y) → self::A
+ : self::A::y = y, super core::Object::•()
+ ;
+}
+class B extends self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x) → self::B
+ : super self::A::•(x)
+ ;
+}
+class C extends self::A /*hasConstConstructor*/ {
+ @#C1
+ final field core::int y = 2;
+ const constructor •() → self::C
+ : super self::A::•(100)
+ ;
+}
+static const field core::int var1 = #C2;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C2;
+static const field core::int var4 = #C2;
+static const field core::int var5 = #C3;
+static method fn() → core::int
+ return (#C4).{self::A::y};
+static method fn2() → core::int {
+ self::A x = #C4;
+ return x.{self::A::y};
+}
+static method fn4() → core::int
+ return (#C5).{self::A::y};
+static method fn5() → core::int
+ return (#C7).{self::C::y};
+static method main() → void {
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C3, 2);
+}
+
+constants {
+ #C1 = core::_Override {}
+ #C2 = 1
+ #C3 = 2
+ #C4 = self::A {y:#C2}
+ #C5 = self::B {y:#C2}
+ #C6 = 100
+ #C7 = self::C {y:#C3, y:#C6}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_instance_fields.dart:
+- A. (from org-dartlang-testcase:///const_functions_instance_fields.dart:12:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- B. (from org-dartlang-testcase:///const_functions_instance_fields.dart:27:9)
+- C. (from org-dartlang-testcase:///const_functions_instance_fields.dart:37:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.transformed.expect
new file mode 100644
index 0000000..265d81d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.strong.transformed.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class A extends core::Object /*hasConstConstructor*/ {
+ final field core::int y;
+ const constructor •(core::int y) → self::A
+ : self::A::y = y, super core::Object::•()
+ ;
+}
+class B extends self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x) → self::B
+ : super self::A::•(x)
+ ;
+}
+class C extends self::A /*hasConstConstructor*/ {
+ @#C1
+ final field core::int y = 2;
+ const constructor •() → self::C
+ : super self::A::•(100)
+ ;
+}
+static const field core::int var1 = #C2;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C2;
+static const field core::int var4 = #C2;
+static const field core::int var5 = #C3;
+static method fn() → core::int
+ return (#C4).{self::A::y};
+static method fn2() → core::int {
+ self::A x = #C4;
+ return x.{self::A::y};
+}
+static method fn4() → core::int
+ return (#C5).{self::A::y};
+static method fn5() → core::int
+ return (#C7).{self::C::y};
+static method main() → void {
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C3, 2);
+}
+
+constants {
+ #C1 = core::_Override {}
+ #C2 = 1
+ #C3 = 2
+ #C4 = self::A {y:#C2}
+ #C5 = self::B {y:#C2}
+ #C6 = 100
+ #C7 = self::C {y:#C3, y:#C6}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_instance_fields.dart:
+- A. (from org-dartlang-testcase:///const_functions_instance_fields.dart:12:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- B. (from org-dartlang-testcase:///const_functions_instance_fields.dart:27:9)
+- C. (from org-dartlang-testcase:///const_functions_instance_fields.dart:37:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline.expect
new file mode 100644
index 0000000..2fd2287
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline.expect
@@ -0,0 +1,29 @@
+import "package:expect/expect.dart";
+
+class A {
+ final int y;
+ const A(this.y);
+}
+
+const var1 = fn();
+int fn() => const A(1).y;
+const var2 = fn2();
+int fn2() {}
+const var3 = const A(1).y;
+
+class B extends A {
+ const B(int x) : super(x);
+}
+
+const var4 = fn4();
+int fn4() => const B(1).y;
+
+class C extends A {
+ @override
+ final int y = 2;
+ const C() : super(100);
+}
+
+const var5 = fn5();
+int fn5() => const C().y;
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..482e50e
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.textual_outline_modelled.expect
@@ -0,0 +1,27 @@
+import "package:expect/expect.dart";
+
+class A {
+ const A(this.y);
+ final int y;
+}
+
+class B extends A {
+ const B(int x) : super(x);
+}
+
+class C extends A {
+ const C() : super(100);
+ @override
+ final int y = 2;
+}
+
+const var1 = fn();
+const var2 = fn2();
+const var3 = const A(1).y;
+const var4 = fn4();
+const var5 = fn5();
+int fn() => const A(1).y;
+int fn2() {}
+int fn4() => const B(1).y;
+int fn5() => const C().y;
+void main() {}
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.expect
new file mode 100644
index 0000000..265d81d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class A extends core::Object /*hasConstConstructor*/ {
+ final field core::int y;
+ const constructor •(core::int y) → self::A
+ : self::A::y = y, super core::Object::•()
+ ;
+}
+class B extends self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x) → self::B
+ : super self::A::•(x)
+ ;
+}
+class C extends self::A /*hasConstConstructor*/ {
+ @#C1
+ final field core::int y = 2;
+ const constructor •() → self::C
+ : super self::A::•(100)
+ ;
+}
+static const field core::int var1 = #C2;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C2;
+static const field core::int var4 = #C2;
+static const field core::int var5 = #C3;
+static method fn() → core::int
+ return (#C4).{self::A::y};
+static method fn2() → core::int {
+ self::A x = #C4;
+ return x.{self::A::y};
+}
+static method fn4() → core::int
+ return (#C5).{self::A::y};
+static method fn5() → core::int
+ return (#C7).{self::C::y};
+static method main() → void {
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C3, 2);
+}
+
+constants {
+ #C1 = core::_Override {}
+ #C2 = 1
+ #C3 = 2
+ #C4 = self::A {y:#C2}
+ #C5 = self::B {y:#C2}
+ #C6 = 100
+ #C7 = self::C {y:#C3, y:#C6}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_instance_fields.dart:
+- A. (from org-dartlang-testcase:///const_functions_instance_fields.dart:12:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- B. (from org-dartlang-testcase:///const_functions_instance_fields.dart:27:9)
+- C. (from org-dartlang-testcase:///const_functions_instance_fields.dart:37:9)
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.outline.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.outline.expect
new file mode 100644
index 0000000..4d35f82
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.outline.expect
@@ -0,0 +1,45 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+import "package:expect/expect.dart";
+
+class A extends core::Object /*hasConstConstructor*/ {
+ final field core::int y;
+ const constructor •(core::int y) → self::A
+ : self::A::y = y, super core::Object::•()
+ ;
+}
+class B extends self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x) → self::B
+ : super self::A::•(x)
+ ;
+}
+class C extends self::A /*hasConstConstructor*/ {
+ @core::override
+ final field core::int y = 2;
+ const constructor •() → self::C
+ : super self::A::•(100)
+ ;
+}
+static const field core::int var1 = self::fn();
+static const field core::int var2 = self::fn2();
+static const field core::int var3 = const self::A::•(1).{self::A::y};
+static const field core::int var4 = self::fn4();
+static const field core::int var5 = self::fn5();
+static method fn() → core::int
+ ;
+static method fn2() → core::int
+ ;
+static method fn4() → core::int
+ ;
+static method fn5() → core::int
+ ;
+static method main() → void
+ ;
+
+
+Extra constant evaluation status:
+Evaluated: StaticGet @ org-dartlang-testcase:///const_functions_instance_fields.dart:34:4 -> InstanceConstant(const _Override{})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///const_functions_instance_fields.dart:24:20 -> InstanceConstant(const A{A.y: 1})
+Extra constant evaluation: evaluated: 9, effectively constant: 2
diff --git a/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.transformed.expect b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.transformed.expect
new file mode 100644
index 0000000..265d81d
--- /dev/null
+++ b/pkg/front_end/testcases/const_functions/const_functions_instance_fields.dart.weak.transformed.expect
@@ -0,0 +1,65 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "package:expect/expect.dart" as exp;
+
+import "package:expect/expect.dart";
+
+class A extends core::Object /*hasConstConstructor*/ {
+ final field core::int y;
+ const constructor •(core::int y) → self::A
+ : self::A::y = y, super core::Object::•()
+ ;
+}
+class B extends self::A /*hasConstConstructor*/ {
+ const constructor •(core::int x) → self::B
+ : super self::A::•(x)
+ ;
+}
+class C extends self::A /*hasConstConstructor*/ {
+ @#C1
+ final field core::int y = 2;
+ const constructor •() → self::C
+ : super self::A::•(100)
+ ;
+}
+static const field core::int var1 = #C2;
+static const field core::int var2 = #C2;
+static const field core::int var3 = #C2;
+static const field core::int var4 = #C2;
+static const field core::int var5 = #C3;
+static method fn() → core::int
+ return (#C4).{self::A::y};
+static method fn2() → core::int {
+ self::A x = #C4;
+ return x.{self::A::y};
+}
+static method fn4() → core::int
+ return (#C5).{self::A::y};
+static method fn5() → core::int
+ return (#C7).{self::C::y};
+static method main() → void {
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C2, 1);
+ exp::Expect::equals(#C3, 2);
+}
+
+constants {
+ #C1 = core::_Override {}
+ #C2 = 1
+ #C3 = 2
+ #C4 = self::A {y:#C2}
+ #C5 = self::B {y:#C2}
+ #C6 = 100
+ #C7 = self::C {y:#C3, y:#C6}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///const_functions_instance_fields.dart:
+- A. (from org-dartlang-testcase:///const_functions_instance_fields.dart:12:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart:25:9)
+- B. (from org-dartlang-testcase:///const_functions_instance_fields.dart:27:9)
+- C. (from org-dartlang-testcase:///const_functions_instance_fields.dart:37:9)
diff --git a/tests/language/const_functions/const_functions_instance_fields_error_test.dart b/tests/language/const_functions/const_functions_instance_fields_error_test.dart
new file mode 100644
index 0000000..4f0bb9e
--- /dev/null
+++ b/tests/language/const_functions/const_functions_instance_fields_error_test.dart
@@ -0,0 +1,41 @@
+// 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 instance field usage with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+class A {
+ final int y;
+
+ const A(this.y);
+}
+
+const var1 = fn();
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() => const A(1).x;
+// ^
+// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
+// [cfe] The getter 'x' isn't defined for the class 'A'.
+
+const var2 = fn2();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn2() {
+ var x = const A(1);
+ return x.x;
+ // ^
+ // [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
+ // [cfe] The getter 'x' isn't defined for the class 'A'.
+}
+
+const var3 = const A(1).x;
+// ^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+// ^
+// [analyzer] COMPILE_TIME_ERROR.UNDEFINED_GETTER
+// [cfe] The getter 'x' isn't defined for the class 'A'.
diff --git a/tests/language/const_functions/const_functions_instance_fields_test.dart b/tests/language/const_functions/const_functions_instance_fields_test.dart
new file mode 100644
index 0000000..8db86c5
--- /dev/null
+++ b/tests/language/const_functions/const_functions_instance_fields_test.dart
@@ -0,0 +1,61 @@
+// 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 instance field usage with const functions.
+
+// SharedOptions=--enable-experiment=const-functions
+
+import "package:expect/expect.dart";
+
+class A {
+ final int y;
+
+ const A(this.y);
+}
+
+const var1 = fn();
+// ^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn() => const A(1).y;
+
+const var2 = fn2();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn2() {
+ var x = const A(1);
+ return x.y;
+}
+
+const var3 = const A(1).y;
+// ^^^^^^^^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+
+class B extends A {
+ const B(int x) : super(x);
+}
+
+const var4 = fn4();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn4() => const B(1).y;
+
+class C extends A {
+ @override
+ final int y = 2;
+
+ const C() : super(100);
+}
+
+const var5 = fn5();
+// ^^^^^
+// [analyzer] COMPILE_TIME_ERROR.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE
+int fn5() => const C().y;
+
+void main() {
+ Expect.equals(var1, 1);
+ Expect.equals(var2, 1);
+ Expect.equals(var3, 1);
+ Expect.equals(var4, 1);
+ Expect.equals(var5, 2);
+}