From d76ffbc1497568dedba37671ffd5a4792a6c1b2a Mon Sep 17 00:00:00 2001 From: Johnni Winther Date: Thu, 31 Oct 2019 11:36:43 +0000 Subject: [PATCH] [cfe] Handle assigned variables in for and for-in Change-Id: I06deda7f017dcd40e5c6987c61261cf3be2be0ff Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/123410 Reviewed-by: Dmitry Stefantsov Commit-Queue: Johnni Winther --- pkg/analyzer/lib/src/fasta/ast_builder.dart | 4 +- .../lib/src/fasta/kernel/body_builder.dart | 115 ++++++++++++--- .../lib/src/fasta/kernel/forest.dart | 1 - .../fasta/kernel/transform_collections.dart | 20 ++- .../src/fasta/parser/forwarding_listener.dart | 8 +- .../lib/src/fasta/parser/listener.dart | 4 +- .../lib/src/fasta/parser/parser.dart | 11 +- .../lib/src/fasta/source/source_loader.dart | 23 ++- .../type_promotion_look_ahead_listener.dart | 4 +- .../error_recovery/empty_await_for.dart | 3 + .../empty_await_for.dart.expect | 56 ++++++++ .../empty_await_for.dart.intertwined.expect | 91 ++++++++++++ .../empty_await_for.dart.parser.expect | 11 ++ .../empty_await_for.dart.scanner.expect | 9 ++ .../error_recovery/empty_for.dart | 3 + .../error_recovery/empty_for.dart.expect | 55 ++++++++ .../empty_for.dart.intertwined.expect | 94 +++++++++++++ .../empty_for.dart.parser.expect | 11 ++ .../empty_for.dart.scanner.expect | 9 ++ .../parser_testcases/general/for.dart.expect | 2 +- .../general/for.dart.intertwined.expect | 2 +- .../general/for_in.dart.expect | 2 +- .../general/for_in.dart.intertwined.expect | 2 +- .../general/for_in_no_decl.dart | 4 + .../general/for_in_no_decl.dart.expect | 41 ++++++ .../for_in_no_decl.dart.intertwined.expect | 100 +++++++++++++ .../general/for_in_no_decl.dart.parser.expect | 11 ++ .../for_in_no_decl.dart.scanner.expect | 11 ++ .../parser_testcases/general/for_no_decl.dart | 4 + .../general/for_no_decl.dart.expect | 54 ++++++++ .../for_no_decl.dart.intertwined.expect | 131 ++++++++++++++++++ .../general/for_no_decl.dart.parser.expect | 11 ++ .../general/for_no_decl.dart.scanner.expect | 11 ++ .../fasta/parser/literal_entry_info_test.dart | 4 +- .../assigned_variables_test.dart | 24 +++- pkg/front_end/test/parser_test_listener.dart | 9 +- 36 files changed, 899 insertions(+), 56 deletions(-) create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_for.dart create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_for.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_for.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/error_recovery/empty_for.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/general/for_in_no_decl.dart create mode 100644 pkg/front_end/parser_testcases/general/for_in_no_decl.dart.expect create mode 100644 pkg/front_end/parser_testcases/general/for_in_no_decl.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/general/for_in_no_decl.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/general/for_in_no_decl.dart.scanner.expect create mode 100644 pkg/front_end/parser_testcases/general/for_no_decl.dart create mode 100644 pkg/front_end/parser_testcases/general/for_no_decl.dart.expect create mode 100644 pkg/front_end/parser_testcases/general/for_no_decl.dart.intertwined.expect create mode 100644 pkg/front_end/parser_testcases/general/for_no_decl.dart.parser.expect create mode 100644 pkg/front_end/parser_testcases/general/for_no_decl.dart.scanner.expect diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index ca91cd843d1..1013cefcc31 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -2524,12 +2524,12 @@ class AstBuilder extends StackListener { } @override - void handleForInitializerExpressionStatement(Token token) { + void handleForInitializerExpressionStatement(Token token, bool forIn) { debugEvent("ForInitializerExpressionStatement"); } @override - void handleForInitializerLocalVariableDeclaration(Token token) { + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { debugEvent("ForInitializerLocalVariableDeclaration"); } 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 794fd40715a..0835379a59e 100644 --- a/pkg/front_end/lib/src/fasta/kernel/body_builder.dart +++ b/pkg/front_end/lib/src/fasta/kernel/body_builder.dart @@ -42,6 +42,8 @@ import '../fasta_codes.dart' as fasta; import '../fasta_codes.dart' show LocatedMessage, Message, noLength, Template; +import '../flow_analysis/flow_analysis.dart'; + import '../identifiers.dart' show Identifier, @@ -2465,16 +2467,29 @@ class BodyBuilder extends ScopeListener void handleForInitializerEmptyStatement(Token token) { debugEvent("ForInitializerEmptyStatement"); push(NullValue.Expression); + // This is matched by the call to [deferNode] in [endForStatement] or + // [endForControlFlow]. + typeInferrer?.assignedVariables?.beginNode(); } @override - void handleForInitializerExpressionStatement(Token token) { + void handleForInitializerExpressionStatement(Token token, bool forIn) { debugEvent("ForInitializerExpressionStatement"); + if (!forIn) { + // This is matched by the call to [deferNode] in [endForStatement] or + // [endForControlFlow]. + typeInferrer?.assignedVariables?.beginNode(); + } } @override - void handleForInitializerLocalVariableDeclaration(Token token) { + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { debugEvent("ForInitializerLocalVariableDeclaration"); + if (!forIn) { + // This is matched by the call to [deferNode] in [endForStatement] or + // [endForControlFlow]. + typeInferrer?.assignedVariables?.beginNode(); + } } @override @@ -2496,10 +2511,12 @@ class BodyBuilder extends ScopeListener Token forToken = pop(); List updates = popListForEffect(updateExpressionCount); Statement conditionStatement = popStatement(); // condition - Object variableOrExpression = pop(); - exitLocalScope(); if (constantContext != ConstantContext.none) { + pop(); // Pop variable or expression. + exitLocalScope(); + typeInferrer?.assignedVariables?.discardNode(); + handleRecoverableError( fasta.templateCantUseControlFlowOrSpreadAsConstant .withArguments(forToken), @@ -2509,6 +2526,16 @@ class BodyBuilder extends ScopeListener return; } + // This is matched by the call to [beginNode] in + // [handleForInitializerEmptyStatement], + // [handleForInitializerExpressionStatement], and + // [handleForInitializerLocalVariableDeclaration]. + AssignedVariablesNodeInfo assignedVariablesNodeInfo = + typeInferrer?.assignedVariables?.deferNode(); + + Object variableOrExpression = pop(); + exitLocalScope(); + transformCollections = true; List variables = buildVariableDeclarations(variableOrExpression); @@ -2519,11 +2546,17 @@ class BodyBuilder extends ScopeListener assert(conditionStatement is EmptyStatement); } if (entry is MapEntry) { - push(forest.createForMapEntry( - offsetForToken(forToken), variables, condition, updates, entry)); + ForMapEntry result = forest.createForMapEntry( + offsetForToken(forToken), variables, condition, updates, entry); + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); + push(result); } else { - push(forest.createForElement(offsetForToken(forToken), variables, - condition, updates, toValue(entry))); + ForElement result = forest.createForElement(offsetForToken(forToken), + variables, condition, updates, toValue(entry)); + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); + push(result); } } @@ -2560,6 +2593,13 @@ class BodyBuilder extends ScopeListener List updates = popListForEffect(updateExpressionCount); Statement conditionStatement = popStatement(); + // This is matched by the call to [beginNode] in + // [handleForInitializerEmptyStatement], + // [handleForInitializerExpressionStatement], and + // [handleForInitializerLocalVariableDeclaration]. + AssignedVariablesNodeInfo assignedVariablesNodeInfo = + typeInferrer?.assignedVariables?.deferNode(); + Object variableOrExpression = pop(); List variables = buildVariableDeclarations(variableOrExpression); @@ -2576,8 +2616,10 @@ class BodyBuilder extends ScopeListener } else { assert(conditionStatement is EmptyStatement); } - Statement result = forest.createForStatement(offsetForToken(forKeyword), - variables, condition, conditionStatement, updates, body); + Statement result = forest.createForStatement( + offsetForToken(forKeyword), variables, condition, updates, body); + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); if (breakTarget.hasUsers) { result = forest.createLabeledStatement(result); breakTarget.resolveBreaks(forest, result); @@ -4359,6 +4401,9 @@ class BodyBuilder extends ScopeListener push(awaitToken ?? NullValue.AwaitToken); push(forToken); push(inKeyword); + // This is matched by the call to [deferNode] in [endForIn] or + // [endForInControlFlow]. + typeInferrer?.assignedVariables?.beginNode(); } @override @@ -4368,11 +4413,13 @@ class BodyBuilder extends ScopeListener Token inToken = pop(); Token forToken = pop(); Token awaitToken = pop(NullValue.AwaitToken); - Expression iterable = popForValue(); - Object lvalue = pop(); // lvalue - exitLocalScope(); if (constantContext != ConstantContext.none) { + popForValue(); // Pop iterable + pop(); // Pop lvalue + exitLocalScope(); + typeInferrer?.assignedVariables?.discardNode(); + handleRecoverableError( fasta.templateCantUseControlFlowOrSpreadAsConstant .withArguments(forToken), @@ -4382,23 +4429,45 @@ class BodyBuilder extends ScopeListener return; } + // This is matched by the call to [beginNode] in [handleForInLoopParts]. + AssignedVariablesNodeInfo assignedVariablesNodeInfo = + typeInferrer?.assignedVariables?.deferNode(); + + Expression iterable = popForValue(); + Object lvalue = pop(); // lvalue + exitLocalScope(); + transformCollections = true; VariableDeclaration variable = buildForInVariable(forToken, lvalue); Expression problem = checkForInVariable(lvalue, variable, forToken); Statement prologue = buildForInBody(lvalue, variable, forToken, inToken); if (entry is MapEntry) { - push(forest.createForInMapEntry(offsetForToken(forToken), variable, - iterable, prologue, entry, problem, - isAsync: awaitToken != null)); + ForInMapEntry result = forest.createForInMapEntry( + offsetForToken(forToken), + variable, + iterable, + prologue, + entry, + problem, + isAsync: awaitToken != null); + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); + push(result); } else { - push(forest.createForInElement(offsetForToken(forToken), variable, - iterable, prologue, toValue(entry), problem, - isAsync: awaitToken != null)); + ForInElement result = forest.createForInElement(offsetForToken(forToken), + variable, iterable, prologue, toValue(entry), problem, + isAsync: awaitToken != null); + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); + push(result); } } VariableDeclaration buildForInVariable(Token token, Object lvalue) { - if (lvalue is VariableDeclaration) return lvalue; + if (lvalue is VariableDeclaration) { + typeInferrer?.assignedVariables?.write(lvalue); + return lvalue; + } return forest.createVariableDeclaration( offsetForToken(token), null, functionNestingLevel, isFinal: true); @@ -4476,6 +4545,10 @@ class BodyBuilder extends ScopeListener Token forToken = pop(); Token awaitToken = pop(NullValue.AwaitToken); + // This is matched by the call to [beginNode] in [handleForInLoopParts]. + AssignedVariablesNodeInfo assignedVariablesNodeInfo = + typeInferrer?.assignedVariables?.deferNode(); + Expression expression = popForValue(); Object lvalue = pop(); exitLocalScope(); @@ -4506,6 +4579,8 @@ class BodyBuilder extends ScopeListener isAsync: awaitToken != null) ..fileOffset = awaitToken?.charOffset ?? forToken.charOffset ..bodyOffset = body.fileOffset; // TODO(ahe): Isn't this redundant? + typeInferrer?.assignedVariables + ?.storeInfo(result, assignedVariablesNodeInfo); if (breakTarget.hasUsers) { result = forest.createLabeledStatement(result); breakTarget.resolveBreaks(forest, result); diff --git a/pkg/front_end/lib/src/fasta/kernel/forest.dart b/pkg/front_end/lib/src/fasta/kernel/forest.dart index 273eee9c319..b2018c1f9fd 100644 --- a/pkg/front_end/lib/src/fasta/kernel/forest.dart +++ b/pkg/front_end/lib/src/fasta/kernel/forest.dart @@ -383,7 +383,6 @@ class Forest { int fileOffset, List variables, Expression condition, - Statement conditionStatement, List updaters, Statement body) { assert(fileOffset != null); diff --git a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart index 0e7d4d4daf9..d210b0c28cd 100644 --- a/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart +++ b/pkg/front_end/lib/src/fasta/kernel/transform_collections.dart @@ -66,7 +66,7 @@ import 'collections.dart' import '../problems.dart' show getFileUri, unhandled; -import '../source/source_loader.dart' show SourceLoader; +import '../source/source_loader.dart'; import 'redirecting_factory_body.dart' show RedirectingFactoryBody; @@ -82,6 +82,7 @@ class CollectionTransformer extends Transformer { final Class mapEntryClass; final Field mapEntryKey; final Field mapEntryValue; + final SourceLoaderDataForTesting dataForTesting; static Procedure _findSetFactory(CoreTypes coreTypes) { Procedure factory = coreTypes.index.getMember('dart:core', 'Set', ''); @@ -105,7 +106,8 @@ class CollectionTransformer extends Transformer { mapEntryKey = loader.coreTypes.index.getMember('dart:core', 'MapEntry', 'key'), mapEntryValue = - loader.coreTypes.index.getMember('dart:core', 'MapEntry', 'value'); + loader.coreTypes.index.getMember('dart:core', 'MapEntry', 'value'), + dataForTesting = loader.dataForTesting; TreeNode _translateListOrSet( Expression node, DartType elementType, List elements, @@ -208,6 +210,7 @@ class CollectionTransformer extends Transformer { ..fileOffset = element.fileOffset; transformList(loop.variables, this, loop); transformList(loop.updates, this, loop); + dataForTesting?.registerAlias(element, loop); body.add(loop); } @@ -228,10 +231,12 @@ class CollectionTransformer extends Transformer { if (element.problem != null) { body.add(new ExpressionStatement(element.problem.accept(this))); } - body.add(new ForInStatement( + ForInStatement loop = new ForInStatement( element.variable, element.iterable.accept(this), loopBody, isAsync: element.isAsync) - ..fileOffset = element.fileOffset); + ..fileOffset = element.fileOffset; + dataForTesting?.registerAlias(element, loop); + body.add(loop); } void _translateSpreadElement(SpreadElement element, DartType elementType, @@ -396,6 +401,7 @@ class CollectionTransformer extends Transformer { ForStatement loop = new ForStatement(entry.variables, entry.condition?.accept(this), entry.updates, loopBody) ..fileOffset = entry.fileOffset; + dataForTesting?.registerAlias(entry, loop); transformList(loop.variables, this, loop); transformList(loop.updates, this, loop); body.add(loop); @@ -418,10 +424,12 @@ class CollectionTransformer extends Transformer { if (entry.problem != null) { body.add(new ExpressionStatement(entry.problem.accept(this))); } - body.add(new ForInStatement( + ForInStatement loop = new ForInStatement( entry.variable, entry.iterable.accept(this), loopBody, isAsync: entry.isAsync) - ..fileOffset = entry.fileOffset); + ..fileOffset = entry.fileOffset; + dataForTesting?.registerAlias(entry, loop); + body.add(loop); } void _translateSpreadEntry(SpreadMapEntry entry, DartType keyType, diff --git a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart index e9274ae39bd..81ae7fdc078 100644 --- a/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart +++ b/pkg/front_end/lib/src/fasta/parser/forwarding_listener.dart @@ -1164,13 +1164,13 @@ class ForwardingListener implements Listener { } @override - void handleForInitializerExpressionStatement(Token token) { - listener?.handleForInitializerExpressionStatement(token); + void handleForInitializerExpressionStatement(Token token, bool forIn) { + listener?.handleForInitializerExpressionStatement(token, forIn); } @override - void handleForInitializerLocalVariableDeclaration(Token token) { - listener?.handleForInitializerLocalVariableDeclaration(token); + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { + listener?.handleForInitializerLocalVariableDeclaration(token, forIn); } @override diff --git a/pkg/front_end/lib/src/fasta/parser/listener.dart b/pkg/front_end/lib/src/fasta/parser/listener.dart index e6799916afc..33ef4abbfaf 100644 --- a/pkg/front_end/lib/src/fasta/parser/listener.dart +++ b/pkg/front_end/lib/src/fasta/parser/listener.dart @@ -407,13 +407,13 @@ class Listener implements UnescapeErrorListener { /// Marks that the grammar term `forInitializerStatement` has been parsed and /// it was an expression statement. - void handleForInitializerExpressionStatement(Token token) { + void handleForInitializerExpressionStatement(Token token, bool forIn) { logEvent("ForInitializerExpressionStatement"); } /// Marks that the grammar term `forInitializerStatement` has been parsed and /// it was a `localVariableDeclaration`. - void handleForInitializerLocalVariableDeclaration(Token token) { + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { logEvent("ForInitializerLocalVariableDeclaration"); } diff --git a/pkg/front_end/lib/src/fasta/parser/parser.dart b/pkg/front_end/lib/src/fasta/parser/parser.dart index 7c96ac8e3dd..871a1ef58d8 100644 --- a/pkg/front_end/lib/src/fasta/parser/parser.dart +++ b/pkg/front_end/lib/src/fasta/parser/parser.dart @@ -5736,12 +5736,19 @@ class Parser { Token parseForLoopPartsMid(Token token, Token awaitToken, Token forToken) { if (token != forToken.next) { token = parseVariablesDeclarationRest(token, false); - listener.handleForInitializerLocalVariableDeclaration(token); + listener.handleForInitializerLocalVariableDeclaration( + token, optional('in', token.next)); } else if (optional(';', token.next)) { listener.handleForInitializerEmptyStatement(token.next); } else { token = parseExpression(token); - listener.handleForInitializerExpressionStatement(token); + listener.handleForInitializerExpressionStatement( + token, + optional('in', token.next) || + optional(':', token.next) || + // If this is an empty `await for`, we rewrite it into an + // `await for (_ in _)`. + (awaitToken != null && optional(')', token.next))); } Token next = token.next; if (optional(';', next)) { diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart index 0dccc2bbc75..b2d4d5ae021 100644 --- a/pkg/front_end/lib/src/fasta/source/source_loader.dart +++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart @@ -10,6 +10,7 @@ import 'dart:convert' show utf8; import 'dart:typed_data' show Uint8List; +import 'package:front_end/src/base/common.dart'; import 'package:kernel/ast.dart' show Arguments, @@ -151,8 +152,12 @@ class SourceLoader extends Loader { SetLiteralTransformer setLiteralTransformer; + final SourceLoaderDataForTesting dataForTesting; + SourceLoader(this.fileSystem, this.includeComments, KernelTarget target) - : super(target); + : dataForTesting = + retainDataForTesting ? new SourceLoaderDataForTesting() : null, + super(target); Template get outlineSummaryTemplate => templateSourceOutlineSummary; @@ -1276,3 +1281,19 @@ class AmbiguousTypesRecord { const AmbiguousTypesRecord(this.cls, this.a, this.b); } + +class SourceLoaderDataForTesting { + final Map _aliasMap = {}; + + /// Registers that [original] has been replaced by [alias] in the generated + /// AST. + void registerAlias(TreeNode original, TreeNode alias) { + _aliasMap[alias] = original; + } + + /// Returns the original node for [alias] or [alias] if it was not registered + /// as an alias. + TreeNode toOriginal(TreeNode alias) { + return _aliasMap[alias] ?? alias; + } +} diff --git a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart index 5d2aa873907..a0f9ab3d5fe 100644 --- a/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart +++ b/pkg/front_end/lib/src/fasta/source/type_promotion_look_ahead_listener.dart @@ -600,13 +600,13 @@ class TypePromotionLookAheadListener extends Listener { } @override - void handleForInitializerExpressionStatement(Token token) { + void handleForInitializerExpressionStatement(Token token, bool forIn) { debugEvent("ForInitializerExpressionStatement", token); state.pop(); // Expression. } @override - void handleForInitializerLocalVariableDeclaration(Token token) { + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { debugEvent("ForInitializerLocalVariableDeclaration", token); } diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart new file mode 100644 index 00000000000..19771e975a6 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart @@ -0,0 +1,3 @@ +main() async { + await for () {} +} diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect new file mode 100644 index 00000000000..2199837eda6 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.expect @@ -0,0 +1,56 @@ +Problems reported: + +parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'. + await for () {} + ^ + +parser_test/error_recovery/empty_await_for:2:14: Expected 'in' before this. + await for () {} + ^ + +parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'. + await for () {} + ^ + +parser_test/error_recovery/empty_await_for:2:14: Expected an identifier, but got ')'. + await for () {} + ^ + +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(async, null) + beginBlockFunctionBody({) + beginForStatement(for) + handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + handleIdentifier(, expression) + handleNoTypeArguments()) + handleNoArguments()) + handleSend(, )) + handleForInitializerExpressionStatement(, true) + handleRecoverableError(Message[ExpectedButGot, Expected 'in' before this., null, {string: in}], ), )) + handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + beginForInExpression()) + handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + handleIdentifier(, expression) + handleNoTypeArguments()) + handleNoArguments()) + handleSend(, )) + endForInExpression()) + handleForInLoopParts(await, for, (, in) + beginForInBody({) + beginBlock({, BlockKind(statement)) + endBlock(0, {, }, BlockKind(statement)) + endForInBody(}) + endForIn(}) + endBlockFunctionBody(1, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.intertwined.expect new file mode 100644 index 00000000000..5b353627dd6 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.intertwined.expect @@ -0,0 +1,91 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + parseTopLevelMethod(, null, , Instance of 'NoType', null, main) + listener: beginTopLevelMethod(, null) + listener: handleNoType() + ensureIdentifier(, topLevelFunctionDeclaration) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(async, null) + inPlainSync() + parseFunctionBody(async, false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, await) + parseStatement({) + parseStatementX({) + parseForStatement(await, await) + listener: beginForStatement(for) + parseForLoopPartsStart(await, for) + parseExpressionStatementOrDeclaration((, true) + parseExpressionStatementOrDeclarationAfterModifiers((, (, null, null, null, true) + parseForLoopPartsMid((, await, for) + parseExpression(() + parsePrecedenceExpression((, 1, true) + parseUnaryExpression((, true) + parsePrimary((, expression) + parseSend((, expression) + ensureIdentifier((, expression) + reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>') + listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + rewriter() + listener: handleIdentifier(, expression) + listener: handleNoTypeArguments()) + parseArgumentsOpt() + listener: handleNoArguments()) + listener: handleSend(, )) + listener: handleForInitializerExpressionStatement(, true) + reportRecoverableError(), Message[ExpectedButGot, Expected 'in' before this., null, {string: in}]) + listener: handleRecoverableError(Message[ExpectedButGot, Expected 'in' before this., null, {string: in}], ), )) + parseForInRest(, await, for, )) + parseForInLoopPartsRest(, await, for, )) + reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>') + listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + listener: beginForInExpression()) + parseExpression(in) + parsePrecedenceExpression(in, 1, true) + parseUnaryExpression(in, true) + parsePrimary(in, expression) + parseSend(in, expression) + ensureIdentifier(in, expression) + reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>') + listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + rewriter() + listener: handleIdentifier(, expression) + listener: handleNoTypeArguments()) + parseArgumentsOpt() + listener: handleNoArguments()) + listener: handleSend(, )) + ensureCloseParen(, () + listener: endForInExpression()) + listener: handleForInLoopParts(await, for, (, in) + listener: beginForInBody({) + parseStatement()) + parseStatementX()) + parseBlock(), BlockKind(statement)) + ensureBlock(), null, null) + listener: beginBlock({, BlockKind(statement)) + notEofOrValue(}, }) + listener: endBlock(0, {, }, BlockKind(statement)) + listener: endForInBody(}) + listener: endForIn(}) + notEofOrValue(}, }) + listener: endBlockFunctionBody(1, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.parser.expect new file mode 100644 index 00000000000..981f0c93e75 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.parser.expect @@ -0,0 +1,11 @@ +NOTICE: Stream was rewritten by parser! + +main() async { +await for (in) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] async[KeywordToken] {[BeginToken] +await[KeywordToken] for[KeywordToken] ([BeginToken][SyntheticStringToken]in[SyntheticKeywordToken][SyntheticStringToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.scanner.expect new file mode 100644 index 00000000000..df66d856d03 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_await_for.dart.scanner.expect @@ -0,0 +1,9 @@ +main() async { +await for () {} +} + + +main[StringToken]([BeginToken])[SimpleToken] async[KeywordToken] {[BeginToken] +await[KeywordToken] for[KeywordToken] ([BeginToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart new file mode 100644 index 00000000000..3c33ee5a8b3 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart @@ -0,0 +1,3 @@ +main() { + for () {} +} diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect new file mode 100644 index 00000000000..63dc8380aac --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.expect @@ -0,0 +1,55 @@ +Problems reported: + +parser_test/error_recovery/empty_for:2:8: Expected an identifier, but got ')'. + for () {} + ^ + +parser_test/error_recovery/empty_for:2:8: Expected ';' after this. + for () {} + ^ + +parser_test/error_recovery/empty_for:2:8: Expected an identifier, but got ')'. + for () {} + ^ + +parser_test/error_recovery/empty_for:2:8: Expected ';' after this. + for () {} + ^ + +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(null, null) + beginBlockFunctionBody({) + beginForStatement(for) + handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + handleIdentifier(, expression) + handleNoTypeArguments()) + handleNoArguments()) + handleSend(, )) + handleForInitializerExpressionStatement(, false) + handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), )) + handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + handleIdentifier(, expression) + handleNoTypeArguments()) + handleNoArguments()) + handleSend(, )) + handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), )) + handleExpressionStatement(;) + handleForLoopParts(for, (, ;, 0) + beginForStatementBody({) + beginBlock({, BlockKind(statement)) + endBlock(0, {, }, BlockKind(statement)) + endForStatementBody(}) + endForStatement(}) + endBlockFunctionBody(1, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.intertwined.expect b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.intertwined.expect new file mode 100644 index 00000000000..96c0c6e6803 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.intertwined.expect @@ -0,0 +1,94 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + parseTopLevelMethod(, null, , Instance of 'NoType', null, main) + listener: beginTopLevelMethod(, null) + listener: handleNoType() + ensureIdentifier(, topLevelFunctionDeclaration) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(null, null) + inPlainSync() + parseFunctionBody(), false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, for) + parseStatement({) + parseStatementX({) + parseForStatement({, null) + listener: beginForStatement(for) + parseForLoopPartsStart(null, for) + parseExpressionStatementOrDeclaration((, true) + parseExpressionStatementOrDeclarationAfterModifiers((, (, null, null, null, true) + parseForLoopPartsMid((, null, for) + parseExpression(() + parsePrecedenceExpression((, 1, true) + parseUnaryExpression((, true) + parsePrimary((, expression) + parseSend((, expression) + ensureIdentifier((, expression) + reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>') + listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + rewriter() + listener: handleIdentifier(, expression) + listener: handleNoTypeArguments()) + parseArgumentsOpt() + listener: handleNoArguments()) + listener: handleSend(, )) + listener: handleForInitializerExpressionStatement(, false) + parseForRest(null, , for) + parseForLoopPartsRest(, for, null) + ensureSemicolon() + reportRecoverableError(, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}]) + listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), )) + rewriter() + parseExpressionStatement(;) + parseExpression(;) + parsePrecedenceExpression(;, 1, true) + parseUnaryExpression(;, true) + parsePrimary(;, expression) + parseSend(;, expression) + ensureIdentifier(;, expression) + reportRecoverableErrorWithToken(), Instance of 'Template<(Token) => Message>') + listener: handleRecoverableError(Message[ExpectedIdentifier, Expected an identifier, but got ')'., null, {token: )}], ), )) + rewriter() + listener: handleIdentifier(, expression) + listener: handleNoTypeArguments()) + parseArgumentsOpt() + listener: handleNoArguments()) + listener: handleSend(, )) + ensureSemicolon() + reportRecoverableError(, Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}]) + listener: handleRecoverableError(Message[ExpectedAfterButGot, Expected ';' after this., null, {string: ;}], ), )) + rewriter() + listener: handleExpressionStatement(;) + listener: handleForLoopParts(for, (, ;, 0) + listener: beginForStatementBody({) + parseStatement()) + parseStatementX()) + parseBlock(), BlockKind(statement)) + ensureBlock(), null, null) + listener: beginBlock({, BlockKind(statement)) + notEofOrValue(}, }) + listener: endBlock(0, {, }, BlockKind(statement)) + listener: endForStatementBody(}) + listener: endForStatement(}) + notEofOrValue(}, }) + listener: endBlockFunctionBody(1, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.parser.expect b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.parser.expect new file mode 100644 index 00000000000..792bb5b3a31 --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.parser.expect @@ -0,0 +1,11 @@ +NOTICE: Stream was rewritten by parser! + +main() { +for (;;) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +for[KeywordToken] ([BeginToken][SyntheticStringToken];[SyntheticToken][SyntheticStringToken];[SyntheticToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.scanner.expect b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.scanner.expect new file mode 100644 index 00000000000..d26ca13c8df --- /dev/null +++ b/pkg/front_end/parser_testcases/error_recovery/empty_for.dart.scanner.expect @@ -0,0 +1,9 @@ +main() { +for () {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +for[KeywordToken] ([BeginToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/general/for.dart.expect b/pkg/front_end/parser_testcases/general/for.dart.expect index 041ba507588..33fd303d93b 100644 --- a/pkg/front_end/parser_testcases/general/for.dart.expect +++ b/pkg/front_end/parser_testcases/general/for.dart.expect @@ -24,7 +24,7 @@ beginCompilationUnit(main) endVariableInitializer(=) endInitializedIdentifier(i) endVariablesDeclaration(1, null) - handleForInitializerLocalVariableDeclaration(0) + handleForInitializerLocalVariableDeclaration(0, false) handleIdentifier(i, expression) handleNoTypeArguments(<) handleNoArguments(<) diff --git a/pkg/front_end/parser_testcases/general/for.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/for.dart.intertwined.expect index 01eb31ae3d0..871903bc6a3 100644 --- a/pkg/front_end/parser_testcases/general/for.dart.intertwined.expect +++ b/pkg/front_end/parser_testcases/general/for.dart.intertwined.expect @@ -56,7 +56,7 @@ parseUnit(main) listener: endVariableInitializer(=) listener: endInitializedIdentifier(i) listener: endVariablesDeclaration(1, null) - listener: handleForInitializerLocalVariableDeclaration(0) + listener: handleForInitializerLocalVariableDeclaration(0, false) parseForRest(null, 0, for) parseForLoopPartsRest(0, for, null) ensureSemicolon(0) diff --git a/pkg/front_end/parser_testcases/general/for_in.dart.expect b/pkg/front_end/parser_testcases/general/for_in.dart.expect index cce9127c822..b075cf9b413 100644 --- a/pkg/front_end/parser_testcases/general/for_in.dart.expect +++ b/pkg/front_end/parser_testcases/general/for_in.dart.expect @@ -20,7 +20,7 @@ beginCompilationUnit(main) handleNoVariableInitializer(in) endInitializedIdentifier(i) endVariablesDeclaration(1, null) - handleForInitializerLocalVariableDeclaration(i) + handleForInitializerLocalVariableDeclaration(i, true) beginForInExpression([]) handleNoTypeArguments([]) handleLiteralList(0, [, null, ]) diff --git a/pkg/front_end/parser_testcases/general/for_in.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/for_in.dart.intertwined.expect index e527725ae2f..429e01efa42 100644 --- a/pkg/front_end/parser_testcases/general/for_in.dart.intertwined.expect +++ b/pkg/front_end/parser_testcases/general/for_in.dart.intertwined.expect @@ -47,7 +47,7 @@ parseUnit(main) listener: handleNoVariableInitializer(in) listener: endInitializedIdentifier(i) listener: endVariablesDeclaration(1, null) - listener: handleForInitializerLocalVariableDeclaration(i) + listener: handleForInitializerLocalVariableDeclaration(i, true) parseForInRest(i, null, for, i) parseForInLoopPartsRest(i, null, for, i) listener: beginForInExpression([]) diff --git a/pkg/front_end/parser_testcases/general/for_in_no_decl.dart b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart new file mode 100644 index 00000000000..179c61d5df4 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart @@ -0,0 +1,4 @@ +main() { + var i; + for (i in []) {} +} diff --git a/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.expect b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.expect new file mode 100644 index 00000000000..e8e31103f25 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.expect @@ -0,0 +1,41 @@ +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(null, null) + beginBlockFunctionBody({) + beginMetadataStar(var) + endMetadataStar(0) + handleNoType(var) + beginVariablesDeclaration(i, null, var) + handleIdentifier(i, localVariableDeclaration) + beginInitializedIdentifier(i) + handleNoVariableInitializer(;) + endInitializedIdentifier(i) + endVariablesDeclaration(1, ;) + beginForStatement(for) + handleIdentifier(i, expression) + handleNoTypeArguments(in) + handleNoArguments(in) + handleSend(i, in) + handleForInitializerExpressionStatement(i, true) + beginForInExpression([]) + handleNoTypeArguments([]) + handleLiteralList(0, [, null, ]) + endForInExpression()) + handleForInLoopParts(null, for, (, in) + beginForInBody({) + beginBlock({, BlockKind(statement)) + endBlock(0, {, }, BlockKind(statement)) + endForInBody(}) + endForIn(}) + endBlockFunctionBody(2, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.intertwined.expect new file mode 100644 index 00000000000..04c39fb8d16 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.intertwined.expect @@ -0,0 +1,100 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + parseTopLevelMethod(, null, , Instance of 'NoType', null, main) + listener: beginTopLevelMethod(, null) + listener: handleNoType() + ensureIdentifier(, topLevelFunctionDeclaration) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(null, null) + inPlainSync() + parseFunctionBody(), false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, var) + parseStatement({) + parseStatementX({) + parseExpressionStatementOrDeclarationAfterModifiers(var, {, null, var, null, false) + looksLikeLocalFunction(i) + listener: beginMetadataStar(var) + listener: endMetadataStar(0) + listener: handleNoType(var) + listener: beginVariablesDeclaration(i, null, var) + parseVariablesDeclarationRest(var, true) + parseOptionallyInitializedIdentifier(var) + ensureIdentifier(var, localVariableDeclaration) + listener: handleIdentifier(i, localVariableDeclaration) + listener: beginInitializedIdentifier(i) + parseVariableInitializerOpt(i) + listener: handleNoVariableInitializer(;) + listener: endInitializedIdentifier(i) + ensureSemicolon(i) + listener: endVariablesDeclaration(1, ;) + notEofOrValue(}, for) + parseStatement(;) + parseStatementX(;) + parseForStatement(;, null) + listener: beginForStatement(for) + parseForLoopPartsStart(null, for) + parseExpressionStatementOrDeclaration((, true) + parseExpressionStatementOrDeclarationAfterModifiers((, (, null, null, null, true) + parseForLoopPartsMid((, null, for) + parseExpression(() + parsePrecedenceExpression((, 1, true) + parseUnaryExpression((, true) + parsePrimary((, expression) + parseSendOrFunctionLiteral((, expression) + parseSend((, expression) + ensureIdentifier((, expression) + listener: handleIdentifier(i, expression) + listener: handleNoTypeArguments(in) + parseArgumentsOpt(i) + listener: handleNoArguments(in) + listener: handleSend(i, in) + listener: handleForInitializerExpressionStatement(i, true) + parseForInRest(i, null, for, i) + parseForInLoopPartsRest(i, null, for, i) + listener: beginForInExpression([]) + parseExpression(in) + parsePrecedenceExpression(in, 1, true) + parseUnaryExpression(in, true) + parsePrimary(in, expression) + listener: handleNoTypeArguments([]) + parseLiteralListSuffix(in, null) + rewriteSquareBrackets(in) + link([, ]) + rewriter() + listener: handleLiteralList(0, [, null, ]) + ensureCloseParen(], () + listener: endForInExpression()) + listener: handleForInLoopParts(null, for, (, in) + listener: beginForInBody({) + parseStatement()) + parseStatementX()) + parseBlock(), BlockKind(statement)) + ensureBlock(), null, null) + listener: beginBlock({, BlockKind(statement)) + notEofOrValue(}, }) + listener: endBlock(0, {, }, BlockKind(statement)) + listener: endForInBody(}) + listener: endForIn(}) + notEofOrValue(}, }) + listener: endBlockFunctionBody(2, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.parser.expect b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.parser.expect new file mode 100644 index 00000000000..b64fd376e73 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.parser.expect @@ -0,0 +1,11 @@ +main() { +var i; +for (i in []) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +var[KeywordToken] i[StringToken];[SimpleToken] +for[KeywordToken] ([BeginToken]i[StringToken] in[KeywordToken] [[BeginToken]][SimpleToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.scanner.expect b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.scanner.expect new file mode 100644 index 00000000000..15d1094a9ba --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_in_no_decl.dart.scanner.expect @@ -0,0 +1,11 @@ +main() { +var i; +for (i in []) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +var[KeywordToken] i[StringToken];[SimpleToken] +for[KeywordToken] ([BeginToken]i[StringToken] in[KeywordToken] [][SimpleToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/general/for_no_decl.dart b/pkg/front_end/parser_testcases/general/for_no_decl.dart new file mode 100644 index 00000000000..2f511e9f79d --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_no_decl.dart @@ -0,0 +1,4 @@ +main() { + int i; + for (i = 0; i < 10; i++) {} +} diff --git a/pkg/front_end/parser_testcases/general/for_no_decl.dart.expect b/pkg/front_end/parser_testcases/general/for_no_decl.dart.expect new file mode 100644 index 00000000000..8187b8f034c --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_no_decl.dart.expect @@ -0,0 +1,54 @@ +beginCompilationUnit(main) + beginMetadataStar(main) + endMetadataStar(0) + beginTopLevelMember(main) + beginTopLevelMethod(, null) + handleNoType() + handleIdentifier(main, topLevelFunctionDeclaration) + handleNoTypeVariables(() + beginFormalParameters((, MemberKind.TopLevelMethod) + endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + handleAsyncModifier(null, null) + beginBlockFunctionBody({) + beginMetadataStar(int) + endMetadataStar(0) + handleIdentifier(int, typeReference) + handleNoTypeArguments(i) + handleType(int, null) + beginVariablesDeclaration(i, null, null) + handleIdentifier(i, localVariableDeclaration) + beginInitializedIdentifier(i) + handleNoVariableInitializer(;) + endInitializedIdentifier(i) + endVariablesDeclaration(1, ;) + beginForStatement(for) + handleIdentifier(i, expression) + handleNoTypeArguments(=) + handleNoArguments(=) + handleSend(i, =) + handleLiteralInt(0) + handleAssignmentExpression(=) + handleForInitializerExpressionStatement(0, false) + handleIdentifier(i, expression) + handleNoTypeArguments(<) + handleNoArguments(<) + handleSend(i, <) + beginBinaryExpression(<) + handleLiteralInt(10) + endBinaryExpression(<) + handleExpressionStatement(;) + handleIdentifier(i, expression) + handleNoTypeArguments(++) + handleNoArguments(++) + handleSend(i, ++) + handleUnaryPostfixAssignmentExpression(++) + handleForLoopParts(for, (, ;, 1) + beginForStatementBody({) + beginBlock({, BlockKind(statement)) + endBlock(0, {, }, BlockKind(statement)) + endForStatementBody(}) + endForStatement(}) + endBlockFunctionBody(2, {, }) + endTopLevelMethod(main, null, }) + endTopLevelDeclaration() +endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/general/for_no_decl.dart.intertwined.expect b/pkg/front_end/parser_testcases/general/for_no_decl.dart.intertwined.expect new file mode 100644 index 00000000000..b1cc14f8c4e --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_no_decl.dart.intertwined.expect @@ -0,0 +1,131 @@ +parseUnit(main) + skipErrorTokens(main) + listener: beginCompilationUnit(main) + syntheticPreviousToken(main) + parseTopLevelDeclarationImpl(, Instance of 'DirectiveContext') + parseMetadataStar() + listener: beginMetadataStar(main) + listener: endMetadataStar(0) + parseTopLevelMemberImpl() + listener: beginTopLevelMember(main) + parseTopLevelMethod(, null, , Instance of 'NoType', null, main) + listener: beginTopLevelMethod(, null) + listener: handleNoType() + ensureIdentifier(, topLevelFunctionDeclaration) + listener: handleIdentifier(main, topLevelFunctionDeclaration) + parseMethodTypeVar(main) + listener: handleNoTypeVariables(() + parseGetterOrFormalParameters(main, main, false, MemberKind.TopLevelMethod) + parseFormalParameters(main, MemberKind.TopLevelMethod) + parseFormalParametersRest((, MemberKind.TopLevelMethod) + listener: beginFormalParameters((, MemberKind.TopLevelMethod) + listener: endFormalParameters(0, (, ), MemberKind.TopLevelMethod) + parseAsyncModifierOpt()) + listener: handleAsyncModifier(null, null) + inPlainSync() + parseFunctionBody(), false, false) + listener: beginBlockFunctionBody({) + notEofOrValue(}, int) + parseStatement({) + parseStatementX({) + parseExpressionStatementOrDeclarationAfterModifiers({, {, null, null, null, false) + looksLikeLocalFunction(i) + listener: beginMetadataStar(int) + listener: endMetadataStar(0) + listener: handleIdentifier(int, typeReference) + listener: handleNoTypeArguments(i) + listener: handleType(int, null) + listener: beginVariablesDeclaration(i, null, null) + parseVariablesDeclarationRest(int, true) + parseOptionallyInitializedIdentifier(int) + ensureIdentifier(int, localVariableDeclaration) + listener: handleIdentifier(i, localVariableDeclaration) + listener: beginInitializedIdentifier(i) + parseVariableInitializerOpt(i) + listener: handleNoVariableInitializer(;) + listener: endInitializedIdentifier(i) + ensureSemicolon(i) + listener: endVariablesDeclaration(1, ;) + notEofOrValue(}, for) + parseStatement(;) + parseStatementX(;) + parseForStatement(;, null) + listener: beginForStatement(for) + parseForLoopPartsStart(null, for) + parseExpressionStatementOrDeclaration((, true) + parseExpressionStatementOrDeclarationAfterModifiers((, (, null, null, null, true) + parseForLoopPartsMid((, null, for) + parseExpression(() + parsePrecedenceExpression((, 1, true) + parseUnaryExpression((, true) + parsePrimary((, expression) + parseSendOrFunctionLiteral((, expression) + parseSend((, expression) + ensureIdentifier((, expression) + listener: handleIdentifier(i, expression) + listener: handleNoTypeArguments(=) + parseArgumentsOpt(i) + listener: handleNoArguments(=) + listener: handleSend(i, =) + parsePrecedenceExpression(=, 1, true) + parseUnaryExpression(=, true) + parsePrimary(=, expression) + parseLiteralInt(=) + listener: handleLiteralInt(0) + listener: handleAssignmentExpression(=) + listener: handleForInitializerExpressionStatement(0, false) + parseForRest(null, 0, for) + parseForLoopPartsRest(0, for, null) + ensureSemicolon(0) + parseExpressionStatement(;) + parseExpression(;) + parsePrecedenceExpression(;, 1, true) + parseUnaryExpression(;, true) + parsePrimary(;, expression) + parseSendOrFunctionLiteral(;, expression) + parseSend(;, expression) + ensureIdentifier(;, expression) + listener: handleIdentifier(i, expression) + listener: handleNoTypeArguments(<) + parseArgumentsOpt(i) + listener: handleNoArguments(<) + listener: handleSend(i, <) + listener: beginBinaryExpression(<) + parsePrecedenceExpression(<, 9, true) + parseUnaryExpression(<, true) + parsePrimary(<, expression) + parseLiteralInt(<) + listener: handleLiteralInt(10) + listener: endBinaryExpression(<) + ensureSemicolon(10) + listener: handleExpressionStatement(;) + parseExpression(;) + parsePrecedenceExpression(;, 1, true) + parseUnaryExpression(;, true) + parsePrimary(;, expression) + parseSendOrFunctionLiteral(;, expression) + parseSend(;, expression) + ensureIdentifier(;, expression) + listener: handleIdentifier(i, expression) + listener: handleNoTypeArguments(++) + parseArgumentsOpt(i) + listener: handleNoArguments(++) + listener: handleSend(i, ++) + listener: handleUnaryPostfixAssignmentExpression(++) + listener: handleForLoopParts(for, (, ;, 1) + listener: beginForStatementBody({) + parseStatement()) + parseStatementX()) + parseBlock(), BlockKind(statement)) + ensureBlock(), null, null) + listener: beginBlock({, BlockKind(statement)) + notEofOrValue(}, }) + listener: endBlock(0, {, }, BlockKind(statement)) + listener: endForStatementBody(}) + listener: endForStatement(}) + notEofOrValue(}, }) + listener: endBlockFunctionBody(2, {, }) + listener: endTopLevelMethod(main, null, }) + listener: endTopLevelDeclaration() + reportAllErrorTokens(main) + listener: endCompilationUnit(1, ) diff --git a/pkg/front_end/parser_testcases/general/for_no_decl.dart.parser.expect b/pkg/front_end/parser_testcases/general/for_no_decl.dart.parser.expect new file mode 100644 index 00000000000..f295eb97c47 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_no_decl.dart.parser.expect @@ -0,0 +1,11 @@ +main() { +int i; +for (i = 0; i < 10; i++) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +int[StringToken] i[StringToken];[SimpleToken] +for[KeywordToken] ([BeginToken]i[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken] i[StringToken] <[BeginToken] 10[StringToken];[SimpleToken] i[StringToken]++[SimpleToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/parser_testcases/general/for_no_decl.dart.scanner.expect b/pkg/front_end/parser_testcases/general/for_no_decl.dart.scanner.expect new file mode 100644 index 00000000000..f295eb97c47 --- /dev/null +++ b/pkg/front_end/parser_testcases/general/for_no_decl.dart.scanner.expect @@ -0,0 +1,11 @@ +main() { +int i; +for (i = 0; i < 10; i++) {} +} + + +main[StringToken]([BeginToken])[SimpleToken] {[BeginToken] +int[StringToken] i[StringToken];[SimpleToken] +for[KeywordToken] ([BeginToken]i[StringToken] =[SimpleToken] 0[StringToken];[SimpleToken] i[StringToken] <[BeginToken] 10[StringToken];[SimpleToken] i[StringToken]++[SimpleToken])[SimpleToken] {[BeginToken]}[SimpleToken] +}[SimpleToken] +[SimpleToken] diff --git a/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart b/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart index 08b25f73829..21baea859ba 100644 --- a/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart +++ b/pkg/front_end/test/fasta/parser/literal_entry_info_test.dart @@ -984,12 +984,12 @@ class TestInfoListener implements Listener { } @override - void handleForInitializerExpressionStatement(Token token) { + void handleForInitializerExpressionStatement(Token token, bool forIn) { calls.add('handleForInitializerExpressionStatement $token'); } @override - void handleForInitializerLocalVariableDeclaration(Token token) { + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { calls.add('handleForInitializerLocalVariableDeclaration $token'); } diff --git a/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart b/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart index b52d7d1b5e5..70ca1e84532 100644 --- a/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart +++ b/pkg/front_end/test/flow_analysis/assigned_variables/assigned_variables_test.dart @@ -6,8 +6,9 @@ import 'dart:io' show Directory, Platform; import 'package:front_end/src/api_prototype/experimental_flags.dart' show ExperimentalFlag; import 'package:front_end/src/fasta/flow_analysis/flow_analysis.dart'; +import 'package:front_end/src/fasta/source/source_loader.dart'; -import 'package:front_end/src/testing/id.dart' show ActualData, Id; +import 'package:front_end/src/testing/id.dart' show ActualData, Id, IdKind; import 'package:front_end/src/testing/id_testing.dart' show DataInterpreter, runTests; import 'package:front_end/src/testing/id_testing.dart'; @@ -58,12 +59,15 @@ class AssignedVariablesDataComputer extends DataComputer<_Data> { } class AssignedVariablesDataExtractor extends CfeDataExtractor<_Data> { + final SourceLoaderDataForTesting _sourceLoaderDataForTesting; final AssignedVariablesForTesting _assignedVariables; AssignedVariablesDataExtractor(InternalCompilerResult compilerResult, Map> actualMap, this._assignedVariables) - : super(compilerResult, actualMap); + : _sourceLoaderDataForTesting = + compilerResult.kernelTargetForTesting.loader.dataForTesting, + super(compilerResult, actualMap); @override _Data computeMemberValue(Id id, Member member) { @@ -78,11 +82,19 @@ class AssignedVariablesDataExtractor extends CfeDataExtractor<_Data> { @override _Data computeNodeValue(Id id, TreeNode node) { - if (!_assignedVariables.isTracked(node)) return null; + switch (id.kind) { + case IdKind.iterator: + case IdKind.current: + case IdKind.moveNext: + return null; + default: + } + TreeNode alias = _sourceLoaderDataForTesting.toOriginal(node); + if (!_assignedVariables.isTracked(alias)) return null; return new _Data( - _convertVars(_assignedVariables.declaredInNode(node)), - _convertVars(_assignedVariables.writtenInNode(node)), - _convertVars(_assignedVariables.capturedInNode(node))); + _convertVars(_assignedVariables.declaredInNode(alias)), + _convertVars(_assignedVariables.writtenInNode(alias)), + _convertVars(_assignedVariables.capturedInNode(alias))); } } diff --git a/pkg/front_end/test/parser_test_listener.dart b/pkg/front_end/test/parser_test_listener.dart index 3455d8b18e7..006c81812c5 100644 --- a/pkg/front_end/test/parser_test_listener.dart +++ b/pkg/front_end/test/parser_test_listener.dart @@ -450,12 +450,13 @@ class ParserTestListener implements Listener { doPrint('handleForInitializerEmptyStatement(' '$token)'); } - void handleForInitializerExpressionStatement(Token token) { - doPrint('handleForInitializerExpressionStatement(' '$token)'); + void handleForInitializerExpressionStatement(Token token, bool forIn) { + doPrint('handleForInitializerExpressionStatement(' '$token, ' '$forIn)'); } - void handleForInitializerLocalVariableDeclaration(Token token) { - doPrint('handleForInitializerLocalVariableDeclaration(' '$token)'); + void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { + doPrint( + 'handleForInitializerLocalVariableDeclaration(' '$token, ' '$forIn)'); } void beginForStatement(Token token) {