Index: pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
diff --git a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
index 2ea91f4f14331f8501b5d7b90f92afac05c12c8f..e3c0d1638c9ddc8a0e8f153a29bc86a4c94eaea1 100644 |
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
@@ -338,50 +338,66 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
return new JumpTarget(kind, functionNestingLevel, member, charOffset); |
} |
+ @override |
+ void beginMetadata(Token token) { |
+ debugEvent("beginMetadata"); |
+ super.push(constantExpressionRequired); |
+ constantExpressionRequired = true; |
+ } |
+ |
@override |
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
debugEvent("Metadata"); |
- pop(); // Arguments. |
- popIfNotNull(periodBeforeName); // Postfix. |
- pop(); // Type arguments. |
- pop(); // Expression or type name (depends on arguments). |
- // TODO(ahe): Implement metadata on local declarations. |
+ var arguments = pop(); |
+ if (arguments != null) { |
+ endConstructorReference(beginToken, periodBeforeName, endToken); |
+ push(arguments); |
+ endNewExpression(beginToken); |
+ push(popForValue()); |
+ } else { |
+ var postfix = popIfNotNull(periodBeforeName); |
+ if (postfix != null) { |
+ addCompileTimeError(offsetForToken(beginToken), "Not implemented."); |
+ } |
+ pop(); // Type arguments. |
+ var e = popForValue(); // Expression. |
+ constantExpressionRequired = pop(); |
+ push(e); |
+ } |
} |
@override |
void endMetadataStar(int count, bool forParameter) { |
debugEvent("MetadataStar"); |
- push(NullValue.Metadata); |
+ push(popList(count) ?? NullValue.Metadata); |
} |
@override |
void endTopLevelFields(int count, Token beginToken, Token endToken) { |
debugEvent("TopLevelFields"); |
doFields(count); |
- // There's no metadata here because of a slight asymmetry between |
- // [parseTopLevelMember] and [parseMember]. This asymmetry leads to |
- // DietListener discarding top-level member metadata. |
} |
@override |
void endFields(int count, Token beginToken, Token endToken) { |
debugEvent("Fields"); |
doFields(count); |
- pop(); // Metadata. |
} |
void doFields(int count) { |
+ List<FieldBuilder> fields = <FieldBuilder>[]; |
for (int i = 0; i < count; i++) { |
Expression initializer = pop(); |
Identifier identifier = pop(); |
+ String name = identifier.name; |
+ FieldBuilder field; |
+ if (classBuilder != null) { |
+ field = classBuilder[name]; |
+ } else { |
+ field = library[name]; |
+ } |
+ fields.add(field); |
if (initializer != null) { |
- String name = identifier.name; |
- FieldBuilder field; |
- if (classBuilder != null) { |
- field = classBuilder[name]; |
- } else { |
- field = library[name]; |
- } |
if (field.next != null) { |
// TODO(ahe): This can happen, for example, if a final field is |
// combined with a setter. |
@@ -394,6 +410,20 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
} |
pop(); // Type. |
pop(); // Modifiers. |
+ List annotations = pop(); |
+ if (annotations != null) { |
+ Field field = fields.first.target; |
+ // The first (and often only field) will not get a clone. |
+ annotations.forEach(field.addAnnotation); |
+ for (int i = 1; i < fields.length; i++) { |
+ // We have to clone the annotations on the remaining fields. |
+ field = fields[i].target; |
+ cloner ??= new CloneVisitor(); |
+ for (Expression annotation in annotations) { |
+ field.addAnnotation(cloner.clone(annotation)); |
+ } |
+ } |
+ } |
} |
@override |
@@ -516,14 +546,18 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
} |
@override |
- void finishFunction( |
- FormalParameters formals, AsyncMarker asyncModifier, Statement body) { |
+ void finishFunction(List annotations, FormalParameters formals, |
+ AsyncMarker asyncModifier, Statement body) { |
debugEvent("finishFunction"); |
typePromoter.finished(); |
_typeInferrer.inferFunctionBody( |
_computeReturnTypeContext(member), asyncModifier, body); |
KernelFunctionBuilder builder = member; |
builder.body = body; |
+ Member target = builder.target; |
+ for (Expression annotation in annotations ?? const []) { |
+ target.addAnnotation(annotation); |
+ } |
if (formals?.optional != null) { |
Iterator<FormalParameterBuilder> formalBuilders = |
builder.formals.skip(formals.required.length).iterator; |
@@ -2211,7 +2245,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
if (target is Constructor || |
(target is Procedure && target.kind == ProcedureKind.Factory)) { |
push(buildStaticInvocation(target, arguments, |
- isConst: optional("const", token), |
+ isConst: optional("const", token) || optional("@", token), |
charOffset: nameToken.charOffset, |
initialTarget: initialTarget)); |
return; |