[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);
+}