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