Skip to content

Commit b083c9a

Browse files
alexmarkovCommit Queue
authored andcommitted
[dyn_modules] Handle implicit uses from const constructors and field initializers of const classes
When const constructor is exposed through a dynamic interface, dynamic module can create constants with that const constructor and it can reference everything used in that constructor including default values of parameters and field initializers. So dynamic interface annotator should visit bodies of const constructors and add all references to implicit uses. Annotator should also visit initializers of instance fields of classes which can be used in a constant (as they participate in the constant evaluation too). Kernel trim tool should not remove such field initializers. TEST=pkg/dynamic_modules/test/data/const_constructor Fixes b/418928636 Change-Id: Ie216f3a4257fe5a905b83af8c60dfe8a5b774ecf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430002 Commit-Queue: Alexander Markov <[email protected]> Reviewed-by: Sigmund Cherem <[email protected]> Reviewed-by: Slava Egorov <[email protected]>
1 parent 4cdb3f2 commit b083c9a

File tree

6 files changed

+65
-0
lines changed

6 files changed

+65
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
# for details. All rights reserved. Use of this source code is governed by a
3+
# BSD-style license that can be found in the LICENSE file.
4+
5+
callable:
6+
- library: 'shared/shared.dart'
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../../common/testing.dart' as helper;
6+
import 'package:expect/expect.dart';
7+
8+
import 'shared/shared.dart'; // ignore: unused_import
9+
10+
/// Verify that default values of const constructor parameters are retained.
11+
void main() async {
12+
final result = (await helper.load('entry1.dart')) as String;
13+
Expect.equals("Foo1:41 Foo2:42 Foo3:43", result);
14+
helper.done();
15+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import '../shared/shared.dart';
6+
7+
@pragma('dyn-module:entry-point')
8+
Object? dynamicModuleEntrypoint() {
9+
return "${const Foo1()} ${const Foo2()} ${const Foo3()}";
10+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
int _defaultF1() => 41;
6+
int _defaultF2() => 42;
7+
int _defaultF3() => 43;
8+
9+
class Foo1 {
10+
final int Function() f1;
11+
const Foo1({this.f1 = _defaultF1});
12+
13+
@override
14+
String toString() => "Foo1:${f1()}";
15+
}
16+
17+
class Foo2 {
18+
final int Function() _f2 = _defaultF2;
19+
const Foo2();
20+
21+
@override
22+
String toString() => "Foo2:${_f2()}";
23+
}
24+
25+
class Foo3 {
26+
final int Function() _f3;
27+
const Foo3() : _f3 = _defaultF3;
28+
29+
@override
30+
String toString() => "Foo3:${_f3()}";
31+
}

pkg/front_end/lib/src/util/trim.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ class Trimmer extends RecursiveVisitor {
213213
void visitField(Field node) {
214214
// Constant initializers are necessary for constant evaluation
215215
if (node.isConst) return;
216+
if (!node.isStatic && node.enclosingClass!.hasConstConstructor) return;
216217

217218
// Unfortunately a `null` initializer may be misinterpreted by the CFE or
218219
// the compiler. Ideally the kernel representation should have a sentinel

pkg/vm/lib/transformations/dynamic_interface_annotator.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ class _ImplicitUsesAnnotator extends RecursiveVisitor {
377377
annotateMember(node);
378378
if (node.isConst) {
379379
annotateConstantClass(node.enclosingClass);
380+
node.visitChildren(this);
380381
}
381382
}
382383

@@ -431,6 +432,7 @@ class _ImplicitUsesAnnotator extends RecursiveVisitor {
431432
for (final f in node.fields) {
432433
if (f.isInstanceMember) {
433434
annotateMember(f);
435+
f.initializer?.accept(this);
434436
}
435437
}
436438
final superclass = node.superclass;

0 commit comments

Comments
 (0)