Skip to content

Commit b1b4828

Browse files
authored
clarify how and when macros should be constructed, remove ability to annotate with const references (#3205)
1 parent c125ae1 commit b1b4828

File tree

1 file changed

+47
-43
lines changed

1 file changed

+47
-43
lines changed

working/macros/feature-specification.md

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -150,19 +150,22 @@ Macros are applied to declarations using the existing metadata annotation
150150
syntax. For example:
151151

152152
```dart
153-
@myCoolMacro
153+
@MyCoolMacro()
154154
class MyClass {}
155155
```
156156

157-
Here, if `myCoolMacro` resolves to an instance of a class implementing one or
158-
more of the macro interfaces, then the annotation is treated as an application
159-
of the `myCoolMacro` macro to the class MyClass.
157+
Here, if the `MyCoolMacro` type is a `macro class`, then the annotation is
158+
treated as an application of the `MyCoolMacro()` macro to the class MyClass.
160159

161160
Macro applications can also be passed arguments, either in the form of
162161
[Code][] expressions, [TypeAnnotation][]s, or certain
163162
types of literal values. See [Macro Arguments](#Macro-arguments) for more
164163
information on how these arguments are handled when executing macros.
165164

165+
Macro applications must always be constructor invocations. It is an error to
166+
annotate a declaration with a constant reference to a macro instance. In the
167+
future we may explore a more concise macro application syntax.
168+
166169
### Code Arguments
167170

168171
Consider this example macro application:
@@ -257,25 +260,25 @@ order of macros:
257260
example:
258261

259262
```dart
260-
@third
261-
@second
262-
@first
263+
@Third()
264+
@Second()
265+
@First()
263266
class C {}
264267
```
265268
266-
Here, the macros applied to C are run `first`, `second`, then `third`.
269+
Here, the macros applied to C are run `First()`, `Second()`, then `Third()`.
267270
268271
* **Macros are applied to superclasses, mixins, and interfaces first, in**
269272
**Phase 2** For example:
270273
271274
```dart
272-
@third
275+
@Third()
273276
class B extends A with C implements D {}
274277
275-
@second
278+
@Second()
276279
class A implements C {}
277280
278-
@first
281+
@First()
279282
class C {}
280283
281284
@first
@@ -415,22 +418,22 @@ ordering problem to discuss. Imagine you have these two classes for tracking
415418
pets and their humans:
416419

417420
```dart
418-
@jsonSerializable
421+
@JsonSerializable()
419422
class Human {
420423
final String name;
421424
final Pet? pet; // Optional, might not have a pet.
422425
}
423426
424-
@jsonSerializable
427+
@JsonSerializable()
425428
class Pet {
426429
final String name;
427430
final Owner? owner; // Optional, might be feral.
428431
}
429432
```
430433

431-
You want to be able to save these to the cloud, so you use a `@jsonSerializable`
432-
macro that generates a `toJson()` method on each class the macro is applied to.
433-
You want the methods to look like this:
434+
You want to be able to save these to the cloud, so you use a
435+
`@JsonSerializable()` macro that generates a `toJson()` method on each class the
436+
macro is applied to. You want the methods to look like this:
434437

435438
```dart
436439
class Human {
@@ -451,10 +454,10 @@ class Pet {
451454
```
452455

453456
Note that the `pet` and `owner` fields are serialized by recursively calling
454-
their `toJson()` methods. To generate that code, the `@jsonSerializable` macro
457+
their `toJson()` methods. To generate that code, the `@JsonSerializable()` macro
455458
needs to look at the type of each field to see if it declares a `toJson()`
456459
method. The problem is that there is *no* order of macro application that will
457-
give the right result. If we apply `@jsonSerializable` to Human first, then it
460+
give the right result. If we apply `@JsonSerializable()` to Human first, then it
458461
won't call `toJson()` on `pet` because Pet doesn't have a `toJson()` method yet.
459462
We get the opposite problem if we apply the macro to Pet first.
460463

@@ -621,7 +624,7 @@ With macros, many of those metadata annotations would instead either *become*
621624
macros or be *read* by them. The latter means that macros also need to be able
622625
to introspect over non-macro metadata annotations applied to declarations.
623626

624-
For example, a `@jsonSerialization` class macro might want to look for an
627+
For example, a `@JsonSerialization()` class macro might want to look for an
625628
`@unseralized` annotation on fields to exclude them from serialization.
626629

627630
**TODO**: The following subsections read more like a design discussion that a
@@ -788,7 +791,7 @@ user-written code is clear. Consider the following example:
788791
```dart
789792
int get x => 1;
790793
791-
@generateX
794+
@GenerateX()
792795
class Bar {
793796
// Generated: int get x => 2;
794797
@@ -912,19 +915,19 @@ Both of these mechanisms allow for normal macro ordering to be circumvented.
912915
Consider the following example, where all macros run in the Declaration phase:
913916

914917
```dart
915-
@macroA
916-
@macroB
918+
@MacroA()
919+
@MacroB()
917920
class X {
918-
@macroC // Added by `@macroA`, runs after both `@macroB` and `@macroA`
921+
@MacroC() // Added by `@MacroA()`, runs after both `@MacroB()` and `@MacroA()`
919922
int? a;
920923
921-
// Generated by `@macroC`, not visible to `@macroB`.
924+
// Generated by `@MacroC()`, not visible to `@MacroB()`.
922925
int? b;
923926
}
924927
```
925928

926-
Normally, macros always run "inside-out". But in this case `@macroC` runs after
927-
both `@macroB` and `@macroA` which were applied to the class.
929+
Normally, macros always run "inside-out". But in this case `@MacroC()` runs after
930+
both `@MacroB()` and `@MacroA()` which were applied to the class.
928931

929932
We still allow this because it doesn't cause any ambiguity in ordering, even
930933
though it violates the normal rules. We could instead only allow adding macros
@@ -998,23 +1001,24 @@ their libraries. At this point, you have a set of mutually interdependent
9981001
libraries. They may contain references to declarations that don't exist because
9991002
macros have yet to produce them.
10001003

1001-
Collect all the metadata annotations whose names can be resolved and that
1002-
resolve to macro classes. Report an error if any application refers to a macro
1003-
declared in this cycle.
1004+
Collect all the metadata annotations which are constructor invocations of
1005+
macro classes. Report an error if any application refers to a macro declared in
1006+
this cycle, or if any annotation is a reference to a const instance of a macro
1007+
class (they must be explicit constructor invocations).
10041008

1005-
**TODO**: The above resolution rules may change based on
1009+
**NOTE**: We may in the future allow constant references to macros in
1010+
annotations, or something similar to that, see discussion in
10061011
https://github.com/dart-lang/language/issues/1890.
10071012

10081013
#### 3. Apply macros
10091014

1010-
In a sandbox environment or isolate, create an instance of the corresponding
1011-
macro class for each macro application. Pass in any macro application arguments
1012-
to the macro's constructor. If a parameter's type is `Code` or a subclass,
1013-
convert the argument expression to a `Code` object. Any bare identifiers in the
1014-
argument expression are converted to `Identifier` (see
1015-
[Identifier Scope](#Identifier-Scope) for scoping information).
1015+
In a sandbox environment, likely a separate isolate or process, create an
1016+
instance of the corresponding macro class for each macro application. See
1017+
[Executing macros](#Executing-macros) for more explanation of how macros are
1018+
constructed and how their arguments are handled.
10161019

1017-
Run all of the macros in phase order:
1020+
Run all of the macros in phase order (see also
1021+
[Application order](#Application-order) for ordering within each phase):
10181022

10191023
1. Invoke the corresponding visit method for all macros that implement phase 1
10201024
APIs.
@@ -1095,14 +1099,14 @@ are ready to be loaded and executed when applied in libraries in later cycles.
10951099
## Executing macros
10961100

10971101
To apply a macro, a Dart compiler constructs an instance of the applied macro's
1098-
class and then invokes methods that implement macro API interfaces. The macro is
1099-
a full-featured Dart program with complete access to the entire Dart language.
1100-
Macros are Turing-complete.
1102+
class and then invokes methods that implement macro API interfaces. Then it
1103+
disposes of the macro instance. Typically this is all done in a separate isolate
1104+
or process from the compiler itself.
11011105

1102-
### Macro arguments
1106+
Macros are full-featured Dart programs with complete access to the entire Dart
1107+
language (but limited access to core libraries). Macros are Turing-complete.
11031108

1104-
**TODO**: How are metadata annotations that refer to constant objects handled
1105-
(#1890)?
1109+
### Macro arguments
11061110

11071111
Each argument in the metadata annotation for the macro application is converted
11081112
to a form that the corresponding constructor on the macro class expects, which

0 commit comments

Comments
 (0)