Skip to content

Commit

Permalink
Parser support for generic annotations.
Browse files Browse the repository at this point in the history
This CL updates the parser so that it allows annotations of the form:

    `@` <constructorDesignation> <argumentPart>

Where <argumentPart> can contain type arguments.  Previously this was
prohibited at parse time.

Generic annotations are still prohibited in the current language
version, but the error is now generated by the parser listener
(BodyBuilder in the case of CFE, AstBuilder in the case of analyzer);
this should open the door for future CLs to add support for generic
annotations when the `generic-metadata` experimental flag is supplied.

Bug: #44838
Change-Id: I90604f38bcb378fc798c5737e486fb26589d4d1e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/182668
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Jens Johansen <jensj@google.com>
  • Loading branch information
stereotype441 authored and commit-bot@chromium.org committed Feb 5, 2021
1 parent 3bf29dc commit 93cd0cd
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 9 deletions.
11 changes: 11 additions & 0 deletions pkg/_fe_analyzer_shared/lib/src/messages/codes_generated.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6430,6 +6430,17 @@ const MessageCode messageMetadataTypeArguments = const MessageCode(
index: 91,
message: r"""An annotation (metadata) can't use type arguments.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Code<Null> codeMetadataTypeArgumentsUninstantiated =
messageMetadataTypeArgumentsUninstantiated;

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const MessageCode messageMetadataTypeArgumentsUninstantiated = const MessageCode(
"MetadataTypeArgumentsUninstantiated",
index: 114,
message:
r"""An annotation (metadata) with type arguments must be followed by an argument list.""");

// DO NOT EDIT. THIS FILE IS GENERATED. SEE TOP OF FILE.
const Template<Message Function(String name)> templateMethodNotFound =
const Template<Message Function(String name)>(
Expand Down
8 changes: 5 additions & 3 deletions pkg/_fe_analyzer_shared/lib/src/parser/parser_impl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1055,16 +1055,18 @@ class Parser {
token = ensureIdentifier(atToken, IdentifierContext.metadataReference);
token =
parseQualifiedRestOpt(token, IdentifierContext.metadataContinuation);
if (optional("<", token.next!)) {
reportRecoverableError(token.next!, codes.messageMetadataTypeArguments);
}
bool hasTypeArguments = optional("<", token.next!);
token = computeTypeParamOrArg(token).parseArguments(token, this);
Token? period = null;
if (optional('.', token.next!)) {
period = token.next!;
token = ensureIdentifier(
period, IdentifierContext.metadataContinuationAfterTypeArguments);
}
if (hasTypeArguments && !optional("(", token.next!)) {
reportRecoverableError(
token, codes.messageMetadataTypeArgumentsUninstantiated);
}
token = parseArgumentsOpt(token);
listener.endMetadata(atToken, period, token.next!);
return token;
Expand Down
1 change: 1 addition & 0 deletions pkg/analyzer/lib/error/error.dart
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ const List<ErrorCode> errorCodeValues = [
ParserErrorCode.ABSTRACT_TYPEDEF,
ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT,
ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS,
ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED,
ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
ParserErrorCode.BINARY_OPERATOR_WRITTEN_OUT,
ParserErrorCode.BREAK_OUTSIDE_OF_LOOP,
Expand Down
3 changes: 3 additions & 0 deletions pkg/analyzer/lib/src/dart/error/syntactic_errors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ class ParserErrorCode extends ErrorCode {
static const ParserErrorCode ANNOTATION_WITH_TYPE_ARGUMENTS =
_ANNOTATION_WITH_TYPE_ARGUMENTS;

static const ParserErrorCode ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED =
_ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED;

/**
* 16.32 Identifier Reference: It is a compile-time error if any of the
* identifiers async, await, or yield is used as an identifier in a function
Expand Down
5 changes: 5 additions & 0 deletions pkg/analyzer/lib/src/dart/error/syntactic_errors.g.dart
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ final fastaAnalyzerErrorCodes = <ErrorCode?>[
_ANNOTATION_ON_TYPE_ARGUMENT,
_BINARY_OPERATOR_WRITTEN_OUT,
_EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD,
_ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED,
];

const ParserErrorCode _ABSTRACT_CLASS_MEMBER = ParserErrorCode(
Expand Down Expand Up @@ -150,6 +151,10 @@ const ParserErrorCode _ANNOTATION_WITH_TYPE_ARGUMENTS = ParserErrorCode(
'ANNOTATION_WITH_TYPE_ARGUMENTS',
r"An annotation (metadata) can't use type arguments.");

const ParserErrorCode _ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED =
ParserErrorCode('ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED',
r"An annotation (metadata) with type arguments must be followed by an argument list.");

const ParserErrorCode _BINARY_OPERATOR_WRITTEN_OUT = ParserErrorCode(
'BINARY_OPERATOR_WRITTEN_OUT',
r"Binary operator '#string' is written as '#string2' instead of the written out word.",
Expand Down
8 changes: 7 additions & 1 deletion pkg/analyzer/lib/src/fasta/ast_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import 'package:_fe_analyzer_shared/src/messages/codes.dart'
messageInvalidInitializer,
messageInvalidSuperInInitializer,
messageInvalidThisInInitializer,
messageMetadataTypeArguments,
messageMissingAssignableSelector,
messageNativeClauseShouldBeAnnotation,
messageOperatorWithTypeParameters,
Expand Down Expand Up @@ -1831,7 +1832,12 @@ class AstBuilder extends StackListener {
var invocation = pop() as MethodInvocation?;
var constructorName =
periodBeforeName != null ? pop() as SimpleIdentifier : null;
pop(); // Type arguments, not allowed.
var typeArguments = pop() as TypeArgumentList?;
if (typeArguments != null &&
!_featureSet.isEnabled(Feature.generic_metadata)) {
handleRecoverableError(messageMetadataTypeArguments,
typeArguments.beginToken, typeArguments.beginToken);
}
var name = pop() as Identifier;
push(ast.annotation(
atSign: atSign,
Expand Down
19 changes: 14 additions & 5 deletions pkg/front_end/lib/src/fasta/kernel/body_builder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,8 @@ class BodyBuilder extends ScopeListener<JumpTarget>
if (arguments != null) {
push(arguments);
_buildConstructorReferenceInvocation(
beginToken.next, beginToken.offset, Constness.explicitConst);
beginToken.next, beginToken.offset, Constness.explicitConst,
inMetadata: true);
push(popForValue());
} else {
pop(); // Name last identifier
Expand Down Expand Up @@ -4360,11 +4361,13 @@ class BodyBuilder extends ScopeListener<JumpTarget>
void endNewExpression(Token token) {
debugEvent("NewExpression");
_buildConstructorReferenceInvocation(
token.next, token.offset, Constness.explicitNew);
token.next, token.offset, Constness.explicitNew,
inMetadata: false);
}

void _buildConstructorReferenceInvocation(
Token nameToken, int offset, Constness constness) {
Token nameToken, int offset, Constness constness,
{bool inMetadata}) {
assert(checkState(nameToken, [
/*arguments*/ ValueKinds.Arguments,
/*constructor name identifier*/ ValueKinds.IdentifierOrNull,
Expand All @@ -4381,6 +4384,10 @@ class BodyBuilder extends ScopeListener<JumpTarget>
Token nameLastToken = nameLastIdentifier?.token ?? nameToken;
String name = pop();
List<UnresolvedType> typeArguments = pop();
if (inMetadata && typeArguments != null) {
handleRecoverableError(fasta.messageMetadataTypeArguments,
nameLastToken.next, nameLastToken.next);
}

Object type = pop();

Expand All @@ -4406,7 +4413,8 @@ class BodyBuilder extends ScopeListener<JumpTarget>
void endImplicitCreationExpression(Token token) {
debugEvent("ImplicitCreationExpression");
_buildConstructorReferenceInvocation(
token.next, token.offset, Constness.implicit);
token.next, token.offset, Constness.implicit,
inMetadata: false);
}

@override
Expand Down Expand Up @@ -4660,7 +4668,8 @@ class BodyBuilder extends ScopeListener<JumpTarget>
void endConstExpression(Token token) {
debugEvent("endConstExpression");
_buildConstructorReferenceInvocation(
token.next, token.offset, Constness.explicitConst);
token.next, token.offset, Constness.explicitConst,
inMetadata: false);
}

@override
Expand Down
7 changes: 7 additions & 0 deletions pkg/front_end/messages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,13 @@ MetadataTypeArguments:
template: "An annotation (metadata) can't use type arguments."
analyzerCode: ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS

MetadataTypeArgumentsUninstantiated:
index: 114
template: "An annotation (metadata) with type arguments must be followed by an argument list."
analyzerCode: ParserErrorCode.ANNOTATION_WITH_TYPE_ARGUMENTS_UNINSTANTIATED
script:
- "@deprecated<int> class C {}"

ConstructorNotFound:
template: "Couldn't find constructor '#name'."
analyzerCode: CONSTRUCTOR_NOT_FOUND
Expand Down
1 change: 1 addition & 0 deletions pkg/front_end/test/spell_checking_list_code.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1268,6 +1268,7 @@ unification
unifier
unify
uninstantiable
uninstantiated
unions
uniqueness
unittest
Expand Down

0 comments on commit 93cd0cd

Please sign in to comment.