Version 1.10.0-dev.1.2
svn merge -c 45059 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 45072 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 45080 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 45111 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 45124 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@45149 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 706b382..77a5aad 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -585,15 +585,17 @@
return units;
}
// add a unit for each unit/library combination
- Source unitSource = contextSource.source;
- List<Source> librarySources = context.getLibrariesContaining(unitSource);
- for (Source librarySource in librarySources) {
- CompilationUnit unit =
- context.resolveCompilationUnit2(unitSource, librarySource);
- if (unit != null) {
- units.add(unit);
+ runWithWorkingCacheSize(context, () {
+ Source unitSource = contextSource.source;
+ List<Source> librarySources = context.getLibrariesContaining(unitSource);
+ for (Source librarySource in librarySources) {
+ CompilationUnit unit =
+ context.resolveCompilationUnit2(unitSource, librarySource);
+ if (unit != null) {
+ units.add(unit);
+ }
}
- }
+ });
// done
return units;
}
@@ -1183,7 +1185,9 @@
return null;
}
// if library has been already resolved, resolve unit
- return context.resolveCompilationUnit2(source, librarySource);
+ return runWithWorkingCacheSize(context, () {
+ return context.resolveCompilationUnit2(source, librarySource);
+ });
}
/**
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 243384f..7f0fe1a 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -20,6 +20,24 @@
import 'package:analyzer/src/generated/source.dart';
/**
+ * Runs the given function [f] with the working cache size in [context].
+ * Returns the result of [f] invocation.
+ */
+runWithWorkingCacheSize(AnalysisContext context, f()) {
+ int currentCacheSize = context.analysisOptions.cacheSize;
+ if (currentCacheSize < PerformAnalysisOperation.WORKING_CACHE_SIZE) {
+ setCacheSize(context, PerformAnalysisOperation.WORKING_CACHE_SIZE);
+ try {
+ return f();
+ } finally {
+ setCacheSize(context, currentCacheSize);
+ }
+ } else {
+ return f();
+ }
+}
+
+/**
* Schedules indexing of the given [file] using the resolved [dartUnit].
*/
void scheduleIndexOperation(AnalysisServer server, String file,
@@ -152,6 +170,16 @@
}
/**
+ * Sets the cache size in the given [context] to the given value.
+ */
+void setCacheSize(AnalysisContext context, int cacheSize) {
+ AnalysisOptionsImpl options =
+ new AnalysisOptionsImpl.con1(context.analysisOptions);
+ options.cacheSize = cacheSize;
+ context.analysisOptions = options;
+}
+
+/**
* Runs the given notification producing function [f], catching exceptions.
*/
void _sendNotification(AnalysisServer server, f()) {
@@ -207,13 +235,13 @@
// sendStatusNotification(context.toString(), taskDescription);
// });
if (!isContinue) {
- _setCacheSize(WORKING_CACHE_SIZE);
+ setCacheSize(context, WORKING_CACHE_SIZE);
}
// prepare results
AnalysisResult result = context.performAnalysisTask();
List<ChangeNotice> notices = result.changeNotices;
if (notices == null) {
- _setCacheSize(IDLE_CACHE_SIZE);
+ setCacheSize(context, IDLE_CACHE_SIZE);
server.sendContextAnalysisDoneNotifications(
context, AnalysisDoneReason.COMPLETE);
return;
@@ -245,13 +273,6 @@
}
}
- void _setCacheSize(int cacheSize) {
- AnalysisOptionsImpl options =
- new AnalysisOptionsImpl.con1(context.analysisOptions);
- options.cacheSize = cacheSize;
- context.analysisOptions = options;
- }
-
void _updateIndex(AnalysisServer server, List<ChangeNotice> notices) {
if (server.index == null) {
return;
diff --git a/pkg/analysis_server/lib/src/services/index/store/codec.dart b/pkg/analysis_server/lib/src/services/index/store/codec.dart
index 0283594..f9190f0 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -81,21 +81,17 @@
for (Source unitSource in unitSources) {
List<Source> libSources = context.getLibrariesContaining(unitSource);
for (Source libSource in libSources) {
- LibraryElement libraryElement = context.getLibraryElement(libSource);
- if (libraryElement == null) {
+ CompilationUnitElement unitElement =
+ context.getCompilationUnitElement(unitSource, libSource);
+ if (unitElement == null) {
return null;
}
if (kindId == ElementKind.LIBRARY.ordinal) {
- return libraryElement;
+ return unitElement.library;
} else if (kindId == ElementKind.COMPILATION_UNIT.ordinal) {
- for (CompilationUnitElement unit in libraryElement.units) {
- if (unit.source.fullName == filePath) {
- return unit;
- }
- }
- return null;
+ return unitElement;
} else {
- Element element = libraryElement.getElementAt(offset);
+ Element element = unitElement.getElementAt(offset);
if (element == null) {
return null;
}
diff --git a/pkg/analyzer/lib/instrumentation/instrumentation.dart b/pkg/analyzer/lib/instrumentation/instrumentation.dart
index 83b8635..ccb2149 100644
--- a/pkg/analyzer/lib/instrumentation/instrumentation.dart
+++ b/pkg/analyzer/lib/instrumentation/instrumentation.dart
@@ -4,6 +4,8 @@
library instrumentation;
+import 'dart:convert';
+
/**
* A container with analysis performance constants.
*/
@@ -62,6 +64,8 @@
static const String TAG_PERFORMANCE = 'Perf';
static const String TAG_REQUEST = 'Req';
static const String TAG_RESPONSE = 'Res';
+ static const String TAG_SUBPROCESS_START = 'SPStart';
+ static const String TAG_SUBPROCESS_RESULT = 'SPResult';
static const String TAG_VERSION = 'Ver';
static const String TAG_WATCH_EVENT = 'Watch';
@@ -72,6 +76,11 @@
InstrumentationServer _instrumentationServer;
/**
+ * Counter used to generate unique ID's for [logSubprocessStart].
+ */
+ int _subprocessCounter = 0;
+
+ /**
* Initialize a newly created instrumentation service to comunicate with the
* given [instrumentationServer].
*/
@@ -191,6 +200,43 @@
}
/**
+ * Log the result of executing a subprocess. [subprocessId] should be the
+ * unique IDreturned by [logSubprocessStart].
+ */
+ void logSubprocessResult(
+ int subprocessId, int exitCode, String stdout, String stderr) {
+ if (_instrumentationServer != null) {
+ _instrumentationServer.log(_join([
+ TAG_SUBPROCESS_RESULT,
+ subprocessId.toString(),
+ exitCode.toString(),
+ JSON.encode(stdout),
+ JSON.encode(stderr)
+ ]));
+ }
+ }
+
+ /**
+ * Log that the given subprocess is about to be executed. Returns a unique
+ * identifier that can be used to identify the subprocess for later log
+ * entries.
+ */
+ int logSubprocessStart(
+ String executablePath, List<String> arguments, String workingDirectory) {
+ int subprocessId = _subprocessCounter++;
+ if (_instrumentationServer != null) {
+ _instrumentationServer.log(_join([
+ TAG_SUBPROCESS_START,
+ subprocessId.toString(),
+ executablePath,
+ workingDirectory,
+ JSON.encode(arguments)
+ ]));
+ }
+ return subprocessId;
+ }
+
+ /**
* Signal that the client has started analysis server.
* This method should be invoked exactly one time.
*/
diff --git a/pkg/analyzer/lib/source/pub_package_map_provider.dart b/pkg/analyzer/lib/source/pub_package_map_provider.dart
index e16fbef..a78d4ad 100644
--- a/pkg/analyzer/lib/source/pub_package_map_provider.dart
+++ b/pkg/analyzer/lib/source/pub_package_map_provider.dart
@@ -156,8 +156,15 @@
* Run pub list to determine the packages and input files.
*/
io.ProcessResult _runPubListDefault(Folder folder) {
- return io.Process.runSync(sdk.pubExecutable.getAbsolutePath(), [
- PUB_LIST_COMMAND
- ], workingDirectory: folder.path);
+ String executablePath = sdk.pubExecutable.getAbsolutePath();
+ List<String> arguments = [PUB_LIST_COMMAND];
+ String workingDirectory = folder.path;
+ int subprocessId = AnalysisEngine.instance.instrumentationService
+ .logSubprocessStart(executablePath, arguments, workingDirectory);
+ io.ProcessResult result = io.Process.runSync(executablePath, arguments,
+ workingDirectory: workingDirectory);
+ AnalysisEngine.instance.instrumentationService.logSubprocessResult(
+ subprocessId, result.exitCode, result.stdout, result.stderr);
+ return result;
}
}
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 9c94c92..861b1ea 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -1213,6 +1213,11 @@
List<ClassElement> get types;
/**
+ * Return the element at the given [offset], maybe `null` if no such element.
+ */
+ Element getElementAt(int offset);
+
+ /**
* Return the enum defined in this compilation unit that has the given [name],
* or `null` if this compilation unit does not define an enum with the given
* name.
@@ -1280,6 +1285,11 @@
TopLevelVariableElementImpl.EMPTY_ARRAY;
/**
+ * A map from offsets to elements of this unit at these offsets.
+ */
+ final Map<int, Element> _offsetToElementMap = new HashMap<int, Element>();
+
+ /**
* Initialize a newly created compilation unit element to have the given
* [name].
*/
@@ -1400,6 +1410,13 @@
@override
accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this);
+ /**
+ * This method is invoked after this unit was incrementally resolved.
+ */
+ void afterIncrementalResolution() {
+ _offsetToElementMap.clear();
+ }
+
@override
void appendTo(StringBuffer buffer) {
if (source == null) {
@@ -1451,6 +1468,14 @@
}
@override
+ Element getElementAt(int offset) {
+ if (_offsetToElementMap.isEmpty) {
+ accept(new _BuildOffsetToElementMap(_offsetToElementMap));
+ }
+ return _offsetToElementMap[offset];
+ }
+
+ @override
ClassElement getEnum(String enumName) {
for (ClassElement enumDeclaration in _enums) {
if (enumDeclaration.name == enumName) {
@@ -6766,11 +6791,6 @@
List<LibraryElement> get visibleLibraries;
/**
- * Return the element at the given [offset], maybe `null` if no such element.
- */
- Element getElementAt(int offset);
-
- /**
* Return a list containing all of the imports that share the given [prefix],
* or an empty array if there are no such imports.
*/
@@ -6840,11 +6860,6 @@
FunctionElement _loadLibraryFunction;
/**
- * A map from offsets to elements of this library at these offsets.
- */
- final Map<int, Element> _offsetToElementMap = new HashMap<int, Element>();
-
- /**
* The export [Namespace] of this library, `null` if it has not been
* computed yet.
*/
@@ -7119,13 +7134,6 @@
@override
accept(ElementVisitor visitor) => visitor.visitLibraryElement(this);
- /**
- * This method is invoked after this library was incrementally resolved.
- */
- void afterIncrementalResolution() {
- _offsetToElementMap.clear();
- }
-
@override
ElementImpl getChild(String identifier) {
if ((_definingCompilationUnit as CompilationUnitElementImpl).identifier ==
@@ -7151,14 +7159,6 @@
}
@override
- Element getElementAt(int offset) {
- if (_offsetToElementMap.isEmpty) {
- accept(new _BuildOffsetToElementMap(_offsetToElementMap));
- }
- return _offsetToElementMap[offset];
- }
-
- @override
List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) {
int count = _imports.length;
List<ImportElement> importList = new List<ImportElement>();
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 4c5acae..0cb42ec 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -219,6 +219,11 @@
int get uriOffset => actualElement.uriOffset;
@override
+ Element getElementAt(int offset) {
+ return actualElement.getElementAt(offset);
+ }
+
+ @override
ClassElement getEnum(String enumName) => actualElement.getEnum(enumName);
@override
@@ -803,9 +808,6 @@
List<LibraryElement> get visibleLibraries => actualElement.visibleLibraries;
@override
- Element getElementAt(int offset) => actualElement.getElementAt(offset);
-
- @override
List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) =>
actualElement.getImportsWithPrefix(prefixElement);
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 1e9b61d..531ac3b 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -788,7 +788,7 @@
/**
* The element of the compilation unit being resolved.
*/
- final CompilationUnitElement _definingUnit;
+ final CompilationUnitElementImpl _definingUnit;
/**
* The context the compilation unit being resolved in.
@@ -887,8 +887,8 @@
_generateLints(rootNode);
// update entry errors
_updateEntry();
- // notify library
- _definingLibrary.afterIncrementalResolution();
+ // notify unit
+ _definingUnit.afterIncrementalResolution();
// OK
return true;
} finally {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d9cc380..ad79134 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -4566,14 +4566,14 @@
}
// ignore places where the element is not actually used
if (node.parent is TypeName) {
- AstNode parent2 = node.parent.parent;
- if (parent2 is IsExpression) {
- return;
- }
- // We need to instantiate/extend/implement a class to actually use it.
- // OTOH, function type aliases are used to define closure structures.
- if (parent2 is VariableDeclarationList && element is ClassElement) {
- return;
+ if (element is ClassElement) {
+ AstNode parent2 = node.parent.parent;
+ if (parent2 is IsExpression) {
+ return;
+ }
+ if (parent2 is VariableDeclarationList) {
+ return;
+ }
}
}
// OK
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 7b173af..6afb5dc 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -3529,6 +3529,20 @@
verify([source]);
}
+ void test_unusedElement_functionTypeAlias_isUsed_isExpression() {
+ enableUnusedElement = true;
+ Source source = addSource(r'''
+typedef _F(a, b);
+main(f) {
+ if (f is _F) {
+ print('F');
+ }
+}''');
+ resolve(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_unusedElement_functionTypeAlias_isUsed_reference() {
enableUnusedElement = true;
Source source = addSource(r'''
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 4aaa293..ac68fbd 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -1069,16 +1069,12 @@
inTryStatement = oldInTryStatement;
}
- visitForIn(ForIn node) {
- if (node.awaitToken != null) {
- // An `await for` loop is enclosed in an implicit try-finally.
- bool oldInTryStatement = inTryStatement;
- inTryStatement = true;
- visitLoop(node);
- inTryStatement = oldInTryStatement;
- } else {
- visitLoop(node);
- }
+ visitAsyncForIn(AsyncForIn node) {
+ // An `await for` loop is enclosed in an implicit try-finally.
+ bool oldInTryStatement = inTryStatement;
+ inTryStatement = true;
+ visitLoop(node);
+ inTryStatement = oldInTryStatement;
}
}
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 5bd9aee..6bbcd29 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -530,6 +530,9 @@
/// Register that [node] is a call to `assert`.
void onAssert(Send node, Registry registry) {}
+ /// Register that an 'await for' has been seen.
+ void onAsyncForIn(AsyncForIn node, Registry registry) {}
+
/// Called during resolution to notify to the backend that the
/// program uses string interpolation.
void onStringInterpolation(Registry registry) {}
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 289b230..a433c46 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -417,7 +417,12 @@
closureScope: getClosureScopeForNode(node));
}
- visitForIn(ast.ForIn node) {
+ visitAsyncForIn(ast.AsyncForIn node) {
+ // await for is not yet implemented.
+ return giveup(node, 'await for');
+ }
+
+ visitSyncForIn(ast.SyncForIn node) {
// [node.declaredIdentifier] can be either an [ast.VariableDefinitions]
// (defining a new local variable) or a send designating some existing
// variable.
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
index 8e29ca0..b15a4e2 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_to_frontend_ast.dart
@@ -775,11 +775,10 @@
} else {
left = makeVariableDeclarations(stmt.leftHandValue);
}
- return new tree.ForIn(
+ return new tree.SyncForIn(
left,
makeExpression(stmt.expression),
makeStatement(stmt.body, shortIf: shortIf),
- awaitToken,
forToken,
inToken);
} else if (stmt is FunctionDeclaration) {
diff --git a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
index a969baa..889827e 100644
--- a/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
+++ b/pkg/compiler/lib/src/inferrer/inferrer_visitor.dart
@@ -269,6 +269,8 @@
assert(this.named.values.every((T type) => type != null));
}
+ ArgumentsTypes.empty() : positional = const [], named = const {};
+
int get length => positional.length + named.length;
Iterator<T> get iterator => new ArgumentsTypesIterator(this);
@@ -713,7 +715,9 @@
T visitDynamicSend(Send node);
- T visitForIn(ForIn node);
+ T visitAsyncForIn(AsyncForIn node);
+
+ T visitSyncForIn(SyncForIn node);
T visitReturn(Return node);
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index d740569..d58c45d 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -1189,7 +1189,7 @@
// Erroneous elements may be unresolved, for example missing getters.
if (Elements.isUnresolved(element)) return types.dynamicType;
// TODO(herhut): should we follow redirecting constructors here? We would
- // need to pay attention of the constructor is pointing to an erroneous
+ // need to pay attention if the constructor is pointing to an erroneous
// element.
return inferrer.registerCalledElement(
node, selector, outermostElement, element, arguments,
@@ -1329,18 +1329,12 @@
return null;
}
- T visitForIn(ast.ForIn node) {
- T expressionType = visit(node.expression);
- Selector iteratorSelector = elements.getIteratorSelector(node);
- Selector currentSelector = elements.getCurrentSelector(node);
- Selector moveNextSelector = elements.getMoveNextSelector(node);
-
- T iteratorType =
- handleDynamicSend(node, iteratorSelector, expressionType, null);
- handleDynamicSend(node, moveNextSelector,
- iteratorType, new ArgumentsTypes<T>([], null));
- T currentType =
- handleDynamicSend(node, currentSelector, iteratorType, null);
+ T handleForInLoop(ast.ForIn node, T iteratorType, Selector currentSelector,
+ Selector moveNextSelector) {
+ handleDynamicSend(node, moveNextSelector, iteratorType,
+ new ArgumentsTypes<T>.empty());
+ T currentType = handleDynamicSend(node, currentSelector, iteratorType,
+ new ArgumentsTypes<T>.empty());
if (node.expression.isThis()) {
// Any reasonable implementation of an iterator would expose
@@ -1366,4 +1360,35 @@
visit(node.body);
});
}
+
+ T visitAsyncForIn(ast.AsyncForIn node) {
+ T expressionType = visit(node.expression);
+
+ Selector currentSelector = elements.getCurrentSelector(node);
+ Selector moveNextSelector = elements.getMoveNextSelector(node);
+
+ js.JavaScriptBackend backend = compiler.backend;
+ Element ctor = backend.getStreamIteratorConstructor();
+
+ /// Synthesize a call to the [StreamIterator] constructor.
+ T iteratorType = handleStaticSend(node, null, ctor,
+ new ArgumentsTypes<T>([expressionType],
+ null));
+
+ return handleForInLoop(node, iteratorType, currentSelector,
+ moveNextSelector);
+ }
+
+ T visitSyncForIn(ast.SyncForIn node) {
+ T expressionType = visit(node.expression);
+ Selector iteratorSelector = elements.getIteratorSelector(node);
+ Selector currentSelector = elements.getCurrentSelector(node);
+ Selector moveNextSelector = elements.getMoveNextSelector(node);
+
+ T iteratorType = handleDynamicSend(node, iteratorSelector, expressionType,
+ new ArgumentsTypes<T>.empty());
+
+ return handleForInLoop(node, iteratorType, currentSelector,
+ moveNextSelector);
+ }
}
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index b87a892..dac18f9 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -674,7 +674,7 @@
}
bool get isSynthesized {
- // Some calls do not have a corresponding node, for example
+ // Some calls do not have a corresponding selector, for example
// fowarding factory constructors, or synthesized super
// constructor calls. We synthesize these calls but do
// not create a selector for them.
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 6d1ead5..94c62a4 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -2680,6 +2680,11 @@
registerBackendStaticInvocation(backend.assertMethod, registry);
}
+ void onAsyncForIn(AsyncForIn node, Registry registry) {
+ registerBackendStaticInvocation(backend.getStreamIteratorConstructor(),
+ registry);
+ }
+
void onStringInterpolation(Registry registry) {
assert(registry.isForResolution);
registerBackendStaticInvocation(
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index 652387b..da69760 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -3598,8 +3598,21 @@
registry.registerDynamicInvocation(selector);
}
- visitForIn(ForIn node) {
- LibraryElement library = enclosingElement.library;
+ visitAsyncForIn(AsyncForIn node) {
+ registry.registerAsyncForIn(node);
+ registry.setCurrentSelector(node, compiler.currentSelector);
+ registry.registerDynamicGetter(compiler.currentSelector);
+ registry.setMoveNextSelector(node, compiler.moveNextSelector);
+ registry.registerDynamicInvocation(compiler.moveNextSelector);
+
+ visit(node.expression);
+
+ Scope blockScope = new BlockScope(scope);
+ visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
+ visitLoopBodyIn(node, node.body, blockScope);
+ }
+
+ visitSyncForIn(SyncForIn node) {
registry.setIteratorSelector(node, compiler.iteratorSelector);
registry.registerDynamicGetter(compiler.iteratorSelector);
registry.setCurrentSelector(node, compiler.currentSelector);
@@ -3608,8 +3621,15 @@
registry.registerDynamicInvocation(compiler.moveNextSelector);
visit(node.expression);
+
Scope blockScope = new BlockScope(scope);
- Node declaration = node.declaredIdentifier;
+ visitForInDeclaredIdentifierIn(node.declaredIdentifier, node, blockScope);
+ visitLoopBodyIn(node, node.body, blockScope);
+ }
+
+ visitForInDeclaredIdentifierIn(Node declaration, ForIn node,
+ Scope blockScope) {
+ LibraryElement library = enclosingElement.library;
bool oldAllowFinalWithoutInitializer = allowFinalWithoutInitializer;
allowFinalWithoutInitializer = true;
@@ -3659,7 +3679,6 @@
// loopVariable may be null if it could not be resolved.
registry.setForInVariable(node, loopVariable);
}
- visitLoopBodyIn(node, node.body, blockScope);
}
visitLabel(Label node) {
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index 15082856..8b37559 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -372,4 +372,8 @@
void registerAsyncMarker(FunctionElement element) {
backend.registerAsyncMarker(element, world, this);
}
+
+ void registerAsyncForIn(AsyncForIn node) {
+ backend.resolutionCallbacks.onAsyncForIn(node, this);
+ }
}
diff --git a/pkg/compiler/lib/src/scanner/listener.dart b/pkg/compiler/lib/src/scanner/listener.dart
index 0ef1f5d..568577a 100644
--- a/pkg/compiler/lib/src/scanner/listener.dart
+++ b/pkg/compiler/lib/src/scanner/listener.dart
@@ -2161,8 +2161,13 @@
Statement body = popNode();
Expression expression = popNode();
Node declaredIdentifier = popNode();
- pushNode(new ForIn(declaredIdentifier, expression, body,
- awaitToken, forToken, inKeyword));
+ if (awaitToken == null) {
+ pushNode(new SyncForIn(declaredIdentifier, expression, body,
+ forToken, inKeyword));
+ } else {
+ pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken,
+ forToken, inKeyword));
+ }
}
void endMetadataStar(int count, bool forParameter) {
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 195b188..189b9b8 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -5424,8 +5424,7 @@
return new JumpHandler(this, element);
}
- buildAsyncForIn(ast.ForIn node) {
- assert(node.isAsync);
+ visitAsyncForIn(ast.AsyncForIn node) {
// The async-for is implemented with a StreamIterator.
HInstruction streamIterator;
@@ -5491,11 +5490,7 @@
});
}
- visitForIn(ast.ForIn node) {
- if (node.isAsync) {
- return buildAsyncForIn(node);
- }
-
+ visitSyncForIn(ast.SyncForIn node) {
// Generate a structure equivalent to:
// Iterator<E> $iter = <iterable>.iterator;
// while ($iter.moveNext()) {
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index fd28580..e5a6c70 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -2914,7 +2914,8 @@
int visitWhile(ast.While node) => HLoopBlockInformation.WHILE_LOOP;
int visitFor(ast.For node) => HLoopBlockInformation.FOR_LOOP;
int visitDoWhile(ast.DoWhile node) => HLoopBlockInformation.DO_WHILE_LOOP;
- int visitForIn(ast.ForIn node) => HLoopBlockInformation.FOR_IN_LOOP;
+ int visitAsyncForIn(ast.AsyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP;
+ int visitSyncForIn(ast.SyncForIn node) => HLoopBlockInformation.FOR_IN_LOOP;
int visitSwitchStatement(ast.SwitchStatement node) =>
HLoopBlockInformation.SWITCH_CONTINUE_LOOP;
}
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index 2c22466..d6222eb 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -9,6 +9,7 @@
R visitNode(Node node);
+ R visitAsyncForIn(AsyncForIn node) => visitLoop(node);
R visitAsyncModifier(AsyncModifier node) => visitNode(node);
R visitAwait(Await node) => visitExpression(node);
R visitBlock(Block node) => visitStatement(node);
@@ -28,7 +29,6 @@
R visitExpression(Expression node) => visitNode(node);
R visitExpressionStatement(ExpressionStatement node) => visitStatement(node);
R visitFor(For node) => visitLoop(node);
- R visitForIn(ForIn node) => visitLoop(node);
R visitFunctionDeclaration(FunctionDeclaration node) => visitStatement(node);
R visitFunctionExpression(FunctionExpression node) => visitExpression(node);
R visitGotoStatement(GotoStatement node) => visitStatement(node);
@@ -50,6 +50,7 @@
R visitLiteralNull(LiteralNull node) => visitLiteral(node);
R visitLiteralString(LiteralString node) => visitStringNode(node);
R visitStringJuxtaposition(StringJuxtaposition node) => visitStringNode(node);
+ R visitSyncForIn(SyncForIn node) => visitLoop(node);
R visitLoop(Loop node) => visitStatement(node);
R visitMetadata(Metadata node) => visitNode(node);
R visitMixinApplication(MixinApplication node) => visitNode(node);
@@ -165,6 +166,8 @@
Expression asExpression() => null;
ExpressionStatement asExpressionStatement() => null;
For asFor() => null;
+ SyncForIn asSyncForIn() => null;
+ AsyncForIn asAsyncForIn() => null;
ForIn asForIn() => null;
FunctionDeclaration asFunctionDeclaration() => null;
FunctionExpression asFunctionExpression() => null;
@@ -1775,25 +1778,31 @@
accept(Visitor visitor) => visitor.visitContinueStatement(this);
}
-class ForIn extends Loop with StoredTreeElementMixin {
+abstract class ForIn extends Loop {
final Node declaredIdentifier;
final Expression expression;
- final Token awaitToken;
final Token forToken;
final Token inToken;
ForIn(this.declaredIdentifier, this.expression,
- Statement body, this.awaitToken, this.forToken, this.inToken)
+ Statement body, this.forToken, this.inToken)
: super(body);
- bool get isAsync => awaitToken != null;
-
Expression get condition => null;
ForIn asForIn() => this;
- accept(Visitor visitor) => visitor.visitForIn(this);
+ Token getEndToken() => body.getEndToken();
+}
+
+class SyncForIn extends ForIn with StoredTreeElementMixin {
+ SyncForIn(declaredIdentifier, expression, Statement body, forToken, inToken)
+ : super(declaredIdentifier, expression, body, forToken, inToken);
+
+ SyncForIn asSyncForIn() => this;
+
+ accept(Visitor visitor) => visitor.visitSyncForIn(this);
visitChildren(Visitor visitor) {
declaredIdentifier.accept(visitor);
@@ -1801,9 +1810,27 @@
body.accept(visitor);
}
- Token getBeginToken() => awaitToken != null ? awaitToken : forToken;
+ Token getBeginToken() => forToken;
+}
- Token getEndToken() => body.getEndToken();
+class AsyncForIn extends ForIn with StoredTreeElementMixin {
+ final Token awaitToken;
+
+ AsyncForIn(declaredIdentifier, expression,
+ Statement body, this.awaitToken, forToken, inToken)
+ : super(declaredIdentifier, expression, body, forToken, inToken);
+
+ AsyncForIn asAsyncForIn() => this;
+
+ accept(Visitor visitor) => visitor.visitAsyncForIn(this);
+
+ visitChildren(Visitor visitor) {
+ declaredIdentifier.accept(visitor);
+ expression.accept(visitor);
+ body.accept(visitor);
+ }
+
+ Token getBeginToken() => awaitToken;
}
class Label extends Node {
diff --git a/pkg/compiler/lib/src/tree/prettyprint.dart b/pkg/compiler/lib/src/tree/prettyprint.dart
index 6248480..f01963b 100644
--- a/pkg/compiler/lib/src/tree/prettyprint.dart
+++ b/pkg/compiler/lib/src/tree/prettyprint.dart
@@ -190,8 +190,12 @@
visitNodeWithChildren(node, "For");
}
- visitForIn(ForIn node) {
- openNode(node, "ForIn", {'await': node.awaitToken});
+ visitAsyncForIn(AsyncForIn node) {
+ openNode(node, "AsyncForIn");
+ }
+
+ visitSyncForIn(SyncForIn node) {
+ openNode(node, "ForIn");
node.visitChildren(this);
closeNode();
}
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index d7dbda7..5325f13 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -623,11 +623,23 @@
visitGotoStatement(node);
}
- visitForIn(ForIn node) {
- if (node.awaitToken != null) {
- write(node.awaitToken.value);
- write(' ');
- }
+ visitAsyncForIn(AsyncForIn node) {
+ write(node.awaitToken.value);
+ write(' ');
+ write(node.forToken.value);
+ space();
+ write('(');
+ visit(node.declaredIdentifier);
+ write(' ');
+ addToken(node.inToken);
+ visit(node.expression);
+ write(')');
+ space();
+ visit(node.body);
+ }
+
+
+ visitSyncForIn(SyncForIn node) {
write(node.forToken.value);
space();
write('(');
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index 04a7a43..078086c 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -1719,7 +1719,13 @@
return const StatementType();
}
- visitForIn(ForIn node) {
+ visitAsyncForIn(AsyncForIn node) {
+ analyze(node.expression);
+ analyze(node.body);
+ return const StatementType();
+ }
+
+ visitSyncForIn(SyncForIn node) {
analyze(node.expression);
analyze(node.body);
return const StatementType();
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 8edad0b..538a0e2 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -90,6 +90,7 @@
void useNode(tree.Node node) {
node
..asAsyncModifier()
+ ..asAsyncForIn()
..asAwait()
..asBreakStatement()
..asCascade()
@@ -126,6 +127,7 @@
..asStringNode()
..asSwitchCase()
..asSwitchStatement()
+ ..asSyncForIn()
..asTryStatement()
..asTypeAnnotation()
..asTypeVariable()
diff --git a/tools/VERSION b/tools/VERSION
index c7af623..82d7fec 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -28,4 +28,4 @@
MINOR 10
PATCH 0
PRERELEASE 1
-PRERELEASE_PATCH 1
+PRERELEASE_PATCH 2