[dyn_modules] Do not trim field initializers in mixins

When applying a mixin during dynamic module compilation, fields and
methods are copied from kernel AST of the mixin.
So field initializers within mixins should be preserved while trimming
host app kernel file, in order to be available for the dynamic module
compilation.

TEST=pkg/dynamic_modules/test/data/mixin_field
Fixes b/418729276

Change-Id: I00c4392989d552e24dc8c4b4b60c1667de234f98
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/429680
Reviewed-by: Sigmund Cherem <sigmund@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/dynamic_modules/test/data/mixin_field/dynamic_interface.yaml b/pkg/dynamic_modules/test/data/mixin_field/dynamic_interface.yaml
new file mode 100644
index 0000000..4c5b159
--- /dev/null
+++ b/pkg/dynamic_modules/test/data/mixin_field/dynamic_interface.yaml
@@ -0,0 +1,10 @@
+# Copyright (c) 2025, 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.
+extendable:
+  - library: 'shared/shared.dart'
+    class: 'Foo'
+
+callable:
+  - library: 'shared/shared.dart'
+    class: 'Foo'
diff --git a/pkg/dynamic_modules/test/data/mixin_field/main.dart b/pkg/dynamic_modules/test/data/mixin_field/main.dart
new file mode 100644
index 0000000..27d6185
--- /dev/null
+++ b/pkg/dynamic_modules/test/data/mixin_field/main.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2025, 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.
+
+import '../../common/testing.dart' as helper;
+
+import 'shared/shared.dart'; // ignore: unused_import
+
+/// A dynamic module can use mixin with a field.
+void main() async {
+  final func = (await helper.load('entry1.dart')) as void Function();
+  func();
+  helper.done();
+}
diff --git a/pkg/dynamic_modules/test/data/mixin_field/modules/entry1.dart b/pkg/dynamic_modules/test/data/mixin_field/modules/entry1.dart
new file mode 100644
index 0000000..5b6b07f
--- /dev/null
+++ b/pkg/dynamic_modules/test/data/mixin_field/modules/entry1.dart
@@ -0,0 +1,19 @@
+// Copyright (c) 2025, 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.
+
+import '../shared/shared.dart';
+
+class Bar with Foo {
+  void doIt() {
+    add(1, 'hello');
+    printAll();
+  }
+}
+
+@pragma('dyn-module:entry-point')
+void Function() main() {
+  return () {
+    Bar().doIt();
+  };
+}
diff --git a/pkg/dynamic_modules/test/data/mixin_field/shared/shared.dart b/pkg/dynamic_modules/test/data/mixin_field/shared/shared.dart
new file mode 100644
index 0000000..81be3de
--- /dev/null
+++ b/pkg/dynamic_modules/test/data/mixin_field/shared/shared.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2025, 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.
+
+mixin Foo {
+  final Map<int, String> _foo = {};
+
+  void add(int i, String s) {
+    _foo[i] = s;
+  }
+
+  void printAll() {
+    print(_foo);
+  }
+}
diff --git a/pkg/front_end/lib/src/util/trim.dart b/pkg/front_end/lib/src/util/trim.dart
index 7fc5816..cb92a41 100644
--- a/pkg/front_end/lib/src/util/trim.dart
+++ b/pkg/front_end/lib/src/util/trim.dart
@@ -148,8 +148,8 @@
   final bool Function(Library) isExtendable;
 
   /// Whether we are within a mixin declaration in an extendable library, and
-  /// hence method bodies need to be preserved.
-  bool preserveMethodBodies = false;
+  /// hence member bodies need to be preserved.
+  bool preserveMemberBodies = false;
 
   Trimmer(this.librariesToClear, this.isExtendable);
 
@@ -181,10 +181,10 @@
 
   @override
   void visitClass(Class node) {
-    preserveMethodBodies = isExtendable(node.enclosingLibrary) &&
+    preserveMemberBodies = isExtendable(node.enclosingLibrary) &&
         (node.isMixinClass || node.isMixinDeclaration);
     super.visitClass(node);
-    preserveMethodBodies = false;
+    preserveMemberBodies = false;
   }
 
   @override
@@ -204,7 +204,7 @@
   void visitProcedure(Procedure node) {
     // Preserve method bodies of mixin declarations, these are copied when
     // mixins are applied in subtypes.
-    if (!preserveMethodBodies) {
+    if (!preserveMemberBodies) {
       node.function.body = null;
     }
   }
@@ -224,7 +224,11 @@
     if (node.isLate && node.isFinal) return;
     if (node.isStatic) return;
 
-    node.initializer = null;
+    // Preserve field initializers in mixin declarations, these are copied when
+    // mixins are applied in subtypes.
+    if (!preserveMemberBodies) {
+      node.initializer = null;
+    }
   }
 }