Parse type variables of local functions before return type.

R=danrubel@google.com

Review-Url: https://codereview.chromium.org/2985673002 .
This commit is contained in:
Peter von der Ahé 2017-08-07 13:46:34 +02:00
parent d109fe7f1a
commit 98422979ac
5 changed files with 82 additions and 35 deletions

View file

@ -1533,12 +1533,12 @@ class AstBuilder extends ScopeListener {
pop(); // constructor initializers
pop(); // separator before constructor initializers
FormalParameterList parameters = pop();
TypeParameterList typeParameters = pop();
FunctionExpression functionExpression =
ast.functionExpression(typeParameters, parameters, body);
SimpleIdentifier name = pop();
TypeAnnotation returnType = pop();
pop(); // modifiers
TypeParameterList typeParameters = pop();
FunctionExpression functionExpression =
ast.functionExpression(typeParameters, parameters, body);
push(ast.functionDeclarationStatement(ast.functionDeclaration(
null, null, null, returnType, null, name, functionExpression)));
}

View file

@ -511,11 +511,11 @@ class NodeListener extends ElementListener {
AsyncModifier asyncModifier = popNode();
NodeList initializers = popNode();
NodeList formals = popNode();
NodeList typeVariables = popNode();
// The name can be an identifier or a send in case of named constructors.
Expression name = popNode();
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
NodeList typeVariables = popNode();
pushNode(new FunctionDeclaration(new FunctionExpression(name, typeVariables,
formals, body, type, modifiers, initializers, null, asyncModifier)));
}

View file

@ -2492,11 +2492,6 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
exitLocalScope();
}
FormalParameters formals = pop();
List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop());
FunctionNode function = formals.addToFunction(new FunctionNode(body,
typeParameters: typeParameters, asyncMarker: asyncModifier)
..fileOffset = formals.charOffset
..fileEndOffset = token.charOffset);
exitLocalScope();
var declaration = pop();
var returnType = pop();
@ -2504,6 +2499,11 @@ class BodyBuilder extends ScopeListener<JumpTarget> implements BuilderHelper {
returnType ??= const DynamicType();
pop(); // Modifiers.
exitFunction();
List<TypeParameter> typeParameters = typeVariableBuildersToKernel(pop());
FunctionNode function = formals.addToFunction(new FunctionNode(body,
typeParameters: typeParameters, asyncMarker: asyncModifier)
..fileOffset = formals.charOffset
..fileEndOffset = token.charOffset);
if (declaration is FunctionDeclaration) {
KernelFunctionDeclaration.setHasImplicitReturnType(
declaration, hasImplicitReturnType);

View file

@ -281,7 +281,8 @@ class Listener {
logEvent("NamedFunctionExpression");
}
/// Handle the beginning of a local function declaration.
/// Handle the beginning of a local function declaration. Substructures:
/// - Type variables
void beginLocalFunctionDeclaration(Token token) {}
/// A function declaration.

View file

@ -1176,14 +1176,8 @@ class Parser {
}
if (looksLikeType && token.isIdentifier) {
// If the identifier token has a type substitution comment /*=T*/,
// then the set of tokens type tokens should be replaced with the
// tokens parsed from the comment.
Token afterId = token.next;
begin =
listener.replaceTokenWithGenericCommentTypeAssign(begin, token);
int afterIdKind = afterId.kind;
if (looksLikeVariableDeclarationEnd(afterIdKind)) {
// We are looking at `type identifier` followed by
@ -1197,18 +1191,44 @@ class Parser {
if (looksLikeFunctionBody(closeBraceTokenFor(afterId).next)) {
// We are looking at `type identifier '(' ... ')'` followed
// `( '{' | '=>' | 'async' | 'sync' )`.
return parseLocalFunctionDeclaration(begin);
// Although it looks like there are no type variables here, they
// may get injected from a comment.
Token formals = parseTypeVariablesOpt(afterId);
listener.beginLocalFunctionDeclaration(begin);
listener.handleModifiers(0);
if (voidToken != null) {
listener.handleVoidKeyword(voidToken);
} else {
commitType();
}
listener.beginFunctionName(token);
token = parseIdentifier(
token, IdentifierContext.localFunctionDeclaration);
listener.endFunctionName(begin, token);
return parseLocalFunctionDeclarationFromFormals(formals);
}
} else if (identical(afterIdKind, LT_TOKEN)) {
// We are looking at `type identifier '<'`.
Token afterTypeVariables = closeBraceTokenFor(afterId)?.next;
if (afterTypeVariables != null &&
optional("(", afterTypeVariables)) {
if (looksLikeFunctionBody(
closeBraceTokenFor(afterTypeVariables).next)) {
Token formals = closeBraceTokenFor(afterId)?.next;
if (formals != null && optional("(", formals)) {
if (looksLikeFunctionBody(closeBraceTokenFor(formals).next)) {
// We are looking at "type identifier '<' ... '>' '(' ... ')'"
// followed by '{', '=>', 'async', or 'sync'.
return parseLocalFunctionDeclaration(begin);
parseTypeVariablesOpt(afterId);
listener.beginLocalFunctionDeclaration(begin);
listener.handleModifiers(0);
if (voidToken != null) {
listener.handleVoidKeyword(voidToken);
} else {
commitType();
}
listener.beginFunctionName(token);
token = parseIdentifier(
token, IdentifierContext.localFunctionDeclaration);
listener.endFunctionName(begin, token);
return parseLocalFunctionDeclarationFromFormals(formals);
}
}
}
@ -1219,7 +1239,21 @@ class Parser {
return parseLabeledStatement(token);
} else if (optional('(', token.next)) {
if (looksLikeFunctionBody(closeBraceTokenFor(token.next).next)) {
return parseLocalFunctionDeclaration(token);
// We are looking at `identifier '(' ... ')'` followed by `'{'`,
// `'=>'`, `'async'`, or `'sync'`.
// Although it looks like there are no type variables here, they
// may get injected from a comment.
Token formals = parseTypeVariablesOpt(token.next);
listener.beginLocalFunctionDeclaration(token);
listener.handleModifiers(0);
listener.handleNoType(token);
listener.beginFunctionName(token);
token = parseIdentifier(
token, IdentifierContext.localFunctionDeclaration);
listener.endFunctionName(begin, token);
return parseLocalFunctionDeclarationFromFormals(formals);
}
} else if (optional('<', token.next)) {
Token afterTypeVariables = closeBraceTokenFor(token.next)?.next;
@ -1227,7 +1261,18 @@ class Parser {
optional("(", afterTypeVariables)) {
if (looksLikeFunctionBody(
closeBraceTokenFor(afterTypeVariables).next)) {
return parseLocalFunctionDeclaration(token);
// We are looking at `identifier '<' ... '>' '(' ... ')'`
// followed by `'{'`, `'=>'`, `'async'`, or `'sync'`.
parseTypeVariablesOpt(token.next);
listener.beginLocalFunctionDeclaration(token);
listener.handleModifiers(0);
listener.handleNoType(token);
listener.beginFunctionName(token);
token = parseIdentifier(
token, IdentifierContext.localFunctionDeclaration);
listener.endFunctionName(begin, token);
return parseLocalFunctionDeclarationFromFormals(
afterTypeVariables);
}
}
// Fall through to expression statement.
@ -2335,16 +2380,17 @@ class Parser {
return isBlock ? token.next : token;
}
Token parseLocalFunctionDeclaration(Token token) {
listener.beginLocalFunctionDeclaration(token);
Token beginToken = token;
token = parseModifiers(token, MemberKind.Local);
listener.beginFunctionName(token);
token = parseIdentifier(token, IdentifierContext.localFunctionDeclaration);
token = parseQualifiedRestOpt(
token, IdentifierContext.localFunctionDeclarationContinuation);
listener.endFunctionName(beginToken, token);
token = parseTypeVariablesOpt(token);
/// Parses the rest of a local function declaration starting from formal
/// parameters.
///
/// Precondition: the parser has previously generated these events:
///
/// - Type variables.
/// - beginLocalFunctionDeclaration.
/// - Modifiers.
/// - Return type.
/// - Function name.
Token parseLocalFunctionDeclarationFromFormals(Token token) {
token = parseFormalParametersOpt(token, MemberKind.Local);
token = parseInitializersOpt(token);
AsyncModifier savedAsyncModifier = asyncState;