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 e3c0d1638c9ddc8a0e8f153a29bc86a4c94eaea1..4524983da5e11658cfc1e957aa54cce7b3db4fe4 100644 |
--- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
+++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart |
@@ -78,7 +78,7 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
@override |
final KernelLibraryBuilder library; |
- final MemberBuilder member; |
+ final ModifierBuilder member; |
final KernelClassBuilder classBuilder; |
@@ -349,20 +349,41 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
debugEvent("Metadata"); |
var arguments = pop(); |
+ pushQualifiedReference(beginToken.next, periodBeforeName); |
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."); |
+ String name = pop(); |
+ pop(); // Type arguments (ignored, already reported by parser). |
+ var expression = pop(); |
+ if (expression is Identifier) { |
+ Identifier identifier = expression; |
+ expression = new UnresolvedAccessor( |
+ this, new Name(identifier.name, library.library), identifier.token); |
+ } |
+ if (name?.isNotEmpty ?? false) { |
+ Token period = periodBeforeName ?? beginToken.next; |
+ FastaAccessor accessor = expression; |
+ expression = accessor.buildPropertyAccess( |
+ new IncompletePropertyAccessor( |
+ this, period.next, new Name(name, library.library)), |
+ period.next.offset, |
+ false); |
+ } |
+ |
+ bool savedConstantExpressionRequired = pop(); |
+ if (expression is! StaticAccessor) { |
+ push(wrapInCompileTimeError( |
+ toValue(expression), |
+ "This can't be used as metadata; metadata should be a reference to " |
+ "a compile-time constant variable, or " |
+ "a call to a constant constructor.")); |
+ } else { |
+ push(toValue(expression)); |
} |
- pop(); // Type arguments. |
- var e = popForValue(); // Expression. |
- constantExpressionRequired = pop(); |
- push(e); |
+ constantExpressionRequired = savedConstantExpressionRequired; |
} |
} |
@@ -2023,25 +2044,43 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper { |
void endConstructorReference( |
Token start, Token periodBeforeName, Token endToken) { |
debugEvent("ConstructorReference"); |
- // A constructor reference can contain up to three identifiers: |
- // |
- // a) type <type-arguments>? |
- // b) type <type-arguments>? . name |
- // c) prefix . type <type-arguments>? |
- // d) prefix . type <type-arguments>? . name |
- // |
- // This isn't a legal constructor reference: |
- // |
- // type . name <type-arguments> |
- // |
- // But the parser can't tell this from type c) above. |
- // |
- // This method pops 2 (or 3 if periodBeforeName != null) values from the |
- // stack and pushes 3 values: a type, a list of type arguments, and a name. |
- // |
- // If the constructor reference can be resolved, type is either a |
- // ClassBuilder, or a ThisPropertyAccessor. Otherwise, it's an error that |
- // should be handled later. |
+ pushQualifiedReference(start, periodBeforeName); |
+ } |
+ |
+ /// A qualfied reference is something that matches one of: |
+ /// |
+ /// identifier |
+ /// identifier typeArguments? '.' identifier |
+ /// identifier '.' identifier typeArguments? '.' identifier |
+ /// |
+ /// That is, one to three identifiers separated by periods and optionally one |
+ /// list of type arguments. |
+ /// |
+ /// A qualified reference can be used to represent both a reference to |
+ /// compile-time constant variable (metadata) or a constructor reference |
+ /// (used by metadata, new/const expression, and redirecting factories). |
+ /// |
+ /// Note that the parser will report errors if metadata includes type |
+ /// arguments, but will other preserve them for error recovery. |
+ /// |
+ /// A constructor reference can contain up to three identifiers: |
+ /// |
+ /// a) type typeArguments? |
+ /// b) type typeArguments? '.' name |
+ /// c) prefix '.' type typeArguments? |
+ /// d) prefix '.' type typeArguments? '.' name |
+ /// |
+ /// This isn't a legal constructor reference: |
+ /// |
+ /// type '.' name typeArguments? |
+ /// |
+ /// But the parser can't tell this from type c) above. |
+ /// |
+ /// This method pops 2 (or 3 if `periodBeforeName != null`) values from the |
+ /// stack and pushes 3 values: an accessor (the type in a constructor |
+ /// reference, or an expression in metadata), a list of type arguments, and a |
+ /// name. |
+ void pushQualifiedReference(Token start, Token periodBeforeName) { |
Identifier suffix = popIfNotNull(periodBeforeName); |
Identifier identifier; |
List<DartType> typeArguments = pop(); |