Ignore synthetic elements created by the parser

Change-Id: I558827417c938a22075c5b5357294d27cbd6286a
Reviewed-on: https://dart-review.googlesource.com/76121
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Commit-Queue: Peter von der Ahé <ahe@google.com>
This commit is contained in:
Peter von der Ahé
2018-09-25 14:15:23 +00:00
committed by commit-bot@chromium.org
parent fc04f56430
commit 4e32a356e0
10 changed files with 435 additions and 205 deletions
@@ -117,8 +117,10 @@ abstract class ProcedureBuilder<T extends TypeBuilder> extends MemberBuilder {
}
FormalParameterBuilder getFormal(String name) {
for (FormalParameterBuilder formal in formals) {
if (formal.name == name) return formal;
if (formals != null) {
for (FormalParameterBuilder formal in formals) {
if (formal.name == name) return formal;
}
}
return null;
}
@@ -31,8 +31,7 @@ import '../parser.dart'
offsetForToken,
optional;
import '../problems.dart'
show internalProblem, unexpected, unhandled, unsupported;
import '../problems.dart' show unexpected, unhandled, unsupported;
import '../quote.dart'
show
@@ -57,6 +56,7 @@ import '../source/scope_listener.dart'
GrowableList,
JumpTargetKind,
NullValue,
ParserRecovery,
ScopeListener;
import '../type_inference/type_inferrer.dart' show TypeInferrer;
@@ -324,8 +324,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
}
Statement popBlock(int count, Token openBrace, Token closeBrace) {
return forest.block(openBrace,
const GrowableList<Statement>().pop(stack, count), closeBrace);
return forest.block(
openBrace,
const GrowableList<Statement>().pop(stack, count) ?? <Statement>[],
closeBrace);
}
Statement popStatementIfNotNull(Object value) {
@@ -471,7 +473,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
if (count == 0) {
push(NullValue.Metadata);
} else {
push(const GrowableList<Expression>().pop(stack, count));
push(const GrowableList<Expression>().pop(stack, count) ??
NullValue.Metadata /* Ignore parser recovery */);
}
}
@@ -1085,8 +1088,13 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
@override
void endArguments(int count, Token beginToken, Token endToken) {
debugEvent("Arguments");
List<Object> arguments =
const FixedNullableList<Object>().pop(stack, count) ?? <Object>[];
List<Object> arguments = count == 0
? <Object>[]
: const FixedNullableList<Object>().pop(stack, count);
if (arguments == null) {
push(new ParserRecovery(beginToken.charOffset));
return;
}
int firstNamedArgumentIndex = arguments.length;
for (int i = 0; i < arguments.length; i++) {
Object node = arguments[i];
@@ -1728,6 +1736,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
} else {
int count = 1 + interpolationCount * 2;
List<Object> parts = const FixedNullableList<Object>().pop(stack, count);
if (parts == null) {
push(new ParserRecovery(endToken.charOffset));
return;
}
Token first = parts.first;
Token last = parts.last;
Quote quote = analyzeQuote(first.lexeme);
@@ -1974,6 +1986,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
currentLocalVariableType = pop();
currentLocalVariableModifiers = pop();
List<Expression> annotations = pop();
if (variables == null) {
push(new ParserRecovery(endToken.charOffset));
return;
}
if (annotations != null) {
bool isFirstVariable = true;
for (VariableDeclarationJudgment variable in variables) {
@@ -2185,7 +2201,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
void handleLiteralMap(
int count, Token leftBrace, Token constKeyword, Token rightBrace) {
debugEvent("LiteralMap");
List<MapEntry> entries = const GrowableList<MapEntry>().pop(stack, count);
List<MapEntry> entries =
const GrowableList<MapEntry>().pop(stack, count) ?? <MapEntry>[];
List<UnresolvedType<KernelTypeBuilder>> typeArguments = pop();
DartType keyType;
DartType valueType;
@@ -2245,6 +2262,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
} else {
List<Identifier> parts =
const FixedNullableList<Identifier>().pop(stack, identifierCount);
if (parts == null) {
push(new ParserRecovery(hashToken.charOffset));
return;
}
value = symbolPartToString(parts.first);
for (int i = 1; i < parts.length; i++) {
value += ".${symbolPartToString(parts[i])}";
@@ -2460,6 +2481,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
modifiers |= finalMask;
}
List<Expression> annotations = pop();
if (nameToken.isSynthetic) {
push(new ParserRecovery(nameToken.charOffset));
return;
}
KernelFormalParameterBuilder parameter;
if (!inCatchClause &&
functionNestingLevel == 0 &&
@@ -2467,11 +2492,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
ProcedureBuilder<TypeBuilder> member = this.member;
parameter = member.getFormal(name.name);
if (parameter == null) {
internalProblem(
fasta.templateInternalProblemNotFoundIn
.withArguments(name.name, "formals"),
offsetForToken(nameToken),
uri);
push(new ParserRecovery(nameToken.charOffset));
return;
}
} else {
parameter = new KernelFormalParameterBuilder(null, modifiers,
@@ -2517,10 +2539,14 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
List<KernelFormalParameterBuilder> parameters =
const FixedNullableList<KernelFormalParameterBuilder>()
.pop(stack, count);
for (KernelFormalParameterBuilder parameter in parameters) {
parameter.kind = kind;
if (parameters == null) {
push(new ParserRecovery(offsetForToken(beginToken)));
} else {
for (KernelFormalParameterBuilder parameter in parameters) {
parameter.kind = kind;
}
push(parameters);
}
push(parameters);
}
@override
@@ -2595,6 +2621,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
if (optionals != null && parameters != null) {
parameters.setRange(count, count + optionalsCount, optionals);
}
assert(parameters?.isNotEmpty ?? true);
FormalParameters formals = new FormalParameters(parameters,
offsetForToken(beginToken), lengthOfSpan(beginToken, endToken), uri);
constantContext = pop();
@@ -3238,7 +3265,8 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
void endTypeArguments(int count, Token beginToken, Token endToken) {
debugEvent("TypeArguments");
push(const FixedNullableList<UnresolvedType<KernelTypeBuilder>>()
.pop(stack, count));
.pop(stack, count) ??
NullValue.TypeArguments);
}
@override
@@ -3564,8 +3592,10 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
enterLocalScope(null, scope.createNestedLabelScope());
LabelTarget target =
new LabelTarget(member, functionNestingLevel, token.charOffset);
for (Label label in labels) {
scope.declareLabel(label.name, target);
if (labels != null) {
for (Label label in labels) {
scope.declareLabel(label.name, target);
}
}
push(target);
}
@@ -3690,7 +3720,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
int count = labelCount + expressionCount;
List<Object> labelsAndExpressions =
const FixedNullableList<Object>().pop(stack, count);
List<Label> labels = new List<Label>(labelCount);
List<Label> labels = labelCount == 0 ? null : new List<Label>(labelCount);
List<Expression> expressions =
new List<Expression>.filled(expressionCount, null, growable: true);
int labelIndex = 0;
@@ -3705,23 +3735,26 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
}
}
assert(scope == switchScope);
for (Label label in labels) {
String labelName = label.name;
if (scope.hasLocalLabel(labelName)) {
// TODO(ahe): Should validate this is a goto target.
if (!scope.claimLabel(labelName)) {
addProblem(
fasta.templateDuplicateLabelInSwitchStatement
.withArguments(labelName),
label.charOffset,
labelName.length);
if (labels != null) {
for (Label label in labels) {
String labelName = label.name;
if (scope.hasLocalLabel(labelName)) {
// TODO(ahe): Should validate this is a goto target.
if (!scope.claimLabel(labelName)) {
addProblem(
fasta.templateDuplicateLabelInSwitchStatement
.withArguments(labelName),
label.charOffset,
labelName.length);
}
} else {
scope.declareLabel(
labelName, createGotoTarget(firstToken.charOffset));
}
} else {
scope.declareLabel(labelName, createGotoTarget(firstToken.charOffset));
}
}
push(expressions);
push(labels);
push(labels ?? NullValue.Labels);
enterLocalScope("switch case");
}
@@ -3749,7 +3782,7 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
push(new SwitchCaseJudgment(expressions, expressionOffsets, block,
isDefault: defaultKeyword != null)
..fileOffset = firstToken.charOffset);
push(labels);
push(labels ?? NullValue.Labels);
}
@override
@@ -3778,10 +3811,12 @@ abstract class BodyBuilder extends ScopeListener<JumpTarget>
for (int i = caseCount - 1; i >= 0; i--) {
List<Label> labels = pop();
SwitchCase current = cases[i] = pop();
for (Label label in labels) {
JumpTarget target = switchScope.lookupLabel(label.name);
if (target != null) {
target.resolveGotos(forest, current);
if (labels != null) {
for (Label label in labels) {
JumpTarget target = switchScope.lookupLabel(label.name);
if (target != null) {
target.resolveGotos(forest, current);
}
}
}
}
@@ -83,6 +83,7 @@ import 'kernel_builder.dart'
ConstructorReferenceBuilder,
Declaration,
DynamicTypeBuilder,
EnumConstantInfo,
FormalParameterBuilder,
InvalidTypeBuilder,
KernelClassBuilder,
@@ -700,22 +701,17 @@ class KernelLibraryBuilder
}
}
@override
void addEnum(
String documentationComment,
List<MetadataBuilder> metadata,
String name,
List<Object> constantNamesAndOffsets,
List<EnumConstantInfo> enumConstantInfos,
int charOffset,
int charEndOffset) {
MetadataCollector metadataCollector = loader.target.metadataCollector;
KernelEnumBuilder builder = new KernelEnumBuilder(
metadataCollector,
metadata,
name,
constantNamesAndOffsets,
this,
charOffset,
charEndOffset);
KernelEnumBuilder builder = new KernelEnumBuilder(metadataCollector,
metadata, name, enumConstantInfos, this, charOffset, charEndOffset);
addBuilder(name, builder, charOffset);
metadataCollector?.setDocumentationComment(
builder.target, documentationComment);
@@ -27,7 +27,8 @@ class KernelMixinApplicationBuilder
KernelMixinApplicationBuilder(
KernelTypeBuilder supertype, List<KernelTypeBuilder> mixins)
: super(supertype, mixins);
: assert(mixins != null),
super(supertype, mixins);
@override
InterfaceType build(LibraryBuilder library) {
@@ -32,8 +32,8 @@ import '../deprecated_problems.dart'
import '../fasta_codes.dart'
show
LocatedMessage,
Code,
LocatedMessage,
Message,
messageExpectedBlockToSkip,
templateInternalProblemNotFound;
@@ -56,7 +56,8 @@ import '../type_inference/type_inference_engine.dart' show TypeInferenceEngine;
import 'source_library_builder.dart' show SourceLibraryBuilder;
import 'stack_listener.dart' show FixedNullableList, NullValue, StackListener;
import 'stack_listener.dart'
show FixedNullableList, NullValue, ParserRecovery, StackListener;
import '../quote.dart' show unescapeString;
@@ -78,6 +79,8 @@ class DietListener extends StackListener {
ClassBuilder currentClass;
bool currentClassIsParserRecovery = false;
/// For top-level declarations, this is the library scope. For class members,
/// this is the instance scope of [currentClass].
Scope memberScope;
@@ -95,12 +98,6 @@ class DietListener extends StackListener {
stringExpectedAfterNative =
library.loader.target.backendTarget.nativeExtensionExpectsString;
void discard(int n) {
for (int i = 0; i < n; i++) {
pop();
}
}
@override
void endMetadataStar(int count) {
debugEvent("MetadataStar");
@@ -235,8 +232,10 @@ class DietListener extends StackListener {
debugEvent("FunctionTypeAlias");
if (equals == null) pop(); // endToken
String name = pop();
Object name = pop();
Token metadata = pop();
checkEmpty(typedefKeyword.charOffset);
if (name is ParserRecovery) return;
Declaration typedefBuilder = lookupBuilder(typedefKeyword, null, name);
parseMetadata(typedefBuilder, metadata, typedefBuilder.target);
@@ -292,9 +291,11 @@ class DietListener extends StackListener {
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
debugEvent("TopLevelMethod");
Token bodyToken = pop();
String name = pop();
Object name = pop();
Token metadata = pop();
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) return;
final StackListener listener =
createFunctionListener(lookupBuilder(beginToken, getOrSet, name));
buildFunctionBody(listener, bodyToken, metadata, MemberKind.TopLevelMethod);
@@ -330,10 +331,16 @@ class DietListener extends StackListener {
@override
void handleQualified(Token period) {
debugEvent("handleQualified");
String suffix = pop();
var prefix = pop();
assert(identical(suffix, period.next.lexeme));
push(new QualifiedName(prefix, period.next));
Object suffix = pop();
Object prefix = pop();
if (prefix is ParserRecovery) {
push(prefix);
} else if (suffix is ParserRecovery) {
push(suffix);
} else {
assert(identical(suffix, period.next.lexeme));
push(new QualifiedName(prefix, period.next));
}
}
@override
@@ -433,9 +440,11 @@ class DietListener extends StackListener {
@override
void endImport(Token importKeyword, Token semicolon) {
debugEvent("Import");
pop(NullValue.Prefix);
Object name = pop(NullValue.Prefix);
Token metadata = pop();
checkEmpty(importKeyword.charOffset);
if (name is ParserRecovery) return;
// Native imports must be skipped because they aren't assigned corresponding
// LibraryDependency nodes.
@@ -507,6 +516,7 @@ class DietListener extends StackListener {
Object name = pop();
Token metadata = pop();
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery || currentClassIsParserRecovery) return;
ProcedureBuilder builder = lookupConstructor(beginToken, name);
if (bodyToken == null || optional("=", bodyToken.endGroup.next)) {
@@ -555,6 +565,7 @@ class DietListener extends StackListener {
Object name = pop();
Token metadata = pop();
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery || currentClassIsParserRecovery) return;
ProcedureBuilder builder;
if (name is QualifiedName ||
(getOrSet == null && name == currentClass.name)) {
@@ -633,8 +644,11 @@ class DietListener extends StackListener {
void buildFields(int count, Token token, bool isTopLevel) {
List<String> names = const FixedNullableList<String>().pop(stack, count);
Declaration declaration = lookupBuilder(token, null, names.first);
Token metadata = pop();
checkEmpty(token.charOffset);
if (names == null || currentClassIsParserRecovery) return;
Declaration declaration = lookupBuilder(token, null, names.first);
// TODO(paulberry): don't re-parse the field if we've already parsed it
// for type inference.
parseFields(
@@ -642,6 +656,7 @@ class DietListener extends StackListener {
token,
metadata,
isTopLevel);
checkEmpty(token.charOffset);
}
@override
@@ -665,11 +680,15 @@ class DietListener extends StackListener {
@override
void beginClassOrMixinBody(Token token) {
debugEvent("beginClassBody");
String name = pop();
debugEvent("beginClassOrMixinBody");
Object name = pop();
Token metadata = pop();
assert(currentClass == null);
assert(memberScope == library.scope);
if (name is ParserRecovery) {
currentClassIsParserRecovery = true;
return;
}
Declaration classBuilder = lookupBuilder(token, null, name);
parseMetadata(classBuilder, metadata, classBuilder.target);
@@ -682,6 +701,7 @@ class DietListener extends StackListener {
void endClassOrMixinBody(int memberCount, Token beginToken, Token endToken) {
debugEvent("ClassOrMixinBody");
currentClass = null;
currentClassIsParserRecovery = false;
memberScope = library.scope;
}
@@ -702,8 +722,10 @@ class DietListener extends StackListener {
debugEvent("Enum");
List<Object> metadataAndValues =
const FixedNullableList<Object>().pop(stack, count * 2);
String name = pop();
Object name = pop();
Token metadata = pop();
checkEmpty(enumKeyword.charOffset);
if (name is ParserRecovery) return;
ClassBuilder enumBuilder = lookupBuilder(enumKeyword, null, name);
parseMetadata(enumBuilder, metadata, enumBuilder.target);
@@ -726,13 +748,20 @@ class DietListener extends StackListener {
Token equals, Token implementsKeyword, Token endToken) {
debugEvent("NamedMixinApplication");
String name = pop();
Object name = pop();
Token metadata = pop();
Declaration classBuilder = lookupBuilder(classKeyword, null, name);
parseMetadata(classBuilder, metadata, classBuilder.target);
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) return;
Declaration classBuilder = library.scopeBuilder[name];
if (classBuilder != null) {
// TODO(ahe): We shouldn't have to check for null here. The problem is
// that we don't create a named mixin application if the mixins or
// supertype are missing. Could we create a class instead? The nested
// declarations wouldn't match up.
parseMetadata(classBuilder, metadata, classBuilder.target);
checkEmpty(beginToken.charOffset);
}
}
AsyncMarker getAsyncMarker(StackListener listener) => listener.pop();
@@ -87,7 +87,8 @@ import '../scanner.dart' show Token;
import 'source_library_builder.dart' show FieldInfo, SourceLibraryBuilder;
import 'stack_listener.dart' show FixedNullableList, NullValue, StackListener;
import 'stack_listener.dart'
show FixedNullableList, NullValue, ParserRecovery, StackListener;
enum MethodBody {
Abstract,
@@ -120,12 +121,18 @@ class OutlineBuilder extends StackListener {
List<String> popIdentifierList(int count) {
if (count == 0) return null;
List<String> list = new List<String>.filled(count, null, growable: true);
List<String> list = new List<String>(count);
bool isParserRecovery = false;
for (int i = count - 1; i >= 0; i--) {
popCharOffset();
list[i] = pop();
Object identifier = pop();
if (identifier is ParserRecovery) {
isParserRecovery = true;
} else {
list[i] = identifier;
}
}
return list;
return isParserRecovery ? null : list;
}
@override
@@ -143,12 +150,16 @@ class OutlineBuilder extends StackListener {
} else {
int charOffset = pop();
Object typeName = pop();
push(new MetadataBuilder.fromConstructor(
library.addConstructorReference(
typeName, typeArguments, postfix, charOffset),
arguments,
library,
beginToken.charOffset));
if (typeName is ParserRecovery) {
push(typeName);
} else {
push(new MetadataBuilder.fromConstructor(
library.addConstructorReference(
typeName, typeArguments, postfix, charOffset),
arguments,
library,
beginToken.charOffset));
}
}
}
@@ -169,15 +180,23 @@ class OutlineBuilder extends StackListener {
@override
void endHide(Token hideKeyword) {
debugEvent("Hide");
List<String> names = pop();
push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
Object names = pop();
if (names is ParserRecovery) {
push(names);
} else {
push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
}
}
@override
void endShow(Token showKeyword) {
debugEvent("Show");
List<String> names = pop();
push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
Object names = pop();
if (names is ParserRecovery) {
push(names);
} else {
push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
}
}
@override
@@ -218,11 +237,13 @@ class OutlineBuilder extends StackListener {
List<Combinator> combinators = pop();
bool isDeferred = pop();
int prefixOffset = pop();
String prefix = pop(NullValue.Prefix);
Object prefix = pop(NullValue.Prefix);
List<Configuration> configurations = pop();
int uriOffset = popCharOffset();
String uri = pop(); // For a conditional import, this is the default URI.
List<MetadataBuilder> metadata = pop();
checkEmpty(importKeyword.charOffset);
if (prefix is ParserRecovery) return;
library.addImport(
metadata,
uri,
@@ -234,7 +255,6 @@ class OutlineBuilder extends StackListener {
prefixOffset,
uriOffset,
importIndex++);
checkEmpty(importKeyword.charOffset);
}
@override
@@ -251,14 +271,23 @@ class OutlineBuilder extends StackListener {
String uri = pop();
if (equalSign != null) popCharOffset();
String condition = popIfNotNull(equalSign) ?? "true";
String dottedName = pop();
push(new Configuration(charOffset, dottedName, condition, uri));
Object dottedName = pop();
if (dottedName is ParserRecovery) {
push(dottedName);
} else {
push(new Configuration(charOffset, dottedName, condition, uri));
}
}
@override
void handleDottedName(int count, Token firstIdentifier) {
debugEvent("DottedName");
push(popIdentifierList(count).join('.'));
List<String> names = popIdentifierList(count);
if (names == null) {
push(new ParserRecovery(firstIdentifier.charOffset));
} else {
push(names.join('.'));
}
}
@override
@@ -300,8 +329,12 @@ class OutlineBuilder extends StackListener {
if (context == IdentifierContext.enumValueDeclaration) {
debugEvent("handleIdentifier");
List<MetadataBuilder> metadata = pop();
push(new EnumConstantInfo(metadata, token.lexeme, token.charOffset,
getDocumentationComment(token)));
if (token.isSynthetic) {
push(new ParserRecovery(token.charOffset));
} else {
push(new EnumConstantInfo(metadata, token.lexeme, token.charOffset,
getDocumentationComment(token)));
}
} else {
super.handleIdentifier(token, context);
push(token.charOffset);
@@ -347,7 +380,12 @@ class OutlineBuilder extends StackListener {
if (hasName) {
// Pop the native clause which in this case is a StringLiteral.
pop(); // Char offset.
nativeMethodName = pop(); // String.
Object name = pop();
if (name is ParserRecovery) {
nativeMethodName = '';
} else {
nativeMethodName = name; // String.
}
} else {
nativeMethodName = '';
}
@@ -369,19 +407,26 @@ class OutlineBuilder extends StackListener {
@override
void handleIdentifierList(int count) {
debugEvent("endIdentifierList");
push(popIdentifierList(count) ?? NullValue.IdentifierList);
push(popIdentifierList(count) ??
(count == 0 ? NullValue.IdentifierList : new ParserRecovery(-1)));
}
@override
void handleQualified(Token period) {
debugEvent("handleQualified");
int suffixOffset = pop();
String suffix = pop();
assert(identical(suffix, period.next.lexeme));
assert(suffixOffset == period.next.charOffset);
Object suffix = pop();
int offset = pop();
var prefix = pop();
push(new QualifiedName(prefix, period.next));
Object prefix = pop();
if (prefix is ParserRecovery) {
push(prefix);
} else if (suffix is ParserRecovery) {
push(suffix);
} else {
assert(identical(suffix, period.next.lexeme));
assert(suffixOffset == period.next.charOffset);
push(new QualifiedName(prefix, period.next));
}
push(offset);
}
@@ -393,7 +438,9 @@ class OutlineBuilder extends StackListener {
Object name = pop();
List<MetadataBuilder> metadata = pop();
library.documentationComment = documentationComment;
library.name = flattenName(name, offsetForToken(libraryKeyword), uri);
if (name is! ParserRecovery) {
library.name = flattenName(name, offsetForToken(libraryKeyword), uri);
}
library.metadata = metadata;
}
@@ -474,7 +521,7 @@ class OutlineBuilder extends StackListener {
debugEvent("handleMixinOn");
push(const FixedNullableList<KernelNamedTypeBuilder>()
.pop(stack, typeCount) ??
NullValue.TypeList);
new ParserRecovery(offsetForToken(onKeyword)));
}
@override
@@ -483,15 +530,20 @@ class OutlineBuilder extends StackListener {
String documentationComment = getDocumentationComment(beginToken);
List<TypeBuilder> interfaces = pop(NullValue.TypeBuilderList);
int supertypeOffset = pop();
TypeBuilder supertype = pop();
TypeBuilder supertype = nullIfParserRecovery(pop());
int modifiers = pop();
List<TypeVariableBuilder> typeVariables = pop();
int charOffset = pop();
String name = pop();
Object name = pop();
if (typeVariables != null && supertype is MixinApplicationBuilder) {
supertype.typeVariables = typeVariables;
}
List<MetadataBuilder> metadata = pop();
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery) {
library.endNestedDeclaration("<syntax-error>");
return;
}
final int startCharOffset =
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
@@ -508,7 +560,10 @@ class OutlineBuilder extends StackListener {
charOffset,
endToken.charOffset,
supertypeOffset);
checkEmpty(beginToken.charOffset);
}
Object nullIfParserRecovery(Object node) {
return node is ParserRecovery ? null : node;
}
@override
@@ -516,14 +571,18 @@ class OutlineBuilder extends StackListener {
debugEvent("endMixinDeclaration");
String documentationComment = getDocumentationComment(mixinToken);
List<TypeBuilder> interfaces = pop(NullValue.TypeBuilderList);
List<KernelTypeBuilder> supertypeConstraints = pop();
List<KernelTypeBuilder> supertypeConstraints = nullIfParserRecovery(pop());
List<TypeVariableBuilder> typeVariables = pop(NullValue.TypeVariables);
int nameOffset = pop();
String name = pop();
Object name = pop();
List<MetadataBuilder> metadata = pop(NullValue.Metadata);
checkEmpty(mixinToken.charOffset);
if (name is ParserRecovery) {
library.endNestedDeclaration("<syntax-error>");
return;
}
int startOffset =
metadata == null ? mixinToken.charOffset : metadata.first.charOffset;
TypeBuilder supertype;
if (supertypeConstraints != null && supertypeConstraints.isNotEmpty) {
if (supertypeConstraints.length == 1) {
@@ -545,7 +604,6 @@ class OutlineBuilder extends StackListener {
nameOffset,
endToken.charOffset,
-1);
checkEmpty(mixinToken.charOffset);
}
ProcedureKind computeProcedureKind(Token token) {
@@ -570,7 +628,7 @@ class OutlineBuilder extends StackListener {
int formalsOffset = pop();
List<TypeVariableBuilder> typeVariables = pop();
int charOffset = pop();
String name = pop();
Object name = pop();
TypeBuilder returnType = pop();
bool isAbstract = kind == MethodBody.Abstract;
if (getOrSet != null && optional("set", getOrSet)) {
@@ -585,13 +643,14 @@ class OutlineBuilder extends StackListener {
modifiers |= abstractMask;
}
List<MetadataBuilder> metadata = pop();
String documentationComment = getDocumentationComment(beginToken);
checkEmpty(beginToken.charOffset);
library
.endNestedDeclaration("#method")
.resolveTypes(typeVariables, library);
if (name is ParserRecovery) return;
final int startCharOffset =
metadata == null ? beginToken.charOffset : metadata.first.charOffset;
String documentationComment = getDocumentationComment(beginToken);
library.addProcedure(
documentationComment,
metadata,
@@ -655,8 +714,9 @@ class OutlineBuilder extends StackListener {
Token varFinalOrConst, Token getOrSet, Token name) {
inConstructor =
name?.lexeme == library.currentDeclaration.name && getOrSet == null;
List<Modifier> modifiers = <Modifier>[];
List<Modifier> modifiers;
if (externalToken != null) {
modifiers ??= <Modifier>[];
modifiers.add(External);
}
if (staticToken != null) {
@@ -664,24 +724,29 @@ class OutlineBuilder extends StackListener {
handleRecoverableError(
messageStaticConstructor, staticToken, staticToken);
} else {
modifiers ??= <Modifier>[];
modifiers.add(Static);
}
}
if (covariantToken != null) {
modifiers ??= <Modifier>[];
modifiers.add(Covariant);
}
if (varFinalOrConst != null) {
String lexeme = varFinalOrConst.lexeme;
if (identical('var', lexeme)) {
modifiers ??= <Modifier>[];
modifiers.add(Var);
} else if (identical('final', lexeme)) {
modifiers ??= <Modifier>[];
modifiers.add(Final);
} else {
modifiers ??= <Modifier>[];
modifiers.add(Const);
}
}
push(varFinalOrConst?.charOffset ?? -1);
push(modifiers);
push(modifiers ?? NullValue.Modifiers);
library.beginNestedDeclaration("#method", hasMembers: false);
}
@@ -698,7 +763,7 @@ class OutlineBuilder extends StackListener {
int formalsOffset = pop();
List<TypeVariableBuilder> typeVariables = pop();
int charOffset = pop();
dynamic nameOrOperator = pop();
Object nameOrOperator = pop();
if (Operator.subtract == nameOrOperator && formals == null) {
nameOrOperator = Operator.unaryMinus;
}
@@ -767,6 +832,11 @@ class OutlineBuilder extends StackListener {
library
.endNestedDeclaration("#method")
.resolveTypes(typeVariables, library);
if (name is ParserRecovery) {
nativeMethodName = null;
inConstructor = false;
return;
}
String constructorName =
kind == ProcedureKind.Getter || kind == ProcedureKind.Setter
? null
@@ -828,10 +898,16 @@ class OutlineBuilder extends StackListener {
@override
void handleNamedMixinApplicationWithClause(Token withKeyword) {
debugEvent("NamedMixinApplicationWithClause");
List<TypeBuilder> mixins = pop();
TypeBuilder supertype = pop();
push(
library.addMixinApplication(supertype, mixins, withKeyword.charOffset));
Object mixins = pop();
Object supertype = pop();
if (mixins is ParserRecovery) {
push(mixins);
} else if (supertype is ParserRecovery) {
push(supertype);
} else {
push(library.addMixinApplication(
supertype, mixins, withKeyword.charOffset));
}
}
@override
@@ -840,15 +916,19 @@ class OutlineBuilder extends StackListener {
debugEvent("endNamedMixinApplication");
String documentationComment = getDocumentationComment(beginToken);
List<TypeBuilder> interfaces = popIfNotNull(implementsKeyword);
TypeBuilder mixinApplication = pop();
Object mixinApplication = pop();
int modifiers = pop();
List<TypeVariableBuilder> typeVariables = pop();
int charOffset = pop();
String name = pop();
Object name = pop();
List<MetadataBuilder> metadata = pop();
checkEmpty(beginToken.charOffset);
if (name is ParserRecovery || mixinApplication is ParserRecovery) {
library.endNestedDeclaration("<syntax-error>");
return;
}
library.addNamedMixinApplication(documentationComment, metadata, name,
typeVariables, modifiers, mixinApplication, interfaces, charOffset);
checkEmpty(beginToken.charOffset);
}
@override
@@ -869,14 +949,18 @@ class OutlineBuilder extends StackListener {
List<TypeBuilder> arguments = pop();
int charOffset = pop();
Object name = pop();
push(library.addNamedType(name, arguments, charOffset));
if (name is ParserRecovery) {
push(name);
} else {
push(library.addNamedType(name, arguments, charOffset));
}
}
@override
void endTypeList(int count) {
debugEvent("TypeList");
push(const FixedNullableList<KernelNamedTypeBuilder>().pop(stack, count) ??
NullValue.TypeList);
new ParserRecovery(-1));
}
@override
@@ -903,12 +987,16 @@ class OutlineBuilder extends StackListener {
Token nameToken, FormalParameterKind kind, MemberKind memberKind) {
debugEvent("FormalParameter");
int charOffset = pop();
String name = pop();
TypeBuilder type = pop();
Object name = pop();
TypeBuilder type = nullIfParserRecovery(pop());
int modifiers = pop();
List<MetadataBuilder> metadata = pop();
push(library.addFormalParameter(
metadata, modifiers, type, name, thisKeyword != null, charOffset));
if (name is ParserRecovery) {
push(name);
} else {
push(library.addFormalParameter(
metadata, modifiers, type, name, thisKeyword != null, charOffset));
}
}
@override
@@ -946,12 +1034,15 @@ class OutlineBuilder extends StackListener {
// case, however, then [beginOptionalFormalParameters] wouldn't always be
// matched by this method.
List<FormalParameterBuilder> parameters =
const FixedNullableList<FormalParameterBuilder>().pop(stack, count) ??
new List<FormalParameterBuilder>(0);
for (FormalParameterBuilder parameter in parameters) {
parameter.kind = kind;
const FixedNullableList<FormalParameterBuilder>().pop(stack, count);
if (parameters == null) {
push(new ParserRecovery(offsetForToken(beginToken)));
} else {
for (FormalParameterBuilder parameter in parameters) {
parameter.kind = kind;
}
push(parameters);
}
push(parameters);
}
@override
@@ -963,7 +1054,7 @@ class OutlineBuilder extends StackListener {
Object last = pop();
if (last is List<FormalParameterBuilder>) {
formals = last;
} else {
} else if (last is! ParserRecovery) {
assert(last != null);
formals = new List<FormalParameterBuilder>(1);
formals[0] = last;
@@ -971,7 +1062,9 @@ class OutlineBuilder extends StackListener {
} else if (count > 1) {
Object last = pop();
count--;
if (last is List<FormalParameterBuilder>) {
if (last is ParserRecovery) {
discard(count);
} else if (last is List<FormalParameterBuilder>) {
formals = const FixedNullableList<FormalParameterBuilder>()
.popPadded(stack, count, last.length);
if (formals != null) {
@@ -979,13 +1072,14 @@ class OutlineBuilder extends StackListener {
}
} else {
formals = const FixedNullableList<FormalParameterBuilder>()
.popPadded(stack, count, last == null ? 0 : 1);
if (formals != null && last != null) {
.popPadded(stack, count, 1);
if (formals != null) {
formals[count] = last;
}
}
}
if (formals != null) {
assert(formals.isNotEmpty);
if (formals.length == 2) {
// The name may be null for generalized function types.
if (formals[0].name != null && formals[0].name == formals[1].name) {
@@ -1046,11 +1140,12 @@ class OutlineBuilder extends StackListener {
List<EnumConstantInfo> enumConstantInfos =
const FixedNullableList<EnumConstantInfo>().pop(stack, count);
int charOffset = pop();
String name = pop();
Object name = pop();
List<MetadataBuilder> metadata = pop();
checkEmpty(enumKeyword.charOffset);
if (name is ParserRecovery) return;
library.addEnum(documentationComment, metadata, name, enumConstantInfos,
charOffset, leftBrace?.endGroup?.charOffset);
checkEmpty(enumKeyword.charOffset);
}
@override
@@ -1098,7 +1193,7 @@ class OutlineBuilder extends StackListener {
debugEvent("endFunctionTypeAlias");
String documentationComment = getDocumentationComment(typedefKeyword);
List<TypeVariableBuilder> typeVariables;
String name;
Object name;
int charOffset;
FunctionTypeBuilder functionType;
if (equals == null) {
@@ -1110,6 +1205,11 @@ class OutlineBuilder extends StackListener {
TypeBuilder returnType = pop();
// Create a nested declaration that is ended below by
// `library.addFunctionType`.
if (name is ParserRecovery) {
pop(); // Metadata.
library.endNestedDeclaration("<syntax-error>");
return;
}
library.beginNestedDeclaration("#function_type", hasMembers: false);
functionType =
library.addFunctionType(returnType, null, formals, charOffset);
@@ -1118,6 +1218,11 @@ class OutlineBuilder extends StackListener {
typeVariables = pop();
charOffset = pop();
name = pop();
if (name is ParserRecovery) {
pop(); // Metadata.
library.endNestedDeclaration("<syntax-error>");
return;
}
if (type is FunctionTypeBuilder) {
// TODO(ahe): We need to start a nested declaration when parsing the
// formals and return type so we can correctly bind
@@ -1131,9 +1236,9 @@ class OutlineBuilder extends StackListener {
}
}
List<MetadataBuilder> metadata = pop();
checkEmpty(typedefKeyword.charOffset);
library.addFunctionTypeAlias(documentationComment, metadata, name,
typeVariables, functionType, charOffset);
checkEmpty(typedefKeyword.charOffset);
}
@override
@@ -1141,15 +1246,16 @@ class OutlineBuilder extends StackListener {
Token varFinalOrConst, int count, Token beginToken, Token endToken) {
debugEvent("endTopLevelFields");
List<FieldInfo> fieldInfos = popFieldInfos(count);
TypeBuilder type = pop();
TypeBuilder type = nullIfParserRecovery(pop());
int modifiers = (staticToken != null ? staticMask : 0) |
(covariantToken != null ? covariantMask : 0) |
Modifier.validateVarFinalOrConst(varFinalOrConst?.lexeme);
List<MetadataBuilder> metadata = pop();
checkEmpty(beginToken.charOffset);
if (fieldInfos == null) return;
String documentationComment = getDocumentationComment(beginToken);
library.addFields(
documentationComment, metadata, modifiers, type, fieldInfos);
checkEmpty(beginToken.charOffset);
}
@override
@@ -1169,6 +1275,7 @@ class OutlineBuilder extends StackListener {
modifiers &= ~constMask;
}
List<MetadataBuilder> metadata = pop();
if (fieldInfos == null) return;
String documentationComment = getDocumentationComment(beginToken);
library.addFields(
documentationComment, metadata, modifiers, type, fieldInfos);
@@ -1177,44 +1284,54 @@ class OutlineBuilder extends StackListener {
List<FieldInfo> popFieldInfos(int count) {
if (count == 0) return null;
List<FieldInfo> fieldInfos = new List<FieldInfo>(count);
bool isParserRecovery = false;
for (int i = count - 1; i != -1; i--) {
Token beforeLast = pop();
Token initializerTokenForInference = pop();
int charOffset = pop();
Object name = pop(NullValue.Identifier);
fieldInfos[i] = new FieldInfo(
name, charOffset, initializerTokenForInference, beforeLast);
if (name is ParserRecovery) {
isParserRecovery = true;
} else {
fieldInfos[i] = new FieldInfo(
name, charOffset, initializerTokenForInference, beforeLast);
}
}
return fieldInfos;
return isParserRecovery ? null : fieldInfos;
}
@override
void beginTypeVariable(Token token) {
debugEvent("beginTypeVariable");
int charOffset = pop();
String name = pop();
Object name = pop();
// TODO(paulberry): type variable metadata should not be ignored. See
// dartbug.com/28981.
/* List<MetadataBuilder> metadata = */ pop();
push(library.addTypeVariable(name, null, charOffset));
if (name is ParserRecovery) {
push(name);
} else {
push(library.addTypeVariable(name, null, charOffset));
}
}
@override
void handleTypeVariablesDefined(Token token, int count) {
debugEvent("TypeVariablesDefined");
assert(count > 0);
push(const FixedNullableList<TypeVariableBuilder>().pop(stack, count));
push(const FixedNullableList<TypeVariableBuilder>().pop(stack, count) ??
NullValue.TypeVariables);
}
@override
void endTypeVariable(Token token, int index, Token extendsOrSuper) {
debugEvent("endTypeVariable");
TypeBuilder bound = pop();
TypeBuilder bound = nullIfParserRecovery(pop());
// Peek to leave type parameters on top of stack.
List typeParameters = peek();
typeParameters[index].bound = bound;
List<TypeVariableBuilder> typeParameters = peek();
if (typeParameters != null) {
typeParameters[index].bound = bound;
}
}
@override
@@ -1222,48 +1339,50 @@ class OutlineBuilder extends StackListener {
debugEvent("endTypeVariables");
// Peek to leave type parameters on top of stack.
List typeParameters = peek();
List<TypeVariableBuilder> typeParameters = peek();
Map<String, TypeVariableBuilder> typeVariablesByName;
for (TypeVariableBuilder builder in typeParameters) {
if (builder.bound != null) {
if (typeVariablesByName == null) {
typeVariablesByName = new Map<String, TypeVariableBuilder>();
for (TypeVariableBuilder builder in typeParameters) {
typeVariablesByName[builder.name] = builder;
if (typeParameters != null) {
for (TypeVariableBuilder builder in typeParameters) {
if (builder.bound != null) {
if (typeVariablesByName == null) {
typeVariablesByName = new Map<String, TypeVariableBuilder>();
for (TypeVariableBuilder builder in typeParameters) {
typeVariablesByName[builder.name] = builder;
}
}
}
// Find cycle: If there's no cycle we can at most step through all
// `typeParameters` (at which point the last builders bound will be
// null).
// If there is a cycle with `builder` 'inside' the steps to get back to
// it will also be bound by `typeParameters.length`.
// If there is a cycle without `builder` 'inside' we will just ignore it
// for now. It will be reported when processing one of the `builder`s
// that is in fact `inside` the cycle. This matches the cyclic class
// hierarchy error.
TypeVariableBuilder bound = builder;
for (int steps = 0;
bound.bound != null && steps < typeParameters.length;
++steps) {
bound = typeVariablesByName[bound.bound.name];
if (bound == null || bound == builder) break;
}
if (bound == builder && bound.bound != null) {
// Write out cycle.
List<String> via = new List<String>();
bound = typeVariablesByName[builder.bound.name];
while (bound != builder) {
via.add(bound.name);
// Find cycle: If there's no cycle we can at most step through all
// `typeParameters` (at which point the last builders bound will be
// null).
// If there is a cycle with `builder` 'inside' the steps to get back to
// it will also be bound by `typeParameters.length`.
// If there is a cycle without `builder` 'inside' we will just ignore it
// for now. It will be reported when processing one of the `builder`s
// that is in fact `inside` the cycle. This matches the cyclic class
// hierarchy error.
TypeVariableBuilder bound = builder;
for (int steps = 0;
bound.bound != null && steps < typeParameters.length;
++steps) {
bound = typeVariablesByName[bound.bound.name];
if (bound == null || bound == builder) break;
}
if (bound == builder && bound.bound != null) {
// Write out cycle.
List<String> via = new List<String>();
bound = typeVariablesByName[builder.bound.name];
while (bound != builder) {
via.add(bound.name);
bound = typeVariablesByName[bound.bound.name];
}
String involvedString = via.join("', '");
addProblem(
templateCycleInTypeVariables.withArguments(
builder.name, involvedString),
builder.charOffset,
builder.name.length);
}
String involvedString = via.join("', '");
addProblem(
templateCycleInTypeVariables.withArguments(
builder.name, involvedString),
builder.charOffset,
builder.name.length);
}
}
}
@@ -1299,8 +1418,12 @@ class OutlineBuilder extends StackListener {
List<TypeBuilder> typeArguments = pop();
int charOffset = pop();
Object name = pop();
push(library.addConstructorReference(
name, typeArguments, suffix, charOffset));
if (name is ParserRecovery) {
push(name);
} else {
push(library.addConstructorReference(
name, typeArguments, suffix, charOffset));
}
}
@override
@@ -1319,7 +1442,7 @@ class OutlineBuilder extends StackListener {
MethodBody kind = pop();
ConstructorReferenceBuilder redirectionTarget;
if (kind == MethodBody.RedirectingFactoryBody) {
redirectionTarget = pop();
redirectionTarget = nullIfParserRecovery(pop());
}
List<FormalParameterBuilder> formals = pop();
int formalsOffset = pop();
@@ -1328,6 +1451,10 @@ class OutlineBuilder extends StackListener {
Object name = pop();
int modifiers = pop();
List<MetadataBuilder> metadata = pop();
if (name is ParserRecovery) {
library.endNestedDeclaration("<syntax-error>");
return;
}
String documentationComment = getDocumentationComment(beginToken);
library.addFactoryMethod(
documentationComment,
@@ -1405,12 +1532,15 @@ class OutlineBuilder extends StackListener {
void handleClassWithClause(Token withKeyword) {
debugEvent("ClassWithClause");
List<TypeBuilder> mixins = pop();
Object mixins = pop();
int extendsOffset = pop();
TypeBuilder supertype = pop();
push(
library.addMixinApplication(supertype, mixins, withKeyword.charOffset));
Object supertype = pop();
if (supertype is ParserRecovery || mixins is ParserRecovery) {
push(new ParserRecovery(withKeyword.charOffset));
} else {
push(library.addMixinApplication(
supertype, mixins, withKeyword.charOffset));
}
push(extendsOffset);
}
@@ -10,7 +10,8 @@ import '../scope.dart' show Scope;
import 'stack_listener.dart' show NullValue, StackListener;
export 'stack_listener.dart' show FixedNullableList, GrowableList, NullValue;
export 'stack_listener.dart'
show FixedNullableList, GrowableList, NullValue, ParserRecovery;
enum JumpTargetKind {
Break,
@@ -116,8 +116,13 @@ class SourceClassBuilder extends KernelClassBuilder {
void buildBuilders(String name, Declaration declaration) {
do {
if (declaration.parent != this) {
unexpected(
"$fileUri", "${declaration.parent.fileUri}", charOffset, fileUri);
if (fileUri != declaration.parent.fileUri) {
unexpected("$fileUri", "${declaration.parent.fileUri}", charOffset,
fileUri);
} else {
unexpected(fullNameForErrors, declaration.parent?.fullNameForErrors,
charOffset, fileUri);
}
} else if (declaration is KernelFieldBuilder) {
// TODO(ahe): It would be nice to have a common interface for the
// build method to avoid duplicating these two cases.
@@ -180,7 +180,8 @@ abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
assert(
(name?.startsWith(currentDeclaration.name) ??
(name == currentDeclaration.name)) ||
currentDeclaration.name == "operator",
currentDeclaration.name == "operator" ||
identical(name, "<syntax-error>"),
"${name} != ${currentDeclaration.name}");
DeclarationBuilder<T> previous = currentDeclaration;
currentDeclaration = currentDeclaration.parent;
@@ -477,6 +478,9 @@ abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
// TODO(ahe): Set the parent correctly here. Could then change the
// implementation of MemberBuilder.isTopLevel to test explicitly for a
// LibraryBuilder.
if (name == null) {
unhandled("null", "name", charOffset, fileUri);
}
if (currentDeclaration == libraryDeclaration) {
if (declaration is MemberBuilder) {
declaration.parent = this;
@@ -54,6 +54,7 @@ enum NullValue {
Identifier,
IdentifierList,
Initializers,
Labels,
Metadata,
Modifiers,
ParameterDefaultValue,
@@ -76,6 +77,12 @@ abstract class StackListener extends Listener {
@override
Uri get uri;
void discard(int n) {
for (int i = 0; i < n; i++) {
pop();
}
}
// TODO(ahe): This doesn't belong here. Only implemented by body_builder.dart
// and ast_builder.dart.
void finishFunction(covariant List<Object> annotations, covariant formals,
@@ -150,7 +157,14 @@ abstract class StackListener extends Listener {
@override
void handleIdentifier(Token token, IdentifierContext context) {
debugEvent("handleIdentifier");
push(token.lexeme);
if (!token.isSynthetic) {
push(token.lexeme);
} else {
// This comes from a synthetic token which is inserted by the parser in
// an attempt to recover. This almost always means that the parser has
// gotten very confused and we need to ignore the results.
push(new ParserRecovery(token.charOffset));
}
}
@override
@@ -410,6 +424,7 @@ class Stack {
final List<Object> array = this.array;
final int length = arrayLength;
final int startIndex = length - count;
bool isParserRecovery = false;
for (int i = 0; i < count; i++) {
int arrayIndex = startIndex + i;
final Object value = array[arrayIndex];
@@ -417,13 +432,18 @@ class Stack {
if (value is NullValue && nullValue == null ||
identical(value, nullValue)) {
list[i] = null;
} else if (value is ParserRecovery) {
isParserRecovery = true;
} else {
if (value is NullValue) {
print(value);
}
list[i] = value;
}
}
arrayLength -= count;
return list;
return isParserRecovery ? null : list;
}
List<Object> get values {
@@ -469,3 +489,10 @@ class GrowableList<T> {
count, new List<T>.filled(count, null, growable: true), nullValue);
}
}
class ParserRecovery {
final int charOffset;
ParserRecovery(this.charOffset);
String toString() => "ParserRecovery(charOffset)";
}