@@ -89,7 +89,7 @@ more of the macro interfaces, then the annotation is treated as an application
8989of the ` myCoolMacro ` macro to the class MyClass.
9090
9191Macro applications can also be passed arguments, either in the form of
92- [ Code] [ ] expressions or certain types of literal values. See
92+ [ Code] [ ] expressions, [ Identifier ] [ ] s, or certain types of literal values. See
9393[ Macro Arguments] ( #Macro-arguments ) for more information on how these arguments
9494are handled when executing macros.
9595
@@ -123,6 +123,37 @@ Most of the time, like here, a macro takes the arguments you pass it and
123123interpolates them back into code that it generates, so passing the arguments as
124124code is what you want.
125125
126+ ### Identifier arguments
127+
128+ If you want to be able to introspect on an identifier passed in to you, you can
129+ do that as well, consider the following:
130+
131+ ``` dart
132+ @GenerateSerializers(MyType)
133+ library my.library;
134+
135+ class MyType {
136+ final String myField;
137+
138+ MyType({required this.myField});
139+ }
140+
141+ /// Generated by introspecting on the fields of [MyType].
142+ class MyTypeSerializer implements Serializer<MyType> {
143+ Map<String, Object?> serialize(MyType instance) => {
144+ 'myField': instance.myField,
145+ };
146+ }
147+
148+ class MyTypeDeserializer implements Deserializer<MyType> {
149+ MyType deserialize(Map<String, Object> json) =>
150+ MyType(myField: json['myField'] as String);
151+ }
152+ ```
153+
154+ Here the macro takes an ` Identifier ` argument, and introspects on it to know
155+ how to generate the desired serialization and deserialization classes.
156+
126157### Value arguments
127158
128159Sometimes, though, the macro wants to receive an actual argument value. For
@@ -466,18 +497,20 @@ This does have two interesting and possibly unexpected consequences:
466497Macros attach new code to the declaration the macro is applied to by calling
467498methods on the builder object given to the macro. For example, a
468499declaration-phase macro applied to a class declaration is given a
469- [ ClassDeclarationBuilder] . That class exposes an [ ` addToClass() ` ] [ addtoclass ]
470- method that adds the given code to the class as a new member.
500+ [ ClassMemberDeclarationBuilder] . That class exposes a
501+ [ ` declareInClass() ` ] [ declareInClass ] method that adds the given code to the
502+ class as a new member.
471503
472- [ addtoclass ] : https://jakemac53.github.io/macro_prototype/doc/api/definition/ClassDeclarationBuilder/addToClass.html
504+ [ ClassMemberDeclarationBuilder ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart#L93
505+ [ declareInClass ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/builders.dart#L95
473506
474507The code itself is an instance of a special [ Code] [ ] class (or one of its
475508subclasses). This is a first-class object that represents a well-formed piece of
476509Dart code. We use this instead of bare strings containing Dart syntax because a
477510code object carries more than just the bare Dart code. In particular, it keeps
478511track of how identifiers in the code are resolved.
479512
480- [ Code ] : https://jakemac53. github.io/macro_prototype/doc/api/definition/Code-class.html
513+ [ Code ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/code.dart#L9
481514
482515Also, when code objects are creating by combining fragments of other code (for
483516example arguments to macros), the resulting code object may keep track of the
@@ -512,21 +545,6 @@ of a given pieces of syntax.
512545** TODO** : We are considering exposing more properties on Code objects to allow
513546introspection (#1933 ).
514547
515- ### Fragments
516-
517- Sometimes when building a piece of Dart code for a macro's output, it's
518- convenient to work with fragments of Dart code that are not themselves valid
519- complete pieces of Dart syntax. For example, imagine a macro that wraps a given
520- expression in ` { return ` and ` ; } ` . Those fragments that are prepended and
521- appended around the expression are not valid standalone productions in the Dart
522- grammar.
523-
524- To represent those, we also have a [ Fragment] [ ] class. Fragments work more like
525- unparsed strings. They can be concatenated and composed to produce a Code object
526- when the result is valid Dart syntax.
527-
528- [ Fragment ] : https://jakemac53.github.io/macro_prototype/doc/api/definition/Fragment-class.html
529-
530548### Identifiers and resolution
531549
532550The classic problem in macro systems since they were first invented in Lisp and
@@ -657,6 +675,8 @@ that top level declaration and insert that into the generated code.
657675
658676** TODO: Define this API. See [ here] ( https://github.com/dart-lang/language/pull/1779#discussion_r683843130 ) .**
659677
678+ [ Identifier ] : https://github.com/dart-lang/sdk/blob/main/pkg/_fe_analyzer_shared/lib/src/macros/api/introspection.dart#L15
679+
660680### Generating macro applications
661681
662682Since macros are regular Dart code and classes, one macro can instantiate and
@@ -788,8 +808,8 @@ In a sandbox environment or isolate, create an instance of the corresponding
788808macro class for each macro application. Pass in any macro application arguments
789809to the macro's constructor. If a parameter's type is ` Code ` or a subclass,
790810convert the argument expression to a ` Code ` object. Any bare identifiers in the
791- argument expression are converted to ` Identifier ` instances whose scope is the
792- library of the macro application .
811+ argument expression are converted to ` Identifier ` (see
812+ [ Identifier Scope ] ( #Identifier-Scope ) for scoping information) .
793813
794814Run all of the macros in phase order:
795815
@@ -885,23 +905,35 @@ Each argument in the metadata annotation for the macro application is converted
885905to a form that the corresponding constructor on the macro class expects, which
886906it specifies through parameter types:
887907
888- * If the parameter type is ` bool ` , ` double ` , ` int ` , ` Null ` , ` num ` , or ` String `
889- (or the nullable forms of any of those), then the argument expression must
890- be a Boolean, number, null, or string literal. Number literals may be
891- negated. String literals may not contain any interpolation, but may be
892- adjacent strings.
908+ * If the parameter type is ` bool ` , ` double ` , ` int ` , ` Null ` , ` num ` , ` String ` ,
909+ ` List ` , ` Set ` , or ` Map ` , (or the nullable forms of any of those), then the
910+ argument expression must be a boolean, number, null, string, list, set, or
911+ map literal.
912+
913+ * Number literals may be negated.
914+ * String literals may not contain any interpolation, but may be adjacent
915+ strings, and may be raw strings.
916+ * List, Set and Map literals may only contain entries matching any of the
917+ supported argument types. If the parameter type specifies a generic type
918+ argument, it must be one of the allowed parameter types or ` Object ` ,
919+ recursively. Note that ` Object ` is allowed in order to exclude null items,
920+ but all the actual entries must be of one of the supported types.
893921
894922 ** TODO** : Do we want to allow more complex expressions? Could we allow
895923 constant expressions whose identifiers can be successfully resolved before
896924 macro expansion (#1929 )?
897925
898- * Else, the argument expression is automatically converted to an object of
899- type [ Code] [ ] representing the unevaluated expression.
926+ * If the parameter type is ` Code ` (or a subtype of ` Code ` ), the argument
927+ expression is automatically converted to a corresponding ` Code ` instance.
928+ These provided code expressions may contain identifiers.
900929
901- Note that this implicit lifting of the argument expression only happens when
902- the macro constructor is invoked through a macro application. If a macro
903- class is directly constructed in Dart (for example, in test code for the
904- macro), then the caller is responsible for creating the Code object.
930+ * If the parameter type is ` Identifier ` then a single identifier must be
931+ passed, and it will be converted to a corresponding ` Identifier ` instance.
932+
933+ Note that this implicit lifting of the argument expression only happens when
934+ the macro constructor is invoked through a macro application. If a macro
935+ class is directly constructed in Dart (for example, in test code for the
936+ macro), then the caller is responsible for creating the Code object.
905937
906938As usual, it is a compile-time error if the type of any argument value (which
907939may be a Code object) is not a subtype of the corresponding parameter type.
@@ -910,6 +942,37 @@ It is a compile-time error if an macro class constructor invoked by a macro
910942application has a parameter whose type is not Code (or any subtype of it) or
911943one of the aforementioned primitive types (or a nullable type of any of those).
912944
945+ #### Identifier Scope
946+
947+ The following rules apply to any ` Identifier ` passed as an argument to a macro
948+ application, whether as a part of a ` Code ` expression or directly as an
949+ ` Identifier ` instance.
950+
951+ The scope of any ` Identifier ` argument is the same as the scope in which the
952+ identifier appears in the source code, which is the same as the argument scope
953+ for a metadata annotation on a declaration. This means:
954+
955+ * Identifiers in macro application arguments may only refer to static and top
956+ level members.
957+ * They cannot refer to local or instance variables, as those can never be in scope
958+ where a macro application appears.
959+ * Identifiers referring to static class members may be unqualified if the
960+ annotation appears on a member of that class.
961+ * For qualified references, only the unqualified name is visible to the macro.
962+ When the identifier is interpolated into an augmentation library, it may be
963+ converted back into a fully qualified reference if needed (although the
964+ prefix may change, or a prefix may be added). This means all of the
965+ following examples are supported, and for each you would only see ` myMember `
966+ as the ` name ` of the identifier:
967+ - ` @MyMacro(some_prefix.myMember) `
968+ - ` @MyMacro(SomeClass.myMember) `
969+ - ` @MyMacro(some_prefix.SomeClass.myMember) `
970+
971+ All identifiers passed to macro constructors must resolve to a real declaration
972+ by the time macro expansion has completed. They may resolve to generated
973+ identifiers, including ones generated by the macro they were passed to,
974+ although that design may be inadvisable.
975+
913976### Runtime environment
914977
915978Since macros are executed at compile time directly inside the compiler, they run
0 commit comments