Skip to content

[record_use] Correctness: Remove support for tracking const annotations #2977

@dcharkes

Description

@dcharkes

Some of the examples in our initial prototype track the use of classes, instance members, and static calls by tracking the const-instances in annotations.

Some examples:

@RecordUse('do_something')
void doSomething() {
  print('a');
}


@RecordUse()
class MethodUse {
  final String nativeResource;

  const MethodUse(this.nativeResource);
}

// const instance `MyClass(42)` not tree-shaken if `doSomething` is not tree-shaken.
@ClassUse('org.my_org.foo.A')
class A {}

@RecordUse()
class ClassUse {
  final String name;

  const ClassUse(this.name);
}

// const instance `MyClass(42)` not tree-shaken if `class A` is not tree-shaken.

While looking at #2893, I realized that this behavior heavily relies on the VM compiler. The VM frontend does not remove annotations, it preserves them in the kernel format and passes them to the backend. The dart2js compiler removes all annotations. (Dart2js only keeps pragmas, and does so in its own format.) Dart2js does not use the kernel format in its later stages but another format. In this format there is a constant pool, but annotation consts do not occur in this constant pool. Implementing the VM-compiler behavior in the JS-compiler is a non-trivial task.

This leads to the observation that there is no semantics specified for annotations in the Dart language spec once you start compiling. Dart compilers may do as they please.

Also, the goal of the two examples above is to track method use and class use. The fields of the const instance would contain some information of the resource being used that is a connection between the Dart definition and the native definition (a C symbol or a Java class). This mapping could be saved in some other location accessible in the link hook.

Since the semantics aren't specified, behavior of this feature would be unpredictable:

  1. If you put the annotation on an instance method. And the compiler figures out only subtypes of the class ever exist in the program and every subtype overrides the method, and none of the overrides call the super method. It could delete the method, and so the annotation
  2. If you put the annotation on a class, but the whole-world optimization figures out only subtypes are used not the class itself, and it can throw the class out of the hierarchy without changing the Dart semantics, then the annotation would disappear.

Instead of tracking annotations on things, we should track the use of those things itself. Then for each of those things, we can define a precise semantics.

cc @goderbauer @mosuem

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions