[vm/aot] Handle FieldInitializer pointing to a Field's Reference which is reused for a getter
This is a follow-up to https://dart-review.googlesource.com/c/sdk/+/186680.
After that change, tree shaker started reusing Reference to a Field
when it is replaced with a getter. As a side-effect, this makes
FieldInitializer.field to crash as Reference is now pointing to Procedure,
not a Field.
The fix is to carefully use 'node.fieldReference.asMember' instead of
'node.field' and then retrieve original Field node if it was replaced
with a getter.
TEST=pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart
Fixes https://github.com/dart-lang/sdk/issues/45324
Change-Id: Ic34e8b9933b00997cd350a4ad93f798c86ac60ad
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/191323
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index ff602a2..221cb64 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -1185,9 +1185,11 @@
if (_isUnreachable(node)) {
return _makeUnreachableInitializer([node.value]);
} else {
- assert(shaker.isMemberBodyReachable(node.field),
- "Field should be reachable: ${node.field}");
- if (!shaker.retainField(node.field)) {
+ final field =
+ fieldMorpher.getOriginalMember(node.fieldReference.asMember) as Field;
+ assert(shaker.isMemberBodyReachable(field),
+ "Field should be reachable: ${field}");
+ if (!shaker.retainField(field)) {
if (mayHaveSideEffects(node.value)) {
return LocalInitializer(
VariableDeclaration(null, initializer: node.value));
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart b/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart
new file mode 100644
index 0000000..6c4d972
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart
@@ -0,0 +1,27 @@
+// 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.
+
+// @dart = 2.12
+
+class A {
+ void doTest(Z a) {
+ print(a.appName);
+ }
+}
+
+class Z {
+ final String? appName;
+ Z({this.appName});
+}
+
+class X extends Base implements Z {}
+
+class Base {
+ String get appName => 'x';
+}
+
+void main() {
+ Z();
+ A().doTest(X());
+}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart.expect
new file mode 100644
index 0000000..2ef7c98
--- /dev/null
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_45324_2.dart.expect
@@ -0,0 +1,34 @@
+library #lib /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class A extends core::Object {
+ synthetic constructor •() → self::A
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:1,getterSelectorId:2] method doTest([@vm.inferred-type.metadata=#lib::X] self::Z a) → void {
+ core::print([@vm.direct-call.metadata=#lib::Base.appName] [@vm.inferred-type.metadata=dart.core::_OneByteString (value: "x")] a.{self::Z::appName});
+ }
+}
+class Z extends core::Object {
+ constructor •() → self::Z
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] abstract get /*isLegacy*/ appName() → core::String?;
+}
+class X extends self::Base implements self::Z {
+ synthetic constructor •() → self::X
+ : super self::Base::•()
+ ;
+}
+abstract class Base extends core::Object {
+ synthetic constructor •() → self::Base
+ : super core::Object::•()
+ ;
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasNonThisUses:false,hasTearOffUses:false,getterSelectorId:3] get appName() → core::String
+ return "x";
+}
+static method main() → void {
+ new self::Z::•();
+ [@vm.direct-call.metadata=#lib::A.doTest] [@vm.inferred-type.metadata=!? (skip check)] new self::A::•().{self::A::doTest}(new self::X::•());
+}