Skip to content

Commit

Permalink
Update macro spec to allow more introspection in Phase 2. (#3480)
Browse files Browse the repository at this point in the history
* Update macro spec to allow more introspection in Phase 2.

* Address review comments.
  • Loading branch information
davidmorgan authored Nov 29, 2023
1 parent 64de872 commit 34f4818
Showing 1 changed file with 26 additions and 40 deletions.
66 changes: 26 additions & 40 deletions working/macros/feature-specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -268,36 +268,14 @@ order of macros:
Here, the macros applied to C are run `First()`, `Second()`, then `Third()`.
* **Macros are applied to superclasses, mixins, and interfaces first, in**
**Phase 2** For example:
Aside from these rules, macros are constrained so that the result is the same
whatever the application order. In most cases this achieved by the split into
phases: within each phase macros can run in any order because the output is not
visible to other macros until the next phase. As a special case, introspection
of types in Phase 2 waits as needed for other macro applications to complete,
failing if there is a cycle.
```dart
@Third()
class B extends A with C implements D {}
@Second()
class A implements C {}
@First()
class C {}
@first
class D {}
```
Here, the macros on `A`, `C` and `D` run before the macros on `B`, and `C`
also runs before `A`. But otherwise the ordering is not defined (it is not
observable).
This only applies to Phase 2, because it is the only phase where the order
would be observable. In particular this allows macros running on `B` to see
any members added to its super classes, mixins, or interfaces, by other
macros running in phase 2.
Aside from these rules, macro introspection is limited so that evaluation order
is not user visible. For example, if two macros are applied to two methods in
the same class, there is no way for those macros to interfere with each other
such that the application order can be detected.
TODO: give an example of a cycle.
### Augmentation library structure and ordering
Expand Down Expand Up @@ -606,17 +584,21 @@ of a function or initializer for a variable. It is encouraged to provide a body
(or initializer) if possible, but you can opt to wait until the definition phase
if needed.

When applied to a class, enum, or mixin a macro in this phase can introspect on
all of the members of that class and its superclasses, but it cannot introspect
on the members of other types. For mixins, the `on` type is considered a
superclass and is introspectable. Note that generic type arguments are not
introspectable.
Phase two macros can introspect on all of the members of a type. If the type
to be introspected is declared in the same library cycle and has one or more
macros applied to it then this introduces an ordering constraint between the
macro applications: the introspection call waits for complete results before
returning, meaning it waits for the macro applications on the target type to
finish.

When applied to an extension, a macro in this phase can introspect on all of the
members of the `on` type, as well as its generic type arguments and the bounds
of any generic type parameters for the extension.
If a cycle arises in macro applications waiting for other macro applications to
complete then a `StateError ` is thrown.

TODO: Define the introspection rules for extension types.
Rules might be added in future to decide in some specific cases which macro
should run with incomplete introspection results to break a cycle. For example,
there might be a rule specifying that an application to a superclass runs first
with incomplete results, allowing an application to a subclass to run
afterwards with introspection onto the declarations added.

### Phase 3: Definitions

Expand All @@ -629,8 +611,8 @@ function body.
Phase three macros can add new supporting declarations to the surrounding scope,
but these are private to the macro generated code, and never show up in
introspection APIs. These macros can fully introspect on any type reachable from
the declarations they are applied to, including introspecting on members of
classes, etc.
the declarations they are applied to without introducing application ordering
constraints as in Phase 2.

## Macro declarations

Expand Down Expand Up @@ -696,6 +678,8 @@ For example, in `ClassDeclarationsMacro`, the introspection object is a
to the immediate superclass, as well as any immediate mixins or interfaces,
but _not_ its members or entire class hierarchy.

TODO: update this example.

### Builder argument

The second argument is an instance of a [builder][] class. It exposes both
Expand All @@ -707,6 +691,8 @@ primary method is `declareInClass`, which the macro can call to add a new member
to the class. It also implements the `ClassIntrospector` interface, which allows
you to get the members of the class, as well as its entire class hierarchy.

TODO: update this example.

[builder]: https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart

### Introspection API ordering
Expand Down

0 comments on commit 34f4818

Please sign in to comment.