Version 1.9.0-dev.8.0

svn merge -r 43548:43712 https://dart.googlecode.com/svn/branches/bleeding_edge trunk

git-svn-id: http://dart.googlecode.com/svn/trunk@43715 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 82af650..fe7de66 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -43,7 +43,7 @@
 </style></head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version 1.0.0</h1>
+    <h1 style="color:#999999">Version 1.2.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -572,17 +572,33 @@
           </dd></dl></dd><dt class="request">analysis.reanalyze</dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "analysis.reanalyze"
+  "params": {
+    "<b>roots</b>": <span style="color:#999999">optional</span> List&lt;<a href="#type_FilePath">FilePath</a>&gt;
+  }
 }</pre><br><pre>response: {
   "id": String
   "error": <span style="color:#999999">optional</span> <a href="#type_RequestError">RequestError</a>
 }</pre></div>
         <p>
-          Force the re-analysis of everything contained in the
-          existing analysis roots. This will cause all previously
-          computed analysis results to be discarded and recomputed,
-          and will cause all subscribed notifications to be re-sent.
+          Force the re-analysis of everything contained in the specified
+          analysis roots. This will cause all previously computed analysis
+          results to be discarded and recomputed, and will cause all subscribed
+          notifications to be re-sent.
         </p>
-      </dd><dt class="request">analysis.setAnalysisRoots</dt><dd><div class="box"><pre>request: {
+        <p>
+          If no analysis roots are provided, then all current analysis roots
+          will be re-analyzed. If an empty list of analysis roots is provided,
+          then nothing will be re-analyzed. If the list contains one or more
+          paths that are not currently analysis roots, then an error of type
+          <tt>INVALID_ANALYSIS_ROOT</tt> will be generated.
+        </p>
+        
+      <h4>Parameters</h4><dl><dt class="field"><b><i>roots ( <span style="color:#999999">optional</span> List&lt;<a href="#type_FilePath">FilePath</a>&gt; )</i></b></dt><dd>
+            
+            <p>
+              A list of the analysis roots that are to be re-analyzed.
+            </p>
+          </dd></dl></dd><dt class="request">analysis.setAnalysisRoots</dt><dd><div class="box"><pre>request: {
   "id": String
   "method": "analysis.setAnalysisRoots"
   "params": {
@@ -1501,7 +1517,9 @@
           text is passed in so that the selection can be preserved across the
           formatting operation. The updated selection will be as close to
           matching the original as possible, but whitespace at the beginning or
-          end of the selected region will be ignored.
+          end of the selected region will be ignored. If preserving selection
+          information is not required, zero (0) can be specified for both the
+          selection offset and selection length.
         </p>
         <p>
           If a request is made for a file which does not exist, or
@@ -1520,16 +1538,12 @@
           </dd><dt class="field"><b><i>selectionOffset ( int )</i></b></dt><dd>
             
             <p>
-              The offset of the current selection in the file. In case
-              preserving, selection information is not required, 0 can be
-              specified for both selection offset and length.
+              The offset of the current selection in the file.
             </p>
           </dd><dt class="field"><b><i>selectionLength ( int )</i></b></dt><dd>
             
             <p>
-              The length of the current selection in the file. In case
-              preserving, selection information is not required, 0 can be
-              specified for both selection offset and length.
+              The length of the current selection in the file.
             </p>
           </dd></dl><h4>Returns</h4><dl><dt class="field"><b><i>edits ( List&lt;<a href="#type_SourceEdit">SourceEdit</a>&gt; )</i></b></dt><dd>
             
@@ -1874,7 +1888,8 @@
       <h4>Parameters</h4><dl><dt class="field"><b><i>contextRoot ( <a href="#type_FilePath">FilePath</a> )</i></b></dt><dd>
             
             <p>
-              The path of the Dart or HTML file that will be launched.
+              The path of the Dart or HTML file that will be launched, or the
+              path of the directory containing the file.
             </p>
           </dd></dl><h4>Returns</h4><dl><dt class="field"><b><i>id ( <a href="#type_ExecutionContextId">ExecutionContextId</a> )</i></b></dt><dd>
             
@@ -1925,25 +1940,27 @@
           context.
         </p>
         <p>
-          Exactly one of the file and uri fields must be provided.
+          Exactly one of the file and uri fields must be provided. If both
+          fields are provided, then an error of type <tt>INVALID_PARAMETER</tt>
+          will be generated. Similarly, if neither field is provided, then an
+          error of type <tt>INVALID_PARAMETER</tt> will be generated.
         </p>
         <p>
           If the file field is provided and the value is not the path of a file
           (either the file does not exist or the path references something other
-          than a file), then an error of type <tt>MAP_URI_INVALID_FILE</tt> will
+          than a file), then an error of type <tt>INVALID_PARAMETER</tt> will
           be generated.
         </p>
         <p>
           If the uri field is provided and the value is not a valid URI or if
           the URI references something that is not a file (either a file that
           does not exist or something other than a file), then an error of type
-          <tt>MAP_URI_INVALID_URI</tt> will be generated.
+          <tt>INVALID_PARAMETER</tt> will be generated.
         </p>
         <p>
-          If the contextRoot used to create the execution context is not a file
-          (either the file does not exist or the path references something other
-          than a file), then an error of type <tt>INVALID_EXECUTION_CONTEXT</tt>
-          will be generated.
+          If the contextRoot used to create the execution context does not
+          exist, then an error of type <tt>INVALID_EXECUTION_CONTEXT</tt> will
+          be generated.
         </p>
         
         
@@ -3076,6 +3093,12 @@
               which does not match a file currently subject to
               analysis.
             </p>
+          </dd><dt class="value">INVALID_EXECUTION_CONTEXT</dt><dd>
+            
+            <p>
+              The context root used to create an execution context does not
+              exist.
+            </p>
           </dd><dt class="value">INVALID_OVERLAY_CHANGE</dt><dd>
             
             <p>
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 9bac7d9..f5430ac 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -67,7 +67,7 @@
    * The version of the analysis server. The value should be replaced
    * automatically during the build.
    */
-  static final String VERSION = '1.0.0';
+  static final String VERSION = '1.1.0';
 
   /**
    * The number of milliseconds to perform operations before inserting
@@ -334,6 +334,21 @@
   }
 
   /**
+   * Performs all scheduled analysis operations.
+   */
+  void test_performAllAnalysisOperations() {
+    while (true) {
+      ServerOperation operation = operationQueue.takeIf((operation) {
+        return operation is PerformAnalysisOperation;
+      });
+      if (operation == null) {
+        break;
+      }
+      operation.perform(this);
+    }
+  }
+
+  /**
    * If the given notice applies to a file contained within an analysis root,
    * notify interested parties that the file has been (at least partially)
    * analyzed.
@@ -353,11 +368,23 @@
    */
   AnalysisContext getAnalysisContext(String path) {
     // try to find a containing context
+    Folder containingFolder = null;
     for (Folder folder in folderMap.keys) {
-      if (folder.contains(path)) {
-        return folderMap[folder];
+      if (folder.path == path || folder.contains(path)) {
+        if (containingFolder == null) {
+          containingFolder = folder;
+        } else if (containingFolder.path.length < folder.path.length) {
+          containingFolder = folder;
+        }
       }
     }
+    if (containingFolder != null) {
+      return folderMap[containingFolder];
+    }
+    Resource resource = resourceProvider.getResource(path);
+    if (resource is Folder) {
+      return null;
+    }
     // check if there is a context that analyzed this source
     return getAnalysisContextForSource(getSource(path));
   }
@@ -943,6 +970,8 @@
   void updateContent(String id, Map<String, dynamic> changes) {
     changes.forEach((file, change) {
       Source source = getSource(file);
+      operationQueue.sourceAboutToChange(source);
+      // Prepare the new contents.
       String oldContents = _overlayState.getContents(source);
       String newContents;
       if (change is AddContentOverlay) {
@@ -1204,12 +1233,11 @@
    * [packageUriResolver].
    */
   SourceFactory _createSourceFactory(UriResolver packageUriResolver) {
-    List<UriResolver> resolvers = <UriResolver>[
-        new DartUriResolver(analysisServer.defaultSdk),
-        new ResourceUriResolver(resourceProvider)];
-    if (packageUriResolver != null) {
-      resolvers.add(packageUriResolver);
-    }
+    UriResolver dartResolver = new DartUriResolver(analysisServer.defaultSdk);
+    UriResolver resourceResolver = new ResourceUriResolver(resourceProvider);
+    List<UriResolver> resolvers = packageUriResolver != null ?
+        <UriResolver>[dartResolver, packageUriResolver, resourceResolver] :
+        <UriResolver>[dartResolver, resourceResolver];
     return new SourceFactory(resolvers);
   }
 }
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index 213f16e..87bc87a 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -68,6 +68,9 @@
    */
   HoverInformation compute() {
     AstNode node = new NodeLocator.con1(_offset).searchWithin(_unit);
+    if (node == null) {
+      return null;
+    }
     if (node.parent is TypeName &&
         node.parent.parent is ConstructorName &&
         node.parent.parent.parent is InstanceCreationExpression) {
diff --git a/pkg/analysis_server/lib/src/domain_execution.dart b/pkg/analysis_server/lib/src/domain_execution.dart
index 586b659..e1654df 100644
--- a/pkg/analysis_server/lib/src/domain_execution.dart
+++ b/pkg/analysis_server/lib/src/domain_execution.dart
@@ -10,6 +10,7 @@
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
 
@@ -98,19 +99,36 @@
           'There is no execution context with an id of $contextId');
     }
     AnalysisContext context = server.getAnalysisContext(path);
-    if (params.file != null) {
-      if (params.uri != null) {
+    if (context == null) {
+      return new Response.invalidExecutionContext(request, contextId);
+    }
+    String file = params.file;
+    String uri = params.uri;
+    if (file != null) {
+      if (uri != null) {
         return new Response.invalidParameter(
             request,
             'file',
             'Either file or uri must be provided, but not both');
       }
-      Source source = server.getSource(params.file);
-      String uri = context.sourceFactory.restoreUri(source).toString();
+      Resource resource = server.resourceProvider.getResource(file);
+      if (!resource.exists) {
+        return new Response.invalidParameter(request, 'file', 'Must exist');
+      } else if (resource is! File) {
+        return new Response.invalidParameter(
+            request,
+            'file',
+            'Must not refer to a directory');
+      }
+      Source source = server.getSource(file);
+      uri = context.sourceFactory.restoreUri(source).toString();
       return new ExecutionMapUriResult(uri: uri).toResponse(request.id);
-    } else if (params.uri != null) {
-      Source source = context.sourceFactory.forUri(params.uri);
-      String file = source.fullName;
+    } else if (uri != null) {
+      Source source = context.sourceFactory.forUri(uri);
+      if (source == null) {
+        return new Response.invalidParameter(request, 'uri', 'Invalid URI');
+      }
+      file = source.fullName;
       return new ExecutionMapUriResult(file: file).toResponse(request.id);
     }
     return new Response.invalidParameter(
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index a7b579f..f4292bb 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -1008,25 +1008,70 @@
     return _JenkinsSmiHash.finish(hash);
   }
 }
+
 /**
  * analysis.reanalyze params
+ *
+ * {
+ *   "roots": optional List<FilePath>
+ * }
  */
-class AnalysisReanalyzeParams {
-  Request toRequest(String id) {
-    return new Request(id, "analysis.reanalyze", null);
+class AnalysisReanalyzeParams implements HasToJson {
+  /**
+   * A list of the analysis roots that are to be re-analyzed.
+   */
+  List<String> roots;
+
+  AnalysisReanalyzeParams({this.roots});
+
+  factory AnalysisReanalyzeParams.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json == null) {
+      json = {};
+    }
+    if (json is Map) {
+      List<String> roots;
+      if (json.containsKey("roots")) {
+        roots = jsonDecoder._decodeList(jsonPath + ".roots", json["roots"], jsonDecoder._decodeString);
+      }
+      return new AnalysisReanalyzeParams(roots: roots);
+    } else {
+      throw jsonDecoder.mismatch(jsonPath, "analysis.reanalyze params");
+    }
   }
 
+  factory AnalysisReanalyzeParams.fromRequest(Request request) {
+    return new AnalysisReanalyzeParams.fromJson(
+        new RequestDecoder(request), "params", request._params);
+  }
+
+  Map<String, dynamic> toJson() {
+    Map<String, dynamic> result = {};
+    if (roots != null) {
+      result["roots"] = roots;
+    }
+    return result;
+  }
+
+  Request toRequest(String id) {
+    return new Request(id, "analysis.reanalyze", toJson());
+  }
+
+  @override
+  String toString() => JSON.encode(toJson());
+
   @override
   bool operator==(other) {
     if (other is AnalysisReanalyzeParams) {
-      return true;
+      return _listEqual(roots, other.roots, (String a, String b) => a == b);
     }
     return false;
   }
 
   @override
   int get hashCode {
-    return 613039876;
+    int hash = 0;
+    hash = _JenkinsSmiHash.combine(hash, roots.hashCode);
+    return _JenkinsSmiHash.finish(hash);
   }
 }
 /**
@@ -3483,16 +3528,12 @@
   String file;
 
   /**
-   * The offset of the current selection in the file. In case preserving,
-   * selection information is not required, 0 can be specified for both
-   * selection offset and length.
+   * The offset of the current selection in the file.
    */
   int selectionOffset;
 
   /**
-   * The length of the current selection in the file. In case preserving,
-   * selection information is not required, 0 can be specified for both
-   * selection offset and length.
+   * The length of the current selection in the file.
    */
   int selectionLength;
 
@@ -4583,7 +4624,8 @@
  */
 class ExecutionCreateContextParams implements HasToJson {
   /**
-   * The path of the Dart or HTML file that will be launched.
+   * The path of the Dart or HTML file that will be launched, or the path of
+   * the directory containing the file.
    */
   String contextRoot;
 
@@ -9208,6 +9250,7 @@
  *   CONTENT_MODIFIED
  *   FORMAT_INVALID_FILE
  *   GET_ERRORS_INVALID_FILE
+ *   INVALID_EXECUTION_CONTEXT
  *   INVALID_OVERLAY_CHANGE
  *   INVALID_PARAMETER
  *   INVALID_REQUEST
@@ -9242,6 +9285,11 @@
   static const GET_ERRORS_INVALID_FILE = const RequestErrorCode._("GET_ERRORS_INVALID_FILE");
 
   /**
+   * The context root used to create an execution context does not exist.
+   */
+  static const INVALID_EXECUTION_CONTEXT = const RequestErrorCode._("INVALID_EXECUTION_CONTEXT");
+
+  /**
    * An analysis.updateContent request contained a ChangeContentOverlay object
    * which can't be applied, due to an edit having an offset or length that is
    * out of range.
@@ -9318,7 +9366,7 @@
   /**
    * A list containing all of the enum values that are defined.
    */
-  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, GET_ERRORS_INVALID_FILE, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNSUPPORTED_FEATURE];
+  static const List<RequestErrorCode> VALUES = const <RequestErrorCode>[CONTENT_MODIFIED, FORMAT_INVALID_FILE, GET_ERRORS_INVALID_FILE, INVALID_EXECUTION_CONTEXT, INVALID_OVERLAY_CHANGE, INVALID_PARAMETER, INVALID_REQUEST, REFACTORING_REQUEST_CANCELLED, SERVER_ALREADY_STARTED, SERVER_ERROR, SORT_MEMBERS_INVALID_FILE, SORT_MEMBERS_PARSE_ERRORS, UNANALYZED_PRIORITY_FILES, UNKNOWN_REQUEST, UNSUPPORTED_FEATURE];
 
   final String name;
 
@@ -9332,6 +9380,8 @@
         return FORMAT_INVALID_FILE;
       case "GET_ERRORS_INVALID_FILE":
         return GET_ERRORS_INVALID_FILE;
+      case "INVALID_EXECUTION_CONTEXT":
+        return INVALID_EXECUTION_CONTEXT;
       case "INVALID_OVERLAY_CHANGE":
         return INVALID_OVERLAY_CHANGE;
       case "INVALID_PARAMETER":
diff --git a/pkg/analysis_server/lib/src/get_handler.dart b/pkg/analysis_server/lib/src/get_handler.dart
index 2e2cb3e..2dadde0 100644
--- a/pkg/analysis_server/lib/src/get_handler.dart
+++ b/pkg/analysis_server/lib/src/get_handler.dart
@@ -29,6 +29,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
 
 import 'analysis_server.dart';
 
@@ -44,9 +45,9 @@
  */
 class GetHandler {
   /**
-   * The path used to request the status of the analysis server as a whole.
+   * The path used to request overall performance information.
    */
-  static const String STATUS_PATH = '/status';
+  static const String ANALYSIS_PERFORMANCE_PATH = '/perf/analysis';
 
   /**
    * The path used to request information about a element model.
@@ -71,6 +72,11 @@
   static const String COMPLETION_PATH = '/completion';
 
   /**
+   * The path used to request communication performance information.
+   */
+  static const String COMMUNICATION_PERFORMANCE_PATH = '/perf/communication';
+
+  /**
    * The path used to request information about a specific context.
    */
   static const String CONTEXT_PATH = '/context';
@@ -96,15 +102,9 @@
   static const String OVERLAYS_PATH = '/overlays';
 
   /**
-   * The path used to request overall performance information.
+   * The path used to request the status of the analysis server as a whole.
    */
-  static const String PERFORMANCE_PATH = '/performance';
-
-  /**
-   * Query parameter used to represent the cache state to search for, when
-   * accessing [CACHE_STATE_PATH].
-   */
-  static const String STATE_QUERY_PARAM = 'state';
+  static const String STATUS_PATH = '/status';
 
   /**
    * Query parameter used to represent the context to search for, when
@@ -135,6 +135,12 @@
    */
   static const String SOURCE_QUERY_PARAM = 'entry';
 
+  /**
+   * Query parameter used to represent the cache state to search for, when
+   * accessing [CACHE_STATE_PATH].
+   */
+  static const String STATE_QUERY_PARAM = 'state';
+
   static final ContentType _htmlContent =
       new ContentType("text", "html", charset: "utf-8");
 
@@ -180,6 +186,8 @@
     String path = request.uri.path;
     if (path == STATUS_PATH) {
       _returnServerStatus(request);
+    } else if (path == ANALYSIS_PERFORMANCE_PATH) {
+      _returnAnalysisPerformance(request);
     } else if (path == AST_PATH) {
       _returnAst(request);
     } else if (path == CACHE_STATE_PATH) {
@@ -188,6 +196,8 @@
       _returnCacheEntry(request);
     } else if (path == COMPLETION_PATH) {
       _returnCompletionInfo(request);
+    } else if (path == COMMUNICATION_PERFORMANCE_PATH) {
+      _returnCommunicationPerformance(request);
     } else if (path == CONTEXT_PATH) {
       _returnContextInfo(request);
     } else if (path == ELEMENT_PATH) {
@@ -198,8 +208,6 @@
       _returnOverlayContents(request);
     } else if (path == OVERLAYS_PATH) {
       _returnOverlaysInfo(request);
-    } else if (path == PERFORMANCE_PATH) {
-      _returnPerformance(request);
     } else {
       _returnUnknownRequest(request);
     }
@@ -246,16 +254,67 @@
   }
 
   /**
-   * Create a link to [path] with query parameters [params], with inner HTML
-   * [innerHtml]. If [hasError] is `true`, then the link will have the class
-   * 'error'.
+   * Return a response displaying overall performance information.
    */
-  String _makeLink(String path, Map<String, String> params, String innerHtml,
-      [bool hasError = false]) {
-    Uri uri = new Uri(path: path, queryParameters: params);
-    String href = HTML_ESCAPE.convert(uri.toString());
-    String classAttribute = hasError ? ' class="error"' : '';
-    return '<a href="$href"$classAttribute>$innerHtml</a>';
+  void _returnAnalysisPerformance(HttpRequest request) {
+    AnalysisServer analysisServer = _server.analysisServer;
+    if (analysisServer == null) {
+      return _returnFailure(request, 'Analysis server is not running');
+    }
+    _writeResponse(request, (StringBuffer buffer) {
+      _writePage(
+          buffer,
+          'Analysis Server - Analysis Performance',
+          [],
+          (StringBuffer buffer) {
+        void writeRow(TimeCounter counter, String label) {
+          _writeRow(buffer, [counter.result, label], classes: ["right", null]);
+        }
+
+        buffer.write('<h3>Analysis Performance</h3>');
+        buffer.write('<p><b>Time spent in each phase of analysis</b></p>');
+        buffer.write(
+            '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+        _writeRow(buffer, ['Time (in ms)', 'Analysis Phase'], header: true);
+        writeRow(PerformanceStatistics.io, 'io');
+        writeRow(PerformanceStatistics.scan, 'scan');
+        writeRow(PerformanceStatistics.parse, 'parse');
+        writeRow(PerformanceStatistics.resolve, 'resolve');
+        writeRow(PerformanceStatistics.errors, 'errors');
+        writeRow(PerformanceStatistics.hints, 'hints');
+        writeRow(PerformanceStatistics.lint, 'lint');
+        buffer.write('</table>');
+
+        Map<DataDescriptor, Map<CacheState, int>> transitionMap = SourceEntry.transitionMap;
+        buffer.write('<p><b>Number of times a state transitioned to VALID (grouped by descriptor)</b></p>');
+        if (transitionMap.isEmpty) {
+          buffer.write('<p>none</p>');
+        } else {
+          List<DataDescriptor> descriptors = transitionMap.keys.toList();
+          descriptors.sort(
+              (DataDescriptor first, DataDescriptor second) =>
+                  first.toString().compareTo(second.toString()));
+          for (DataDescriptor key in descriptors) {
+            Map<CacheState, int> countMap = transitionMap[key];
+            List<CacheState> oldStates = countMap.keys.toList();
+            oldStates.sort(
+                (CacheState first, CacheState second) =>
+                    first.toString().compareTo(second.toString()));
+            buffer.write('<p>${key.toString()}</p>');
+            buffer.write(
+                '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+            _writeRow(buffer, ['Count', 'Previous State'], header: true);
+            for (CacheState state in oldStates) {
+              _writeRow(
+                  buffer,
+                  [countMap[state], state.toString()],
+                  classes: ["right", null]);
+            }
+            buffer.write('</table>');
+          }
+        }
+      });
+    });
   }
 
   /**
@@ -381,7 +440,7 @@
           if (analyzingContext == context) {
             buffer.write(folder.path);
           } else {
-            buffer.write(_makeLink(CACHE_ENTRY_PATH, {
+            buffer.write(makeLink(CACHE_ENTRY_PATH, {
               CONTEXT_QUERY_PARAM: folder.path,
               SOURCE_QUERY_PARAM: sourceUri
             }, HTML_ESCAPE.convert(folder.path)));
@@ -485,7 +544,7 @@
       if (state != stateFilter || rowDesc.toString() != descriptorFilter) {
         return;
       }
-      String link = _makeLink(CACHE_ENTRY_PATH, {
+      String link = makeLink(CACHE_ENTRY_PATH, {
         CONTEXT_QUERY_PARAM: folder.path,
         SOURCE_QUERY_PARAM: source.uri.toString()
       }, HTML_ESCAPE.convert(source.fullName));
@@ -512,6 +571,91 @@
   }
 
   /**
+   * Return a response displaying overall performance information.
+   */
+  void _returnCommunicationPerformance(HttpRequest request) {
+    AnalysisServer analysisServer = _server.analysisServer;
+    if (analysisServer == null) {
+      return _returnFailure(request, 'Analysis server is not running');
+    }
+    _writeResponse(request, (StringBuffer buffer) {
+      _writePage(
+          buffer,
+          'Analysis Server - Communication Performance',
+          [],
+          (StringBuffer buffer) {
+        buffer.write('<h3>Communication Performance</h3>');
+        _writeTwoColumns(buffer, (StringBuffer buffer) {
+          ServerPerformance perf = analysisServer.performanceDuringStartup;
+          int requestCount = perf.requestCount;
+          num averageLatency =
+              requestCount > 0 ? (perf.requestLatency / requestCount).round() : 0;
+          int maximumLatency = perf.maxLatency;
+          num slowRequestPercent =
+              requestCount > 0 ? (perf.slowRequestCount * 100 / requestCount).round() : 0;
+          buffer.write('<h4>Startup</h4>');
+          buffer.write('<table>');
+          _writeRow(
+              buffer,
+              [requestCount, 'requests'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [averageLatency, 'ms average latency'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [maximumLatency, 'ms maximum latency'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [slowRequestPercent, '% > 150 ms latency'],
+              classes: ["right", null]);
+          if (analysisServer.performanceAfterStartup != null) {
+            int startupTime =
+                analysisServer.performanceAfterStartup.startTime -
+                perf.startTime;
+            _writeRow(
+                buffer,
+                [startupTime, 'ms for initial analysis to complete']);
+          }
+          buffer.write('</table>');
+        }, (StringBuffer buffer) {
+          ServerPerformance perf = analysisServer.performanceAfterStartup;
+          if (perf == null) {
+            return;
+          }
+          int requestCount = perf.requestCount;
+          num averageLatency =
+              requestCount > 0 ? (perf.requestLatency * 10 / requestCount).round() / 10 : 0;
+          int maximumLatency = perf.maxLatency;
+          num slowRequestPercent =
+              requestCount > 0 ? (perf.slowRequestCount * 100 / requestCount).round() : 0;
+          buffer.write('<h4>Current</h4>');
+          buffer.write('<table>');
+          _writeRow(
+              buffer,
+              [requestCount, 'requests'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [averageLatency, 'ms average latency'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [maximumLatency, 'ms maximum latency'],
+              classes: ["right", null]);
+          _writeRow(
+              buffer,
+              [slowRequestPercent, '% > 150 ms latency'],
+              classes: ["right", null]);
+          buffer.write('</table>');
+        });
+      });
+    });
+  }
+
+  /**
    * Return a response displaying code completion information.
    */
   void _returnCompletionInfo(HttpRequest request) {
@@ -567,7 +711,7 @@
         if (exception != null) {
           exceptions.add(exception);
         }
-        String link = _makeLink(CACHE_ENTRY_PATH, {
+        String link = makeLink(CACHE_ENTRY_PATH, {
           CONTEXT_QUERY_PARAM: folder.path,
           SOURCE_QUERY_PARAM: source.uri.toString()
         }, sourceName, exception != null);
@@ -601,7 +745,7 @@
           buffer.write(links[fileName]);
           buffer.write('</td><td>');
           if (overlayMap.containsKey(fileName)) {
-            buffer.write(_makeLink(OVERLAY_PATH, {
+            buffer.write(makeLink(OVERLAY_PATH, {
               ID_PARAM: overlayMap[fileName].toString()
             }, 'overlay'));
           }
@@ -632,7 +776,7 @@
               CONTEXT_QUERY_PARAM: folder.path,
               DESCRIPTOR_QUERY_PARAM: row.name
             };
-            rowText.add(_makeLink(CACHE_STATE_PATH, params, text));
+            rowText.add(makeLink(CACHE_STATE_PATH, params, text));
           }
           _writeRow(buffer, rowText, classes: [null, "right"]);
         });
@@ -826,91 +970,6 @@
   }
 
   /**
-   * Return a response displaying overall performance information.
-   */
-  void _returnPerformance(HttpRequest request) {
-    AnalysisServer analysisServer = _server.analysisServer;
-    if (analysisServer == null) {
-      return _returnFailure(request, 'Analysis server is not running');
-    }
-    _writeResponse(request, (StringBuffer buffer) {
-      _writePage(
-          buffer,
-          'Analysis Server - Performance',
-          [],
-          (StringBuffer buffer) {
-        buffer.write('<h3>Communication Performance</h3>');
-        _writeTwoColumns(buffer, (StringBuffer buffer) {
-          ServerPerformance perf = analysisServer.performanceDuringStartup;
-          int requestCount = perf.requestCount;
-          num averageLatency =
-              requestCount > 0 ? (perf.requestLatency / requestCount).round() : 0;
-          int maximumLatency = perf.maxLatency;
-          num slowRequestPercent =
-              requestCount > 0 ? (perf.slowRequestCount * 100 / requestCount).round() : 0;
-          buffer.write('<h4>Startup</h4>');
-          buffer.write('<table>');
-          _writeRow(
-              buffer,
-              [requestCount, 'requests'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [averageLatency, 'ms average latency'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [maximumLatency, 'ms maximum latency'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [slowRequestPercent, '% > 150 ms latency'],
-              classes: ["right", null]);
-          if (analysisServer.performanceAfterStartup != null) {
-            int startupTime =
-                analysisServer.performanceAfterStartup.startTime -
-                perf.startTime;
-            _writeRow(
-                buffer,
-                [startupTime, 'ms for initial analysis to complete']);
-          }
-          buffer.write('</table>');
-        }, (StringBuffer buffer) {
-          ServerPerformance perf = analysisServer.performanceAfterStartup;
-          if (perf == null) {
-            return;
-          }
-          int requestCount = perf.requestCount;
-          num averageLatency =
-              requestCount > 0 ? (perf.requestLatency * 10 / requestCount).round() / 10 : 0;
-          int maximumLatency = perf.maxLatency;
-          num slowRequestPercent =
-              requestCount > 0 ? (perf.slowRequestCount * 100 / requestCount).round() : 0;
-          buffer.write('<h4>Current</h4>');
-          buffer.write('<table>');
-          _writeRow(
-              buffer,
-              [requestCount, 'requests'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [averageLatency, 'ms average latency'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [maximumLatency, 'ms maximum latency'],
-              classes: ["right", null]);
-          _writeRow(
-              buffer,
-              [slowRequestPercent, '% > 150 ms latency'],
-              classes: ["right", null]);
-          buffer.write('</table>');
-        });
-      });
-    });
-  }
-
-  /**
    * Return a response indicating the status of the analysis server.
    */
   void _returnServerStatus(HttpRequest request) {
@@ -935,13 +994,14 @@
       _writePage(buffer, 'Analysis Server', [], (StringBuffer buffer) {
         buffer.write('<h3>Pages</h3>');
         buffer.write('<p>');
-        buffer.write(_makeLink(COMPLETION_PATH, {}, 'Completion data'));
+        buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data'));
         buffer.write('</p>');
         buffer.write('<p>');
-        buffer.write(_makeLink(PERFORMANCE_PATH, {}, 'Performance'));
+        buffer.write(
+            makeLink(COMMUNICATION_PERFORMANCE_PATH, {}, 'Performance'));
         buffer.write('</p>');
         buffer.write('<p>');
-        buffer.write(_makeLink(STATUS_PATH, {}, 'Server status'));
+        buffer.write(makeLink(STATUS_PATH, {}, 'Server status'));
         buffer.write('</p>');
       });
     });
@@ -1000,7 +1060,7 @@
           buffer.write('<br>');
         }
         String key = folder.shortName;
-        buffer.write(_makeLink(CONTEXT_PATH, {
+        buffer.write(makeLink(CONTEXT_PATH, {
           CONTEXT_QUERY_PARAM: folder.path
         }, key, _hasException(folderMap[folder])));
       });
@@ -1030,6 +1090,11 @@
       int freq = AnalysisServer.performOperationDelayFreqency;
       String delay = freq > 0 ? '1 ms every $freq ms' : 'off';
       buffer.write('<p><b>perform operation delay:</b> $delay</p>');
+
+      buffer.write('<p><b>Performance Data</b></p>');
+      buffer.write('<p>');
+      buffer.write(makeLink(ANALYSIS_PERFORMANCE_PATH, {}, 'Task data'));
+      buffer.write('</p>');
     }, (StringBuffer buffer) {
       _writeSubscriptionMap(
           buffer,
@@ -1104,7 +1169,7 @@
         header: true);
     int index = 0;
     for (CompletionPerformance performance in handler.performanceList) {
-      String link = _makeLink(COMPLETION_PATH, {
+      String link = makeLink(COMPLETION_PATH, {
         'index': '$index'
       }, '${performance.startTimeAndMs}');
       _writeRow(
@@ -1177,7 +1242,7 @@
     _writeTwoColumns(buffer, (StringBuffer buffer) {
       buffer.write('<p><b>Performance Data</b></p>');
       buffer.write('<p>');
-      buffer.write(_makeLink(COMPLETION_PATH, {}, 'Completion data'));
+      buffer.write(makeLink(COMPLETION_PATH, {}, 'Completion data'));
       buffer.write('</p>');
     }, (StringBuffer buffer) {
     });
@@ -1418,7 +1483,7 @@
       buffer.write('<p><b>Performance Data</b></p>');
       buffer.write('<p>');
       buffer.write(
-          _makeLink(PERFORMANCE_PATH, {}, 'Communication performance'));
+          makeLink(COMMUNICATION_PERFORMANCE_PATH, {}, 'Communication performance'));
       buffer.write('</p>');
     }, (StringBuffer buffer) {
       _writeSubscriptionList(buffer, ServerService.VALUES, services);
@@ -1547,15 +1612,28 @@
       buffer.write('</ul>');
     } else if (value is AstNode) {
       String link =
-          _makeLink(AST_PATH, linkParameters, value.runtimeType.toString());
+          makeLink(AST_PATH, linkParameters, value.runtimeType.toString());
       buffer.write('<i>$link</i>');
     } else if (value is Element) {
       String link =
-          _makeLink(ELEMENT_PATH, linkParameters, value.runtimeType.toString());
+          makeLink(ELEMENT_PATH, linkParameters, value.runtimeType.toString());
       buffer.write('<i>$link</i>');
     } else {
       buffer.write(HTML_ESCAPE.convert(value.toString()));
       buffer.write(' <i>(${value.runtimeType.toString()})</i>');
     }
   }
+
+  /**
+   * Create a link to [path] with query parameters [params], with inner HTML
+   * [innerHtml]. If [hasError] is `true`, then the link will have the class
+   * 'error'.
+   */
+  static String makeLink(String path, Map<String, String> params,
+      String innerHtml, [bool hasError = false]) {
+    Uri uri = new Uri(path: path, queryParameters: params);
+    String href = HTML_ESCAPE.convert(uri.toString());
+    String classAttribute = hasError ? ' class="error"' : '';
+    return '<a href="$href"$classAttribute>$innerHtml</a>';
+  }
 }
diff --git a/pkg/analysis_server/lib/src/operation/operation.dart b/pkg/analysis_server/lib/src/operation/operation.dart
index 03fd913..e9ed101 100644
--- a/pkg/analysis_server/lib/src/operation/operation.dart
+++ b/pkg/analysis_server/lib/src/operation/operation.dart
@@ -5,6 +5,7 @@
 library operation;
 
 import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analyzer/src/generated/source.dart';
 
 
 /**
@@ -58,3 +59,16 @@
   @override
   String toString() => name;
 }
+
+
+/**
+ * [SourceSensitiveOperation] can decide if the operation should be discarded
+ * before a change is applied to a [Source].
+ */
+abstract class SourceSensitiveOperation extends ServerOperation {
+  /**
+   * The given [source] is about to be changed.
+   * Check if this [SourceSensitiveOperation] should be discarded.
+   */
+  bool shouldBeDiscardedOnSourceChange(Source source);
+}
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index ec612a5..7d77d4a 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -264,11 +264,12 @@
       return;
     }
     for (ChangeNotice notice in notices) {
+      String file = notice.source.fullName;
       // Dart
       try {
         CompilationUnit dartUnit = notice.resolvedDartUnit;
         if (dartUnit != null) {
-          server.addOperation(new _DartIndexOperation(context, dartUnit));
+          server.addOperation(new _DartIndexOperation(context, file, dartUnit));
         }
       } catch (exception, stackTrace) {
         server.sendServerErrorNotification(exception, stackTrace);
@@ -277,7 +278,7 @@
       try {
         HtmlUnit htmlUnit = notice.resolvedHtmlUnit;
         if (htmlUnit != null) {
-          server.addOperation(new _HtmlIndexOperation(context, htmlUnit));
+          server.addOperation(new _HtmlIndexOperation(context, file, htmlUnit));
         }
       } catch (exception, stackTrace) {
         server.sendServerErrorNotification(exception, stackTrace);
@@ -298,11 +299,11 @@
 }
 
 
-class _DartIndexOperation extends ServerOperation {
+class _DartIndexOperation extends _SingleFileOperation {
   final AnalysisContext context;
   final CompilationUnit unit;
 
-  _DartIndexOperation(this.context, this.unit);
+  _DartIndexOperation(this.context, String file, this.unit) : super(file);
 
   @override
   ServerOperationPriority get priority {
@@ -328,11 +329,10 @@
 }
 
 
-abstract class _DartNotificationOperation extends ServerOperation {
-  final String file;
+abstract class _DartNotificationOperation extends _SingleFileOperation {
   final CompilationUnit unit;
 
-  _DartNotificationOperation(this.file, this.unit);
+  _DartNotificationOperation(String file, this.unit) : super(file);
 
   @override
   ServerOperationPriority get priority {
@@ -376,11 +376,11 @@
 }
 
 
-class _HtmlIndexOperation extends ServerOperation {
+class _HtmlIndexOperation extends _SingleFileOperation {
   final AnalysisContext context;
   final HtmlUnit unit;
 
-  _HtmlIndexOperation(this.context, this.unit);
+  _HtmlIndexOperation(this.context, String file, this.unit) : super(file);
 
   @override
   ServerOperationPriority get priority {
@@ -395,12 +395,12 @@
 }
 
 
-class _NotificationErrorsOperation extends ServerOperation {
-  final String file;
+class _NotificationErrorsOperation extends _SingleFileOperation {
   final LineInfo lineInfo;
   final List<AnalysisError> errors;
 
-  _NotificationErrorsOperation(this.file, this.lineInfo, this.errors);
+  _NotificationErrorsOperation(String file, this.lineInfo, this.errors)
+      : super(file);
 
   @override
   ServerOperationPriority get priority {
@@ -412,3 +412,15 @@
     sendAnalysisNotificationErrors(server, file, lineInfo, errors);
   }
 }
+
+
+abstract class _SingleFileOperation extends SourceSensitiveOperation {
+  final String file;
+
+  _SingleFileOperation(this.file);
+
+  @override
+  bool shouldBeDiscardedOnSourceChange(Source source) {
+    return source.fullName == file;
+  }
+}
diff --git a/pkg/analysis_server/lib/src/operation/operation_queue.dart b/pkg/analysis_server/lib/src/operation/operation_queue.dart
index 67ca993..deaa512 100644
--- a/pkg/analysis_server/lib/src/operation/operation_queue.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_queue.dart
@@ -8,6 +8,7 @@
 
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/operation/operation.dart';
+import 'package:analyzer/src/generated/source.dart';
 
 
 /**
@@ -51,8 +52,8 @@
   }
 
   /**
-   * Return the next operation to perform, or `null` if the queue is empty. This
-   * method does not change the queue.
+   * Return the next operation to perform, or `null` if the queue is empty.
+   * This method does not change the queue.
    */
   ServerOperation peek() {
     for (Queue<ServerOperation> queue in _queues) {
@@ -78,6 +79,20 @@
   }
 
   /**
+   * The given [source] if about to changed.
+   */
+  void sourceAboutToChange(Source source) {
+    for (Queue<ServerOperation> queue in _queues) {
+      queue.removeWhere((operation) {
+        if (operation is SourceSensitiveOperation) {
+          return operation.shouldBeDiscardedOnSourceChange(source);
+        }
+        return false;
+      });
+    }
+  }
+
+  /**
    * Returns the next operation to perform or `null` if empty.
    */
   ServerOperation take() {
@@ -88,4 +103,19 @@
     }
     return null;
   }
+
+  /**
+   * Returns an operation that satisfies the given [test] or `null`.
+   */
+  ServerOperation takeIf(bool test(ServerOperation operation)) {
+    for (Queue<ServerOperation> queue in _queues) {
+      for (var operation in queue) {
+        if (test(operation)) {
+          queue.remove(operation);
+          return operation;
+        }
+      }
+    }
+    return null;
+  }
 }
diff --git a/pkg/analysis_server/lib/src/protocol.dart b/pkg/analysis_server/lib/src/protocol.dart
index dfa810cd..10aea74 100644
--- a/pkg/analysis_server/lib/src/protocol.dart
+++ b/pkg/analysis_server/lib/src/protocol.dart
@@ -763,6 +763,18 @@
 
   /**
    * Initialize a newly created instance to represent an error condition caused
+   * by a [request] that specifies an execution context whose context root does
+   * not exist.
+   */
+  Response.invalidExecutionContext(Request request, String contextId)
+      : this(
+          request.id,
+          error: new RequestError(
+              RequestErrorCode.INVALID_EXECUTION_CONTEXT,
+              "Invalid execution context: $contextId"));
+
+  /**
+   * Initialize a newly created instance to represent an error condition caused
    * by a [request] that had invalid parameter.  [path] is the path to the
    * invalid parameter, in Javascript notation (e.g. "foo.bar" means that the
    * parameter "foo" contained a key "bar" whose value was the wrong type).
@@ -773,7 +785,7 @@
           request.id,
           error: new RequestError(
               RequestErrorCode.INVALID_PARAMETER,
-              "Expected parameter $path to $expectation"));
+              "Invalid parameter '$path'. $expectation."));
 
   /**
    * Initialize a newly created instance to represent an error condition caused
@@ -785,6 +797,17 @@
           error: new RequestError(RequestErrorCode.INVALID_REQUEST, 'Invalid request'));
 
   /**
+   * Initialize a newly created instance to represent the
+   * REFACTORING_REQUEST_CANCELLED error condition.
+   */
+  Response.refactoringRequestCancelled(Request request)
+      : this(
+          request.id,
+          error: new RequestError(
+              RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
+              'The `edit.getRefactoring` request was cancelled.'));
+
+  /**
    * Initialize a newly created instance to represent the SERVER_ERROR error
    * condition.
    */
@@ -810,17 +833,6 @@
 
   /**
    * Initialize a newly created instance to represent the
-   * REFACTORING_REQUEST_CANCELLED error condition.
-   */
-  Response.refactoringRequestCancelled(Request request)
-      : this(
-          request.id,
-          error: new RequestError(
-              RequestErrorCode.REFACTORING_REQUEST_CANCELLED,
-              'The `edit.getRefactoring` request was cancelled.'));
-
-  /**
-   * Initialize a newly created instance to represent the
    * SORT_MEMBERS_PARSE_ERRORS error condition.
    */
   Response.sortMembersParseErrors(Request request, int numErrors)
diff --git a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
index 54bb27d..3c20785 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart_completion_manager.dart
@@ -118,6 +118,9 @@
       request.unit = unit;
       request.node = new NodeLocator.con1(request.offset).searchWithin(unit);
       request.target = new CompletionTarget.forOffset(unit, request.offset);
+      if (request.node == null) {
+        return [];
+      }
 
       request.replacementOffset = request.offset;
       request.replacementLength = 0;
diff --git a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
index 71f55ba..31b0587 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -81,6 +81,7 @@
     }
     // try to add proposals
     _addProposal_addTypeAnnotation_DeclaredIdentifier();
+    _addProposal_addTypeAnnotation_SimpleFormalParameter();
     _addProposal_addTypeAnnotation_VariableDeclaration();
     _addProposal_assignToLocalVariable();
     _addProposal_convertToBlockFunctionBody();
@@ -314,6 +315,44 @@
     _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
   }
 
+  void _addProposal_addTypeAnnotation_SimpleFormalParameter() {
+    AstNode node = this.node;
+    // should be the name of a simple parameter
+    if (node is! SimpleIdentifier || node.parent is! SimpleFormalParameter) {
+      _coverageMarker();
+      return;
+    }
+    SimpleIdentifier name = node;
+    SimpleFormalParameter parameter = node.parent;
+    // the parameter should not have a type
+    if (parameter.type != null) {
+      _coverageMarker();
+      return;
+    }
+    // prepare propagated type
+    DartType type = name.propagatedType;
+    // TODO(scheglov) If the parameter is in a method declaration, and if the
+    // method overrides a method that has a type for the corresponding
+    // parameter, it would be nice to copy down the type from the overridden
+    // method.
+    if (type is! InterfaceType) {
+      _coverageMarker();
+      return;
+    }
+    // prepare type source
+    String typeSource;
+    {
+      _configureTargetLocation(node);
+      Set<LibraryElement> librariesToImport = new Set<LibraryElement>();
+      typeSource = utils.getTypeSource(type, librariesToImport);
+      _addLibraryImports(librariesToImport);
+    }
+    // add edit
+    _addInsertEdit(name.offset, '$typeSource ');
+    // add proposal
+    _addAssist(AssistKind.ADD_TYPE_ANNOTATION, []);
+  }
+
   void _addProposal_assignToLocalVariable() {
     // prepare enclosing ExpressionStatement
     Statement statement = node.getAncestor((node) => node is Statement);
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index 4aa4c62..18094cf 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -47,6 +47,8 @@
  * An enumeration of possible quick fix kinds.
  */
 class FixKind {
+  static const ADD_ASYNC =
+      const FixKind('ADD_ASYNC', 50, "Add 'async' modifier");
   static const ADD_PACKAGE_DEPENDENCY =
       const FixKind('ADD_PACKAGE_DEPENDENCY', 50, "Add dependency on package '{0}'");
   static const ADD_SUPER_CONSTRUCTOR_INVOCATION = const FixKind(
diff --git a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
index c46ee05..05e1e61 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -192,18 +192,23 @@
       _addFix_createMissingOverrides(missingOverrides);
       _addFix_createNoSuchMethod();
     }
-    if (errorCode == StaticWarningCode.UNDEFINED_CLASS) {
+    if (errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
+        errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
+        errorCode == StaticWarningCode.UNDEFINED_CLASS) {
       _addFix_importLibrary_withType();
       _addFix_createClass();
       _addFix_undefinedClass_useSimilar();
     }
     if (errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER) {
-      _addFix_createField();
-      _addFix_createGetter();
-      _addFix_createFunction_forFunctionType();
-      _addFix_importLibrary_withType();
-      _addFix_importLibrary_withTopLevelVariable();
-      _addFix_createLocalVariable();
+      bool isAsync = _addFix_addAsync();
+      if (!isAsync) {
+        _addFix_createField();
+        _addFix_createGetter();
+        _addFix_createFunction_forFunctionType();
+        _addFix_importLibrary_withType();
+        _addFix_importLibrary_withTopLevelVariable();
+        _addFix_createLocalVariable();
+      }
     }
     if (errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER) {
       _addFix_useStaticAccess_method();
@@ -264,6 +269,22 @@
     exitPosition = null;
   }
 
+  /**
+   * Returns `true` if the `async` proposal was added.
+   */
+  bool _addFix_addAsync() {
+    AstNode node = this.node;
+    if (_isAwaitNode()) {
+      FunctionBody body = node.getAncestor((n) => n is FunctionBody);
+      if (body.keyword == null) {
+        _addReplaceEdit(rf.rangeStartLength(body, 0), 'async ');
+        _addFix(FixKind.ADD_ASYNC, []);
+        return true;
+      }
+    }
+    return false;
+  }
+
   void _addFix_boolInsteadOfBoolean() {
     SourceRange range = rf.rangeError(error);
     _addReplaceEdit(range, 'bool');
@@ -816,8 +837,13 @@
     SourceBuilder sb = new SourceBuilder(file, target.offset);
     {
       // append type
-      DartType fieldType = _inferUndefinedExpressionType(node);
-      _appendType(sb, fieldType, groupId: 'TYPE', orVar: true);
+      DartType type = _inferUndefinedExpressionType(node);
+      if (!(type == null ||
+          type is InterfaceType ||
+          type is FunctionType && type.element != null && !type.element.isSynthetic)) {
+        return;
+      }
+      _appendType(sb, type, groupId: 'TYPE', orVar: true);
       // append name
       {
         sb.startPosition('NAME');
@@ -1164,6 +1190,9 @@
 
   void _addFix_insertSemicolon() {
     if (error.message.contains("';'")) {
+      if (_isAwaitNode()) {
+        return;
+      }
       int insertOffset = error.offset + error.length;
       _addInsertEdit(insertOffset, ';');
       _addFix(FixKind.INSERT_SEMICOLON, []);
@@ -1609,6 +1638,9 @@
 
   void _addFixToElement(FixKind kind, List args, Element element) {
     Source source = element.source;
+    if (source.isInSystemLibrary) {
+      return;
+    }
     String file = source.fullName;
     int fileStamp = element.context.getModificationStamp(source);
     _addFix(kind, args, file: file, fileStamp: fileStamp);
@@ -2065,6 +2097,11 @@
     return method != null && method.isStatic;
   }
 
+  bool _isAwaitNode() {
+    AstNode node = this.node;
+    return node is SimpleIdentifier && node.name == 'await';
+  }
+
   _ConstructorLocation
       _prepareNewConstructorLocation(ClassDeclaration classDeclaration) {
     List<ClassMember> members = classDeclaration.members;
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 8f6a2ed..ef36535b 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -93,8 +93,7 @@
     List<int> path = _indexToPath[index];
     List<String> components = _getLocationComponents(path);
     ElementLocation location = new ElementLocationImpl.con3(components);
-    Element element = context.getElement(location);
-    return element;
+    return context.getElement(location);
   }
 
   /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
index bea040a..c6ed68c 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_getter_to_method.dart
@@ -47,28 +47,28 @@
   }
 
   @override
-  Future<SourceChange> createChange() {
+  Future<SourceChange> createChange() async {
     change = new SourceChange(refactoringName);
     // function
     if (element.enclosingElement is CompilationUnitElement) {
       _updateElementDeclaration(element);
-      return _updateElementReferences(element).then((_) => change);
+      await _updateElementReferences(element);
     }
     // method
     if (element.enclosingElement is ClassElement) {
       FieldElement field = element.variable;
-      return getHierarchyMembers(searchEngine, field).then((elements) {
-        return Future.forEach(elements, (FieldElement field) {
-          PropertyAccessorElement getter = field.getter;
-          if (!getter.isSynthetic) {
-            _updateElementDeclaration(getter);
-            return _updateElementReferences(getter);
-          }
-        });
-      }).then((_) => change);
+      Set<ClassMemberElement> elements =
+          await getHierarchyMembers(searchEngine, field);
+      await Future.forEach(elements, (FieldElement field) {
+        PropertyAccessorElement getter = field.getter;
+        if (!getter.isSynthetic) {
+          _updateElementDeclaration(getter);
+          return _updateElementReferences(getter);
+        }
+      });
     }
-    // not reachable
-    return null;
+    // done
+    return change;
   }
 
   @override
@@ -106,16 +106,15 @@
     }
   }
 
-  Future _updateElementReferences(Element element) {
-    return searchEngine.searchReferences(element).then((matches) {
-      List<SourceReference> references = getSourceReferences(matches);
-      for (SourceReference reference in references) {
-        Element refElement = reference.element;
-        SourceRange refRange = reference.range;
-        // insert "()"
-        var edit = new SourceEdit(refRange.end, 0, "()");
-        doSourceChange_addElementEdit(change, refElement, edit);
-      }
-    });
+  Future _updateElementReferences(Element element) async {
+    List<SearchMatch> matches = await searchEngine.searchReferences(element);
+    List<SourceReference> references = getSourceReferences(matches);
+    for (SourceReference reference in references) {
+      Element refElement = reference.element;
+      SourceRange refRange = reference.range;
+      // insert "()"
+      var edit = new SourceEdit(refRange.end, 0, "()");
+      doSourceChange_addElementEdit(change, refElement, edit);
+    }
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
index 55cc6a7..e0a94cc 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/convert_method_to_getter.dart
@@ -46,25 +46,25 @@
   }
 
   @override
-  Future<SourceChange> createChange() {
+  Future<SourceChange> createChange() async {
     change = new SourceChange(refactoringName);
     // FunctionElement
     if (element is FunctionElement) {
       _updateElementDeclaration(element);
-      return _updateElementReferences(element).then((_) => change);
+      await _updateElementReferences(element);
     }
     // MethodElement
     if (element is MethodElement) {
       MethodElement method = element;
-      return getHierarchyMembers(searchEngine, method).then((elements) {
-        return Future.forEach(elements, (Element element) {
-          _updateElementDeclaration(element);
-          return _updateElementReferences(element);
-        });
-      }).then((_) => change);
+      Set<ClassMemberElement> elements =
+          await getHierarchyMembers(searchEngine, method);
+      await Future.forEach(elements, (Element element) {
+        _updateElementDeclaration(element);
+        return _updateElementReferences(element);
+      });
     }
-    // not reachable
-    return null;
+    // done
+    return change;
   }
 
   @override
@@ -114,27 +114,26 @@
     }
   }
 
-  Future _updateElementReferences(Element element) {
-    return searchEngine.searchReferences(element).then((matches) {
-      List<SourceReference> references = getSourceReferences(matches);
-      for (SourceReference reference in references) {
-        Element refElement = reference.element;
-        SourceRange refRange = reference.range;
-        // prepare invocation
-        MethodInvocation invocation;
-        {
-          CompilationUnit refUnit = refElement.unit;
-          AstNode refNode =
-              new NodeLocator.con1(refRange.offset).searchWithin(refUnit);
-          invocation = refNode.getAncestor((node) => node is MethodInvocation);
-        }
-        // we need invocation
-        if (invocation != null) {
-          SourceRange range = rangeEndEnd(refRange, invocation);
-          SourceEdit edit = newSourceEdit_range(range, '');
-          doSourceChange_addElementEdit(change, refElement, edit);
-        }
+  Future _updateElementReferences(Element element) async {
+    List<SearchMatch> matches = await searchEngine.searchReferences(element);
+    List<SourceReference> references = getSourceReferences(matches);
+    for (SourceReference reference in references) {
+      Element refElement = reference.element;
+      SourceRange refRange = reference.range;
+      // prepare invocation
+      MethodInvocation invocation;
+      {
+        CompilationUnit refUnit = refElement.unit;
+        AstNode refNode =
+            new NodeLocator.con1(refRange.offset).searchWithin(refUnit);
+        invocation = refNode.getAncestor((node) => node is MethodInvocation);
       }
-    });
+      // we need invocation
+      if (invocation != null) {
+        SourceRange range = rangeEndEnd(refRange, invocation);
+        SourceEdit edit = newSourceEdit_range(range, '');
+        doSourceChange_addElementEdit(change, refElement, edit);
+      }
+    }
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
index 963a6f4..c222ff0 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/extract_method.dart
@@ -25,6 +25,7 @@
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/resolver.dart' show ExitDetector;
 
 
 const String _TOKEN_SEPARATOR = '\uFFFF';
@@ -57,6 +58,10 @@
  */
 class ExtractMethodRefactoringImpl extends RefactoringImpl implements
     ExtractMethodRefactoring {
+  static const ERROR_EXITS =
+      'Selected statements contain a return statement, but not all possible '
+          'execuion flows exit. Semantics may not be preserved.';
+
   final SearchEngine searchEngine;
   final CompilationUnit unit;
   final int selectionOffset;
@@ -164,14 +169,13 @@
   }
 
   @override
-  Future<RefactoringStatus> checkFinalConditions() {
+  Future<RefactoringStatus> checkFinalConditions() async {
     RefactoringStatus result = new RefactoringStatus();
     result.addStatus(validateMethodName(name));
     result.addStatus(_checkParameterNames());
-    return _checkPossibleConflicts().then((status) {
-      result.addStatus(status);
-      return result;
-    });
+    RefactoringStatus status = await _checkPossibleConflicts();
+    result.addStatus(status);
+    return result;
   }
 
 
@@ -572,7 +576,14 @@
     if (_selectionExpression != null) {
       _returnType = _selectionExpression.bestType;
     }
-    // may be ends with "return" statement
+    // verify that none or all execution flows end with a "return"
+    if (_selectionStatements != null) {
+      bool hasReturn = _selectionStatements.any(_mayEndWithReturnStatement);
+      if (hasReturn && !ExitDetector.exits(_selectionStatements.last)) {
+        result.addError(ERROR_EXITS);
+      }
+    }
+    // maybe ends with "return" statement
     if (_selectionStatements != null) {
       _ReturnTypeComputer returnTypeComputer = new _ReturnTypeComputer();
       _selectionStatements.forEach((statement) {
@@ -580,7 +591,7 @@
       });
       _returnType = returnTypeComputer.returnType;
     }
-    // may be single variable to return
+    // maybe single variable to return
     if (assignedUsedVariables.length == 1) {
       // we cannot both return variable and have explicit return statement
       if (_returnType != null) {
@@ -698,6 +709,15 @@
     node.accept(visitor);
     return visitor.result;
   }
+
+  /**
+   * Returns `true` if the given [statement] may end with a [ReturnStatement].
+   */
+  static bool _mayEndWithReturnStatement(Statement statement) {
+    _HasReturnStatementVisitor visitor = new _HasReturnStatementVisitor();
+    statement.accept(visitor);
+    return visitor.hasReturn;
+  }
 }
 
 
@@ -865,6 +885,20 @@
 }
 
 
+class _HasReturnStatementVisitor extends RecursiveAstVisitor {
+  bool hasReturn = false;
+
+  @override
+  visitBlockFunctionBody(BlockFunctionBody node) {
+  }
+
+  @override
+  visitReturnStatement(ReturnStatement node) {
+    hasReturn = true;
+  }
+}
+
+
 class _InitializeOccurrencesVisitor extends GeneralizingAstVisitor<Object> {
   final ExtractMethodRefactoringImpl ref;
   final _SourcePattern selectionPattern;
@@ -972,7 +1006,6 @@
   }
 }
 
-
 class _InitializeParametersVisitor extends GeneralizingAstVisitor<Object> {
   final ExtractMethodRefactoringImpl ref;
   final List<VariableElement> assignedUsedVariables;
@@ -1031,6 +1064,7 @@
   }
 }
 
+
 class _IsUsedAfterSelectionVisitor extends GeneralizingAstVisitor {
   final ExtractMethodRefactoringImpl ref;
   final VariableElement element;
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
index 2c4e115..064021a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_local.dart
@@ -66,7 +66,7 @@
   }
 
   @override
-  Future<RefactoringStatus> checkInitialConditions() {
+  Future<RefactoringStatus> checkInitialConditions() async {
     RefactoringStatus result = new RefactoringStatus();
     // prepare variable
     {
@@ -96,22 +96,20 @@
       return new Future.value(result);
     }
     // prepare references
-    return searchEngine.searchReferences(_variableElement).then((references) {
-      this._references = references;
-      // should not have assignments
-      for (SearchMatch reference in _references) {
-        if (reference.kind != MatchKind.READ) {
-          String message = format(
-              "Local variable '{0}' is assigned more than once.",
-              [_variableElement.displayName]);
-          return new RefactoringStatus.fatal(
-              message,
-              newLocation_fromMatch(reference));
-        }
+    _references = await searchEngine.searchReferences(_variableElement);
+    // should not have assignments
+    for (SearchMatch reference in _references) {
+      if (reference.kind != MatchKind.READ) {
+        String message = format(
+            "Local variable '{0}' is assigned more than once.",
+            [_variableElement.displayName]);
+        return new RefactoringStatus.fatal(
+            message,
+            newLocation_fromMatch(reference));
       }
-      // done
-      return result;
-    });
+    }
+    // done
+    return result;
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
index af23849..dbbbe21 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/inline_method.dart
@@ -275,7 +275,7 @@
   }
 
   @override
-  Future<RefactoringStatus> checkInitialConditions() {
+  Future<RefactoringStatus> checkInitialConditions() async {
     RefactoringStatus result = new RefactoringStatus();
     // prepare method information
     result.addStatus(_prepareMethod());
@@ -290,16 +290,14 @@
     // analyze method body
     result.addStatus(_prepareMethodParts());
     // process references
-    return searchEngine.searchReferences(_methodElement).then((references) {
-      _referenceProcessors.clear();
-      for (SearchMatch reference in references) {
-        _ReferenceProcessor processor =
-            new _ReferenceProcessor(this, reference);
-        _referenceProcessors.add(processor);
-      }
-    }).then((_) {
-      return result;
-    });
+    List<SearchMatch> references =
+        await searchEngine.searchReferences(_methodElement);
+    _referenceProcessors.clear();
+    for (SearchMatch reference in references) {
+      _ReferenceProcessor processor = new _ReferenceProcessor(this, reference);
+      _referenceProcessors.add(processor);
+    }
+    return result;
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
index b0e7197..0811b75 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/move_file.dart
@@ -56,10 +56,10 @@
   }
 
   @override
-  Future<SourceChange> createChange() {
+  Future<SourceChange> createChange() async {
     change = new SourceChange('Update File References');
     List<Source> librarySources = context.getLibrariesContaining(source);
-    return Future.forEach(librarySources, (Source librarySource) {
+    await Future.forEach(librarySources, (Source librarySource) async {
       CompilationUnitElement unitElement =
           context.getCompilationUnitElement(source, librarySource);
       if (unitElement != null) {
@@ -73,17 +73,16 @@
           _updateUriReferences(library.parts);
         }
         // update reference to the unit
-        return searchEngine.searchReferences(unitElement).then((matches) {
-          List<SourceReference> references = getSourceReferences(matches);
-          for (SourceReference reference in references) {
-            String newUri = _computeNewUri(reference);
-            reference.addEdit(change, "'$newUri'");
-          }
-        });
+        List<SearchMatch> matches =
+            await searchEngine.searchReferences(unitElement);
+        List<SourceReference> references = getSourceReferences(matches);
+        for (SourceReference reference in references) {
+          String newUri = _computeNewUri(reference);
+          reference.addEdit(change, "'$newUri'");
+        }
       }
-    }).then((_) {
-      return change;
     });
+    return change;
   }
 
   @override
diff --git a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
index 0654b95..ebb09d3 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/refactoring_internal.dart
@@ -45,18 +45,14 @@
   final List<String> potentialEditIds = <String>[];
 
   @override
-  Future<RefactoringStatus> checkAllConditions() {
+  Future<RefactoringStatus> checkAllConditions() async {
     RefactoringStatus result = new RefactoringStatus();
-    return checkInitialConditions().then((status) {
-      result.addStatus(status);
-      if (result.hasFatalError) {
-        return result;
-      }
-      return checkFinalConditions().then((status) {
-        result.addStatus(status);
-        return result;
-      });
-    });
+    result.addStatus(await checkInitialConditions());
+    if (result.hasFatalError) {
+      return result;
+    }
+    result.addStatus(await checkFinalConditions());
+    return result;
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index 746a8d6..1da2200 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -157,9 +157,10 @@
   }
 
   @override
-  Future<SourceChange> createChange() {
+  Future<SourceChange> createChange() async {
     change = new SourceChange(refactoringName);
-    return fillChange().then((_) => change);
+    await fillChange();
+    return change;
   }
 
   /**
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
index 321785e..25e979e 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_class_member.dart
@@ -82,7 +82,7 @@
   }
 
   @override
-  Future fillChange() {
+  Future fillChange() async {
     // update declarations
     for (Element renameElement in _validator.elements) {
       if (renameElement.isSynthetic && renameElement is FieldElement) {
@@ -95,24 +95,24 @@
     // update references
     addReferenceEdits(_validator.references);
     // potential matches
-    return searchEngine.searchMemberReferences(oldName).then((nameMatches) {
-      List<SourceReference> nameRefs = getSourceReferences(nameMatches);
-      for (SourceReference reference in nameRefs) {
-        // ignore resolved reference, we have already updated it
-        if (reference.isResolved) {
+    List<SearchMatch> nameMatches =
+        await searchEngine.searchMemberReferences(oldName);
+    List<SourceReference> nameRefs = getSourceReferences(nameMatches);
+    for (SourceReference reference in nameRefs) {
+      // ignore resolved reference, we have already updated it
+      if (reference.isResolved) {
+        continue;
+      }
+      // check the element being renamed is accessible
+      {
+        LibraryElement whereLibrary = reference.element.library;
+        if (!element.isAccessibleIn(whereLibrary)) {
           continue;
         }
-        // check the element being renamed is accessible
-        {
-          LibraryElement whereLibrary = reference.element.library;
-          if (!element.isAccessibleIn(whereLibrary)) {
-            continue;
-          }
-        }
-        // add edit
-        reference.addEdit(change, newName, id: _newPotentialId());
       }
-    });
+      // add edit
+      reference.addEdit(change, newName, id: _newPotentialId());
+    }
   }
 
   String _newPotentialId() {
@@ -149,7 +149,7 @@
         elementClass = element.enclosingElement,
         elementKind = element.kind;
 
-  Future<RefactoringStatus> validate() {
+  Future<RefactoringStatus> validate() async {
     RefactoringStatus result = new RefactoringStatus();
     // check if there is a member with "newName" in the same ClassElement
     for (Element newNameMember in getChildren(elementClass, name)) {
@@ -163,93 +163,85 @@
     }
     // do chained computations
     Set<ClassElement> superClasses = getSuperClasses(elementClass);
-    Set<ClassElement> subClasses;
-    return _prepareReferences().then((_) {
-      return getSubClasses(searchEngine, elementClass).then((_subs) {
-        subClasses = _subs;
-      });
-    }).then((_) {
-      // check shadowing in hierarchy
-      return searchEngine.searchElementDeclarations(name).then((decls) {
-        for (SearchMatch decl in decls) {
-          Element nameElement = getSyntheticAccessorVariable(decl.element);
-          Element nameClass = nameElement.enclosingElement;
-          // renamed Element shadows member of superclass
-          if (superClasses.contains(nameClass)) {
-            result.addError(
-                format(
-                    isRename ?
-                        "Renamed {0} will shadow {1} '{2}'." :
-                        "Created {0} will shadow {1} '{2}'.",
-                    elementKind.displayName,
-                    getElementKindName(nameElement),
-                    getElementQualifiedName(nameElement)),
-                newLocation_fromElement(nameElement));
-          }
-          // renamed Element is shadowed by member of subclass
-          if (isRename && subClasses.contains(nameClass)) {
-            result.addError(
-                format(
-                    "Renamed {0} will be shadowed by {1} '{2}'.",
-                    elementKind.displayName,
-                    getElementKindName(nameElement),
-                    getElementQualifiedName(nameElement)),
-                newLocation_fromElement(nameElement));
-          }
-          // renamed Element is shadowed by local
-          if (nameElement is LocalElement) {
-            LocalElement localElement = nameElement;
-            ClassElement enclosingClass =
-                nameElement.getAncestor((element) => element is ClassElement);
-            if (enclosingClass == elementClass ||
-                subClasses.contains(enclosingClass)) {
-              for (SearchMatch reference in references) {
-                if (isReferenceInLocalRange(localElement, reference)) {
-                  result.addError(
-                      format(
-                          "Usage of renamed {0} will be shadowed by {1} '{2}'.",
-                          elementKind.displayName,
-                          getElementKindName(localElement),
-                          localElement.displayName),
-                      newLocation_fromMatch(reference));
-                }
-              }
+    await _prepareReferences();
+    Set<ClassElement> subClasses =
+        await getSubClasses(searchEngine, elementClass);
+    // check shadowing in hierarchy
+    List<SearchMatch> declarations =
+        await searchEngine.searchElementDeclarations(name);
+    for (SearchMatch declaration in declarations) {
+      Element nameElement = getSyntheticAccessorVariable(declaration.element);
+      Element nameClass = nameElement.enclosingElement;
+      // renamed Element shadows member of superclass
+      if (superClasses.contains(nameClass)) {
+        result.addError(
+            format(
+                isRename ?
+                    "Renamed {0} will shadow {1} '{2}'." :
+                    "Created {0} will shadow {1} '{2}'.",
+                elementKind.displayName,
+                getElementKindName(nameElement),
+                getElementQualifiedName(nameElement)),
+            newLocation_fromElement(nameElement));
+      }
+      // renamed Element is shadowed by member of subclass
+      if (isRename && subClasses.contains(nameClass)) {
+        result.addError(
+            format(
+                "Renamed {0} will be shadowed by {1} '{2}'.",
+                elementKind.displayName,
+                getElementKindName(nameElement),
+                getElementQualifiedName(nameElement)),
+            newLocation_fromElement(nameElement));
+      }
+      // renamed Element is shadowed by local
+      if (nameElement is LocalElement) {
+        LocalElement localElement = nameElement;
+        ClassElement enclosingClass =
+            nameElement.getAncestor((element) => element is ClassElement);
+        if (enclosingClass == elementClass ||
+            subClasses.contains(enclosingClass)) {
+          for (SearchMatch reference in references) {
+            if (isReferenceInLocalRange(localElement, reference)) {
+              result.addError(
+                  format(
+                      "Usage of renamed {0} will be shadowed by {1} '{2}'.",
+                      elementKind.displayName,
+                      getElementKindName(localElement),
+                      localElement.displayName),
+                  newLocation_fromMatch(reference));
             }
           }
         }
-      });
-    }).then((_) => result);
+      }
+    }
+    // done
+    return result;
   }
 
   /**
    * Fills [elements] with [Element]s to rename.
    */
-  Future _prepareElements() {
+  Future _prepareElements() async {
     if (element is ClassMemberElement) {
-      return getHierarchyMembers(
-          searchEngine,
-          element).then((Set<Element> elements) {
-        this.elements = elements;
-      });
+      elements = await getHierarchyMembers(searchEngine, element);
     } else {
       elements = new Set.from([element]);
-      return new Future.value();
     }
   }
 
   /**
    * Fills [references] with all references to [elements].
    */
-  Future _prepareReferences() {
+  Future _prepareReferences() async {
     if (!isRename) {
       return new Future.value();
     }
-    return _prepareElements().then((_) {
-      return Future.forEach(elements, (Element element) {
-        return searchEngine.searchReferences(element).then((references) {
-          this.references.addAll(references);
-        });
-      });
+    await _prepareElements();
+    await Future.forEach(elements, (Element element) async {
+      List<SearchMatch> elementReferences =
+          await searchEngine.searchReferences(element);
+      references.addAll(elementReferences);
     });
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
index caecadd..544b79a 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_constructor.dart
@@ -50,17 +50,16 @@
   }
 
   @override
-  Future fillChange() {
+  Future fillChange() async {
     String replacement = newName.isEmpty ? '' : '.${newName}';
     // update references
-    return searchEngine.searchReferences(element).then((matches) {
-      List<SourceReference> references = getSourceReferences(matches);
-      if (!element.isSynthetic) {
-        for (SourceReference reference in references) {
-          reference.addEdit(change, replacement);
-        }
+    List<SearchMatch> matches = await searchEngine.searchReferences(element);
+    List<SourceReference> references = getSourceReferences(matches);
+    if (!element.isSynthetic) {
+      for (SourceReference reference in references) {
+        reference.addEdit(change, replacement);
       }
-    });
+    }
   }
 
   void _analyzePossibleConflicts(RefactoringStatus result) {
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
index 67c3968..8b8dfbf 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_import.dart
@@ -47,7 +47,7 @@
   }
 
   @override
-  Future fillChange() {
+  Future fillChange() async {
     // update declaration
     {
       PrefixElement prefix = element.prefix;
@@ -73,15 +73,14 @@
       }
     }
     // update references
-    return searchEngine.searchReferences(element).then((refMatches) {
-      List<SourceReference> references = getSourceReferences(refMatches);
-      for (SourceReference reference in references) {
-        if (newName.isEmpty) {
-          reference.addEdit(change, newName);
-        } else {
-          reference.addEdit(change, "${newName}.");
-        }
+    List<SearchMatch> matches = await searchEngine.searchReferences(element);
+    List<SourceReference> references = getSourceReferences(matches);
+    for (SourceReference reference in references) {
+      if (newName.isEmpty) {
+        reference.addEdit(change, newName);
+      } else {
+        reference.addEdit(change, "${newName}.");
       }
-    });
+    }
   }
 }
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
index 9a9d65e..1880928 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_unit_member.dart
@@ -140,16 +140,13 @@
     elementKind = element.kind;
   }
 
-  Future<RefactoringStatus> validate() {
+  Future<RefactoringStatus> validate() async {
     _validateWillConflict();
-    List<Future> futures = <Future>[];
     if (isRename) {
-      futures.add(_validateWillBeShadowed());
+      await _validateWillBeShadowed();
     }
-    futures.add(_validateWillShadow());
-    return Future.wait(futures).then((_) {
-      return result;
-    });
+    await _validateWillShadow();
+    return result;
   }
 
   /**
@@ -179,29 +176,27 @@
   /**
    * Validates if any usage of [element] renamed to [name] will be shadowed.
    */
-  Future _validateWillBeShadowed() {
+  Future _validateWillBeShadowed() async {
     if (!isRename) {
-      return new Future.value();
+      return;
     }
-    return searchEngine.searchReferences(element).then((references) {
-      for (SearchMatch reference in references) {
-        Element refElement = reference.element;
-        ClassElement refClass =
-            refElement.getAncestor((e) => e is ClassElement);
-        if (refClass != null) {
-          visitChildren(refClass, (shadow) {
-            if (hasDisplayName(shadow, name)) {
-              String message = format(
-                  "Reference to renamed {0} will be shadowed by {1} '{2}'.",
-                  getElementKindName(element),
-                  getElementKindName(shadow),
-                  getElementQualifiedName(shadow));
-              result.addError(message, newLocation_fromElement(shadow));
-            }
-          });
-        }
+    List<SearchMatch> references = await searchEngine.searchReferences(element);
+    for (SearchMatch reference in references) {
+      Element refElement = reference.element;
+      ClassElement refClass = refElement.getAncestor((e) => e is ClassElement);
+      if (refClass != null) {
+        visitChildren(refClass, (shadow) {
+          if (hasDisplayName(shadow, name)) {
+            String message = format(
+                "Reference to renamed {0} will be shadowed by {1} '{2}'.",
+                getElementKindName(element),
+                getElementKindName(shadow),
+                getElementQualifiedName(shadow));
+            result.addError(message, newLocation_fromElement(shadow));
+          }
+        });
       }
-    });
+    }
   }
 
   /**
@@ -223,40 +218,40 @@
   /**
    * Validates if renamed [element] will shadow any [Element] named [name].
    */
-  Future _validateWillShadow() {
-    return searchEngine.searchMemberDeclarations(name).then((declarations) {
-      return Future.forEach(declarations, (SearchMatch declaration) {
-        Element member = declaration.element;
-        ClassElement declaringClass = member.enclosingElement;
-        return searchEngine.searchReferences(member).then((memberReferences) {
-          for (SearchMatch memberReference in memberReferences) {
-            Element refElement = memberReference.element;
-            // cannot be shadowed if qualified
-            if (memberReference.isQualified) {
-              continue;
-            }
-            // cannot be shadowed if declared in the same class as reference
-            ClassElement refClass =
-                refElement.getAncestor((e) => e is ClassElement);
-            if (refClass == declaringClass) {
-              continue;
-            }
-            // ignore if not visible
-            if (!_isVisibleAt(element, memberReference)) {
-              continue;
-            }
-            // OK, reference will be shadowed be the element being renamed
-            String message = format(
-                isRename ?
-                    "Renamed {0} will shadow {1} '{2}'." :
-                    "Created {0} will shadow {1} '{2}'.",
-                elementKind.displayName,
-                getElementKindName(member),
-                getElementQualifiedName(member));
-            result.addError(message, newLocation_fromMatch(memberReference));
-          }
-        });
-      });
-    });
+  Future _validateWillShadow() async {
+    List<SearchMatch> declarations =
+        await searchEngine.searchMemberDeclarations(name);
+    for (SearchMatch declaration in declarations) {
+      Element member = declaration.element;
+      ClassElement declaringClass = member.enclosingElement;
+      List<SearchMatch> memberReferences =
+          await searchEngine.searchReferences(member);
+      for (SearchMatch memberReference in memberReferences) {
+        Element refElement = memberReference.element;
+        // cannot be shadowed if qualified
+        if (memberReference.isQualified) {
+          continue;
+        }
+        // cannot be shadowed if declared in the same class as reference
+        ClassElement refClass =
+            refElement.getAncestor((e) => e is ClassElement);
+        if (refClass == declaringClass) {
+          continue;
+        }
+        // ignore if not visible
+        if (!_isVisibleAt(element, memberReference)) {
+          continue;
+        }
+        // OK, reference will be shadowed be the element being renamed
+        String message = format(
+            isRename ?
+                "Renamed {0} will shadow {1} '{2}'." :
+                "Created {0} will shadow {1} '{2}'.",
+            elementKind.displayName,
+            getElementKindName(member),
+            getElementQualifiedName(member));
+        result.addError(message, newLocation_fromMatch(memberReference));
+      }
+    }
   }
 }
diff --git a/pkg/analysis_server/lib/src/status/ast_writer.dart b/pkg/analysis_server/lib/src/status/ast_writer.dart
index 97e9fa4..99229a0 100644
--- a/pkg/analysis_server/lib/src/status/ast_writer.dart
+++ b/pkg/analysis_server/lib/src/status/ast_writer.dart
@@ -6,8 +6,11 @@
 
 import 'dart:convert';
 
+import 'package:analysis_server/src/get_handler.dart';
 import 'package:analyzer/src/generated/ast.dart';
+import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/source.dart';
 
 /**
  * A visitor that will produce an HTML representation of an AST structure.
@@ -140,6 +143,7 @@
       _writeProperty("element", node.element);
     } else if (node is ExportDirective) {
       _writeProperty("element", node.element);
+      _writeProperty("source", node.source);
     } else if (node is FunctionExpressionInvocation) {
       _writeProperty('static element', node.staticElement);
       _writeProperty('static type', node.staticType);
@@ -147,10 +151,12 @@
       _writeProperty('propagated type', node.propagatedType);
     } else if (node is ImportDirective) {
       _writeProperty("element", node.element);
+      _writeProperty("source", node.source);
     } else if (node is LibraryDirective) {
       _writeProperty("element", node.element);
     } else if (node is PartDirective) {
       _writeProperty("element", node.element);
+      _writeProperty("source", node.source);
     } else if (node is PartOfDirective) {
       _writeProperty("element", node.element);
     } else if (node is PostfixExpression) {
@@ -183,7 +189,11 @@
     if (value != null) {
       String valueString = null;
       try {
-        valueString = value.toString();
+        if (value is Source) {
+          valueString = 'Source (uri="${value.uri}", path="${value.fullName}")';
+        } else {
+          valueString = value.toString();
+        }
       } catch (exception, stackTrace) {
         exceptions.add(new CaughtException(exception, stackTrace));
       }
@@ -195,6 +205,16 @@
         buffer.write('</span>');
       } else {
         buffer.write(HTML_ESCAPE.convert(valueString));
+        if (value is Element && value is! LibraryElement) {
+          String name = value.name;
+          if (name != null) {
+            buffer.write('&nbsp;&nbsp;[');
+            buffer.write(GetHandler.makeLink(GetHandler.INDEX_ELEMENT_BY_NAME, {
+              'name': name
+            }, 'search index'));
+            buffer.write(']');
+          }
+        }
       }
       buffer.write('<br>');
     }
diff --git a/pkg/analysis_server/lib/src/status/element_writer.dart b/pkg/analysis_server/lib/src/status/element_writer.dart
index be7e59c..6625a43 100644
--- a/pkg/analysis_server/lib/src/status/element_writer.dart
+++ b/pkg/analysis_server/lib/src/status/element_writer.dart
@@ -6,6 +6,7 @@
 
 import 'dart:convert';
 
+import 'package:analysis_server/src/get_handler.dart';
 import 'package:analyzer/src/generated/element.dart';
 
 /**
@@ -42,7 +43,18 @@
     }
     buffer.write(' <span style="color:gray">(');
     buffer.write(element.runtimeType);
-    buffer.write(')</span><br>');
+    buffer.write(')</span>');
+    if (element is! LibraryElement) {
+      String name = element.name;
+      if (name != null) {
+        buffer.write('&nbsp;&nbsp;[');
+        buffer.write(GetHandler.makeLink(GetHandler.INDEX_ELEMENT_BY_NAME, {
+          'name': name
+        }, 'search index'));
+        buffer.write(']');
+      }
+    }
+    buffer.write('<br>');
     indentLevel++;
     try {
       element.visitChildren(this);
diff --git a/pkg/analysis_server/test/analysis/update_content_test.dart b/pkg/analysis_server/test/analysis/update_content_test.dart
index f4d5bca..5b780a7 100644
--- a/pkg/analysis_server/test/analysis/update_content_test.dart
+++ b/pkg/analysis_server/test/analysis/update_content_test.dart
@@ -21,6 +21,8 @@
 @reflectiveTest
 class UpdateContentTest extends AbstractAnalysisTest {
   Map<String, List<AnalysisError>> filesErrors = {};
+  int serverErrorCount = 0;
+  int navigationCount = 0;
 
   @override
   void processNotification(Notification notification) {
@@ -28,6 +30,37 @@
       var decoded = new AnalysisErrorsParams.fromNotification(notification);
       filesErrors[decoded.file] = decoded.errors;
     }
+    if (notification.event == ANALYSIS_NAVIGATION) {
+      navigationCount++;
+    }
+    if (notification.event == SERVER_ERROR) {
+      serverErrorCount++;
+    }
+  }
+
+  test_discardNotifications_onSourceChange() async {
+    createProject();
+    addTestFile('');
+    await server.onAnalysisComplete;
+    server.setAnalysisSubscriptions({
+      AnalysisService.NAVIGATION: [testFile].toSet()
+    });
+    // update file, analyze, but don't sent notifications
+    navigationCount = 0;
+    server.updateContent('1', {
+      testFile: new AddContentOverlay('foo() {}')
+    });
+    server.test_performAllAnalysisOperations();
+    expect(serverErrorCount, 0);
+    expect(navigationCount, 0);
+    // replace the file contents,
+    // should discard any pending notification operations
+    server.updateContent('2', {
+      testFile: new AddContentOverlay('bar() {}')
+    });
+    await server.onAnalysisComplete;
+    expect(serverErrorCount, 0);
+    expect(navigationCount, 1);
   }
 
   test_illegal_ChangeContentOverlay() {
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index 90ab3ca..2a8a68c 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -136,6 +136,34 @@
     });
   }
 
+  test_getAnalysisContext_nested() {
+    String dir1Path = '/dir1';
+    String dir2Path = dir1Path + '/dir2';
+    String filePath = dir2Path + '/file.dart';
+    Folder dir1 = resourceProvider.newFolder(dir1Path);
+    Folder dir2 = resourceProvider.newFolder(dir2Path);
+    resourceProvider.newFile(filePath, 'library lib;');
+
+    AnalysisContext context1 = AnalysisEngine.instance.createAnalysisContext();
+    AnalysisContext context2 = AnalysisEngine.instance.createAnalysisContext();
+    server.folderMap[dir1] = context1;
+    server.folderMap[dir2] = context2;
+
+    expect(server.getAnalysisContext(filePath), context2);
+  }
+
+  test_getAnalysisContext_simple() {
+    String dirPath = '/dir';
+    String filePath = dirPath + '/file.dart';
+    Folder dir = resourceProvider.newFolder(dirPath);
+    resourceProvider.newFile(filePath, 'library lib;');
+
+    AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+    server.folderMap[dir] = context;
+
+    expect(server.getAnalysisContext(filePath), context);
+  }
+
   Future test_contextsChangedEvent() {
     resourceProvider.newFolder('/foo');
 
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 08fa7e6..21307d5 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -364,46 +364,6 @@
     });
   }
 
-  test_partFile() {
-    addFile('/project/bin/testA.dart', '''
-      library libA;
-      part "$testFile";
-      import 'dart:html';
-      class A { }
-    ''');
-    addTestFile('''
-      part of libA;
-      main() {^}''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
-      assertNoResult('test');
-    });
-  }
-
-  test_partFile2() {
-    addFile('/testA.dart', '''
-      part of libA;
-      class A { }''');
-    addTestFile('''
-      library libA;
-      part "/testA.dart";
-      import 'dart:html';
-      main() {^}
-    ''');
-    return getSuggestions().then((_) {
-      expect(replacementOffset, equals(completionOffset));
-      expect(replacementLength, equals(0));
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
-      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
-      assertNoResult('test');
-    });
-  }
-
   test_imports_prefixed() {
     addTestFile('''
       import 'dart:html' as foo;
@@ -484,6 +444,61 @@
     });
   }
 
+  test_partFile() {
+    addFile('/project/bin/testA.dart', '''
+      library libA;
+      part "$testFile";
+      import 'dart:html';
+      class A { }
+    ''');
+    addTestFile('''
+      part of libA;
+      main() {^}''');
+    return getSuggestions().then((_) {
+      expect(replacementOffset, equals(completionOffset));
+      expect(replacementLength, equals(0));
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
+      assertNoResult('test');
+    });
+  }
+
+  test_partFile2() {
+    addFile('/testA.dart', '''
+      part of libA;
+      class A { }''');
+    addTestFile('''
+      library libA;
+      part "/testA.dart";
+      import 'dart:html';
+      main() {^}
+    ''');
+    return getSuggestions().then((_) {
+      expect(replacementOffset, equals(completionOffset));
+      expect(replacementLength, equals(0));
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'HtmlElement');
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'A');
+      assertNoResult('test');
+    });
+  }
+
+  test_simple() {
+    addTestFile('''
+      void main() {
+        ^
+      }
+    ''');
+    return getSuggestions().then((_) {
+      expect(replacementOffset, equals(completionOffset));
+      expect(replacementLength, equals(0));
+      assertHasResult(CompletionSuggestionKind.INVOCATION, 'Object');
+      assertNoResult('HtmlElement');
+      assertNoResult('test');
+    });
+  }
+
   test_topLevel() {
     addTestFile('''
       typedef foo();
diff --git a/pkg/analysis_server/test/domain_execution_test.dart b/pkg/analysis_server/test/domain_execution_test.dart
index a77ccf8..60c2454 100644
--- a/pkg/analysis_server/test/domain_execution_test.dart
+++ b/pkg/analysis_server/test/domain_execution_test.dart
@@ -10,10 +10,12 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_execution.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/file_system/memory_file_system.dart';
 import 'package:analyzer/instrumentation/instrumentation.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/source_io.dart';
 import 'package:typed_mock/typed_mock.dart';
 import 'package:unittest/unittest.dart';
 
@@ -84,64 +86,103 @@
       });
     });
 
-//    group('mapUri', () {
-//      String contextId;
-//
-//      setUp(() {
-//        Request request =
-//            new ExecutionCreateContextParams('/a/b.dart').toRequest('0');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseSuccess('0'));
-//        ExecutionCreateContextResult result =
-//            new ExecutionCreateContextResult.fromResponse(response);
-//        contextId = result.id;
-//      });
-//
-//      tearDown(() {
-//        Request request =
-//            new ExecutionDeleteContextParams(contextId).toRequest('1');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseSuccess('1'));
-//      });
-//
-//      test('file to URI', () {
-//        Request request =
-//            new ExecutionMapUriParams(contextId, file: '/a/b.dart').toRequest('2');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseSuccess('2'));
-//        ExecutionMapUriResult result =
-//            new ExecutionMapUriResult.fromResponse(response);
-//        expect(result.file, isNull);
-//        expect(result.uri, isNotNull);
-//        // TODO(brianwilkerson) Test for the correct result.
-//      });
-//
-//      test('URI to file', () {
-//        Request request =
-//            new ExecutionMapUriParams(contextId, uri: '/a/b.dart').toRequest('3');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseSuccess('3'));
-//        ExecutionMapUriResult result =
-//            new ExecutionMapUriResult.fromResponse(response);
-//        expect(result.file, isNotNull);
-//        expect(result.uri, isNull);
-//        // TODO(brianwilkerson) Test for the correct result.
-//      });
-//
-//      test('invalid context id', () {
-//        Request request =
-//            new ExecutionMapUriParams('xxx', uri: '').toRequest('4');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseFailure('4'));
-//      });
-//
-//      test('both file and uri', () {
-//        Request request =
-//            new ExecutionMapUriParams('xxx', file: '', uri: '').toRequest('5');
-//        Response response = handler.handleRequest(request);
-//        expect(response, isResponseFailure('5'));
-//      });
-//    });
+    group('mapUri', () {
+      String contextId;
+
+      setUp(() {
+        Folder folder = provider.newFile('/a/b.dart', '').parent;
+        server.folderMap.putIfAbsent(folder, () {
+          SourceFactory factory =
+              new SourceFactory([new ResourceUriResolver(provider)]);
+          AnalysisContext context =
+              AnalysisEngine.instance.createAnalysisContext();
+          context.sourceFactory = factory;
+          return context;
+        });
+        Request request =
+            new ExecutionCreateContextParams('/a/b.dart').toRequest('0');
+        Response response = handler.handleRequest(request);
+        expect(response, isResponseSuccess('0'));
+        ExecutionCreateContextResult result =
+            new ExecutionCreateContextResult.fromResponse(response);
+        contextId = result.id;
+      });
+
+      tearDown(() {
+        Request request =
+            new ExecutionDeleteContextParams(contextId).toRequest('1');
+        Response response = handler.handleRequest(request);
+        expect(response, isResponseSuccess('1'));
+      });
+
+      group('file to URI', () {
+        test('does not exist', () {
+          Request request =
+              new ExecutionMapUriParams(contextId, file: '/a/c.dart').toRequest('2');
+          Response response = handler.handleRequest(request);
+          expect(response, isResponseFailure('2'));
+        });
+
+        test('directory', () {
+          provider.newFolder('/a/d');
+          Request request =
+              new ExecutionMapUriParams(contextId, file: '/a/d').toRequest('2');
+          Response response = handler.handleRequest(request);
+          expect(response, isResponseFailure('2'));
+        });
+
+        test('valid', () {
+          Request request =
+              new ExecutionMapUriParams(contextId, file: '/a/b.dart').toRequest('2');
+          Response response = handler.handleRequest(request);
+          expect(response, isResponseSuccess('2'));
+          ExecutionMapUriResult result =
+              new ExecutionMapUriResult.fromResponse(response);
+          expect(result.file, isNull);
+          expect(result.uri, 'file:///a/b.dart');
+        });
+      });
+
+      group('URI to file', () {
+        test('invalid', () {
+          Request request =
+              new ExecutionMapUriParams(contextId, uri: 'foo:///a/b.dart').toRequest('2');
+          Response response = handler.handleRequest(request);
+          expect(response, isResponseFailure('2'));
+        });
+
+        test('valid', () {
+          Request request =
+              new ExecutionMapUriParams(contextId, uri: 'file:///a/b.dart').toRequest('2');
+          Response response = handler.handleRequest(request);
+          expect(response, isResponseSuccess('2'));
+          ExecutionMapUriResult result =
+              new ExecutionMapUriResult.fromResponse(response);
+          expect(result.file, '/a/b.dart');
+          expect(result.uri, isNull);
+        });
+      });
+
+      test('invalid context id', () {
+        Request request =
+            new ExecutionMapUriParams('xxx', uri: '').toRequest('4');
+        Response response = handler.handleRequest(request);
+        expect(response, isResponseFailure('4'));
+      });
+
+      test('both file and uri', () {
+        Request request =
+            new ExecutionMapUriParams('xxx', file: '', uri: '').toRequest('5');
+        Response response = handler.handleRequest(request);
+        expect(response, isResponseFailure('5'));
+      });
+
+      test('neither file nor uri', () {
+        Request request = new ExecutionMapUriParams('xxx').toRequest('6');
+        Response response = handler.handleRequest(request);
+        expect(response, isResponseFailure('6'));
+      });
+    });
 
     group('setSubscriptions', () {
       test('failure - invalid service name', () {
diff --git a/pkg/analysis_server/test/domain_server_test.dart b/pkg/analysis_server/test/domain_server_test.dart
index 2b3cad1..dc76e84 100644
--- a/pkg/analysis_server/test/domain_server_test.dart
+++ b/pkg/analysis_server/test/domain_server_test.dart
@@ -40,7 +40,7 @@
       expect(response.toJson(), equals({
         Response.ID: '0',
         Response.RESULT: {
-          VERSION: '1.0.0'
+          VERSION: AnalysisServer.VERSION
         }
       }));
     });
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 4850c83..f49ae4a 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -314,13 +314,26 @@
   }
 
   /**
-   * Force the re-analysis of everything contained in the existing analysis
+   * Force the re-analysis of everything contained in the specified analysis
    * roots. This will cause all previously computed analysis results to be
    * discarded and recomputed, and will cause all subscribed notifications to
    * be re-sent.
+   *
+   * If no analysis roots are provided, then all current analysis roots will be
+   * re-analyzed. If an empty list of analysis roots is provided, then nothing
+   * will be re-analyzed. If the list contains one or more paths that are not
+   * currently analysis roots, then an error of type INVALID_ANALYSIS_ROOT will
+   * be generated.
+   *
+   * Parameters
+   *
+   * roots ( optional List<FilePath> )
+   *
+   *   A list of the analysis roots that are to be re-analyzed.
    */
-  Future sendAnalysisReanalyze() {
-    return server.send("analysis.reanalyze", null)
+  Future sendAnalysisReanalyze({List<String> roots}) {
+    var params = new AnalysisReanalyzeParams(roots: roots).toJson();
+    return server.send("analysis.reanalyze", params)
         .then((result) {
       expect(result, isNull);
       return null;
@@ -1047,7 +1060,9 @@
    * text is passed in so that the selection can be preserved across the
    * formatting operation. The updated selection will be as close to matching
    * the original as possible, but whitespace at the beginning or end of the
-   * selected region will be ignored.
+   * selected region will be ignored. If preserving selection information is
+   * not required, zero (0) can be specified for both the selection offset and
+   * selection length.
    *
    * If a request is made for a file which does not exist, or which is not
    * currently subject to analysis (e.g. because it is not associated with any
@@ -1062,15 +1077,11 @@
    *
    * selectionOffset ( int )
    *
-   *   The offset of the current selection in the file. In case preserving,
-   *   selection information is not required, 0 can be specified for both
-   *   selection offset and length.
+   *   The offset of the current selection in the file.
    *
    * selectionLength ( int )
    *
-   *   The length of the current selection in the file. In case preserving,
-   *   selection information is not required, 0 can be specified for both
-   *   selection offset and length.
+   *   The length of the current selection in the file.
    *
    * Returns
    *
@@ -1325,7 +1336,8 @@
    *
    * contextRoot ( FilePath )
    *
-   *   The path of the Dart or HTML file that will be launched.
+   *   The path of the Dart or HTML file that will be launched, or the path of
+   *   the directory containing the file.
    *
    * Returns
    *
@@ -1366,22 +1378,22 @@
    * Map a URI from the execution context to the file that it corresponds to,
    * or map a file to the URI that it corresponds to in the execution context.
    *
-   * Exactly one of the file and uri fields must be provided.
+   * Exactly one of the file and uri fields must be provided. If both fields
+   * are provided, then an error of type INVALID_PARAMETER will be generated.
+   * Similarly, if neither field is provided, then an error of type
+   * INVALID_PARAMETER will be generated.
    *
    * If the file field is provided and the value is not the path of a file
    * (either the file does not exist or the path references something other
-   * than a file), then an error of type MAP_URI_INVALID_FILE will be
-   * generated.
+   * than a file), then an error of type INVALID_PARAMETER will be generated.
    *
    * If the uri field is provided and the value is not a valid URI or if the
    * URI references something that is not a file (either a file that does not
    * exist or something other than a file), then an error of type
-   * MAP_URI_INVALID_URI will be generated.
+   * INVALID_PARAMETER will be generated.
    *
-   * If the contextRoot used to create the execution context is not a file
-   * (either the file does not exist or the path references something other
-   * than a file), then an error of type INVALID_EXECUTION_CONTEXT will be
-   * generated.
+   * If the contextRoot used to create the execution context does not exist,
+   * then an error of type INVALID_EXECUTION_CONTEXT will be generated.
    *
    * Parameters
    *
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 3605eee..6072aec 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -198,8 +198,15 @@
 
 /**
  * analysis.reanalyze params
+ *
+ * {
+ *   "roots": optional List<FilePath>
+ * }
  */
-final Matcher isAnalysisReanalyzeParams = isNull;
+final Matcher isAnalysisReanalyzeParams = new LazyMatcher(() => new MatchesJsonObject(
+  "analysis.reanalyze params", null, optionalFields: {
+    "roots": isListOf(isFilePath)
+  }));
 
 /**
  * analysis.reanalyze result
@@ -1799,6 +1806,7 @@
  *   CONTENT_MODIFIED
  *   FORMAT_INVALID_FILE
  *   GET_ERRORS_INVALID_FILE
+ *   INVALID_EXECUTION_CONTEXT
  *   INVALID_OVERLAY_CHANGE
  *   INVALID_PARAMETER
  *   INVALID_REQUEST
@@ -1816,6 +1824,7 @@
   "CONTENT_MODIFIED",
   "FORMAT_INVALID_FILE",
   "GET_ERRORS_INVALID_FILE",
+  "INVALID_EXECUTION_CONTEXT",
   "INVALID_OVERLAY_CHANGE",
   "INVALID_PARAMETER",
   "INVALID_REQUEST",
diff --git a/pkg/analysis_server/test/operation/operation_queue_test.dart b/pkg/analysis_server/test/operation/operation_queue_test.dart
index 0a4f13e..2fd7100 100644
--- a/pkg/analysis_server/test/operation/operation_queue_test.dart
+++ b/pkg/analysis_server/test/operation/operation_queue_test.dart
@@ -9,108 +9,17 @@
 import 'package:analysis_server/src/operation/operation_analysis.dart';
 import 'package:analysis_server/src/operation/operation_queue.dart';
 import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
 import 'package:typed_mock/typed_mock.dart';
 import 'package:unittest/unittest.dart';
+
 import '../mocks.dart';
-import 'package:analyzer/src/generated/source.dart';
+import '../reflective_tests.dart';
+
 
 main() {
   groupSep = ' | ';
-
-  group('ServerOperationQueue', () {
-    ServerOperationQueue queue;
-
-    setUp(() {
-      queue = new ServerOperationQueue();
-    });
-
-    test('clear', () {
-      var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
-      var operationB = mockOperation(ServerOperationPriority.ANALYSIS_CONTINUE);
-      queue.add(operationA);
-      queue.add(operationB);
-      // there are some operations
-      expect(queue.isEmpty, false);
-      // clear - no operations
-      queue.clear();
-      expect(queue.isEmpty, true);
-    });
-
-    group('isEmpty', () {
-      test('true', () {
-        expect(queue.isEmpty, isTrue);
-      });
-
-      test('false', () {
-        var operation = mockOperation(ServerOperationPriority.ANALYSIS);
-        queue.add(operation);
-        expect(queue.isEmpty, isFalse);
-      });
-    });
-
-    group('take', () {
-      test('empty', () {
-        expect(queue.take(), isNull);
-      });
-
-      test('use operation priorities', () {
-        var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
-        var operationB =
-            mockOperation(ServerOperationPriority.ANALYSIS_CONTINUE);
-        var operationC =
-            mockOperation(ServerOperationPriority.PRIORITY_ANALYSIS);
-        queue.add(operationA);
-        queue.add(operationB);
-        queue.add(operationC);
-        expect(queue.take(), operationC);
-        expect(queue.take(), operationB);
-        expect(queue.take(), operationA);
-        expect(queue.take(), isNull);
-      });
-
-      test('continue analysis first', () {
-        var analysisContext = new AnalysisContextMock();
-        var operationA = new PerformAnalysisOperation(analysisContext, false);
-        var operationB = new PerformAnalysisOperation(analysisContext, true);
-        queue.add(operationA);
-        queue.add(operationB);
-        expect(queue.take(), operationB);
-        expect(queue.take(), operationA);
-        expect(queue.take(), isNull);
-      });
-
-      test('priority context first', () {
-        var prioritySource = new MockSource();
-        var analysisContextA = new AnalysisContextMock();
-        var analysisContextB = new AnalysisContextMock();
-        analysisContextB.prioritySources = [prioritySource];
-        var operationA = new PerformAnalysisOperation(analysisContextA, false);
-        var operationB = new PerformAnalysisOperation(analysisContextB, false);
-        queue.add(operationA);
-        queue.add(operationB);
-        expect(queue.take(), operationB);
-        expect(queue.take(), operationA);
-        expect(queue.take(), isNull);
-      });
-
-      test('reschedule', () {
-        var prioritySource = new MockSource();
-        var analysisContextA = new AnalysisContextMock();
-        var analysisContextB = new AnalysisContextMock();
-        var operationA = new PerformAnalysisOperation(analysisContextA, false);
-        var operationB = new PerformAnalysisOperation(analysisContextB, false);
-        queue.add(operationA);
-        queue.add(operationB);
-        // update priority sources and reschedule
-        analysisContextB.prioritySources = [prioritySource];
-        queue.reschedule();
-        // verify order
-        expect(queue.take(), operationB);
-        expect(queue.take(), operationA);
-        expect(queue.take(), isNull);
-      });
-    });
-  });
+  runReflectiveTests(ServerOperationQueueTest);
 }
 
 
@@ -118,7 +27,7 @@
  *  Return a [ServerOperation] mock with the given priority.
  */
 ServerOperation mockOperation(ServerOperationPriority priority) {
-  ServerOperation operation = new ServerOperationMock();
+  ServerOperation operation = new _ServerOperationMock();
   when(operation.priority).thenReturn(priority);
   return operation;
 }
@@ -130,15 +39,144 @@
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
+
 class AnalysisServerMock extends TypedMock implements AnalysisServer {
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
+
 class ServerContextManagerMock extends TypedMock implements ServerContextManager
     {
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
 
-class ServerOperationMock extends TypedMock implements ServerOperation {
+
+@reflectiveTest
+class ServerOperationQueueTest {
+  ServerOperationQueue queue = new ServerOperationQueue();
+
+  void test_clear() {
+    var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
+    var operationB = mockOperation(ServerOperationPriority.ANALYSIS_CONTINUE);
+    queue.add(operationA);
+    queue.add(operationB);
+    // there are some operations
+    expect(queue.isEmpty, false);
+    // clear - no operations
+    queue.clear();
+    expect(queue.isEmpty, true);
+  }
+
+  void test_isEmpty_false() {
+    var operation = mockOperation(ServerOperationPriority.ANALYSIS);
+    queue.add(operation);
+    expect(queue.isEmpty, isFalse);
+  }
+
+  void test_isEmpty_true() {
+    expect(queue.isEmpty, isTrue);
+  }
+
+  void test_reschedule() {
+    var prioritySource = new MockSource();
+    var analysisContextA = new AnalysisContextMock();
+    var analysisContextB = new AnalysisContextMock();
+    var operationA = new PerformAnalysisOperation(analysisContextA, false);
+    var operationB = new PerformAnalysisOperation(analysisContextB, false);
+    queue.add(operationA);
+    queue.add(operationB);
+    // update priority sources and reschedule
+    analysisContextB.prioritySources = [prioritySource];
+    queue.reschedule();
+    // verify order
+    expect(queue.take(), operationB);
+    expect(queue.take(), operationA);
+    expect(queue.take(), isNull);
+  }
+
+  void test_sourceAboutToChange() {
+    Source sourceA = new _SourceMock();
+    Source sourceB = new _SourceMock();
+    var opA1 = new _SourceSensitiveOperationMock(sourceA);
+    var opA2 = new _SourceSensitiveOperationMock(sourceA);
+    var opB1 = new _SourceSensitiveOperationMock(sourceB);
+    var opB2 = new _SourceSensitiveOperationMock(sourceB);
+    queue.add(opA1);
+    queue.add(opB1);
+    queue.add(opA2);
+    queue.add(opB2);
+    queue.sourceAboutToChange(sourceA);
+    expect(queue.take(), same(opB1));
+    expect(queue.take(), same(opB2));
+  }
+
+  void test_take_continueAnalysisFirst() {
+    var analysisContext = new AnalysisContextMock();
+    var operationA = new PerformAnalysisOperation(analysisContext, false);
+    var operationB = new PerformAnalysisOperation(analysisContext, true);
+    queue.add(operationA);
+    queue.add(operationB);
+    expect(queue.take(), operationB);
+    expect(queue.take(), operationA);
+    expect(queue.take(), isNull);
+  }
+
+  void test_take_empty() {
+    expect(queue.take(), isNull);
+  }
+
+  void test_take_priorityContextFirst() {
+    var prioritySource = new MockSource();
+    var analysisContextA = new AnalysisContextMock();
+    var analysisContextB = new AnalysisContextMock();
+    analysisContextB.prioritySources = [prioritySource];
+    var operationA = new PerformAnalysisOperation(analysisContextA, false);
+    var operationB = new PerformAnalysisOperation(analysisContextB, false);
+    queue.add(operationA);
+    queue.add(operationB);
+    expect(queue.take(), operationB);
+    expect(queue.take(), operationA);
+    expect(queue.take(), isNull);
+  }
+
+  void test_take_useOperationPriorities() {
+    var operationA = mockOperation(ServerOperationPriority.ANALYSIS);
+    var operationB = mockOperation(ServerOperationPriority.ANALYSIS_CONTINUE);
+    var operationC = mockOperation(ServerOperationPriority.PRIORITY_ANALYSIS);
+    queue.add(operationA);
+    queue.add(operationB);
+    queue.add(operationC);
+    expect(queue.take(), operationC);
+    expect(queue.take(), operationB);
+    expect(queue.take(), operationA);
+    expect(queue.take(), isNull);
+  }
+}
+
+
+class _ServerOperationMock extends TypedMock implements ServerOperation {
   noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
 }
+
+class _SourceMock extends TypedMock implements Source {
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _SourceSensitiveOperationMock extends TypedMock implements
+    SourceSensitiveOperation {
+  final Source source;
+
+  _SourceSensitiveOperationMock(this.source);
+
+  @override
+  ServerOperationPriority get priority {
+    return ServerOperationPriority.ANALYSIS_NOTIFICATION;
+  }
+
+  noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+  @override
+  bool shouldBeDiscardedOnSourceChange(Source source) {
+    return source == this.source;
+  }
+}
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 1b252f3..5db7631 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -531,6 +531,41 @@
     assertNoAssistAt('var ', AssistKind.ADD_TYPE_ANNOTATION);
   }
 
+  void test_addTypeAnnotation_parameter_BAD_hasExplicitType() {
+    _indexTestUnit('''
+foo(f(int p)) {}
+main() {
+  foo((num test) {});
+}
+''');
+    assertNoAssistAt('test', AssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  void test_addTypeAnnotation_parameter_BAD_noPropagatedType() {
+    _indexTestUnit('''
+foo(f(p)) {}
+main() {
+  foo((test) {});
+}
+''');
+    assertNoAssistAt('test', AssistKind.ADD_TYPE_ANNOTATION);
+  }
+
+  void test_addTypeAnnotation_parameter_OK() {
+    _indexTestUnit('''
+foo(f(int p)) {}
+main() {
+  foo((test) {});
+}
+''');
+    assertHasAssistAt('test', AssistKind.ADD_TYPE_ANNOTATION, '''
+foo(f(int p)) {}
+main() {
+  foo((int test) {});
+}
+''');
+  }
+
   void test_addTypeAnnotation_topLevelField_OK_int() {
     _indexTestUnit('''
 var V = 0;
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 3ca13a6..9e33386 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -12,6 +12,7 @@
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
 import 'package:analyzer/src/generated/error.dart';
+import 'package:analyzer/src/generated/parser.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:unittest/unittest.dart';
 
@@ -26,12 +27,15 @@
 }
 
 
+typedef bool AnalysisErrorFilter(AnalysisError error);
+
+
 @reflectiveTest
 class FixProcessorTest extends AbstractSingleUnitTest {
   Index index;
   SearchEngineImpl searchEngine;
 
-  bool checkHasSingleError = true;
+  AnalysisErrorFilter errorFilter = null;
 
   Fix fix;
   SourceChange change;
@@ -104,6 +108,59 @@
     verifyNoTestUnitErrors = false;
   }
 
+  void test_addSync_blockFunctionBody() {
+    _indexTestUnit('''
+foo() {}
+main() {
+  await foo();
+}
+''');
+    List<AnalysisError> errors = context.computeErrors(testSource);
+    expect(errors, hasLength(2));
+    // ParserError: Expected to find ';'
+    {
+      AnalysisError error = errors[0];
+      expect(error.message, "Expected to find ';'");
+      List<Fix> fixes = computeFixes(searchEngine, testUnit, error);
+      expect(fixes, isEmpty);
+    }
+    // Undefined name 'await'
+    {
+      AnalysisError error = errors[1];
+      expect(error.message, "Undefined name 'await'");
+      List<Fix> fixes = computeFixes(searchEngine, testUnit, error);
+      // has exactly one fix
+      expect(fixes, hasLength(1));
+      Fix fix = fixes[0];
+      expect(fix.kind, FixKind.ADD_ASYNC);
+      // apply to "file"
+      List<SourceFileEdit> fileEdits = fix.change.edits;
+      expect(fileEdits, hasLength(1));
+      resultCode = SourceEdit.applySequence(testCode, fileEdits[0].edits);
+      // verify
+      expect(resultCode, '''
+foo() {}
+main() async {
+  await foo();
+}
+''');
+    }
+  }
+
+  void test_addSync_expressionFunctionBody() {
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+    };
+    _indexTestUnit('''
+foo() {}
+main() => await foo();
+''');
+    assertHasFix(FixKind.ADD_ASYNC, '''
+foo() {}
+main() async => await foo();
+''');
+  }
+
   void test_boolean() {
     _indexTestUnit('''
 main() {
@@ -395,6 +452,15 @@
     assertNoFix(FixKind.CREATE_CONSTRUCTOR_SUPER);
   }
 
+  void test_createField_BAD_inSDK() {
+    _indexTestUnit('''
+main(List p) {
+  p.foo = 1;
+}
+''');
+    assertNoFix(FixKind.CREATE_FIELD);
+  }
+
   void test_createField_getter_multiLevel() {
     _indexTestUnit('''
 class A {
@@ -694,6 +760,15 @@
     expect(fileEdit.edits[0].replacement, contains('library my.file;'));
   }
 
+  void test_createGetter_BAD_inSDK() {
+    _indexTestUnit('''
+main(List p) {
+  int v = p.foo;
+}
+''');
+    assertNoFix(FixKind.CREATE_GETTER);
+  }
+
   void test_createGetter_multiLevel() {
     _indexTestUnit('''
 class A {
@@ -836,7 +911,6 @@
   }
 }
 ''');
-    // TODO
     assertHasFix(FixKind.CREATE_GETTER, '''
 class A {
   get test => null;
@@ -848,6 +922,34 @@
 ''');
   }
 
+  void test_createLocalVariable_functionType_named() {
+    _indexTestUnit('''
+typedef MY_FUNCTION(int p);
+foo(MY_FUNCTION f) {}
+main() {
+  foo(bar);
+}
+''');
+    assertHasFix(FixKind.CREATE_LOCAL_VARIABLE, '''
+typedef MY_FUNCTION(int p);
+foo(MY_FUNCTION f) {}
+main() {
+  MY_FUNCTION bar;
+  foo(bar);
+}
+''');
+  }
+
+  void test_createLocalVariable_functionType_synthetic() {
+    _indexTestUnit('''
+foo(f(int p)) {}
+main() {
+  foo(bar);
+}
+''');
+    assertNoFix(FixKind.CREATE_LOCAL_VARIABLE);
+  }
+
   void test_createLocalVariable_read_typeAssignment() {
     _indexTestUnit('''
 main() {
@@ -1744,6 +1846,21 @@
 ''');
   }
 
+  void test_importLibrarySdk_withType_AsExpression() {
+    _indexTestUnit('''
+main(p) {
+  p as Future;
+}
+''');
+    assertHasFix(FixKind.IMPORT_LIBRARY_SDK, '''
+import 'dart:async';
+
+main(p) {
+  p as Future;
+}
+''');
+  }
+
   void test_importLibrarySdk_withType_invocationTarget() {
     _indexTestUnit('''
 main() {
@@ -1759,6 +1876,21 @@
 ''');
   }
 
+  void test_importLibrarySdk_withType_IsExpression() {
+    _indexTestUnit('''
+main(p) {
+  p is Future;
+}
+''');
+    assertHasFix(FixKind.IMPORT_LIBRARY_SDK, '''
+import 'dart:async';
+
+main(p) {
+  p is Future;
+}
+''');
+  }
+
   void test_importLibrarySdk_withType_typeAnnotation() {
     _indexTestUnit('''
 main() {
@@ -1992,7 +2124,9 @@
   }
 
   void test_replaceVarWithDynamic() {
-    checkHasSingleError = false;
+    errorFilter = (AnalysisError error) {
+      return error.errorCode == ParserErrorCode.VAR_AS_TYPE_NAME;
+    };
     _indexTestUnit('''
 class A {
   Map<String, var> m;
@@ -2289,6 +2423,15 @@
 ''');
   }
 
+  void test_undefinedMethod_create_BAD_inSDK() {
+    _indexTestUnit('''
+main() {
+  List.foo();
+}
+''');
+    assertNoFix(FixKind.CREATE_METHOD);
+  }
+
   void test_undefinedMethod_create_generic_BAD() {
     _indexTestUnit('''
 class A<T> {
@@ -2714,9 +2857,10 @@
           error.errorCode == HintCode.UNUSED_FIELD ||
           error.errorCode == HintCode.UNUSED_LOCAL_VARIABLE;
     });
-    if (checkHasSingleError) {
-      expect(errors, hasLength(1));
+    if (errorFilter != null) {
+      errors = errors.where(errorFilter).toList();
     }
+    expect(errors, hasLength(1));
     return errors[0];
   }
 
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
index 8f11a33..b748ea7 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_refactoring.dart
@@ -74,22 +74,19 @@
   /**
    * Asserts that [refactoring] initial/final conditions status is OK.
    */
-  Future assertRefactoringConditionsOK() {
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatusOK(status);
-      return refactoring.checkFinalConditions().then((status) {
-        assertRefactoringStatusOK(status);
-      });
-    });
+  Future assertRefactoringConditionsOK() async {
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatusOK(status);
+    status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
   /**
    * Asserts that [refactoring] final conditions status is OK.
    */
-  Future assertRefactoringFinalConditionsOK() {
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+  Future assertRefactoringFinalConditionsOK() async {
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
   /**
@@ -129,13 +126,11 @@
    * Checks that all conditions of [refactoring] are OK and the result of
    * applying the [Change] to [testUnit] is [expectedCode].
    */
-  Future assertSuccessfulRefactoring(String expectedCode) {
-    return assertRefactoringConditionsOK().then((_) {
-      return refactoring.createChange().then((SourceChange change) {
-        this.refactoringChange = change;
-        assertTestChangeResult(expectedCode);
-      });
-    });
+  Future assertSuccessfulRefactoring(String expectedCode) async {
+    await assertRefactoringConditionsOK();
+    SourceChange change = await refactoring.createChange();
+    this.refactoringChange = change;
+    assertTestChangeResult(expectedCode);
   }
 
   /**
diff --git a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
index 75d922c..871f806 100644
--- a/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
+++ b/pkg/analysis_server/test/services/refactoring/abstract_rename.dart
@@ -75,25 +75,4 @@
     }
     return null;
   }
-
-//  /**
-//   * Asserts result of applying [change] to [testCode].
-//   */
-//  void assertTestChangeResult(Change change, String expected)
-//      {
-//    assertChangeResult(change, testSource, expected);
-//  }
-//
-//  /**
-//   * Asserts result of applying [change] to [source].
-//   */
-//  void assertChangeResult(Change change, Source source, String expected)
-//       {
-//    SourceChange sourceChange = getSourceChange(compositeChange, source);
-//    assertNotNull("No change for: " + source.toString(), sourceChange);
-//    String sourceResult = getChangeResult(context, source, sourceChange);
-//    assertEquals(expected, sourceResult);
-////    AnalysisContext context = getAnalysisContext();
-////    assertChangeResult(context, compositeChange, source, expected);
-//  }
 }
diff --git a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
index 643079a..4b9f82d 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_getter_to_method_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/src/protocol.dart' hide ElementKind;
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:unittest/unittest.dart';
@@ -131,26 +132,23 @@
         'Only explicit getters can be converted to methods.');
   }
 
-  Future _assertInitialConditions_fatal(String message) {
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: message);
-    });
+  Future _assertInitialConditions_fatal(String message) async {
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: message);
   }
 
   /**
    * Checks that all conditions are OK and the result of applying [refactoring]
    * change to [testUnit] is [expectedCode].
    */
-  Future _assertSuccessfulRefactoring(String expectedCode) {
-    return assertRefactoringConditionsOK().then((_) {
-      return refactoring.createChange().then((SourceChange refactoringChange) {
-        this.refactoringChange = refactoringChange;
-        assertTestChangeResult(expectedCode);
-      });
-    });
+  Future _assertSuccessfulRefactoring(String expectedCode) async {
+    await assertRefactoringConditionsOK();
+    SourceChange refactoringChange = await refactoring.createChange();
+    this.refactoringChange = refactoringChange;
+    assertTestChangeResult(expectedCode);
   }
 
   void _createRefactoring(String elementName) {
diff --git a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
index a4216f0..32780d8 100644
--- a/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/convert_method_to_getter_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/src/protocol.dart' hide ElementKind;
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:unittest/unittest.dart';
@@ -172,26 +173,23 @@
         'Only class methods or top-level functions can be converted to getters.');
   }
 
-  Future _assertInitialConditions_fatal(String message) {
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: message);
-    });
+  Future _assertInitialConditions_fatal(String message) async {
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: message);
   }
 
   /**
    * Checks that all conditions are OK and the result of applying the [Change]
    * to [testUnit] is [expectedCode].
    */
-  Future _assertSuccessfulRefactoring(String expectedCode) {
-    return assertRefactoringConditionsOK().then((_) {
-      return refactoring.createChange().then((SourceChange refactoringChange) {
-        this.refactoringChange = refactoringChange;
-        assertTestChangeResult(expectedCode);
-      });
-    });
+  Future _assertSuccessfulRefactoring(String expectedCode) async {
+    await assertRefactoringConditionsOK();
+    SourceChange refactoringChange = await refactoring.createChange();
+    this.refactoringChange = refactoringChange;
+    assertTestChangeResult(expectedCode);
   }
 
   void _createRefactoring(String elementName) {
diff --git a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
index efe7091..75ad10b 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_local_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/refactoring/extract_local.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:unittest/unittest.dart';
@@ -25,7 +26,7 @@
 class ExtractLocalTest extends RefactoringTest {
   ExtractLocalRefactoringImpl refactoring;
 
-  test_checkFinalConditions_sameVariable_after() {
+  test_checkFinalConditions_sameVariable_after() async {
     indexTestUnit('''
 main() {
   int a = 1 + 2;
@@ -34,16 +35,15 @@
 ''');
     _createRefactoringForString('1 + 2');
     // conflicting name
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.WARNING,
-          expectedMessage:
-              "A variable with name 'res' is already defined in the visible scope.");
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.WARNING,
+        expectedMessage:
+            "A variable with name 'res' is already defined in the visible scope.");
   }
 
-  test_checkFinalConditions_sameVariable_before() {
+  test_checkFinalConditions_sameVariable_before() async {
     indexTestUnit('''
 main() {
   var res;
@@ -52,16 +52,15 @@
 ''');
     _createRefactoringForString('1 + 2');
     // conflicting name
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.WARNING,
-          expectedMessage:
-              "A variable with name 'res' is already defined in the visible scope.");
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.WARNING,
+        expectedMessage:
+            "A variable with name 'res' is already defined in the visible scope.");
   }
 
-  test_checkInitialConditions_assignmentLeftHandSize() {
+  test_checkInitialConditions_assignmentLeftHandSize() async {
     indexTestUnit('''
 main() {
   var v = 0;
@@ -70,15 +69,14 @@
 ''');
     _createRefactoringWithSuffix('v', ' = 1;');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Cannot extract the left-hand side of an assignment.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Cannot extract the left-hand side of an assignment.');
   }
 
-  test_checkInitialConditions_methodName_reference() {
+  test_checkInitialConditions_methodName_reference() async {
     indexTestUnit('''
 main() {
   main();
@@ -86,15 +84,14 @@
 ''');
     _createRefactoringWithSuffix('main', '();');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Cannot extract a single method name.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Cannot extract a single method name.');
   }
 
-  test_checkInitialConditions_nameOfProperty_prefixedIdentifier() {
+  test_checkInitialConditions_nameOfProperty_prefixedIdentifier() async {
     indexTestUnit('''
 main(p) {
   p.value; // marker
@@ -102,15 +99,14 @@
 ''');
     _createRefactoringWithSuffix('value', '; // marker');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Cannot extract name part of a property access.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Cannot extract name part of a property access.');
   }
 
-  test_checkInitialConditions_nameOfProperty_propertyAccess() {
+  test_checkInitialConditions_nameOfProperty_propertyAccess() async {
     indexTestUnit('''
 main() {
   foo().length; // marker
@@ -119,15 +115,14 @@
 ''');
     _createRefactoringWithSuffix('length', '; // marker');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Cannot extract name part of a property access.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Cannot extract name part of a property access.');
   }
 
-  test_checkInitialConditions_namePartOfDeclaration_variable() {
+  test_checkInitialConditions_namePartOfDeclaration_variable() async {
     indexTestUnit('''
 main() {
   int vvv = 0;
@@ -135,30 +130,28 @@
 ''');
     _createRefactoringWithSuffix('vvv', ' = 0;');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Cannot extract the name part of a declaration.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Cannot extract the name part of a declaration.');
   }
 
-  test_checkInitialConditions_notPartOfFunction() {
+  test_checkInitialConditions_notPartOfFunction() async {
     indexTestUnit('''
 int a = 1 + 2;
 ''');
     _createRefactoringForString('1 + 2');
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage:
-              'Expression inside of function must be selected to activate this refactoring.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            'Expression inside of function must be selected to activate this refactoring.');
   }
 
-  test_checkInitialConditions_stringSelection_leadingQuote() {
+  test_checkInitialConditions_stringSelection_leadingQuote() async {
     indexTestUnit('''
 main() {
   var vvv = 'abc';
@@ -166,16 +159,15 @@
 ''');
     _createRefactoringForString("'a");
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage:
-              'Cannot extract only leading or trailing quote of string literal.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            'Cannot extract only leading or trailing quote of string literal.');
   }
 
-  test_checkInitialConditions_stringSelection_trailingQuote() {
+  test_checkInitialConditions_stringSelection_trailingQuote() async {
     indexTestUnit('''
 main() {
   var vvv = 'abc';
@@ -183,13 +175,12 @@
 ''');
     _createRefactoringForString("c'");
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage:
-              'Cannot extract only leading or trailing quote of string literal.');
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            'Cannot extract only leading or trailing quote of string literal.');
   }
 
   test_checkLocalName() {
@@ -469,7 +460,7 @@
 ''');
   }
 
-  test_guessNames_fragmentExpression() {
+  test_guessNames_fragmentExpression() async {
     indexTestUnit('''
 main() {
   var a = 111 + 222 + 333 + 444;
@@ -477,12 +468,11 @@
 ''');
     _createRefactoringForString('222 + 333');
     // check guesses
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.names, isEmpty);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.names, isEmpty);
   }
 
-  test_guessNames_singleExpression() {
+  test_guessNames_singleExpression() async {
     indexTestUnit('''
 class TreeItem {}
 TreeItem getSelectedItem() => null;
@@ -493,14 +483,13 @@
 ''');
     _createRefactoringWithSuffix('getSelectedItem()', '); // marker');
     // check guesses
-    return refactoring.checkInitialConditions().then((_) {
-      expect(
-          refactoring.names,
-          unorderedEquals(['selectedItem', 'item', 'my', 'treeItem']));
-    });
+    await refactoring.checkInitialConditions();
+    expect(
+        refactoring.names,
+        unorderedEquals(['selectedItem', 'item', 'my', 'treeItem']));
   }
 
-  test_guessNames_stringPart() {
+  test_guessNames_stringPart() async {
     indexTestUnit('''
 main() {
   var s = 'Hello Bob... welcome to Dart!';
@@ -508,9 +497,8 @@
 ''');
     _createRefactoringForString('Hello Bob');
     // check guesses
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.names, unorderedEquals(['helloBob', 'bob']));
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.names, unorderedEquals(['helloBob', 'bob']));
   }
 
   test_occurences_differentVariable() {
@@ -692,7 +680,7 @@
 ''');
   }
 
-  test_offsets_lengths() {
+  test_offsets_lengths() async {
     indexTestUnit('''
 int foo() => 42;
 main() {
@@ -701,13 +689,12 @@
 }
 ''');
     _createRefactoringWithSuffix('foo()', '; // marker');
-    // apply refactoring
-    return refactoring.checkInitialConditions().then((_) {
-      expect(
-          refactoring.offsets,
-          unorderedEquals([findOffset('foo();'), findOffset('foo( );')]));
-      expect(refactoring.lengths, unorderedEquals([5, 6]));
-    });
+    // check offsets
+    await refactoring.checkInitialConditions();
+    expect(
+        refactoring.offsets,
+        unorderedEquals([findOffset('foo();'), findOffset('foo( );')]));
+    expect(refactoring.lengths, unorderedEquals([5, 6]));
   }
 
   test_singleExpression() {
@@ -955,26 +942,23 @@
 ''');
   }
 
-  Future _assertInitialConditions_fatal_selection() {
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: 'Expression must be selected to activate this refactoring.');
-    });
+  Future _assertInitialConditions_fatal_selection() async {
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: 'Expression must be selected to activate this refactoring.');
   }
 
   /**
    * Checks that all conditions are OK and the result of applying the [Change]
    * to [testUnit] is [expectedCode].
    */
-  Future _assertSuccessfulRefactoring(String expectedCode) {
-    return assertRefactoringConditionsOK().then((_) {
-      return refactoring.createChange().then((SourceChange refactoringChange) {
-        this.refactoringChange = refactoringChange;
-        assertTestChangeResult(expectedCode);
-      });
-    });
+  Future _assertSuccessfulRefactoring(String expectedCode) async {
+    await assertRefactoringConditionsOK();
+    SourceChange refactoringChange = await refactoring.createChange();
+    this.refactoringChange = refactoringChange;
+    assertTestChangeResult(expectedCode);
   }
 
   void _createRefactoring(int offset, int length) {
diff --git a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
index c77bd77..95c05a5 100644
--- a/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/extract_method_test.dart
@@ -7,6 +7,7 @@
 import 'dart:async';
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analysis_server/src/services/refactoring/extract_method.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:unittest/unittest.dart';
@@ -362,7 +363,7 @@
         'Not all selected statements are enclosed by the same parent statement.');
   }
 
-  test_bad_parameterName_duplicate() {
+  test_bad_parameterName_duplicate() async {
     indexTestUnit('''
 main() {
   int v1 = 1;
@@ -374,19 +375,18 @@
 ''');
     _createRefactoringForStartEndComments();
     // update parameters
-    return refactoring.checkInitialConditions().then((_) {
-      {
-        var parameters = _getParametersCopy();
-        expect(parameters, hasLength(2));
-        parameters[0].name = 'dup';
-        parameters[1].name = 'dup';
-        refactoring.parameters = parameters;
-      }
-      return _assertFinalConditionsError("Parameter 'dup' already exists");
-    });
+    await refactoring.checkInitialConditions();
+    {
+      List<RefactoringMethodParameter> parameters = _getParametersCopy();
+      expect(parameters, hasLength(2));
+      parameters[0].name = 'dup';
+      parameters[1].name = 'dup';
+      refactoring.parameters = parameters;
+    }
+    return _assertFinalConditionsError("Parameter 'dup' already exists");
   }
 
-  test_bad_parameterName_inUse() {
+  test_bad_parameterName_inUse() async {
     indexTestUnit('''
 main() {
   int v1 = 1;
@@ -398,16 +398,15 @@
 ''');
     _createRefactoringForStartEndComments();
     // update parameters
-    return refactoring.checkInitialConditions().then((_) {
-      {
-        var parameters = _getParametersCopy();
-        expect(parameters, hasLength(2));
-        parameters[0].name = 'a';
-        refactoring.parameters = parameters;
-      }
-      return _assertFinalConditionsError(
-          "'a' is already used as a name in the selected code");
-    });
+    await refactoring.checkInitialConditions();
+    {
+      List<RefactoringMethodParameter> parameters = _getParametersCopy();
+      expect(parameters, hasLength(2));
+      parameters[0].name = 'a';
+      refactoring.parameters = parameters;
+    }
+    return _assertFinalConditionsError(
+        "'a' is already used as a name in the selected code");
   }
 
   test_bad_selectionEndsInSomeNode() {
@@ -425,6 +424,21 @@
             "Extend selection to a valid range.");
   }
 
+  test_bad_statements_exit_notAllExecutionFlows() {
+    indexTestUnit('''
+main(int p) {
+// start
+  if (p == 0) {
+    return;
+  }
+// end
+  print(p);
+}
+''');
+    _createRefactoringForStartEndComments();
+    return _assertConditionsError(ExtractMethodRefactoringImpl.ERROR_EXITS);
+  }
+
   test_bad_statements_return_andAssignsVariable() {
     indexTestUnit('''
 main() {
@@ -611,7 +625,7 @@
         "Operation not applicable to a while statement's expression and body.");
   }
 
-  test_canExtractGetter_false_fieldAssignment() {
+  test_canExtractGetter_false_fieldAssignment() async {
     indexTestUnit('''
 class A {
   var f;
@@ -624,13 +638,12 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, false);
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, false);
+    expect(refactoring.createGetter, false);
   }
 
-  test_canExtractGetter_false_hasParameters() {
+  test_canExtractGetter_false_hasParameters() async {
     indexTestUnit('''
 main(int p) {
   int a = p + 1;
@@ -638,13 +651,12 @@
 ''');
     _createRefactoringForString('p + 1');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, false);
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, false);
+    expect(refactoring.createGetter, false);
   }
 
-  test_canExtractGetter_false_returnNotUsed_assignment() {
+  test_canExtractGetter_false_returnNotUsed_assignment() async {
     indexTestUnit('''
 var topVar = 0;
 f(int p) {
@@ -653,13 +665,12 @@
 ''');
     _createRefactoringForString('topVar = 5');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, false);
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, false);
+    expect(refactoring.createGetter, false);
   }
 
-  test_canExtractGetter_false_returnNotUsed_noReturn() {
+  test_canExtractGetter_false_returnNotUsed_noReturn() async {
     indexTestUnit('''
 var topVar = 0;
 main() {
@@ -672,13 +683,12 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, false);
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, false);
+    expect(refactoring.createGetter, false);
   }
 
-  test_canExtractGetter_true() {
+  test_canExtractGetter_true() async {
     indexTestUnit('''
 main() {
   int a = 1 + 2;
@@ -686,10 +696,9 @@
 ''');
     _createRefactoringForString('1 + 2');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, true);
-      expect(refactoring.createGetter, true);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, true);
+    expect(refactoring.createGetter, true);
   }
 
   test_checkName() {
@@ -791,7 +800,7 @@
 ''');
   }
 
-  test_closure_bad_referencesLocalVariable() {
+  test_closure_bad_referencesLocalVariable() async {
     indexTestUnit('''
 process(f(x)) {}
 main() {
@@ -801,16 +810,15 @@
 ''');
     _createRefactoringForString('(x) => x * k');
     // check
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage:
-              'Cannot extract closure as method, it references 1 external variable(s).');
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            'Cannot extract closure as method, it references 1 external variable(s).');
   }
 
-  test_closure_bad_referencesParameter() {
+  test_closure_bad_referencesParameter() async {
     indexTestUnit('''
 process(f(x)) {}
 main(int k) {
@@ -819,13 +827,12 @@
 ''');
     _createRefactoringForString('(x) => x * k');
     // check
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage:
-              'Cannot extract closure as method, it references 1 external variable(s).');
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            'Cannot extract closure as method, it references 1 external variable(s).');
   }
 
   test_fromTopLevelVariableInitializerClosure() {
@@ -849,7 +856,7 @@
 ''');
   }
 
-  test_getExtractGetter_false_do() {
+  test_getExtractGetter_false_do() async {
     indexTestUnit('''
 main() {
 // start
@@ -863,12 +870,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_false_for() {
+  test_getExtractGetter_false_for() async {
     indexTestUnit('''
 main() {
 // start
@@ -882,12 +888,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_false_forEach() {
+  test_getExtractGetter_false_forEach() async {
     indexTestUnit('''
 main() {
 // start
@@ -901,12 +906,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_false_methodInvocation_expression() {
+  test_getExtractGetter_false_methodInvocation_expression() async {
     indexTestUnit('''
 main() {
   int v = calculateSomething() + 5;
@@ -915,12 +919,11 @@
 ''');
     _createRefactoringForString('calculateSomething() + 5');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_false_methodInvocation_statements() {
+  test_getExtractGetter_false_methodInvocation_statements() async {
     indexTestUnit('''
 main() {
 // start
@@ -932,12 +935,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_false_while() {
+  test_getExtractGetter_false_while() async {
     indexTestUnit('''
 main() {
 // start
@@ -951,12 +953,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, false);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, false);
   }
 
-  test_getExtractGetter_true_simpleBlock() {
+  test_getExtractGetter_true_simpleBlock() async {
     indexTestUnit('''
 main() {
 // start
@@ -967,12 +968,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, true);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, true);
   }
 
-  test_getExtractGetter_true_singleExpression() {
+  test_getExtractGetter_true_singleExpression() async {
     indexTestUnit('''
 main() {
 // start
@@ -983,9 +983,8 @@
 ''');
     _createRefactoringForString('1 + 2');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.createGetter, true);
-    });
+    await assertRefactoringConditionsOK();
+    expect(refactoring.createGetter, true);
   }
 
   test_getRefactoringName_function() {
@@ -1010,7 +1009,7 @@
     expect(refactoring.refactoringName, 'Extract Method');
   }
 
-  test_names_singleExpression() {
+  test_names_singleExpression() async {
     indexTestUnit('''
 class TreeItem {}
 TreeItem getSelectedItem() => null;
@@ -1022,14 +1021,13 @@
 ''');
     _createRefactoringWithSuffix('getSelectedItem()', '); // marker');
     // check names
-    return refactoring.checkInitialConditions().then((_) {
-      expect(
-          refactoring.names,
-          unorderedEquals(['selectedItem', 'item', 'my', 'treeItem2']));
-    });
+    await refactoring.checkInitialConditions();
+    expect(
+        refactoring.names,
+        unorderedEquals(['selectedItem', 'item', 'my', 'treeItem2']));
   }
 
-  test_offsets_lengths() {
+  test_offsets_lengths() async {
     indexTestUnit('''
 main() {
   int a = 1 + 2;
@@ -1038,15 +1036,14 @@
 ''');
     _createRefactoringForString('1 +  2');
     // apply refactoring
-    return refactoring.checkInitialConditions().then((_) {
-      expect(
-          refactoring.offsets,
-          unorderedEquals([findOffset('1 + 2'), findOffset('1 +  2')]));
-      expect(refactoring.lengths, unorderedEquals([5, 6]));
-    });
+    await refactoring.checkInitialConditions();
+    expect(
+        refactoring.offsets,
+        unorderedEquals([findOffset('1 + 2'), findOffset('1 +  2')]));
+    expect(refactoring.lengths, unorderedEquals([5, 6]));
   }
 
-  test_returnType_expression() {
+  test_returnType_expression() async {
     indexTestUnit('''
 main() {
   int a = 1 + 2;
@@ -1054,12 +1051,11 @@
 ''');
     _createRefactoringForString('1 + 2');
     // do check
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.returnType, 'int');
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.returnType, 'int');
   }
 
-  test_returnType_statements() {
+  test_returnType_statements() async {
     indexTestUnit('''
 main() {
 // start
@@ -1070,12 +1066,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // do check
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.returnType, 'double');
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.returnType, 'double');
   }
 
-  test_returnType_statements_nullMix() {
+  test_returnType_statements_nullMix() async {
     indexTestUnit('''
 main(bool p) {
 // start
@@ -1088,12 +1083,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // do check
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.returnType, 'int');
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.returnType, 'int');
   }
 
-  test_returnType_statements_void() {
+  test_returnType_statements_void() async {
     indexTestUnit('''
 main() {
 // start
@@ -1103,12 +1097,11 @@
 ''');
     _createRefactoringForStartEndComments();
     // do check
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.returnType, 'void');
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.returnType, 'void');
   }
 
-  test_setExtractGetter() {
+  test_setExtractGetter() async {
     indexTestUnit('''
 main() {
   int a = 1 + 2;
@@ -1116,20 +1109,17 @@
 ''');
     _createRefactoringForString('1 + 2');
     // apply refactoring
-    return assertRefactoringConditionsOK().then((_) {
-      expect(refactoring.canCreateGetter, true);
-      expect(refactoring.createGetter, true);
-      return refactoring.createChange().then((SourceChange refactoringChange) {
-        this.refactoringChange = refactoringChange;
-        assertTestChangeResult('''
+    await assertRefactoringConditionsOK();
+    expect(refactoring.canCreateGetter, true);
+    expect(refactoring.createGetter, true);
+    refactoringChange = await refactoring.createChange();
+    assertTestChangeResult('''
 main() {
   int a = res;
 }
 
 int get res => 1 + 2;
 ''');
-      });
-    });
   }
 
   test_singleExpression() {
@@ -1609,7 +1599,7 @@
 ''');
   }
 
-  test_singleExpression_withVariables_doRename() {
+  test_singleExpression_withVariables_doRename() async {
     indexTestUnit('''
 main() {
   int v1 = 1;
@@ -1621,19 +1611,19 @@
 ''');
     _createRefactoringForString('v1 + v2 + v1');
     // apply refactoring
-    return refactoring.checkInitialConditions().then((_) {
-      {
-        var parameters = _getParametersCopy();
-        expect(parameters, hasLength(2));
-        expect(parameters[0].name, 'v1');
-        expect(parameters[1].name, 'v2');
-        parameters[0].name = 'par1';
-        parameters[1].name = 'param2';
-        refactoring.parameters = parameters;
-      }
-      return assertRefactoringFinalConditionsOK().then((_) {
-        refactoring.createGetter = false;
-        return _assertRefactoringChange('''
+    await refactoring.checkInitialConditions();
+    {
+      List<RefactoringMethodParameter> parameters = _getParametersCopy();
+      expect(parameters, hasLength(2));
+      expect(parameters[0].name, 'v1');
+      expect(parameters[1].name, 'v2');
+      parameters[0].name = 'par1';
+      parameters[1].name = 'param2';
+      refactoring.parameters = parameters;
+    }
+    await assertRefactoringFinalConditionsOK();
+    refactoring.createGetter = false;
+    return _assertRefactoringChange('''
 main() {
   int v1 = 1;
   int v2 = 2;
@@ -1644,11 +1634,9 @@
 
 int res(int par1, int param2) => par1 + param2 + par1;
 ''');
-      });
-    });
   }
 
-  test_singleExpression_withVariables_doReorder() {
+  test_singleExpression_withVariables_doReorder() async {
     indexTestUnit('''
 main() {
   int v1 = 1;
@@ -1660,19 +1648,19 @@
 ''');
     _createRefactoringForString('v1 + v2');
     // apply refactoring
-    return refactoring.checkInitialConditions().then((_) {
-      {
-        var parameters = _getParametersCopy();
-        expect(parameters, hasLength(2));
-        expect(parameters[0].name, 'v1');
-        expect(parameters[1].name, 'v2');
-        var parameter = parameters.removeAt(1);
-        parameters.insert(0, parameter);
-        refactoring.parameters = parameters;
-      }
-      return assertRefactoringFinalConditionsOK().then((_) {
-        refactoring.createGetter = false;
-        return _assertRefactoringChange('''
+    await refactoring.checkInitialConditions();
+    {
+      List<RefactoringMethodParameter> parameters = _getParametersCopy();
+      expect(parameters, hasLength(2));
+      expect(parameters[0].name, 'v1');
+      expect(parameters[1].name, 'v2');
+      var parameter = parameters.removeAt(1);
+      parameters.insert(0, parameter);
+      refactoring.parameters = parameters;
+    }
+    await assertRefactoringFinalConditionsOK();
+    refactoring.createGetter = false;
+    return _assertRefactoringChange('''
 main() {
   int v1 = 1;
   int v2 = 2;
@@ -1683,8 +1671,6 @@
 
 int res(int v2, int v1) => v1 + v2;
 ''');
-      });
-    });
   }
 
   test_singleExpression_withVariables_namedExpression() {
@@ -1710,7 +1696,7 @@
 ''');
   }
 
-  test_singleExpression_withVariables_newType() {
+  test_singleExpression_withVariables_newType() async {
     indexTestUnit('''
 main() {
   int v1 = 1;
@@ -1721,21 +1707,21 @@
 ''');
     _createRefactoringForString('v1 + v2 + v3');
     // apply refactoring
-    return refactoring.checkInitialConditions().then((_) {
-      {
-        var parameters = _getParametersCopy();
-        expect(parameters, hasLength(3));
-        expect(parameters[0].name, 'v1');
-        expect(parameters[1].name, 'v2');
-        expect(parameters[2].name, 'v3');
-        parameters[0].type = 'num';
-        parameters[1].type = 'dynamic';
-        parameters[2].type = '';
-        refactoring.parameters = parameters;
-      }
-      return assertRefactoringFinalConditionsOK().then((_) {
-        refactoring.createGetter = false;
-        return _assertRefactoringChange('''
+    await refactoring.checkInitialConditions();
+    {
+      List<RefactoringMethodParameter> parameters = _getParametersCopy();
+      expect(parameters, hasLength(3));
+      expect(parameters[0].name, 'v1');
+      expect(parameters[1].name, 'v2');
+      expect(parameters[2].name, 'v3');
+      parameters[0].type = 'num';
+      parameters[1].type = 'dynamic';
+      parameters[2].type = '';
+      refactoring.parameters = parameters;
+    }
+    await assertRefactoringFinalConditionsOK();
+    refactoring.createGetter = false;
+    return _assertRefactoringChange('''
 main() {
   int v1 = 1;
   int v2 = 2;
@@ -1745,8 +1731,6 @@
 
 int res(num v1, v2, v3) => v1 + v2 + v3;
 ''');
-      });
-    });
   }
 
   test_singleExpression_withVariables_useBestType() {
@@ -1971,7 +1955,7 @@
 ''');
   }
 
-  test_statements_definesVariable_twoUsedOutside() {
+  test_statements_definesVariable_twoUsedOutside() async {
     indexTestUnit('''
 main() {
 // start
@@ -1983,9 +1967,8 @@
 ''');
     _createRefactoringForStartEndComments();
     // check conditions
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
   }
 
   test_statements_duplicate_absolutelySame() {
@@ -2112,6 +2095,21 @@
 ''');
   }
 
+  test_statements_exit_throws() async {
+    indexTestUnit('''
+main(int p) {
+// start
+  if (p == 0) {
+    return;
+  }
+  throw 'boo!';
+// end
+}
+''');
+    _createRefactoringForStartEndComments();
+    await assertRefactoringConditionsOK();
+  }
+
   test_statements_inSwitchMember() {
     indexTestUnit('''
 class A {
@@ -2324,8 +2322,10 @@
 main(bool b) {
 // start
   if (b) {
+    print(true);
     return <int>[];
   } else {
+    print(false);
     return <String>[];
   }
 // end
@@ -2342,8 +2342,10 @@
 
 List res(bool b) {
   if (b) {
+    print(true);
     return <int>[];
   } else {
+    print(false);
     return <String>[];
   }
 }
@@ -2404,49 +2406,44 @@
 ''');
   }
 
-  Future _assertConditionsError(String message) {
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: message);
-    });
+  Future _assertConditionsError(String message) async {
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: message);
   }
 
-  Future _assertConditionsFatal(String message) {
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: message);
-    });
+  Future _assertConditionsFatal(String message) async {
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: message);
   }
 
-  Future _assertFinalConditionsError(String message) {
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: message);
-    });
+  Future _assertFinalConditionsError(String message) async {
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: message);
   }
 
-  Future _assertRefactoringChange(String expectedCode) {
-    return refactoring.createChange().then((SourceChange refactoringChange) {
-      this.refactoringChange = refactoringChange;
-      assertTestChangeResult(expectedCode);
-    });
+  Future _assertRefactoringChange(String expectedCode) async {
+    SourceChange refactoringChange = await refactoring.createChange();
+    this.refactoringChange = refactoringChange;
+    assertTestChangeResult(expectedCode);
   }
 
   /**
    * Checks that all conditions are OK and the result of applying the [Change]
    * to [testUnit] is [expectedCode].
    */
-  Future _assertSuccessfulRefactoring(String expectedCode) {
-    return assertRefactoringConditionsOK().then((_) {
-      refactoring.createGetter = false;
-      return _assertRefactoringChange(expectedCode);
-    });
+  Future _assertSuccessfulRefactoring(String expectedCode) async {
+    await assertRefactoringConditionsOK();
+    refactoring.createGetter = false;
+    return _assertRefactoringChange(expectedCode);
   }
 
   void _createRefactoring(int offset, int length) {
diff --git a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
index b4646f0..335387b 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_local_test.dart
@@ -24,7 +24,7 @@
 class InlineLocalTest extends RefactoringTest {
   InlineLocalRefactoringImpl refactoring;
 
-  test_access() {
+  test_access() async {
     indexTestUnit('''
 main() {
   int test = 1 + 2;
@@ -35,35 +35,32 @@
     _createRefactoring('test =');
     expect(refactoring.refactoringName, 'Inline Local Variable');
     // check initial conditions and access
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.variableName, 'test');
-      expect(refactoring.referenceCount, 2);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.variableName, 'test');
+    expect(refactoring.referenceCount, 2);
   }
 
-  test_bad_selectionMethod() {
+  test_bad_selectionMethod() async {
     indexTestUnit(r'''
 main() {
 }
 ''');
     _createRefactoring('main() {');
-    return refactoring.checkInitialConditions().then((status) {
-      _assert_fatalError_selection(status);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    _assert_fatalError_selection(status);
   }
 
-  test_bad_selectionParameter() {
+  test_bad_selectionParameter() async {
     indexTestUnit(r'''
 main(int test) {
 }
 ''');
     _createRefactoring('test) {');
-    return refactoring.checkInitialConditions().then((status) {
-      _assert_fatalError_selection(status);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    _assert_fatalError_selection(status);
   }
 
-  test_bad_selectionVariable_hasAssignments_1() {
+  test_bad_selectionVariable_hasAssignments_1() async {
     indexTestUnit(r'''
 main() {
   int test = 0;
@@ -71,15 +68,14 @@
 }
 ''');
     _createRefactoring('test = 0');
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedContextSearch: 'test = 1');
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedContextSearch: 'test = 1');
   }
 
-  test_bad_selectionVariable_hasAssignments_2() {
+  test_bad_selectionVariable_hasAssignments_2() async {
     indexTestUnit(r'''
 main() {
   int test = 0;
@@ -87,15 +83,14 @@
 }
 ''');
     _createRefactoring('test = 0');
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedContextSearch: 'test += 1');
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedContextSearch: 'test += 1');
   }
 
-  test_bad_selectionVariable_notInBlock() {
+  test_bad_selectionVariable_notInBlock() async {
     indexTestUnit(r'''
 main() {
   if (true)
@@ -103,21 +98,19 @@
 }
 ''');
     _createRefactoring('test = 0');
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
   }
 
-  test_bad_selectionVariable_notInitialized() {
+  test_bad_selectionVariable_notInitialized() async {
     indexTestUnit(r'''
 main() {
   int test;
 }
 ''');
     _createRefactoring('test;');
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
   }
 
   test_OK_cascade_intoCascade() {
diff --git a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
index 01dfc52..8a93a7f 100644
--- a/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/inline_method_test.dart
@@ -14,6 +14,7 @@
 
 import '../../reflective_tests.dart';
 import 'abstract_refactoring.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 
 
 main() {
@@ -28,7 +29,7 @@
   bool deleteSource;
   bool inlineAll;
 
-  test_access_FunctionElement() {
+  test_access_FunctionElement() async {
     indexTestUnit(r'''
 test(a, b) {
   return a + b;
@@ -39,15 +40,14 @@
 ''');
     _createRefactoring('test(1, 2)');
     // validate state
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.refactoringName, 'Inline Function');
-      expect(refactoring.className, isNull);
-      expect(refactoring.methodName, 'test');
-      expect(refactoring.isDeclaration, isFalse);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.refactoringName, 'Inline Function');
+    expect(refactoring.className, isNull);
+    expect(refactoring.methodName, 'test');
+    expect(refactoring.isDeclaration, isFalse);
   }
 
-  test_access_MethodElement() {
+  test_access_MethodElement() async {
     indexTestUnit(r'''
 class A {
   test(a, b) {
@@ -60,15 +60,14 @@
 ''');
     _createRefactoring('test(a, b)');
     // validate state
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.refactoringName, 'Inline Method');
-      expect(refactoring.className, 'A');
-      expect(refactoring.methodName, 'test');
-      expect(refactoring.isDeclaration, isTrue);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.refactoringName, 'Inline Method');
+    expect(refactoring.className, 'A');
+    expect(refactoring.methodName, 'test');
+    expect(refactoring.isDeclaration, isTrue);
   }
 
-  test_bad_cascadeInvocation() {
+  test_bad_cascadeInvocation() async {
     indexTestUnit(r'''
 class A {
   foo() {}
@@ -82,14 +81,13 @@
 ''');
     _createRefactoring('test() {');
     // error
-    return refactoring.checkAllConditions().then((status) {
-      var location = new SourceRange(findOffset('..test()'), '..test()'.length);
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: 'Cannot inline cascade invocation.',
-          expectedContextRange: location);
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    var location = new SourceRange(findOffset('..test()'), '..test()'.length);
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: 'Cannot inline cascade invocation.',
+        expectedContextRange: location);
   }
 
   test_bad_constructor() {
@@ -103,7 +101,7 @@
     return _assertInvalidSelection();
   }
 
-  test_bad_deleteSource_inlineOne() {
+  test_bad_deleteSource_inlineOne() async {
     indexTestUnit(r'''
 test(a, b) {
   return a + b;
@@ -114,18 +112,17 @@
 }
 ''');
     _createRefactoring('test(1, 2)');
-    // error
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatusOK(status);
-      refactoring.deleteSource = true;
-      refactoring.inlineAll = false;
-      return refactoring.checkFinalConditions().then((status) {
-        assertRefactoringStatus(
-            status,
-            RefactoringProblemSeverity.ERROR,
-            expectedMessage: 'All references must be inlined to remove the source.');
-      });
-    });
+    // initial conditions
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatusOK(status);
+    refactoring.deleteSource = true;
+    refactoring.inlineAll = false;
+    // final conditions
+    status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: 'All references must be inlined to remove the source.');
   }
 
   test_bad_notExecutableElement() {
@@ -776,7 +773,7 @@
 ''');
   }
 
-  test_initialMode_all() {
+  test_initialMode_all() async {
     indexTestUnit(r'''
 test(a, b) {
   return a + b;
@@ -787,13 +784,12 @@
 ''');
     _createRefactoring('test(a, b)');
     // validate state
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.deleteSource, true);
-      expect(refactoring.inlineAll, true);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.deleteSource, true);
+    expect(refactoring.inlineAll, true);
   }
 
-  test_initialMode_single() {
+  test_initialMode_single() async {
     indexTestUnit(r'''
 test(a, b) {
   return a + b;
@@ -806,10 +802,9 @@
     _createRefactoring('test(1, 2)');
     deleteSource = false;
     // validate state
-    return refactoring.checkInitialConditions().then((_) {
-      expect(refactoring.deleteSource, false);
-      expect(refactoring.inlineAll, false);
-    });
+    await refactoring.checkInitialConditions();
+    expect(refactoring.deleteSource, false);
+    expect(refactoring.inlineAll, false);
   }
 
   test_method_emptyBody() {
@@ -1104,7 +1099,7 @@
 ''');
   }
 
-  test_noArgument_required() {
+  test_noArgument_required() async {
     verifyNoTestUnitErrors = false;
     indexTestUnit(r'''
 test(a) {
@@ -1116,14 +1111,13 @@
 ''');
     _createRefactoring('test();');
     // error
-    return refactoring.checkAllConditions().then((status) {
-      var location = new SourceRange(findOffset('test();'), 'test()'.length);
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: 'No argument for the parameter "a".',
-          expectedContextRange: location);
-    });
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    var location = new SourceRange(findOffset('test();'), 'test()'.length);
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: 'No argument for the parameter "a".',
+        expectedContextRange: location);
   }
 
   test_reference_expressionBody() {
@@ -1393,22 +1387,20 @@
 ''');
   }
 
-  Future _assertConditionsError(String message) {
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: message);
-    });
+  Future _assertConditionsError(String message) async {
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: message);
   }
 
-  Future _assertConditionsFatal(String message) {
-    return refactoring.checkAllConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.FATAL,
-          expectedMessage: message);
-    });
+  Future _assertConditionsFatal(String message) async {
+    RefactoringStatus status = await refactoring.checkAllConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.FATAL,
+        expectedMessage: message);
   }
 
   Future _assertInvalidSelection() {
@@ -1416,23 +1408,23 @@
         'Method declaration or reference must be selected to activate this refactoring.');
   }
 
-  Future _assertSuccessfulRefactoring(String expectedCode) {
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatusOK(status);
-      if (deleteSource != null) {
-        refactoring.deleteSource = deleteSource;
-      }
-      if (inlineAll != null) {
-        refactoring.inlineAll = inlineAll;
-      }
-      return refactoring.checkFinalConditions().then((status) {
-        assertRefactoringStatusOK(status);
-        return refactoring.createChange().then((SourceChange change) {
-          this.refactoringChange = change;
-          assertTestChangeResult(expectedCode);
-        });
-      });
-    });
+  Future _assertSuccessfulRefactoring(String expectedCode) async {
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatusOK(status);
+    // configure
+    if (deleteSource != null) {
+      refactoring.deleteSource = deleteSource;
+    }
+    if (inlineAll != null) {
+      refactoring.inlineAll = inlineAll;
+    }
+    // final conditions
+    status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
+    // change
+    SourceChange change = await refactoring.createChange();
+    this.refactoringChange = change;
+    assertTestChangeResult(expectedCode);
   }
 
   void _createRefactoring(String search) {
diff --git a/pkg/analysis_server/test/services/refactoring/move_file_test.dart b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
index 9b42a64..3772650 100644
--- a/pkg/analysis_server/test/services/refactoring/move_file_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/move_file_test.dart
@@ -6,7 +6,6 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/src/protocol.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/source/package_map_resolver.dart';
@@ -29,7 +28,7 @@
 class MoveFileTest extends RefactoringTest {
   MoveFileRefactoring refactoring;
 
-  test_definingUnit() {
+  test_definingUnit() async {
     String pathA = '/project/000/1111/a.dart';
     String pathB = '/project/000/1111/b.dart';
     String pathC = '/project/000/1111/22/c.dart';
@@ -51,11 +50,11 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/1111/22/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertNoFileChange(pathA);
-      assertFileChangeResult(pathB, "import '22/new_name.dart';");
-      assertNoFileChange(pathC);
-      assertFileChangeResult(testFile, '''
+    await _assertSuccessfulRefactoring();
+    assertNoFileChange(pathA);
+    assertFileChangeResult(pathB, "import '22/new_name.dart';");
+    assertNoFileChange(pathC);
+    assertFileChangeResult(testFile, '''
 library lib;
 import 'dart:math';
 import 'c.dart';
@@ -63,10 +62,9 @@
 part '../a.dart';
 part '/absolute/uri.dart';
 ''');
-    });
   }
 
-  test_importedLibrary() {
+  test_importedLibrary() async {
     String pathA = '/project/000/1111/a.dart';
     testFile = '/project/000/1111/sub/folder/test.dart';
     addSource(pathA, '''
@@ -76,15 +74,14 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/new/folder/name/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 import '../new/folder/name/new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
-  test_importedLibrary_down() {
+  test_importedLibrary_down() async {
     String pathA = '/project/000/1111/a.dart';
     testFile = '/project/000/1111/test.dart';
     addSource(pathA, '''
@@ -94,15 +91,14 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/1111/22/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 import '22/new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
-  test_importedLibrary_package() {
+  test_importedLibrary_package() async {
     // configure packages
     testFile = '/packages/my_pkg/aaa/test.dart';
     provider.newFile(testFile, '');
@@ -123,15 +119,14 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/packages/my_pkg/bbb/ccc/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 import 'package:my_pkg/bbb/ccc/new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
-  test_importedLibrary_up() {
+  test_importedLibrary_up() async {
     String pathA = '/project/000/1111/a.dart';
     testFile = '/project/000/1111/22/test.dart';
     addSource(pathA, '''
@@ -141,15 +136,14 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/1111/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 import 'new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
-  test_sourcedUnit() {
+  test_sourcedUnit() async {
     String pathA = '/project/000/1111/a.dart';
     testFile = '/project/000/1111/22/test.dart';
     addSource(pathA, '''
@@ -159,15 +153,14 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/1111/22/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 part '22/new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
-  test_sourcedUnit_multipleLibraries() {
+  test_sourcedUnit_multipleLibraries() async {
     String pathA = '/project/000/1111/a.dart';
     String pathB = '/project/000/b.dart';
     testFile = '/project/000/1111/22/test.dart';
@@ -181,26 +174,22 @@
     _performAnalysis();
     // perform refactoring
     _createRefactoring('/project/000/1111/22/new_name.dart');
-    return _assertSuccessfulRefactoring().then((_) {
-      assertFileChangeResult(pathA, '''
+    await _assertSuccessfulRefactoring();
+    assertFileChangeResult(pathA, '''
 part '22/new_name.dart';
 ''');
-      assertFileChangeResult(pathB, '''
+    assertFileChangeResult(pathB, '''
 part '1111/22/new_name.dart';
 ''');
-      assertNoFileChange(testFile);
-    });
+    assertNoFileChange(testFile);
   }
 
   /**
    * Checks that all conditions are OK.
    */
-  Future _assertSuccessfulRefactoring() {
-    return assertRefactoringConditionsOK().then((_) {
-      return refactoring.createChange().then((SourceChange refactoringChange) {
-        this.refactoringChange = refactoringChange;
-      });
-    });
+  Future _assertSuccessfulRefactoring() async {
+    await assertRefactoringConditionsOK();
+    refactoringChange = await refactoring.createChange();
   }
 
   void _createRefactoring(String newName) {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 63b8f83..fe91fd6 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -5,6 +5,7 @@
 library test.services.refactoring.rename_class_member;
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:unittest/unittest.dart';
 
 import '../../reflective_tests.dart';
@@ -19,7 +20,7 @@
 
 @reflectiveTest
 class RenameClassMemberTest extends RenameRefactoringTest {
-  test_checkFinalConditions_hasMember_MethodElement() {
+  test_checkFinalConditions_hasMember_MethodElement() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -29,16 +30,15 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Class 'A' already declares method with name 'newName'.",
-          expectedContextSearch: 'newName() {} // existing');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Class 'A' already declares method with name 'newName'.",
+        expectedContextSearch: 'newName() {} // existing');
   }
 
-  test_checkFinalConditions_OK_noShadow() {
+  test_checkFinalConditions_OK_noShadow() async {
     indexTestUnit('''
 class A {
   int newName;
@@ -55,12 +55,11 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowed_byLocal_inSameClass() {
+  test_checkFinalConditions_shadowed_byLocal_inSameClass() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -73,17 +72,16 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage:
-              "Usage of renamed method will be shadowed by local variable 'newName'.",
-          expectedContextSearch: 'test(); // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Usage of renamed method will be shadowed by local variable 'newName'.",
+        expectedContextSearch: 'test(); // marker');
   }
 
-  test_checkFinalConditions_shadowed_byLocal_inSubClass() {
+  test_checkFinalConditions_shadowed_byLocal_inSubClass() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -98,17 +96,16 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage:
-              "Usage of renamed method will be shadowed by local variable 'newName'.",
-          expectedContextSearch: 'test(); // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Usage of renamed method will be shadowed by local variable 'newName'.",
+        expectedContextSearch: 'test(); // marker');
   }
 
-  test_checkFinalConditions_shadowed_byLocal_OK_qualifiedReference() {
+  test_checkFinalConditions_shadowed_byLocal_OK_qualifiedReference() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -121,12 +118,11 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowed_byLocal_OK_renamedNotUsed() {
+  test_checkFinalConditions_shadowed_byLocal_OK_renamedNotUsed() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -138,12 +134,11 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowed_byParameter_inSameClass() {
+  test_checkFinalConditions_shadowed_byParameter_inSameClass() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -155,17 +150,16 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage:
-              "Usage of renamed method will be shadowed by parameter 'newName'.",
-          expectedContextSearch: 'test(); // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Usage of renamed method will be shadowed by parameter 'newName'.",
+        expectedContextSearch: 'test(); // marker');
   }
 
-  test_checkFinalConditions_shadowed_inSubClass() {
+  test_checkFinalConditions_shadowed_inSubClass() async {
     indexTestUnit('''
 class A {
   newName() {} // marker
@@ -180,16 +174,15 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Renamed method will shadow method 'A.newName'.",
-          expectedContextSearch: 'newName() {} // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Renamed method will shadow method 'A.newName'.",
+        expectedContextSearch: 'newName() {} // marker');
   }
 
-  test_checkFinalConditions_shadowsSuper_inSubClass_FieldElement() {
+  test_checkFinalConditions_shadowsSuper_inSubClass_FieldElement() async {
     indexTestUnit('''
 class A {
   int newName; // marker
@@ -206,16 +199,15 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Renamed method will shadow field 'A.newName'.",
-          expectedContextSearch: 'newName; // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Renamed method will shadow field 'A.newName'.",
+        expectedContextSearch: 'newName; // marker');
   }
 
-  test_checkFinalConditions_shadowsSuper_MethodElement() {
+  test_checkFinalConditions_shadowsSuper_MethodElement() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -230,16 +222,15 @@
     createRenameRefactoringAtString('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Renamed method will be shadowed by method 'B.newName'.",
-          expectedContextSearch: 'newName() {} // marker');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Renamed method will be shadowed by method 'B.newName'.",
+        expectedContextSearch: 'newName() {} // marker');
   }
 
-  test_checkInitialConditions_operator() {
+  test_checkInitialConditions_operator() async {
     indexTestUnit('''
 class A {
   operator -(other) => this;
@@ -248,9 +239,8 @@
     createRenameRefactoringAtString('-(other)');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkInitialConditions().then((status) {
-      assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
-    });
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL);
   }
 
   test_checkNewName_FieldElement() {
@@ -539,7 +529,7 @@
 ''');
   }
 
-  test_createChange_MethodElement_potential() {
+  test_createChange_MethodElement_potential() async {
     indexTestUnit('''
 class A {
   test() {}
@@ -556,7 +546,7 @@
     expect(refactoring.oldName, 'test');
     refactoring.newName = 'newName';
     // validate change
-    return assertSuccessfulRefactoring('''
+    await assertSuccessfulRefactoring('''
 class A {
   newName() {}
 }
@@ -565,12 +555,11 @@
   new A().newName();
   a.newName(); // 2
 }
-''').then((_) {
-      assertPotentialEdits(['test(); // 1', 'test(); // 2']);
-    });
+''');
+    assertPotentialEdits(['test(); // 1', 'test(); // 2']);
   }
 
-  test_createChange_MethodElement_potential_private_otherLibrary() {
+  test_createChange_MethodElement_potential_private_otherLibrary() async {
     indexUnit('/lib.dart', '''
 library lib;
 main(p) {
@@ -592,7 +581,7 @@
     expect(refactoring.oldName, '_test');
     refactoring.newName = 'newName';
     // validate change
-    return assertSuccessfulRefactoring('''
+    await assertSuccessfulRefactoring('''
 class A {
   newName() {}
 }
@@ -600,9 +589,8 @@
   a.newName();
   new A().newName();
 }
-''').then((_) {
-      assertNoFileChange('/lib.dart');
-    });
+''');
+    assertNoFileChange('/lib.dart');
   }
 
   test_createChange_PropertyAccessorElement_getter() {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
index 90b6153..2d01a48 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_constructor_test.dart
@@ -5,6 +5,7 @@
 library test.services.refactoring.rename_constructor;
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:unittest/unittest.dart';
@@ -21,7 +22,7 @@
 
 @reflectiveTest
 class RenameConstructorTest extends RenameRefactoringTest {
-  test_checkFinalConditions_hasMember_constructor() {
+  test_checkFinalConditions_hasMember_constructor() async {
     indexTestUnit('''
 class A {
   A.test() {}
@@ -31,16 +32,15 @@
     _createConstructorDeclarationRefactoring('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Class 'A' already declares constructor with name 'newName'.",
-          expectedContextSearch: 'newName() {} // existing');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Class 'A' already declares constructor with name 'newName'.",
+        expectedContextSearch: 'newName() {} // existing');
   }
 
-  test_checkFinalConditions_hasMember_method() {
+  test_checkFinalConditions_hasMember_method() async {
     indexTestUnit('''
 class A {
   A.test() {}
@@ -50,13 +50,12 @@
     _createConstructorDeclarationRefactoring('test() {}');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Class 'A' already declares method with name 'newName'.",
-          expectedContextSearch: 'newName() {} // existing');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Class 'A' already declares method with name 'newName'.",
+        expectedContextSearch: 'newName() {} // existing');
   }
 
   test_checkNewName() {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
index 552ff56..4df587d 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_library_test.dart
@@ -46,7 +46,7 @@
         expectedMessage: "The new name must be different than the current name.");
   }
 
-  test_createChange() {
+  test_createChange() async {
     Source unitSource = addSource('/part.dart', '''
 part of my.app;
 ''');
@@ -63,14 +63,13 @@
     expect(refactoring.elementKindName, 'library');
     refactoring.newName = 'the.new.name';
     // validate change
-    return assertSuccessfulRefactoring('''
+    await assertSuccessfulRefactoring('''
 library the.new.name;
 part 'part.dart';
-''').then((_) {
-      assertFileChangeResult('/part.dart', '''
+''');
+    assertFileChangeResult('/part.dart', '''
 part of the.new.name;
 ''');
-    });
   }
 
   void _createRenameRefactoring() {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
index 8cb9478..92c67d9 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_local_test.dart
@@ -9,6 +9,7 @@
 
 import '../../reflective_tests.dart';
 import 'abstract_rename.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 
 
 main() {
@@ -19,7 +20,7 @@
 
 @reflectiveTest
 class RenameLocalTest extends RenameRefactoringTest {
-  test_checkFinalConditions_hasLocalFunction_after() {
+  test_checkFinalConditions_hasLocalFunction_after() async {
     indexTestUnit('''
 main() {
   int test = 0;
@@ -29,16 +30,15 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Duplicate function 'newName'.",
-          expectedContextSearch: 'newName() => 1');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Duplicate function 'newName'.",
+        expectedContextSearch: 'newName() => 1');
   }
 
-  test_checkFinalConditions_hasLocalFunction_before() {
+  test_checkFinalConditions_hasLocalFunction_before() async {
     indexTestUnit('''
 main() {
   newName() => 1;
@@ -48,15 +48,14 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Duplicate function 'newName'.");
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Duplicate function 'newName'.");
   }
 
-  test_checkFinalConditions_hasLocalVariable_after() {
+  test_checkFinalConditions_hasLocalVariable_after() async {
     indexTestUnit('''
 main() {
   int test = 0;
@@ -67,17 +66,16 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      expect(status.problems, hasLength(1));
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Duplicate local variable 'newName'.",
-          expectedContextSearch: 'newName = 1;');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    expect(status.problems, hasLength(1));
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Duplicate local variable 'newName'.",
+        expectedContextSearch: 'newName = 1;');
   }
 
-  test_checkFinalConditions_hasLocalVariable_before() {
+  test_checkFinalConditions_hasLocalVariable_before() async {
     indexTestUnit('''
 main() {
   var newName = 1;
@@ -87,13 +85,12 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Duplicate local variable 'newName'.",
-          expectedContextSearch: 'newName = 1;');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Duplicate local variable 'newName'.",
+        expectedContextSearch: 'newName = 1;');
   }
 
   test_checkFinalConditions_hasLocalVariable_otherBlock() {
@@ -128,7 +125,7 @@
     return assertRefactoringConditionsOK();
   }
 
-  test_checkFinalConditions_shadows_classMember() {
+  test_checkFinalConditions_shadows_classMember() async {
     indexTestUnit('''
 class A {
   var newName = 1;
@@ -141,14 +138,13 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: 'Usage of field "A.newName" declared in "test.dart" '
-              'will be shadowed by renamed local variable.',
-          expectedContextSearch: 'newName);');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: 'Usage of field "A.newName" declared in "test.dart" '
+            'will be shadowed by renamed local variable.',
+        expectedContextSearch: 'newName);');
   }
 
   test_checkFinalConditions_shadows_classMemberOK_qualifiedReference() {
@@ -181,7 +177,7 @@
     return assertRefactoringFinalConditionsOK();
   }
 
-  test_checkFinalConditions_shadows_topLevelFunction() {
+  test_checkFinalConditions_shadows_topLevelFunction() async {
     indexTestUnit('''
 newName() {}
 main() {
@@ -192,12 +188,11 @@
     createRenameRefactoringAtString('test = 0');
     // check status
     refactoring.newName = 'newName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedContextSearch: 'newName(); // ref');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedContextSearch: 'newName(); // ref');
   }
 
   test_checkNewName_FunctionElement() {
@@ -416,7 +411,7 @@
 ''');
   }
 
-  test_createChange_parameter_namedInOtherFile() {
+  test_createChange_parameter_namedInOtherFile() async {
     indexTestUnit('''
 class A {
   A({test});
@@ -433,18 +428,17 @@
     expect(refactoring.refactoringName, 'Rename Parameter');
     refactoring.newName = 'newName';
     // validate change
-    return assertSuccessfulRefactoring('''
+    await assertSuccessfulRefactoring('''
 class A {
   A({newName});
 }
-''').then((_) {
-      assertFileChangeResult('/test2.dart', '''
+''');
+    assertFileChangeResult('/test2.dart', '''
 import 'test.dart';
 main() {
   new A(newName: 2);
 }
 ''');
-    });
   }
 
   test_oldName() {
diff --git a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
index 803e9ba..1754975 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_unit_member_test.dart
@@ -5,6 +5,7 @@
 library test.services.refactoring.rename_unit_member;
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/status.dart';
 import 'package:unittest/unittest.dart';
 
 import '../../reflective_tests.dart';
@@ -19,7 +20,7 @@
 
 @reflectiveTest
 class RenameUnitMemberTest extends RenameRefactoringTest {
-  test_checkFinalConditions_hasTopLevel_ClassElement() {
+  test_checkFinalConditions_hasTopLevel_ClassElement() async {
     indexTestUnit('''
 class Test {}
 class NewName {} // existing
@@ -27,16 +28,15 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Library already declares class with name 'NewName'.",
-          expectedContextSearch: 'NewName {} // existing');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Library already declares class with name 'NewName'.",
+        expectedContextSearch: 'NewName {} // existing');
   }
 
-  test_checkFinalConditions_hasTopLevel_FunctionTypeAliasElement() {
+  test_checkFinalConditions_hasTopLevel_FunctionTypeAliasElement() async {
     indexTestUnit('''
 class Test {}
 typedef NewName(); // existing
@@ -44,17 +44,16 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage:
-              "Library already declares function type alias with name 'NewName'.",
-          expectedContextSearch: 'NewName(); // existing');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Library already declares function type alias with name 'NewName'.",
+        expectedContextSearch: 'NewName(); // existing');
   }
 
-  test_checkFinalConditions_OK_qualifiedSuper_MethodElement() {
+  test_checkFinalConditions_OK_qualifiedSuper_MethodElement() async {
     indexTestUnit('''
 class Test {}
 class A {
@@ -69,12 +68,11 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowedBy_MethodElement() {
+  test_checkFinalConditions_shadowedBy_MethodElement() async {
     indexTestUnit('''
 class Test {}
 class A {
@@ -87,17 +85,16 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage:
-              "Reference to renamed class will be shadowed by method 'A.NewName'.",
-          expectedContextSearch: 'NewName() {}');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage:
+            "Reference to renamed class will be shadowed by method 'A.NewName'.",
+        expectedContextSearch: 'NewName() {}');
   }
 
-  test_checkFinalConditions_shadowsInSubClass_importedLib() {
+  test_checkFinalConditions_shadowsInSubClass_importedLib() async {
     indexTestUnit('''
 class Test {}
 ''');
@@ -116,15 +113,18 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Renamed class will shadow method 'A.NewName'.");
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Renamed class will shadow method 'A.NewName'.");
   }
 
-  test_checkFinalConditions_shadowsInSubClass_importedLib_hideCombinator() {
+
+
+
+
+      test_checkFinalConditions_shadowsInSubClass_importedLib_hideCombinator() async {
     indexTestUnit('''
 class Test {}
 ''');
@@ -143,12 +143,11 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowsInSubClass_MethodElement() {
+  test_checkFinalConditions_shadowsInSubClass_MethodElement() async {
     indexTestUnit('''
 class Test {}
 class A {
@@ -163,16 +162,15 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatus(
-          status,
-          RefactoringProblemSeverity.ERROR,
-          expectedMessage: "Renamed class will shadow method 'A.NewName'.",
-          expectedContextSearch: 'NewName(); // super-ref');
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatus(
+        status,
+        RefactoringProblemSeverity.ERROR,
+        expectedMessage: "Renamed class will shadow method 'A.NewName'.",
+        expectedContextSearch: 'NewName(); // super-ref');
   }
 
-  test_checkFinalConditions_shadowsInSubClass_notImportedLib() {
+  test_checkFinalConditions_shadowsInSubClass_notImportedLib() async {
     indexUnit('/lib.dart', '''
 library my.lib;
 class A {
@@ -190,12 +188,11 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
-  test_checkFinalConditions_shadowsInSubClass_notSubClass() {
+  test_checkFinalConditions_shadowsInSubClass_notSubClass() async {
     indexTestUnit('''
 class Test {}
 class A {
@@ -210,9 +207,8 @@
     createRenameRefactoringAtString('Test {}');
     // check status
     refactoring.newName = 'NewName';
-    return refactoring.checkFinalConditions().then((status) {
-      assertRefactoringStatusOK(status);
-    });
+    RefactoringStatus status = await refactoring.checkFinalConditions();
+    assertRefactoringStatusOK(status);
   }
 
   test_checkNewName_ClassElement() {
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index 37c4ea7..b34defb 100644
--- a/pkg/analysis_server/tool/spec/spec_input.html
+++ b/pkg/analysis_server/tool/spec/spec_input.html
@@ -6,7 +6,7 @@
   </head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version <version>1.0.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.2.0</version></h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -468,11 +468,26 @@
       </request>
       <request method="reanalyze">
         <p>
-          Force the re-analysis of everything contained in the
-          existing analysis roots. This will cause all previously
-          computed analysis results to be discarded and recomputed,
-          and will cause all subscribed notifications to be re-sent.
+          Force the re-analysis of everything contained in the specified
+          analysis roots. This will cause all previously computed analysis
+          results to be discarded and recomputed, and will cause all subscribed
+          notifications to be re-sent.
         </p>
+        <p>
+          If no analysis roots are provided, then all current analysis roots
+          will be re-analyzed. If an empty list of analysis roots is provided,
+          then nothing will be re-analyzed. If the list contains one or more
+          paths that are not currently analysis roots, then an error of type
+          <tt>INVALID_ANALYSIS_ROOT</tt> will be generated.
+        </p>
+        <params>
+          <field name="roots" optional="true">
+            <list><ref>FilePath</ref></list>
+            <p>
+              A list of the analysis roots that are to be re-analyzed.
+            </p>
+          </field>
+        </params>
       </request>
       <request method="setAnalysisRoots">
         <p>
@@ -1285,7 +1300,9 @@
           text is passed in so that the selection can be preserved across the
           formatting operation. The updated selection will be as close to
           matching the original as possible, but whitespace at the beginning or
-          end of the selected region will be ignored.
+          end of the selected region will be ignored. If preserving selection
+          information is not required, zero (0) can be specified for both the
+          selection offset and selection length.
         </p>
         <p>
           If a request is made for a file which does not exist, or
@@ -1304,17 +1321,13 @@
           <field name="selectionOffset">
             <ref>int</ref>
             <p>
-              The offset of the current selection in the file. In case
-              preserving, selection information is not required, 0 can be
-              specified for both selection offset and length.
+              The offset of the current selection in the file.
             </p>
           </field>
           <field name="selectionLength">
             <ref>int</ref>
             <p>
-              The length of the current selection in the file. In case
-              preserving, selection information is not required, 0 can be
-              specified for both selection offset and length.
+              The length of the current selection in the file.
             </p>
           </field>
           <!--
@@ -1626,7 +1639,8 @@
           <field name="contextRoot">
             <ref>FilePath</ref>
             <p>
-              The path of the Dart or HTML file that will be launched.
+              The path of the Dart or HTML file that will be launched, or the
+              path of the directory containing the file.
             </p>
           </field>
         </params>
@@ -1662,25 +1676,27 @@
           context.
         </p>
         <p>
-          Exactly one of the file and uri fields must be provided.
+          Exactly one of the file and uri fields must be provided. If both
+          fields are provided, then an error of type <tt>INVALID_PARAMETER</tt>
+          will be generated. Similarly, if neither field is provided, then an
+          error of type <tt>INVALID_PARAMETER</tt> will be generated.
         </p>
         <p>
           If the file field is provided and the value is not the path of a file
           (either the file does not exist or the path references something other
-          than a file), then an error of type <tt>MAP_URI_INVALID_FILE</tt> will
+          than a file), then an error of type <tt>INVALID_PARAMETER</tt> will
           be generated.
         </p>
         <p>
           If the uri field is provided and the value is not a valid URI or if
           the URI references something that is not a file (either a file that
           does not exist or something other than a file), then an error of type
-          <tt>MAP_URI_INVALID_URI</tt> will be generated.
+          <tt>INVALID_PARAMETER</tt> will be generated.
         </p>
         <p>
-          If the contextRoot used to create the execution context is not a file
-          (either the file does not exist or the path references something other
-          than a file), then an error of type <tt>INVALID_EXECUTION_CONTEXT</tt>
-          will be generated.
+          If the contextRoot used to create the execution context does not
+          exist, then an error of type <tt>INVALID_EXECUTION_CONTEXT</tt> will
+          be generated.
         </p>
         <params>
           <field name="id">
@@ -3072,6 +3088,13 @@
             </p>
           </value>
           <value>
+            <code>INVALID_EXECUTION_CONTEXT</code>
+            <p>
+              The context root used to create an execution context does not
+              exist.
+            </p>
+          </value>
+          <value>
             <code>INVALID_OVERLAY_CHANGE</code>
             <p>
               An analysis.updateContent request contained a
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index a6580f5..ff3e5ff 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -147,6 +147,9 @@
     return null;
   }
 
+  @override
+  Uri restoreAbsolute(Source source) => source.uri;
+
   /**
    * Return `true` if the given URI is a `file` URI.
    *
diff --git a/pkg/analyzer/lib/source/package_map_resolver.dart b/pkg/analyzer/lib/source/package_map_resolver.dart
index 2f70b86..badaf3a 100644
--- a/pkg/analyzer/lib/source/package_map_resolver.dart
+++ b/pkg/analyzer/lib/source/package_map_resolver.dart
@@ -49,16 +49,13 @@
     // Prepare path.
     String path = uri.path;
     // Prepare path components.
-    String pkgName;
-    String relPath;
     int index = path.indexOf('/');
     if (index == -1 || index == 0) {
       return null;
-    } else {
-      // <pkgName>/<relPath>
-      pkgName = path.substring(0, index);
-      relPath = path.substring(index + 1);
     }
+    // <pkgName>/<relPath>
+    String pkgName = path.substring(0, index);
+    String relPath = path.substring(index + 1);
     // Try to find an existing file.
     List<Folder> packageDirs = packageMap[pkgName];
     if (packageDirs != null) {
diff --git a/pkg/analyzer/lib/src/error_formatter.dart b/pkg/analyzer/lib/src/error_formatter.dart
index b64dfc6..ea0ad47 100644
--- a/pkg/analyzer/lib/src/error_formatter.dart
+++ b/pkg/analyzer/lib/src/error_formatter.dart
@@ -56,7 +56,8 @@
       out.write(escapePipe(error.message));
     } else {
       String errorType = severity.displayName;
-      if (error.errorCode.type == ErrorType.HINT) {
+      if (error.errorCode.type == ErrorType.HINT ||
+          error.errorCode.type == ErrorType.LINT) {
         errorType = error.errorCode.type.displayName;
       }
       // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index 337dc99..ebfbcac 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -87,6 +87,9 @@
       identical(object, this);
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
       Set<TypeImpl_TypePair> visitedTypePairs) =>
       true;
@@ -2179,6 +2182,9 @@
       identical(object, this);
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
       Set<TypeImpl_TypePair> visitedTypePairs) {
     // T is S
@@ -4791,26 +4797,32 @@
   }
 
   @override
-  int get hashCode {
+  int get hashCode => internalHashCode(<DartType>[]);
+
+  @override
+  int internalHashCode(List<DartType> visitedTypes) {
     if (element == null) {
       return 0;
+    } else if (visitedTypes.contains(this)) {
+      return 3;
     }
+    visitedTypes.add(this);
     // Reference the arrays of parameters
     List<DartType> normalParameterTypes = this.normalParameterTypes;
     List<DartType> optionalParameterTypes = this.optionalParameterTypes;
     Iterable<DartType> namedParameterTypes = this.namedParameterTypes.values;
     // Generate the hashCode
-    int hashCode = returnType.hashCode;
+    int code = (returnType as TypeImpl).internalHashCode(visitedTypes);
     for (int i = 0; i < normalParameterTypes.length; i++) {
-      hashCode = (hashCode << 1) + normalParameterTypes[i].hashCode;
+      code = (code << 1) + (normalParameterTypes[i] as TypeImpl).internalHashCode(visitedTypes);
     }
     for (int i = 0; i < optionalParameterTypes.length; i++) {
-      hashCode = (hashCode << 1) + optionalParameterTypes[i].hashCode;
+      code = (code << 1) + (optionalParameterTypes[i] as TypeImpl).internalHashCode(visitedTypes);
     }
     for (DartType type in namedParameterTypes) {
-      hashCode = (hashCode << 1) + type.hashCode;
+      code = (code << 1) + (type as TypeImpl).internalHashCode(visitedTypes);
     }
-    return hashCode;
+    return code;
   }
 
   @override
@@ -4935,7 +4947,11 @@
       internalEquals(object, new HashSet<ElementPair>());
 
   @override
-  void appendTo(StringBuffer buffer) {
+  void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
+    if (!visitedTypes.add(this)) {
+      buffer.write(name == null ? '...' : name);
+      return;
+    }
     List<DartType> normalParameterTypes = this.normalParameterTypes;
     List<DartType> optionalParameterTypes = this.optionalParameterTypes;
     Map<String, DartType> namedParameterTypes = this.namedParameterTypes;
@@ -4949,7 +4965,7 @@
         } else {
           needsComma = true;
         }
-        (type as TypeImpl).appendTo(buffer);
+        (type as TypeImpl).appendTo(buffer, visitedTypes);
       }
     }
     if (optionalParameterTypes.length > 0) {
@@ -4964,7 +4980,7 @@
         } else {
           needsComma = true;
         }
-        (type as TypeImpl).appendTo(buffer);
+        (type as TypeImpl).appendTo(buffer, visitedTypes);
       }
       buffer.write("]");
       needsComma = true;
@@ -4983,7 +4999,7 @@
         }
         buffer.write(name);
         buffer.write(": ");
-        (type as TypeImpl).appendTo(buffer);
+        (type as TypeImpl).appendTo(buffer, visitedTypes);
       });
       buffer.write("}");
       needsComma = true;
@@ -4993,7 +5009,7 @@
     if (returnType == null) {
       buffer.write("null");
     } else {
-      (returnType as TypeImpl).appendTo(buffer);
+      (returnType as TypeImpl).appendTo(buffer, visitedTypes);
     }
   }
 
@@ -6256,6 +6272,9 @@
   }
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   List<InterfaceType> get interfaces {
     ClassElement classElement = element;
     List<InterfaceType> interfaces = classElement.interfaces;
@@ -6335,7 +6354,11 @@
       internalEquals(object, new HashSet<ElementPair>());
 
   @override
-  void appendTo(StringBuffer buffer) {
+  void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
+    if (!visitedTypes.add(this)) {
+      buffer.write(name == null ? '...' : name);
+      return;
+    }
     buffer.write(name);
     int argumentCount = typeArguments.length;
     if (argumentCount > 0) {
@@ -6344,7 +6367,7 @@
         if (i > 0) {
           buffer.write(", ");
         }
-        (typeArguments[i] as TypeImpl).appendTo(buffer);
+        (typeArguments[i] as TypeImpl).appendTo(buffer, visitedTypes);
       }
       buffer.write(">");
     }
@@ -9985,9 +10008,14 @@
   bool get isVoid => false;
 
   /**
-   * Append a textual representation of this type to the given [buffer].
+   * Append a textual representation of this type to the given [buffer]. The set
+   * of [visitedTypes] is used to prevent infinite recusion.
    */
-  void appendTo(StringBuffer buffer) {
+  void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
+    if (!visitedTypes.add(this)) {
+      buffer.write(name == null ? '...' : name);
+      return;
+    }
     if (name == null) {
       buffer.write("<unnamed type>");
     } else {
@@ -10000,6 +10028,8 @@
 
   bool internalEquals(Object object, Set<ElementPair> visitedElementPairs);
 
+  int internalHashCode(List<DartType> visitedTypes);
+
   bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
       Set<TypeImpl_TypePair> visitedTypePairs);
 
@@ -10127,7 +10157,7 @@
   @override
   String toString() {
     StringBuffer buffer = new StringBuffer();
-    appendTo(buffer);
+    appendTo(buffer, new HashSet<DartType>());
     return buffer.toString();
   }
 
@@ -10346,6 +10376,9 @@
       this == object;
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool internalIsMoreSpecificThan(DartType s, bool withDynamic,
       Set<TypeImpl_TypePair> visitedTypePairs) {
     //
@@ -10503,6 +10536,9 @@
       identical(object, this);
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool internalIsMoreSpecificThan(DartType type, bool withDynamic,
       Set<TypeImpl_TypePair> visitedTypePairs) {
     // T is S
@@ -10583,6 +10619,9 @@
   int get hashCode => _types.hashCode;
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool operator ==(Object other) {
     if (other == null || other is! UnionType) {
       return false;
@@ -10594,11 +10633,15 @@
   }
 
   @override
-  void appendTo(StringBuffer buffer) {
+  void appendTo(StringBuffer buffer, Set<DartType> visitedTypes) {
+    if (!visitedTypes.add(this)) {
+      buffer.write(name == null ? '...' : name);
+      return;
+    }
     String prefix = "{";
     for (DartType type in _types) {
       buffer.write(prefix);
-      (type as TypeImpl).appendTo(buffer);
+      (type as TypeImpl).appendTo(buffer, visitedTypes);
       prefix = ",";
     }
     buffer.write("}");
@@ -11087,6 +11130,9 @@
   int get hashCode => 2;
 
   @override
+  int internalHashCode(List<DartType> visitedTypes) => hashCode;
+
+  @override
   bool get isVoid => true;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index af7eb92..67a7a23 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -715,17 +715,16 @@
   LineInfo getLineInfo(Source source);
 
   /**
-   * Return the modification stamp for the given source. A modification stamp is a non-negative
-   * integer with the property that if the contents of the source have not been modified since the
-   * last time the modification stamp was accessed then the same value will be returned, but if the
-   * contents of the source have been modified one or more times (even if the net change is zero)
-   * the stamps will be different.
+   * Return the modification stamp for the [source], or a negative value if the
+   * source does not exist. A modification stamp is a non-negative integer with
+   * the property that if the contents of the source have not been modified
+   * since the last time the modification stamp was accessed then the same value
+   * will be returned, but if the contents of the source have been modified one
+   * or more times (even if the net change is zero) the stamps will be different.
    *
-   * This method should be used rather than the method [Source.getModificationStamp] because
-   * contexts can have local overrides of the content of a source that the source is not aware of.
-   *
-   * @param source the source whose modification stamp is to be returned
-   * @return the modification stamp for the source
+   * This method should be used rather than the method
+   * [Source.getModificationStamp] because contexts can have local overrides of
+   * the content of a source that the source is not aware of.
    */
   int getModificationStamp(Source source);
 
@@ -1977,7 +1976,10 @@
       if (AnalysisEngine.isHtmlFileName(sourceName)) {
         return computeHtmlElement(source);
       }
-    } on AnalysisException catch (exception) {
+    } catch (exception) {
+      // If the location cannot be decoded for some reason then the underlying
+      // cause should have been logged already and we can fall though to return
+      // null.
     }
     return null;
   }
@@ -4682,6 +4684,11 @@
     CaughtException thrownException = task.exception;
     if (thrownException != null) {
       sourceEntry.recordContentError(thrownException);
+      {
+        sourceEntry.setValue(SourceEntry.CONTENT_ERRORS, task.errors);
+        ChangeNoticeImpl notice = _getNotice(source);
+        notice.setErrors(sourceEntry.allErrors, null);
+      }
       _workManager.remove(source);
       throw new AnalysisException('<rethrow>', thrownException);
     }
@@ -7870,7 +7877,8 @@
       new DataDescriptor<CompilationUnit>("DartEntry.RESOLVED_UNIT");
 
   /**
-   * The data descriptor representing the token stream.
+   * The data descriptor representing the errors resulting from scanning the
+   * source.
    */
   static final DataDescriptor<List<AnalysisError>> SCAN_ERRORS =
       new DataDescriptor<List<AnalysisError>>(
@@ -7917,6 +7925,7 @@
    */
   List<AnalysisError> get allErrors {
     List<AnalysisError> errors = new List<AnalysisError>();
+    errors.addAll(super.allErrors);
     errors.addAll(getValue(SCAN_ERRORS));
     errors.addAll(getValue(PARSE_ERRORS));
     ResolutionState state = _resolutionState;
@@ -9031,6 +9040,11 @@
   String _content;
 
   /**
+   * The errors that were produced by getting the source content.
+   */
+  final List<AnalysisError> errors = <AnalysisError>[];
+
+  /**
    * The time at which the contents of the source were last modified.
    */
   int _modificationTime = -1;
@@ -9094,6 +9108,11 @@
           _modificationTime,
           _content);
     } catch (exception, stackTrace) {
+      errors.add(
+          new AnalysisError.con1(
+              source,
+              ScannerErrorCode.UNABLE_GET_CONTENT,
+              [exception]));
       throw new AnalysisException(
           "Could not get contents of $source",
           new CaughtException(exception, stackTrace));
@@ -9165,6 +9184,7 @@
    */
   List<AnalysisError> get allErrors {
     List<AnalysisError> errors = new List<AnalysisError>();
+    errors.addAll(super.allErrors);
     errors.addAll(getValue(PARSE_ERRORS));
     errors.addAll(getValue(RESOLUTION_ERRORS));
     errors.addAll(getValue(HINTS));
@@ -10924,6 +10944,7 @@
   void setValue(DataDescriptor /*<V>*/ descriptor, dynamic /*V*/ value) {
     CachedResult result =
         resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
+    SourceEntry.countTransition(descriptor, result);
     result.state = CacheState.VALID;
     result.value = value == null ? descriptor.defaultValue : value;
   }
@@ -11592,6 +11613,15 @@
       new DataDescriptor<String>("SourceEntry.CONTENT");
 
   /**
+   * The data descriptor representing the errors resulting from reading the
+   * source content.
+   */
+  static final DataDescriptor<List<AnalysisError>> CONTENT_ERRORS =
+      new DataDescriptor<List<AnalysisError>>(
+          "SourceEntry.CONTENT_ERRORS",
+          AnalysisError.NO_ERRORS);
+
+  /**
    * The data descriptor representing the line information.
    */
   static final DataDescriptor<LineInfo> LINE_INFO =
@@ -11605,6 +11635,13 @@
   static int _EXPLICITLY_ADDED_FLAG = 0;
 
   /**
+   * A table mapping data descriptors to a count of the number of times a value
+   * was set when in a given state.
+   */
+  static final Map<DataDescriptor, Map<CacheState, int>> transitionMap =
+      new HashMap<DataDescriptor, Map<CacheState, int>>();
+
+  /**
    * The most recent time at which the state of the source matched the state
    * represented by this entry.
    */
@@ -11629,11 +11666,18 @@
       new HashMap<DataDescriptor, CachedResult>();
 
   /**
+   * Return all of the errors associated with this entry.
+   */
+  List<AnalysisError> get allErrors {
+    return getValue(CONTENT_ERRORS);
+  }
+
+  /**
    * Get a list of all the library-independent descriptors for which values may
    * be stored in this SourceEntry.
    */
   List<DataDescriptor> get descriptors {
-    return <DataDescriptor>[SourceEntry.CONTENT, SourceEntry.LINE_INFO];
+    return <DataDescriptor>[CONTENT, CONTENT_ERRORS, LINE_INFO];
   }
 
   /**
@@ -11732,6 +11776,7 @@
    */
   void invalidateAllInformation() {
     setState(CONTENT, CacheState.INVALID);
+    setState(CONTENT_ERRORS, CacheState.INVALID);
     setState(LINE_INFO, CacheState.INVALID);
   }
 
@@ -11794,10 +11839,23 @@
     _validateStateChange(descriptor, CacheState.VALID);
     CachedResult result =
         resultMap.putIfAbsent(descriptor, () => new CachedResult(descriptor));
+    countTransition(descriptor, result);
     result.state = CacheState.VALID;
     result.value = value == null ? descriptor.defaultValue : value;
   }
 
+  /**
+   * Increment the count of the number of times that data represented by the
+   * given [descriptor] was transitioned from the current state (as found in the
+   * given [result] to a valid state.
+   */
+  static void countTransition(DataDescriptor descriptor, CachedResult result) {
+    Map<CacheState, int> countMap =
+        transitionMap.putIfAbsent(descriptor, () => new HashMap<CacheState, int>());
+    int count = countMap[result.state];
+    countMap[result.state] = count == null ? 1 : count + 1;
+  }
+
   @override
   String toString() {
     StringBuffer buffer = new StringBuffer();
@@ -11826,7 +11884,9 @@
    * Return `true` if the [descriptor] is valid for this entry.
    */
   bool _isValidDescriptor(DataDescriptor descriptor) {
-    return descriptor == CONTENT || descriptor == LINE_INFO;
+    return descriptor == CONTENT ||
+        descriptor == CONTENT_ERRORS ||
+        descriptor == LINE_INFO;
   }
 
   /**
@@ -11887,6 +11947,12 @@
     }
     needsSeparator =
         _writeStateDiffOn(buffer, needsSeparator, "content", CONTENT, oldEntry);
+    needsSeparator = _writeStateDiffOn(
+        buffer,
+        needsSeparator,
+        "contentErrors",
+        CONTENT_ERRORS,
+        oldEntry);
     needsSeparator =
         _writeStateDiffOn(buffer, needsSeparator, "lineInfo", LINE_INFO, oldEntry);
     return needsSeparator;
@@ -11900,6 +11966,7 @@
     buffer.write("time = ");
     buffer.write(modificationTime);
     _writeStateOn(buffer, "content", CONTENT);
+    _writeStateOn(buffer, "contentErrors", CONTENT_ERRORS);
     _writeStateOn(buffer, "lineInfo", LINE_INFO);
   }
 
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 038d0f0..ef8b807 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -1170,8 +1170,8 @@
   List<AnalysisError> _newScanErrors = <AnalysisError>[];
   List<AnalysisError> _newParseErrors = <AnalysisError>[];
 
-  PoorMansIncrementalResolver(this._typeProvider, this._unitSource,
-      this._entry, this._oldUnit, bool resolveApiChanges) {
+  PoorMansIncrementalResolver(this._typeProvider, this._unitSource, this._entry,
+      this._oldUnit, bool resolveApiChanges) {
     _resolveApiChanges = resolveApiChanges;
   }
 
@@ -1426,21 +1426,29 @@
   }
 
   static _TokenDifferenceKind _compareToken(Token oldToken, Token newToken,
-      int delta) {
-    if (oldToken == null && newToken == null) {
-      return null;
-    }
-    if (oldToken == null || newToken == null) {
-      return _TokenDifferenceKind.CONTENT;
-    }
-    if (oldToken.type != newToken.type) {
-      return _TokenDifferenceKind.CONTENT;
-    }
-    if (oldToken.lexeme != newToken.lexeme) {
-      return _TokenDifferenceKind.CONTENT;
-    }
-    if (newToken.offset - oldToken.offset != delta) {
-      return _TokenDifferenceKind.OFFSET;
+      int delta, bool forComment) {
+    while (true) {
+      if (oldToken == null && newToken == null) {
+        return null;
+      }
+      if (oldToken == null || newToken == null) {
+        return _TokenDifferenceKind.CONTENT;
+      }
+      if (oldToken.type != newToken.type) {
+        return _TokenDifferenceKind.CONTENT;
+      }
+      if (oldToken.lexeme != newToken.lexeme) {
+        return _TokenDifferenceKind.CONTENT;
+      }
+      if (newToken.offset - oldToken.offset != delta) {
+        return _TokenDifferenceKind.OFFSET;
+      }
+      // continue if comment tokens are being checked
+      if (!forComment) {
+        break;
+      }
+      oldToken = oldToken.next;
+      newToken = newToken.next;
     }
     return null;
   }
@@ -1457,7 +1465,7 @@
       {
         Token oldComment = oldToken.precedingComments;
         Token newComment = newToken.precedingComments;
-        if (_compareToken(oldComment, newComment, 0) != null) {
+        if (_compareToken(oldComment, newComment, 0, true) != null) {
           _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
           if (oldComment is DocumentationCommentToken ||
               newComment is DocumentationCommentToken) {
@@ -1467,7 +1475,8 @@
         }
       }
       // compare tokens
-      _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, 0);
+      _TokenDifferenceKind diffKind =
+          _compareToken(oldToken, newToken, 0, false);
       if (diffKind != null) {
         return new _TokenPair(diffKind, oldToken, newToken);
       }
@@ -1483,7 +1492,8 @@
     int delta = newToken.offset - oldToken.offset;
     while (oldToken.previous != oldToken && newToken.previous != newToken) {
       // compare tokens
-      _TokenDifferenceKind diffKind = _compareToken(oldToken, newToken, delta);
+      _TokenDifferenceKind diffKind =
+          _compareToken(oldToken, newToken, delta, false);
       if (diffKind != null) {
         return new _TokenPair(diffKind, oldToken.next, newToken.next);
       }
@@ -1491,7 +1501,7 @@
       {
         Token oldComment = oldToken.precedingComments;
         Token newComment = newToken.precedingComments;
-        if (_compareToken(oldComment, newComment, delta) != null) {
+        if (_compareToken(oldComment, newComment, delta, true) != null) {
           _TokenDifferenceKind diffKind = _TokenDifferenceKind.COMMENT;
           if (oldComment is DocumentationCommentToken ||
               newComment is DocumentationCommentToken) {
diff --git a/pkg/analyzer/lib/src/generated/java_io.dart b/pkg/analyzer/lib/src/generated/java_io.dart
index 5e900d1..e947d80 100644
--- a/pkg/analyzer/lib/src/generated/java_io.dart
+++ b/pkg/analyzer/lib/src/generated/java_io.dart
@@ -71,9 +71,11 @@
     return _newFile().existsSync();
   }
   int lastModified() {
-    if (!_newFile().existsSync()) return 0;
-    return _newFile().lastModifiedSync().millisecondsSinceEpoch;
-
+    try {
+      return _newFile().lastModifiedSync().millisecondsSinceEpoch;
+    } catch (exception) {
+      return -1;
+    }
   }
   List<JavaFile> listFiles() {
     var files = <JavaFile>[];
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 9f3ab6d..a40c7e6 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -598,7 +598,7 @@
     }
     // Check the block for a return statement, if not, create the hint
     BlockFunctionBody blockFunctionBody = body as BlockFunctionBody;
-    if (!blockFunctionBody.accept(new ExitDetector())) {
+    if (!ExitDetector.exits(blockFunctionBody)) {
       _errorReporter.reportErrorForNode(
           HintCode.MISSING_RETURN,
           returnType,
@@ -4331,6 +4331,13 @@
     }
     return false;
   }
+
+  /**
+   * Return `true` if the given [node] exits.
+   */
+  static bool exits(AstNode node) {
+    return new ExitDetector()._nodeExits(node);
+  }
 }
 
 /**
@@ -7962,7 +7969,7 @@
     }
     LibraryElement asyncElement = _asyncLibrary.libraryElement;
     if (asyncElement == null) {
-      throw new AnalysisException("Coulb not resolve dart:async");
+      throw new AnalysisException("Could not resolve dart:async");
     }
     _buildDirectiveModels();
     _typeProvider = new TypeProviderImpl(coreElement, asyncElement);
diff --git a/pkg/analyzer/lib/src/generated/scanner.dart b/pkg/analyzer/lib/src/generated/scanner.dart
index 436a5bb..29ec7cc 100644
--- a/pkg/analyzer/lib/src/generated/scanner.dart
+++ b/pkg/analyzer/lib/src/generated/scanner.dart
@@ -1816,6 +1816,9 @@
   static const ScannerErrorCode MISSING_QUOTE =
       const ScannerErrorCode('MISSING_QUOTE', "Expected quote (' or \")");
 
+  static const ScannerErrorCode UNABLE_GET_CONTENT =
+      const ScannerErrorCode('UNABLE_GET_CONTENT', "Unable to get content: {0}");
+
   static const ScannerErrorCode UNTERMINATED_MULTI_LINE_COMMENT =
       const ScannerErrorCode(
           'UNTERMINATED_MULTI_LINE_COMMENT',
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 01bff35..7c48e3c 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -439,17 +439,16 @@
   bool get isInSystemLibrary;
 
   /**
-   * Return the modification stamp for this source. A modification stamp is a non-negative integer
-   * with the property that if the contents of the source have not been modified since the last time
-   * the modification stamp was accessed then the same value will be returned, but if the contents
-   * of the source have been modified one or more times (even if the net change is zero) the stamps
-   * will be different.
+   * Return the modification stamp for this source, or a negative value if the
+   * source does not exist. A modification stamp is a non-negative integer with
+   * the property that if the contents of the source have not been modified
+   * since the last time the modification stamp was accessed then the same value
+   * will be returned, but if the contents of the source have been modified one
+   * or more times (even if the net change is zero) the stamps will be different.
    *
    * Clients should consider using the the method
-   * [AnalysisContext.getModificationStamp] because contexts can have local overrides
-   * of the content of a source that the source is not aware of.
-   *
-   * @return the modification stamp for this source
+   * [AnalysisContext.getModificationStamp] because contexts can have local
+   * overrides of the content of a source that the source is not aware of.
    */
   int get modificationStamp;
 
@@ -662,7 +661,7 @@
   Source fromEncoding(String encoding) {
     Source source = forUri(encoding);
     if (source == null) {
-      throw new IllegalArgumentException("Invalid source encoding: $encoding");
+      throw new IllegalArgumentException("Invalid source encoding: '$encoding'");
     }
     return source;
   }
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 7b461df..da3e457 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -1433,7 +1433,8 @@
       type = _dynamicType;
     }
     if (body.isAsynchronous) {
-      return _typeProvider.futureType.substitute4(<DartType>[type]);
+      return _typeProvider.futureType.substitute4(
+          <DartType>[flattenFutures(_typeProvider, type)]);
     } else {
       return type;
     }
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index a00b215..3fd8ddb 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -49,6 +49,12 @@
  */
 abstract class AnalysisTask {
   /**
+   * A table mapping the types of analysis tasks to the number of times each
+   * kind of task has been performed.
+   */
+  static final Map<Type, int> countMap = new HashMap<Type, int>();
+
+  /**
    * A table mapping the types of analysis tasks to stopwatches used to compute
    * how much time was spent executing each kind of task.
    */
@@ -164,6 +170,8 @@
    */
   void _safelyPerform() {
     try {
+      int count = countMap[runtimeType];
+      countMap[runtimeType] = count == null ? 1 : count + 1;
       Stopwatch stopwatch = stopwatchMap[runtimeType];
       if (stopwatch == null) {
         stopwatch = new Stopwatch();
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 6c686bb..e0c1fe4 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.23.0
+version: 0.24.0-dev.1
 author: Dart Team <misc@dartlang.org>
 description: Static analyzer for Dart.
 homepage: http://www.dartlang.org
diff --git a/pkg/analyzer/test/generated/all_the_rest_test.dart b/pkg/analyzer/test/generated/all_the_rest_test.dart
index e4e8404..18af984 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -7342,9 +7342,8 @@
   }
 
   void _assertHasReturn(bool expectedResult, String source) {
-    ExitDetector detector = new ExitDetector();
     Statement statement = ParserTestCase.parseStatement(source);
-    expect(statement.accept(detector), same(expectedResult));
+    expect(ExitDetector.exits(statement), expectedResult);
   }
 
   void _assertTrue(String source) {
@@ -7378,7 +7377,7 @@
     FunctionDeclaration function = unit.declarations.last;
     BlockFunctionBody body = function.functionExpression.body;
     Statement statement = body.block.statements[1];
-    expect(statement.accept(new ExitDetector()), false);
+    expect(ExitDetector.exits(statement), false);
   }
 
   void test_switch_withEnum_false_withDefault() {
@@ -7400,7 +7399,7 @@
     FunctionDeclaration function = unit.declarations.last;
     BlockFunctionBody body = function.functionExpression.body;
     Statement statement = body.block.statements[1];
-    expect(statement.accept(new ExitDetector()), false);
+    expect(ExitDetector.exits(statement), false);
   }
 
   void test_switch_withEnum_true_noDefault() {
@@ -7420,7 +7419,7 @@
     FunctionDeclaration function = unit.declarations.last;
     BlockFunctionBody body = function.functionExpression.body;
     Statement statement = body.block.statements[0];
-    expect(statement.accept(new ExitDetector()), true);
+    expect(ExitDetector.exits(statement), true);
   }
 
   void test_switch_withEnum_true_withDefault() {
@@ -7440,7 +7439,7 @@
     FunctionDeclaration function = unit.declarations.last;
     BlockFunctionBody body = function.functionExpression.body;
     Statement statement = body.block.statements[0];
-    expect(statement.accept(new ExitDetector()), true);
+    expect(ExitDetector.exits(statement), true);
   }
 }
 
diff --git a/pkg/analyzer/test/generated/element_test.dart b/pkg/analyzer/test/generated/element_test.dart
index e89fb06..64d5fb4 100644
--- a/pkg/analyzer/test/generated/element_test.dart
+++ b/pkg/analyzer/test/generated/element_test.dart
@@ -1709,6 +1709,14 @@
     expect(namedParameters, hasLength(1));
     expect(namedParameters[namedParameterName], namedParameterType);
   }
+
+  void test_toString_recursive() {
+    FunctionElementImpl t = ElementFactory.functionElement("t");
+    FunctionElementImpl s = ElementFactory.functionElement("s");
+    t.returnType = s.type;
+    s.returnType = t.type;
+    expect(t.type.toString(), '() \u2192 () \u2192 ...');
+  }
 }
 
 @reflectiveTest
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index 0089eb8..540f2d9 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -1636,6 +1636,42 @@
         reason: "part resolved 3");
   }
 
+  void test_performAnalysisTask_getContentException_dart() {
+    // add source that throw an exception on "get content"
+    Source source = new _Source_getContent_throwException('test.dart');
+    {
+      ChangeSet changeSet = new ChangeSet();
+      changeSet.addedSource(source);
+      _context.applyChanges(changeSet);
+    }
+    // prepare errors
+    _analyzeAll_assertFinished();
+    List<AnalysisError> errors = _context.getErrors(source).errors;
+    // validate errors
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.source, same(source));
+    expect(error.errorCode, ScannerErrorCode.UNABLE_GET_CONTENT);
+  }
+
+  void test_performAnalysisTask_getContentException_html() {
+    // add source that throw an exception on "get content"
+    Source source = new _Source_getContent_throwException('test.html');
+    {
+      ChangeSet changeSet = new ChangeSet();
+      changeSet.addedSource(source);
+      _context.applyChanges(changeSet);
+    }
+    // prepare errors
+    _analyzeAll_assertFinished();
+    List<AnalysisError> errors = _context.getErrors(source).errors;
+    // validate errors
+    expect(errors, hasLength(1));
+    AnalysisError error = errors[0];
+    expect(error.source, same(source));
+    expect(error.errorCode, ScannerErrorCode.UNABLE_GET_CONTENT);
+  }
+
   void test_performAnalysisTask_importedLibraryAdd() {
     Source libASource =
         _addSource("/libA.dart", "library libA; import 'libB.dart';");
@@ -2219,7 +2255,6 @@
   }
 }
 
-
 class AnalysisContextImplTest_Source_exists_true extends TestSource {
   @override
   bool exists() => true;
@@ -2360,6 +2395,10 @@
     DartEntry entry = new DartEntry();
     expect(entry.allErrors, hasLength(0));
     entry.setValue(
+        SourceEntry.CONTENT_ERRORS,
+        <AnalysisError>[
+            new AnalysisError.con1(source, ScannerErrorCode.UNABLE_GET_CONTENT)]);
+    entry.setValue(
         DartEntry.SCAN_ERRORS,
         <AnalysisError>[
             new AnalysisError.con1(source, ScannerErrorCode.UNTERMINATED_STRING_LITERAL)]);
@@ -2383,7 +2422,7 @@
         DartEntry.HINTS,
         source,
         <AnalysisError>[new AnalysisError.con1(source, HintCode.DEAD_CODE)]);
-    expect(entry.allErrors, hasLength(5));
+    expect(entry.allErrors, hasLength(6));
   }
 
   void test_creation() {
@@ -2665,6 +2704,7 @@
     DartEntry entry = _entryWithValidState(librarySource);
     entry.invalidateAllInformation();
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.INVALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.INVALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.INVALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -2713,6 +2753,7 @@
     DartEntry entry = _entryWithValidState(librarySource);
     entry.invalidateAllResolutionInformation(false);
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -2761,6 +2802,7 @@
     DartEntry entry = _entryWithValidState(librarySource);
     entry.invalidateAllResolutionInformation(true);
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -2842,6 +2884,7 @@
         firstLibrary,
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -2909,6 +2952,7 @@
     entry.recordContentError(
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.ERROR));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.ERROR));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -2969,6 +3013,7 @@
         firstLibrary,
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3035,6 +3080,7 @@
     DartEntry entry = _entryWithValidState(firstLibrary);
     entry.recordParseError(new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3094,6 +3140,7 @@
     entry.recordResolutionError(
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3154,6 +3201,7 @@
         firstLibrary,
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3220,6 +3268,7 @@
     DartEntry entry = _entryWithValidState(firstLibrary);
     entry.recordScanError(new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.ERROR));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3280,6 +3329,7 @@
         firstLibrary,
         new CaughtException(new AnalysisException(), null));
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3655,6 +3705,7 @@
   DartEntry _entryWithValidState([Source firstLibrary, Source secondLibrary]) {
     DartEntry entry = new DartEntry();
     entry.setValue(SourceEntry.CONTENT, null);
+    entry.setValue(SourceEntry.CONTENT_ERRORS, null);
     entry.setValue(SourceEntry.LINE_INFO, null);
     entry.setValue(DartEntry.CONTAINING_LIBRARIES, null);
     entry.setValue(DartEntry.ELEMENT, null);
@@ -3695,6 +3746,7 @@
     // Validate that the state was set correctly.
     //
     expect(entry.getState(SourceEntry.CONTENT), same(CacheState.VALID));
+    expect(entry.getState(SourceEntry.CONTENT_ERRORS), same(CacheState.VALID));
     expect(entry.getState(SourceEntry.LINE_INFO), same(CacheState.VALID));
     expect(
         entry.getState(DartEntry.CONTAINING_LIBRARIES),
@@ -3989,6 +4041,7 @@
   bool visitGenerateDartHintsTask(GenerateDartHintsTask task) => true;
 }
 
+
 class GenerateDartHintsTaskTestTV_perform extends TestTaskVisitor<bool> {
   Source librarySource;
   Source partSource;
@@ -4115,12 +4168,12 @@
   }
 }
 
-
 class GetContentTaskTestTV_accept extends TestTaskVisitor<bool> {
   @override
   bool visitGetContentTask(GetContentTask task) => true;
 }
 
+
 class GetContentTaskTestTV_perform_exception extends TestTaskVisitor<bool> {
   @override
   bool visitGetContentTask(GetContentTask task) {
@@ -4129,7 +4182,6 @@
   }
 }
 
-
 class GetContentTaskTestTV_perform_valid extends TestTaskVisitor<bool> {
   InternalAnalysisContext context;
   Source source;
@@ -4999,12 +5051,12 @@
   }
 }
 
+
 class LintGeneratorTest_Linter_Null_Visitor extends Linter {
   @override
   AstVisitor getVisitor() => null;
 }
 
-
 @reflectiveTest
 class ParseDartTaskTest extends EngineTestCase {
   void test_accept() {
@@ -7093,6 +7145,17 @@
 }
 
 
+class _Source_getContent_throwException extends NonExistingSource {
+  _Source_getContent_throwException(String name)
+      : super(name, UriKind.FILE_URI);
+
+  @override
+  TimestampedData<String> get contents {
+    throw 'Read error';
+  }
+}
+
+
 class _UniversalCachePartitionTest_test_setMaxCacheSize implements
     CacheRetentionPolicy {
   @override
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 5e41ef6..314b7ca 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -2779,6 +2779,38 @@
 ''');
   }
 
+  void test_dartDoc_elegant_updateText_insertToken() {
+    _resolveUnit(r'''
+/// A
+/// [int]
+class Test {
+}
+''');
+    _updateAndValidate(r'''
+/// A
+///
+/// [int]
+class Test {
+}
+''');
+  }
+
+  void test_dartDoc_elegant_updateText_removeToken() {
+    _resolveUnit(r'''
+/// A
+///
+/// [int]
+class Test {
+}
+''');
+    _updateAndValidate(r'''
+/// A
+/// [int]
+class Test {
+}
+''');
+  }
+
   void test_endOfLineComment_add_beforeKeywordToken() {
     _resolveUnit(r'''
 main() {
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 3238e50..1761c81 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -339,6 +339,22 @@
     verify([source]);
   }
 
+  void test_async_flattened() {
+    Source source = addSource('''
+import 'dart:async';
+typedef Future<int> CreatesFutureInt();
+main() {
+  CreatesFutureInt createFutureInt = () async => f();
+  Future<int> futureInt = createFutureInt();
+  futureInt.then((int i) => print(i));
+}
+Future<int> f() => null;
+''');
+    resolve(source);
+    assertNoErrors(source);
+    verify([source]);
+  }
+
   void test_async_future_dynamic_with_return() {
     Source source = addSource('''
 import 'dart:async';
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index b2f48d0..fb54593 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -10030,6 +10030,69 @@
     _listener.assertNoErrors();
   }
 
+  void test_visitFunctionExpression_async_block() {
+    // () async {}
+    BlockFunctionBody body = AstFactory.blockFunctionBody2();
+    body.keyword = TokenFactory.tokenFromString('async');
+    FunctionExpression node =
+        _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+    DartType resultType = _analyze(node);
+    _assertFunctionType(
+        _typeProvider.futureDynamicType,
+        null,
+        null,
+        null,
+        resultType);
+    _listener.assertNoErrors();
+  }
+
+  void test_visitFunctionExpression_async_expression() {
+    // () async => e, where e has type int
+    InterfaceType intType = _typeProvider.intType;
+    InterfaceType futureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[intType]);
+    Expression expression = _resolvedVariable(intType, 'e');
+    ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+    body.keyword = TokenFactory.tokenFromString('async');
+    FunctionExpression node =
+        _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+    DartType resultType = _analyze(node);
+    _assertFunctionType(futureIntType, null, null, null, resultType);
+    _listener.assertNoErrors();
+  }
+
+  void test_visitFunctionExpression_async_expression_flatten() {
+    // () async => e, where e has type Future<int>
+    InterfaceType intType = _typeProvider.intType;
+    InterfaceType futureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[intType]);
+    Expression expression = _resolvedVariable(futureIntType, 'e');
+    ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+    body.keyword = TokenFactory.tokenFromString('async');
+    FunctionExpression node =
+        _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+    DartType resultType = _analyze(node);
+    _assertFunctionType(futureIntType, null, null, null, resultType);
+    _listener.assertNoErrors();
+  }
+
+  void test_visitFunctionExpression_async_expression_flatten_twice() {
+    // () async => e, where e has type Future<Future<int>>
+    InterfaceType intType = _typeProvider.intType;
+    InterfaceType futureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[intType]);
+    InterfaceType futureFutureIntType =
+        _typeProvider.futureType.substitute4(<DartType>[futureIntType]);
+    Expression expression = _resolvedVariable(futureFutureIntType, 'e');
+    ExpressionFunctionBody body = AstFactory.expressionFunctionBody(expression);
+    body.keyword = TokenFactory.tokenFromString('async');
+    FunctionExpression node =
+        _resolvedFunctionExpression(AstFactory.formalParameterList([]), body);
+    DartType resultType = _analyze(node);
+    _assertFunctionType(futureIntType, null, null, null, resultType);
+    _listener.assertNoErrors();
+  }
+
   void test_visitFunctionExpression_generator_async() {
     // () async* {}
     BlockFunctionBody body = AstFactory.blockFunctionBody2();
@@ -10864,7 +10927,7 @@
         expect(namedTypes[name], same(type));
       });
     }
-    expect(functionType.returnType, same(expectedReturnType));
+    expect(functionType.returnType, equals(expectedReturnType));
   }
 
   void _assertType(InterfaceTypeImpl expectedType,
diff --git a/pkg/analyzer2dart/lib/src/converted_world.dart b/pkg/analyzer2dart/lib/src/converted_world.dart
index f54a7a6..600487a 100644
--- a/pkg/analyzer2dart/lib/src/converted_world.dart
+++ b/pkg/analyzer2dart/lib/src/converted_world.dart
@@ -31,6 +31,8 @@
   final dart2js.FunctionElement mainFunction;
   Map<dart2js.AstElement, ir.Node> executableElements =
       new HashMap<dart2js.AstElement, ir.Node>();
+  final List<dart2js.ClassElement> instantiatedClasses =
+      <dart2js.ClassElement>[];
 
   _ConvertedWorldImpl(this.mainFunction);
 
@@ -40,8 +42,6 @@
 
   Iterable<dart2js.AstElement> get resolvedElements => executableElements.keys;
 
-  Iterable<dart2js.ClassElement> get instantiatedClasses => [];
-
   ir.Node getIr(dart2js.Element element) => executableElements[element];
 
   final dart2js.DartTypes dartTypes = new _DartTypes();
@@ -61,9 +61,8 @@
         converter.convertElement(analyzerElement);
     CpsElementVisitor visitor = new CpsElementVisitor(converter, node);
     ir.Node cpsNode = analyzerElement.accept(visitor);
-    if (cpsNode != null) {
-      convertedWorld.executableElements[dart2jsElement] = cpsNode;
-    } else {
+    convertedWorld.executableElements[dart2jsElement] = cpsNode;
+    if (cpsNode == null && !analyzerElement.isSynthetic) {
       String message =
          'No CPS node generated for $analyzerElement (${node.runtimeType}).';
       reportSourceMessage(analyzerElement.source, node, message);
@@ -71,9 +70,18 @@
     }
   }
 
+  void convertClass(analyzer.ClassElement analyzerElement, _) {
+    // Skip conversion of SDK sources since we don't generate code for it
+    // anyway.
+    if (analyzerElement.source.isInSystemLibrary) return;
+    convertedWorld.instantiatedClasses.add(
+        converter.convertElement(analyzerElement));
+  }
+
   closedWorld.executableElements.forEach(convert);
   closedWorld.variables.forEach(convert);
   closedWorld.fields.forEach(convert);
+  closedWorld.instantiatedClasses.forEach(convertClass);
 
   return convertedWorld;
 }
diff --git a/pkg/analyzer2dart/lib/src/cps_generator.dart b/pkg/analyzer2dart/lib/src/cps_generator.dart
index 11c8a84..879b308 100644
--- a/pkg/analyzer2dart/lib/src/cps_generator.dart
+++ b/pkg/analyzer2dart/lib/src/cps_generator.dart
@@ -35,7 +35,14 @@
     CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element);

     FunctionDeclaration functionDeclaration = node;

     return visitor.handleFunctionDeclaration(

-        element, functionDeclaration.functionExpression);

+        element, functionDeclaration.functionExpression.body);

+  }

+

+  @override

+  ir.FunctionDefinition visitMethodElement(analyzer.MethodElement element) {

+    CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element);

+    MethodDeclaration methodDeclaration = node;

+    return visitor.handleFunctionDeclaration(element, methodDeclaration.body);

   }

 

   @override

@@ -52,8 +59,13 @@
     CpsGeneratingVisitor visitor = new CpsGeneratingVisitor(converter, element);

     if (!element.isFactory) {

       ConstructorDeclaration constructorDeclaration = node;

-      return visitor.handleConstructorDeclaration(

-          element, constructorDeclaration);

+      FunctionBody body;

+      if (constructorDeclaration != null) {

+        body = constructorDeclaration.body;

+      } else {

+        assert(element.isSynthetic);

+      }

+      return visitor.handleConstructorDeclaration(element, body);

     }

     // TODO(johnniwinther): Support factory constructors.

     return null;

@@ -78,8 +90,7 @@
   ir.Node visit(AstNode node) => node.accept(this);

 

   ir.ConstructorDefinition handleConstructorDeclaration(

-      analyzer.ConstructorElement constructor, ConstructorDeclaration node) {

-    FunctionBody body = node.body;

+      analyzer.ConstructorElement constructor, FunctionBody body) {

     dart2js.ConstructorElement element = converter.convertElement(constructor);

     return withBuilder(

         new DartIrBuilder(DART_CONSTANT_SYSTEM,

@@ -91,7 +102,8 @@
           constructor.parameters.map(converter.convertElement));

       // Visit the body directly to avoid processing the signature as

       // expressions.

-      visit(node.body);

+      // Call to allow for `body == null` in case of synthesized constructors.

+      build(body);

       return irBuilder.makeConstructorDefinition(const [], const []);

     });

   }

@@ -112,7 +124,7 @@
   }

 

   ir.FunctionDefinition handleFunctionDeclaration(

-      analyzer.FunctionElement function, FunctionExpression node) {

+      analyzer.ExecutableElement function, FunctionBody body) {

     dart2js.FunctionElement element = converter.convertElement(function);

     return withBuilder(

         new DartIrBuilder(DART_CONSTANT_SYSTEM,

@@ -124,7 +136,7 @@
           function.parameters.map(converter.convertElement));

       // Visit the body directly to avoid processing the signature as

       // expressions.

-      visit(node.body);

+      visit(body);

       return irBuilder.makeFunctionDefinition(const []);

     });

   }

@@ -132,12 +144,13 @@
   @override

   ir.Primitive visitFunctionExpression(FunctionExpression node) {

     return irBuilder.buildFunctionExpression(

-        handleFunctionDeclaration(node.element, node));

+        handleFunctionDeclaration(node.element, node.body));

   }

 

   @override

   ir.FunctionDefinition visitFunctionDeclaration(FunctionDeclaration node) {

-    return handleFunctionDeclaration(node.element, node.functionExpression);

+    return handleFunctionDeclaration(

+        node.element, node.functionExpression.body);

   }

 

   @override

@@ -146,7 +159,7 @@
     analyzer.FunctionElement function = functionDeclaration.element;

     dart2js.FunctionElement element = converter.convertElement(function);

     ir.FunctionDefinition definition = handleFunctionDeclaration(

-        function, functionDeclaration.functionExpression);

+        function, functionDeclaration.functionExpression.body);

     irBuilder.declareLocalFunction(element, definition);

   }

 

@@ -204,9 +217,10 @@
                                      AccessSemantics semantics) {

     analyzer.Element staticElement = semantics.element;

     dart2js.Element element = converter.convertElement(staticElement);

+    ir.Primitive receiver = irBuilder.buildLocalGet(element);

     List<ir.Definition> arguments = visitArguments(node.argumentList);

-    return irBuilder.buildLocalInvocation(

-      element,

+    return irBuilder.buildCallInvocation(

+      receiver,

       createSelectorFromMethodInvocation(

           node.argumentList, node.methodName.name),

       arguments);

@@ -229,7 +243,7 @@
       FunctionExpressionInvocation node) {

     ir.Primitive target = build(node.function);

     List<ir.Definition> arguments = visitArguments(node.argumentList);

-    return irBuilder.buildFunctionExpressionInvocation(

+    return irBuilder.buildCallInvocation(

         target,

         createSelectorFromMethodInvocation(node.argumentList, 'call'),

         arguments);

diff --git a/pkg/analyzer2dart/lib/src/dart_backend.dart b/pkg/analyzer2dart/lib/src/dart_backend.dart
index 8a932e9..880f968 100644
--- a/pkg/analyzer2dart/lib/src/dart_backend.dart
+++ b/pkg/analyzer2dart/lib/src/dart_backend.dart
@@ -28,7 +28,7 @@
           element,
           convertedWorld.getIr(element));
     },
-    shouldOutput: (_) => true,
+    shouldOutput: (Element element) => !element.isSynthesized,
     isSafeToRemoveTypeDeclarations: (_) => false);
 }
 
diff --git a/pkg/analyzer2dart/lib/src/element_converter.dart b/pkg/analyzer2dart/lib/src/element_converter.dart
index 4b97325..666124e 100644
--- a/pkg/analyzer2dart/lib/src/element_converter.dart
+++ b/pkg/analyzer2dart/lib/src/element_converter.dart
@@ -163,4 +163,9 @@
       analyzer.ConstructorElement input) {
     return new ConstructorElementY(converter, input);
   }
+
+  @override
+  dart2js.MethodElement visitMethodElement(analyzer.MethodElement input) {
+    return new InstanceMethodElementY(converter, input);
+  }
 }
diff --git a/pkg/analyzer2dart/lib/src/modely.dart b/pkg/analyzer2dart/lib/src/modely.dart
index 200a75b..4df5cdc 100644
--- a/pkg/analyzer2dart/lib/src/modely.dart
+++ b/pkg/analyzer2dart/lib/src/modely.dart
@@ -50,6 +50,9 @@
   @override
   bool get isLocal => false;
 
+  @override
+  bool get isSynthesized => false;
+
   unsupported(String method) {
     throw new UnsupportedError(
         "'$method' is unsupported on $this ($runtimeType)");
@@ -152,9 +155,6 @@
   bool get isNative => unsupported('isNative');
 
   @override
-  bool get isSynthesized => unsupported('isSynthesized');
-
-  @override
   bool get isTopLevel => unsupported('isTopLevel');
 
   @override
@@ -798,6 +798,9 @@
 
   @override
   bool get isClassMember => true;
+
+  @override
+  bool get isTopLevel => false;
 }
 
 class ConstructorElementY extends ElementY
@@ -824,6 +827,9 @@
   @override
   bool get isStatic => false;
 
+  @override
+  bool get isSynthesized => element.isSynthetic;
+
   ConstructorElementY(ElementConverter converter,
                       analyzer.ConstructorElement element)
       : super(converter, element);
@@ -843,3 +849,35 @@
   @override
   get nestedClosures => unsupported('nestedClosures');
 }
+
+class InstanceMethodElementY extends ElementY
+    with AnalyzableElementY,
+         AstElementY,
+         FunctionElementMixin,
+         ClassMemberMixin
+    implements dart2js.MethodElement {
+
+  analyzer.MethodElement get element => super.element;
+
+  @override
+  dart2js.ElementKind get kind => dart2js.ElementKind.FUNCTION;
+
+  @override
+  bool get isStatic => element.isStatic;
+
+  @override
+  bool get isAbstract => element.isAbstract;
+
+  @override
+  bool get isFactoryConstructor => false;
+
+  @override
+  bool get isInstanceMember => true;
+
+  InstanceMethodElementY(ElementConverter converter,
+                         analyzer.MethodElement element)
+      : super(converter, element);
+
+  @override
+  get nestedClosures => unsupported('nestedClosures');
+}
\ No newline at end of file
diff --git a/pkg/analyzer2dart/lib/src/tree_shaker.dart b/pkg/analyzer2dart/lib/src/tree_shaker.dart
index 7e765cc..6b9eaa6 100644
--- a/pkg/analyzer2dart/lib/src/tree_shaker.dart
+++ b/pkg/analyzer2dart/lib/src/tree_shaker.dart
@@ -90,7 +90,16 @@
       // constructor, in which case all we need to do is record the class as
       // being instantiated by this method.  TODO(paulberry): handle the
       // mixin case.
-      analysis.instantiates.add(method.enclosingElement);
+      ClassElement instantiatedClass = method.enclosingElement;
+      analysis.instantiates.add(instantiatedClass);
+      if (instantiatedClass.supertype != null) {
+        ClassElement superClass = instantiatedClass.supertype.element;
+        ConstructorElement superConstructor = superClass.unnamedConstructor;
+        if (superConstructor != null) {
+          // TODO(johnniwinther): Register instantiated type and selector.
+          analysis.calls.add(superConstructor);
+        }
+      }
     } else {
       // This is an executable element with no associated declaration in the
       // AST, and it's not a constructor.  TODO(paulberry): can this ever
@@ -369,7 +378,18 @@
       // we don't need to, because the redirected-to constructor will take care
       // of that).
       if (node.initializers.length != 1 || node.initializers[0] is! RedirectingConstructorInvocation) {
+        ClassElement classElement = node.element.enclosingElement;
         analysis.instantiates.add(node.element.enclosingElement);
+        if (!node.initializers.any((i) => i is SuperConstructorInvocation)) {
+          if (classElement.supertype != null) {
+            ClassElement superClass = classElement.supertype.element;
+            ConstructorElement superConstructor = superClass.unnamedConstructor;
+            if (superConstructor != null) {
+              // TODO(johnniwinther): Register instantiated type and selector.
+              analysis.calls.add(superConstructor);
+            }
+          }
+        }
       }
     } else if (node.redirectedConstructor != null) {
       if (node.redirectedConstructor.staticElement == null) {
diff --git a/pkg/analyzer2dart/test/end2end_data.dart b/pkg/analyzer2dart/test/end2end_data.dart
index b1c6ac3..d439638 100644
--- a/pkg/analyzer2dart/test/end2end_data.dart
+++ b/pkg/analyzer2dart/test/end2end_data.dart
@@ -820,6 +820,13 @@
 
   const Group('Constructors', const <TestSpec>[
     const TestSpec('''
+class C {}
+main() {
+  return new C();
+}
+'''),
+
+    const TestSpec('''
 class C {
   C() {}
 }
@@ -827,5 +834,37 @@
   return new C();
 }
 '''),
+
+    const TestSpec('''
+class B {}
+class C extends B {
+  C() {}
+}
+main() {
+  return new C();
+}
+'''),
+
+    const TestSpec('''
+class B {
+  B() {}
+}
+class C extends B {}
+main() {
+  return new C();
+}
+'''),
   ]),
+
+  const Group('Instance method', const <TestSpec>[
+    const TestSpec('''
+class C {
+  C() {}
+  foo() {}
+}
+main() {
+  return new C().foo();
+}
+'''),
+]),
 ];
diff --git a/pkg/analyzer2dart/test/end2end_test.dart b/pkg/analyzer2dart/test/end2end_test.dart
index 6cc500c0..18fe84a 100644
--- a/pkg/analyzer2dart/test/end2end_test.dart
+++ b/pkg/analyzer2dart/test/end2end_test.dart
@@ -21,8 +21,8 @@
 import 'output_helper.dart';
 import 'end2end_data.dart';
 
-main() {
-  performTests(TEST_DATA, unittester, checkResult);
+main(List<String> args) {
+  performTests(TEST_DATA, unittester, checkResult, args);
 }
 
 checkResult(TestSpec result) {
diff --git a/pkg/analyzer2dart/test/sexpr_data.dart b/pkg/analyzer2dart/test/sexpr_data.dart
index 646a42a..d380c6d 100644
--- a/pkg/analyzer2dart/test/sexpr_data.dart
+++ b/pkg/analyzer2dart/test/sexpr_data.dart
@@ -1386,6 +1386,25 @@
 
   const Group('Constructors', const <TestSpec>[
     const TestSpec('''
+class C {}
+main() {
+  return new C();
+}
+''',
+    const {
+'main': '''
+(FunctionDefinition main () return
+  (LetCont ((k0 (v0)
+      (InvokeContinuation return (v0))))
+    (InvokeConstructor C () k0)))
+''',
+'C.':  '''
+(FunctionDefinition  () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+'''}),
+
+    const TestSpec('''
 class C {
   C() {}
 }
@@ -1405,5 +1424,85 @@
   (LetPrim (v0 (Constant (Null)))
     (InvokeContinuation return (v0))))
 '''}),
+
+    const TestSpec('''
+class B {}
+class C extends B {
+  C() {}
+}
+main() {
+  return new C();
+}
+''',
+    const {
+'main': '''
+(FunctionDefinition main () return
+  (LetCont ((k0 (v0)
+      (InvokeContinuation return (v0))))
+    (InvokeConstructor C () k0)))
+''',
+'B.':  '''
+(FunctionDefinition  () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+''',
+'C.': '''
+(FunctionDefinition  () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+'''}),
+
+    const TestSpec('''
+class B {
+  B() {}
+}
+class C extends B {}
+main() {
+  return new C();
+}
+''',
+    const {
+'main': '''
+(FunctionDefinition main () return
+  (LetCont ((k0 (v0)
+      (InvokeContinuation return (v0))))
+    (InvokeConstructor C () k0)))
+''',
+'B.': '''
+(FunctionDefinition  () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+''',
+'C.':  '''
+(FunctionDefinition  () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+'''}),
+  ]),
+
+  const Group('Instance method', const <TestSpec>[
+    const TestSpec('''
+class C {
+  C() {}
+  foo() {}
+}
+main() {
+  return new C().foo();
+}
+''',
+    const {
+'main': '''
+(FunctionDefinition main () return
+  (LetCont ((k0 (v0)
+      (LetCont ((k1 (v1)
+          (InvokeContinuation return (v1))))
+        (InvokeMethod v0 foo () k1))))
+    (InvokeConstructor C () k0)))
+''',
+'C.foo': '''
+(FunctionDefinition foo () return
+  (LetPrim (v0 (Constant (Null)))
+    (InvokeContinuation return (v0))))
+'''}),
   ]),
 ];
diff --git a/pkg/analyzer2dart/test/sexpr_test.dart b/pkg/analyzer2dart/test/sexpr_test.dart
index e4f83ee..9450ced 100644
--- a/pkg/analyzer2dart/test/sexpr_test.dart
+++ b/pkg/analyzer2dart/test/sexpr_test.dart
@@ -9,6 +9,7 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:compiler/src/cps_ir/cps_ir_nodes.dart';
 import 'package:compiler/src/cps_ir/cps_ir_nodes_sexpr.dart';
 import 'package:compiler/src/elements/elements.dart' as dart2js;
 import 'package:unittest/unittest.dart';
@@ -20,8 +21,8 @@
 import 'test_helper.dart';
 import 'sexpr_data.dart';
 
-main() {
-  performTests(TEST_DATA, unittester, checkResult);
+main(List<String> args) {
+  performTests(TEST_DATA, unittester, checkResult, args);
 }
 
 checkResult(TestSpec result) {
@@ -41,13 +42,22 @@
   void checkOutput(String elementName,
                    dart2js.Element element,
                    String expectedOutput) {
-    expectedOutput = expectedOutput.trim();
-    String output = convertedWorld.getIr(element)
-        .accept(new SExpressionStringifier());
-    expect(output, equals(expectedOutput),
-        reason: "\nInput:\n${result.input}\n"
-                "Expected for '$elementName':\n$expectedOutput\n"
-                "Actual for '$elementName':\n$output\n");
+    ExecutableDefinition ir = convertedWorld.getIr(element);
+    if (expectedOutput == null) {
+      expect(ir, isNull,
+          reason: "\nInput:\n${result.input}\n"
+                  "No CPS IR expected for $element");
+    } else {
+      expect(ir, isNotNull,
+          reason: "\nInput:\n${result.input}\n"
+                  "No CPS IR for $element");
+      expectedOutput = expectedOutput.trim();
+      String output = ir.accept(new SExpressionStringifier());
+      expect(output, equals(expectedOutput),
+          reason: "\nInput:\n${result.input}\n"
+                  "Expected for '$elementName':\n$expectedOutput\n"
+                  "Actual for '$elementName':\n$output\n");
+    }
   }
 
   if (result.output is String) {
diff --git a/pkg/analyzer2dart/test/test_helper.dart b/pkg/analyzer2dart/test/test_helper.dart
index 9bb0b4a..86a52b0 100644
--- a/pkg/analyzer2dart/test/test_helper.dart
+++ b/pkg/analyzer2dart/test/test_helper.dart
@@ -25,8 +25,16 @@
 typedef RunTest(TestSpecBase result);
 
 /// Test [data] using [testGroup] and [check].
-void performTests(List<Group> data, TestGroup testGroup, RunTest runTest) {
+void performTests(List<Group> data,
+                  TestGroup testGroup,
+                  RunTest runTest,
+                  List<String> groupsToRun) {
   for (Group group in data) {
+    if (groupsToRun.isNotEmpty &&
+        !groupsToRun.contains(group.name)) {
+      // Skip this group.
+      continue;
+    }
     testGroup(group, runTest);
   }
 }
diff --git a/pkg/analyzer2dart/test/tree_shaker_test.dart b/pkg/analyzer2dart/test/tree_shaker_test.dart
index 9ba20c7..cedb449 100644
--- a/pkg/analyzer2dart/test/tree_shaker_test.dart
+++ b/pkg/analyzer2dart/test/tree_shaker_test.dart
@@ -99,6 +99,18 @@
     helper.assertNoInstantiatedClass('B');
   });
 
+  test('Super class instantiation', () {
+    var helper = new TreeShakerTestHelper('''
+main() {
+  var x = new B();
+}
+class A {}
+class B extends A {}
+''');
+    helper.assertHasInstantiatedClass('A');
+    helper.assertHasInstantiatedClass('B');
+  });
+
   test('Method invocation', () {
     var helper = new TreeShakerTestHelper('''
 main() {
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 8ce30bb..be603fa 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -84,7 +84,6 @@
             suppressWarnings: hasOption(options, '--suppress-warnings'),
             enableExperimentalMirrors:
                 hasOption(options, '--enable-experimental-mirrors'),
-            enableAsyncAwait: hasOption(options, '--enable-async'),
             generateCodeWithCompileTimeErrors:
                 hasOption(options, '--generate-code-with-compile-time-errors'),
             allowNativeExtensions:
@@ -106,10 +105,6 @@
       throw new ArgumentError("[packageRoot] must end with a /.");
     }
     if (!analyzeOnly) {
-      if (enableAsyncAwait && emitJavaScript) {
-        throw new ArgumentError(
-            "--enable-async is currently only supported with --analyze-only");
-      }
       if (allowNativeExtensions) {
         throw new ArgumentError(
             "--allow-native-extensions is only supported in combination with "
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 93e7bb2..fbefe05 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -272,6 +272,7 @@
                                 ClosureClassElement enclosing)
       : expression = other,
         super(name, other.kind, other.modifiers, enclosing, false) {
+    asyncMarker = other.asyncMarker;
     functionSignatureCache = other.functionSignature;
   }
 
@@ -347,7 +348,13 @@
   // contain any nested closure.
   final Map<Node, ClosureScope> capturingScopes = new Map<Node, ClosureScope>();
 
-  final Set<Local> usedVariablesInTry = new Set<Local>();
+  /// Variables that are used in a try must be treated as boxed because the
+  /// control flow can be non-linear.
+  ///
+  /// Also parameters to a `sync*` generator must be boxed, because of the way
+  /// we rewrite sync* functions. See also comments in [useLocal].
+  /// TODO(johnniwinter): Add variables to this only if the variable is mutated.
+  final Set<Local> variablesUsedInTryOrGenerator = new Set<Local>();
 
   ClosureClassMap(this.closureElement,
                   this.closureClassElement,
@@ -427,6 +434,7 @@
   int closureFieldCounter = 0;
   int boxedFieldCounter = 0;
   bool inTryStatement = false;
+
   final Map<Node, ClosureClassMap> closureMappingCache;
 
   // Map of captured variables. Initially they will map to `null`. If
@@ -588,9 +596,13 @@
       // Note that nested (named) functions are immutable.
       if (variable != closureData.thisLocal &&
           variable != closureData.closureElement) {
-        // TODO(ngeoffray): only do this if the variable is mutated.
-        closureData.usedVariablesInTry.add(variable);
+        closureData.variablesUsedInTryOrGenerator.add(variable);
       }
+    } else if (variable is LocalParameterElement &&
+        variable.functionDeclaration.asyncMarker == AsyncMarker.SYNC_STAR) {
+      // Parameters in a sync* function are shared between each Iterator created
+      // by the Iterable returned by the function, therefore they must be boxed.
+      closureData.variablesUsedInTryOrGenerator.add(variable);
     }
   }
 
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index 5fb178d..13d5d63 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -676,10 +676,10 @@
           target.functionSignature.parameterCount,
           new ErroneousAstConstant(context, node));
     }
-    return selector.makeArgumentsList2(arguments,
-                                       target,
-                                       compileArgument,
-                                       compileDefaultValue);
+    return selector.makeArgumentsList(arguments,
+                                      target,
+                                      compileArgument,
+                                      compileDefaultValue);
   }
 
   AstConstant visitNewExpression(NewExpression node) {
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index a99134f..a3adcdb 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -176,6 +176,11 @@
   void registerInstantiation(InterfaceType type) {
     world.registerInstantiatedType(type, this);
   }
+
+  void registerAsyncMarker(FunctionElement element) {
+    backend.registerAsyncMarker(element, world, this);
+  }
+
 }
 
 /// [WorkItem] used exclusively by the [CodegenEnqueuer].
@@ -229,6 +234,8 @@
   void registerInstantiation(InterfaceType type);
 
   void registerGetOfStaticFunction(FunctionElement element);
+
+  void registerAsyncMarker(FunctionElement element);
 }
 
 abstract class Backend {
@@ -516,6 +523,10 @@
   void forgetElement(Element element) {}
 
   void registerMainHasArguments(Enqueuer enqueuer) {}
+
+  void registerAsyncMarker(FunctionElement element,
+                             Enqueuer enqueuer,
+                             Registry registry) {}
 }
 
 /// Backend callbacks function specific to the resolution phase.
@@ -740,12 +751,6 @@
 
   final bool suppressWarnings;
 
-  /// `true` if async/await features are supported.
-  final bool enableAsyncAwait;
-
-  /// `true` if the compiler uses the [JavaScriptBackend].
-  final bool emitJavaScript;
-
   /// If `true`, some values are cached for reuse in incremental compilation.
   /// Incremental compilation is basically calling [run] more than once.
   final bool hasIncrementalSupport;
@@ -768,6 +773,7 @@
   CompilerTask measuredTask;
   Element _currentElement;
   LibraryElement coreLibrary;
+  LibraryElement asyncLibrary;
 
   LibraryElement mainApp;
   FunctionElement mainFunction;
@@ -1007,14 +1013,11 @@
             this.suppressWarnings: false,
             bool hasIncrementalSupport: false,
             this.enableExperimentalMirrors: false,
-            bool enableAsyncAwait: false,
             this.allowNativeExtensions: false,
             this.generateCodeWithCompileTimeErrors: false,
             api.CompilerOutputProvider outputProvider,
             List<String> strips: const []})
-      : this.emitJavaScript = emitJavaScript,
-        this.enableAsyncAwait = enableAsyncAwait || !emitJavaScript,
-        this.disableTypeInferenceFlag =
+      : this.disableTypeInferenceFlag =
           disableTypeInferenceFlag || !emitJavaScript,
         this.analyzeOnly =
             analyzeOnly || analyzeSignaturesOnly || analyzeAllFlag,
@@ -1242,6 +1245,7 @@
       mirrorSystemClass = findRequiredElement(library, 'MirrorSystem');
       mirrorsUsedClass = findRequiredElement(library, 'MirrorsUsed');
     } else if (uri == DART_ASYNC) {
+      asyncLibrary = library;
       deferredLibraryClass = findRequiredElement(library, 'DeferredLibrary');
       _coreTypes.futureClass = findRequiredElement(library, 'Future');
       _coreTypes.streamClass = findRequiredElement(library, 'Stream');
@@ -1906,12 +1910,9 @@
   SourceSpan spanFromHInstruction(HInstruction instruction) {
     Element element = _elementFromHInstruction(instruction);
     if (element == null) element = currentElement;
-    var position = instruction.sourcePosition;
+    SourceInformation position = instruction.sourceInformation;
     if (position == null) return spanFromElement(element);
-    Token token = position.token;
-    if (token == null) return spanFromElement(element);
-    Uri uri = element.compilationUnit.script.readableUri;
-    return spanFromTokens(token, token, uri);
+    return position.sourceSpan;
   }
 
   /**
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
index f883b9b..366f409 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder.dart
@@ -731,18 +731,9 @@
         (k) => new ir.ConcatenateStrings(k, arguments));
   }
 
-  /// Create an invocation of [local] where the argument structure is defined
-  /// by [selector] and the argument values are defined by [arguments].
-  ir.Primitive buildLocalInvocation(LocalElement local,
-                                    Selector selector,
-                                    List<ir.Definition> arguments) {
-    return _buildInvokeCall(buildLocalGet(local), selector, arguments);
-  }
-
-  /// Create an invocation of the [functionExpression] where the argument
-  /// structure are defined by [selector] and the argument values are defined by
-  /// [arguments].
-  ir.Primitive buildFunctionExpressionInvocation(
+  /// Create an invocation of the `call` method of [functionExpression], where
+  /// the named arguments are given by [selector].
+  ir.Primitive buildCallInvocation(
       ir.Primitive functionExpression,
       Selector selector,
       List<ir.Definition> arguments) {
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
index 9eafea6..e859eef 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_visitor.dart
@@ -67,11 +67,16 @@
       // TODO(sigurdm): Support native functions for dart2js.
       assert(invariant(element, !element.isNative));
 
-      // TODO(kmillikin,sigurdm): Support constructors.
-      if (element is ConstructorElement && !element.isGenerativeConstructor) {
-        return false;
+      if (element is ConstructorElement) {
+        if (!element.isGenerativeConstructor) {
+          // TODO(kmillikin,sigurdm): Support constructors.
+          return false;
+        }
+        if (element.isSynthesized) {
+          // Do generate CPS for synthetic constructors.
+          return true;
+        }
       }
-
     } else if (element is! FieldElement) {
       compiler.internalError(element, "Unexpected element type $element");
     }
@@ -144,7 +149,27 @@
   ClosureScope getClosureScopeForNode(ast.Node node);
   ClosureEnvironment getClosureEnvironment();
 
+  /// Normalizes the argument list to a static invocation (i.e. where the target
+  /// element is known).
+  ///
+  /// For the JS backend, inserts default arguments and normalizes order of
+  /// named arguments.
+  ///
+  /// For the Dart backend, returns [arguments].
+  List<ir.Primitive> normalizeStaticArguments(
+      Selector selector,
+      FunctionElement target,
+      List<ir.Primitive> arguments);
 
+  /// Normalizes the argument list of a dynamic invocation (i.e. where the
+  /// target element is unknown).
+  ///
+  /// For the JS backend, normalizes order of named arguments.
+  ///
+  /// For the Dart backend, returns [arguments].
+  List<ir.Primitive> normalizeDynamicArguments(
+      Selector selector,
+      List<ir.Primitive> arguments);
 
   ir.FunctionDefinition _makeFunctionBody(FunctionElement element,
                                           ast.FunctionExpression node) {
@@ -549,19 +574,13 @@
   ir.Primitive visitClosureSend(ast.Send node) {
     assert(irBuilder.isOpen);
     Element element = elements[node];
-    Selector closureSelector = elements.getSelector(node);
-    if (element == null) {
-      ir.Primitive closureTarget = visit(node.selector);
-      List<ir.Primitive> args =
-          node.arguments.mapToList(visit, growable:false);
-      return irBuilder.buildFunctionExpressionInvocation(
-          closureTarget, elements.getSelector(node), args);
-    } else {
-      List<ir.Primitive> args =
-          node.arguments.mapToList(visit, growable:false);
-      return irBuilder.buildLocalInvocation(
-          element, elements.getSelector(node), args);
-    }
+    Selector selector = elements.getSelector(node);
+    ir.Primitive receiver = (element == null)
+        ? visit(node.selector)
+        : irBuilder.buildLocalGet(element);
+    List<ir.Primitive> arguments = node.arguments.mapToList(visit);
+    arguments = normalizeDynamicArguments(selector, arguments);
+    return irBuilder.buildCallInvocation(receiver, selector, arguments);
   }
 
   /// If [node] is null, returns this.
@@ -583,10 +602,8 @@
     assert(irBuilder.isOpen);
     Selector selector = elements.getSelector(node);
     ir.Primitive receiver = visitReceiver(node.receiver);
-    List<ir.Primitive> arguments = new List<ir.Primitive>();
-    for (ast.Node n in node.arguments) {
-      arguments.add(visit(n));
-    }
+    List<ir.Primitive> arguments = node.arguments.mapToList(visit);
+    arguments = normalizeDynamicArguments(selector, arguments);
     return irBuilder.buildDynamicInvocation(receiver, selector, arguments);
   }
 
@@ -712,10 +729,31 @@
 
     Selector selector = elements.getSelector(node);
 
-    // TODO(lry): support default arguments, need support for locals.
-    List<ir.Primitive> arguments =
-        node.arguments.mapToList(visit, growable:false);
-    return irBuilder.buildStaticInvocation(element, selector, arguments);
+    if (selector.isCall && (element.isGetter || element.isField)) {
+      // We are invoking a static field or getter as if it was a method, e.g:
+      //
+      //     get foo => {..}
+      //     main() {  foo(1, 2, 3);  }
+      //
+      // We invoke the getter of 'foo' and then invoke the 'call' method
+      // on the result, using the given arguments.
+      Selector getter = new Selector.getterFrom(selector);
+      Selector call = new Selector.callClosureFrom(selector);
+      ir.Primitive receiver = irBuilder.buildStaticGet(element, getter);
+      List<ir.Primitive> arguments = node.arguments.mapToList(visit);
+      arguments = normalizeDynamicArguments(selector, arguments);
+      return irBuilder.buildCallInvocation(receiver, call, arguments);
+    } else if (selector.isGetter) {
+      // We are reading a static field or invoking a static getter.
+      return irBuilder.buildStaticGet(element, selector);
+    } else {
+      // We are invoking a static method.
+      assert(selector.isCall);
+      assert(element is FunctionElement);
+      List<ir.Primitive> arguments = node.arguments.mapToList(visit);
+      arguments = normalizeStaticArguments(selector, element, arguments);
+      return irBuilder.buildStaticInvocation(element, selector, arguments);
+    }
   }
 
   ir.Primitive visitSuperSend(ast.Send node) {
@@ -725,9 +763,9 @@
     } else {
       Selector selector = elements.getSelector(node);
       Element target = elements[node];
-      List<ir.Primitive> arguments = new List<ir.Primitive>();
-      for (ast.Node n in node.arguments) {
-        arguments.add(visit(n));
+      List<ir.Primitive> arguments = node.arguments.mapToList(visit);
+      if (selector.isCall) {
+        arguments = normalizeStaticArguments(selector, target, arguments);
       }
       return irBuilder.buildSuperInvocation(target, selector, arguments);
     }
@@ -861,8 +899,9 @@
     Selector selector = elements.getSelector(node.send);
     DartType type = elements.getType(node);
     ast.Node selectorNode = node.send.selector;
-    List<ir.Definition> arguments =
+    List<ir.Primitive> arguments =
         node.send.arguments.mapToList(visit, growable:false);
+    arguments = normalizeStaticArguments(selector, element, arguments);
     return irBuilder.buildConstructorInvocation(
         element, selector, type, arguments);
   }
@@ -887,12 +926,9 @@
     return irBuilder.buildStringConcatenation(arguments);
   }
 
-  ir.Primitive translateConstant(ast.Node node, [ConstantExpression constant]) {
+  ir.Primitive translateConstant(ast.Node node) {
     assert(irBuilder.isOpen);
-    if (constant == null) {
-      constant = getConstantForNode(node);
-    }
-    return irBuilder.buildConstantLiteral(constant);
+    return irBuilder.buildConstantLiteral(getConstantForNode(node));
   }
 
   ir.ExecutableDefinition nullIfGiveup(ir.ExecutableDefinition action()) {
@@ -1107,6 +1143,19 @@
 
     return withBuilder(builder, () => _makeFunctionBody(element, node));
   }
+
+  List<ir.Primitive> normalizeStaticArguments(
+      Selector selector,
+      FunctionElement target,
+      List<ir.Primitive> arguments) {
+    return arguments;
+  }
+
+  List<ir.Primitive> normalizeDynamicArguments(
+      Selector selector,
+      List<ir.Primitive> arguments) {
+    return arguments;
+  }
 }
 
 /// IR builder specific to the JavaScript backend, coupled to the [JsIrBuilder].
@@ -1242,6 +1291,18 @@
     return visitor.withBuilder(irBuilder, () => visitor.visit(expression));
   }
 
+  /// Builds the IR for a constant taken from a different [context].
+  ///
+  /// Such constants need to be compiled with a different [sourceFile] and
+  /// [elements] mapping.
+  ir.Primitive inlineConstant(AstElement context, ast.Expression exp) {
+    JsIrBuilderVisitor visitor = new JsIrBuilderVisitor(
+        context.resolvedAst.elements,
+        compiler,
+        elementSourceFile(context));
+    return visitor.withBuilder(irBuilder, () => visitor.translateConstant(exp));
+  }
+
   /// Builds the IR for a given constructor.
   ///
   /// 1. Evaluates all own or inherited field initializers.
@@ -1408,8 +1469,9 @@
       ir.Primitive value;
       // Load argument if provided.
       if (signature.optionalParametersAreNamed) {
-        int translatedIndex = selector.namedArguments.indexOf(param.name);
-        if (translatedIndex != -1) {
+        int nameIndex = selector.namedArguments.indexOf(param.name);
+        if (nameIndex != -1) {
+          int translatedIndex = selector.positionalArgumentCount + nameIndex;
           value = arguments[translatedIndex];
         }
       } else if (index < arguments.length) {
@@ -1418,7 +1480,7 @@
       // Load default if argument was not provided.
       if (value == null) {
         if (param.initializer != null) {
-          value = visit(param.initializer);
+          value = inlineExpression(target, param.initializer);
         } else {
           value = irBuilder.buildNullLiteral();
         }
@@ -1545,5 +1607,80 @@
     return withBuilder(builder, () => _makeFunctionBody(element, node));
   }
 
+  /// Creates a primitive for the default value of [parameter].
+  ir.Primitive translateDefaultValue(ParameterElement parameter) {
+    if (parameter.initializer == null) {
+      return irBuilder.buildNullLiteral();
+    } else {
+      return inlineConstant(parameter.executableContext, parameter.initializer);
+    }
+  }
+
+  /// Inserts default arguments and normalizes order of named arguments.
+  List<ir.Primitive> normalizeStaticArguments(
+      Selector selector,
+      FunctionElement target,
+      List<ir.Primitive> arguments) {
+    target = target.implementation;
+    FunctionSignature signature = target.functionSignature;
+    if (!signature.optionalParametersAreNamed &&
+        signature.parameterCount == arguments.length) {
+      // Optimization: don't copy the argument list for trivial cases.
+      return arguments;
+    }
+
+    List<ir.Primitive> result = <ir.Primitive>[];
+    int i = 0;
+    signature.forEachRequiredParameter((ParameterElement element) {
+      result.add(arguments[i]);
+      ++i;
+    });
+
+    if (!signature.optionalParametersAreNamed) {
+      signature.forEachOptionalParameter((ParameterElement element) {
+        if (i < arguments.length) {
+          result.add(arguments[i]);
+          ++i;
+        } else {
+          result.add(translateDefaultValue(element));
+        }
+      });
+    } else {
+      int offset = i;
+      // Iterate over the optional parameters of the signature, and try to
+      // find them in [compiledNamedArguments]. If found, we use the
+      // value in the temporary list, otherwise the default value.
+      signature.orderedOptionalParameters.forEach((ParameterElement element) {
+        int nameIndex = selector.namedArguments.indexOf(element.name);
+        if (nameIndex != -1) {
+          int translatedIndex = offset + nameIndex;
+          result.add(arguments[translatedIndex]);
+        } else {
+          result.add(translateDefaultValue(element));
+        }
+      });
+    }
+    return result;
+  }
+
+  /// Normalizes order of named arguments.
+  List<ir.Primitive> normalizeDynamicArguments(
+      Selector selector,
+      List<ir.Primitive> arguments) {
+    assert(arguments.length == selector.argumentCount);
+    // Optimization: don't copy the argument list for trivial cases.
+    if (selector.namedArguments.isEmpty) return arguments;
+    List<ir.Primitive> result = <ir.Primitive>[];
+    for (int i=0; i < selector.positionalArgumentCount; i++) {
+      result.add(arguments[i]);
+    }
+    for (String argName in selector.getOrderedNamedArguments()) {
+      int nameIndex = selector.namedArguments.indexOf(argName);
+      int translatedIndex = selector.positionalArgumentCount + nameIndex;
+      result.add(arguments[translatedIndex]);
+    }
+    return result;
+  }
+
 }
 
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 4aad6af..1fbf543 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -114,7 +114,6 @@
   bool stripArgumentSet = false;
   bool analyzeOnly = false;
   bool analyzeAll = false;
-  bool enableAsyncAwait = false;
   bool allowNativeExtensions = false;
   bool trustTypeAnnotations = false;
   bool trustPrimitives = false;
@@ -192,11 +191,6 @@
     passThrough(argument);
   }
 
-  setEnableAsync(String argument) {
-    enableAsyncAwait = true;
-    passThrough(argument);
-  }
-
   setAllowNativeExtensions(String argument) {
     allowNativeExtensions = true;
     passThrough(argument);
@@ -340,7 +334,12 @@
     new OptionHandler('--show-package-warnings', passThrough),
     new OptionHandler('--csp', passThrough),
     new OptionHandler('--enable-experimental-mirrors', passThrough),
-    new OptionHandler('--enable-async', setEnableAsync),
+    new OptionHandler('--enable-async', (_) {
+      diagnosticHandler.info(
+          "Option '--enable-async' is no longer needed. "
+          "Async-await is supported by default.",
+          api.Diagnostic.HINT);
+    }),
     new OptionHandler('--enable-enum', (_) {
       diagnosticHandler.info(
           "Option '--enable-enum' is no longer needed. "
@@ -410,10 +409,6 @@
   }
   if (analyzeAll) analyzeOnly = true;
   if (!analyzeOnly) {
-    if (enableAsyncAwait && outputLanguage != OUTPUT_LANGUAGE_DART) {
-      helpAndFail("Option '--enable-async' is currently only supported in "
-                  "combination with the '--analyze-only' option.");
-    }
     if (allowNativeExtensions) {
       helpAndFail("Option '--allow-native-extensions' is only supported in "
                   "combination with the '--analyze-only' option.");
diff --git a/pkg/compiler/lib/src/dart2jslib.dart b/pkg/compiler/lib/src/dart2jslib.dart
index fcfbf5e..19700eb 100644
--- a/pkg/compiler/lib/src/dart2jslib.dart
+++ b/pkg/compiler/lib/src/dart2jslib.dart
@@ -33,6 +33,7 @@
          DeferredLoaderGetterElementX;
 import 'helpers/helpers.dart';  // Included for debug helpers.
 import 'io/code_output.dart' show CodeBuffer;
+import 'io/source_information.dart' show SourceInformation;
 import 'js/js.dart' as js;
 import 'js_backend/js_backend.dart' as js_backend;
 import 'library_loader.dart'
diff --git a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
index 01a9ae0..2779663 100644
--- a/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend_ast_emitter.dart
@@ -434,7 +434,7 @@
   Expression makeAssignment(Expression target, Expression value) {
     // Try to print as compound assignment or increment
     if (value is BinaryOperator && isCompoundableOperator(value.operator)) {
-      Expression leftOperand = value.left;
+      Receiver leftOperand = value.left;
       Expression rightOperand = value.right;
       bool valid = false;
       if (isSameVariable(target, leftOperand)) {
diff --git a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
index dea26fa..020b81b 100644
--- a/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/simple_types_inferrer.dart
@@ -541,10 +541,11 @@
         locals.update(element, parameterType, node);
       });
       ClassElement cls = analyzedElement.enclosingClass;
+      Spannable spannable = node;
       if (analyzedElement.isSynthesized) {
-        node = analyzedElement;
+        spannable = analyzedElement;
         ConstructorElement constructor = analyzedElement;
-        synthesizeForwardingCall(node, constructor.definingConstructor);
+        synthesizeForwardingCall(spannable, constructor.definingConstructor);
       } else {
         visitingInitializers = true;
         visit(node.initializers);
@@ -570,7 +571,8 @@
           if (field.isFinal) return;
           T type = locals.fieldScope.readField(field);
           if (type == null && field.initializer == null) {
-            inferrer.recordTypeOfNonFinalField(node, field, types.nullType);
+            inferrer.recordTypeOfNonFinalField(
+                spannable, field, types.nullType);
           }
         });
       }
@@ -580,7 +582,12 @@
         locals.update(element, inferrer.typeOfElement(element), node);
       });
       visit(node.body);
-      if (returnType == null) {
+      if (function.asyncMarker != AsyncMarker.SYNC) {
+        // TODO(herhut): Should be type Future/Iterable/Stream instead of
+        // dynamic.
+        returnType = inferrer.addReturnTypeFor(
+            analyzedElement, returnType, types.dynamicType);
+      } else if (returnType == null) {
         // No return in the body.
         returnType = locals.seenReturnOrThrow
             ? types.nonNullEmpty()  // Body always throws.
@@ -995,6 +1002,12 @@
     return null;
   }
 
+  T visitAwait(ast.Await node) {
+    T futureType = node.expression.accept(this);
+    // TODO(herhut): Return a better type here if possible.
+    return types.dynamicType;
+  }
+
   T visitStaticSend(ast.Send node) {
     Element element = elements[node];
     if (elements.isAssert(node)) {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
index f60b4c5..7304661 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_inferrer.dart
@@ -45,6 +45,7 @@
     show ImmutableEmptySet,
          Setlet,
          Spannable;
+import '../js_backend/js_backend.dart' show Annotations, JavaScriptBackend;
 
 import 'inferrer_visitor.dart'
     show ArgumentsTypes,
@@ -559,6 +560,9 @@
   TypeGraphInferrerEngine(Compiler compiler, this.mainElement)
         : super(compiler, new TypeInformationSystem(compiler));
 
+  JavaScriptBackend get backend => compiler.backend;
+  Annotations get annotations => backend.annotations;
+
   /**
    * A set of selector names that [List] implements, that we know return
    * their element type.
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 36aee09..6a9610d 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -392,8 +392,11 @@
 
   TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
     if (element.isField &&
-        !inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
-      // Do not infer types for fields being assigned by synthesized calls.
+        (!inferrer.backend.canBeUsedForGlobalOptimizations(element) ||
+         inferrer.annotations.assumeDynamic(element))) {
+      // Do not infer types for fields that have a corresponding annotation or
+      // are assigned by synthesized calls
+
       giveUp(inferrer);
       return safeType(inferrer);
     }
@@ -437,7 +440,9 @@
   TypeMask potentiallyNarrowType(TypeMask mask,
                                  TypeGraphInferrerEngine inferrer) {
     Compiler compiler = inferrer.compiler;
-    if (!compiler.trustTypeAnnotations && !compiler.enableTypeAssertions) {
+    if (!compiler.trustTypeAnnotations &&
+        !compiler.enableTypeAssertions &&
+        !inferrer.annotations.trustTypeAnnotations(element)) {
       return mask;
     }
     if (element.isGenerativeConstructor ||
@@ -496,6 +501,7 @@
  */
 class ParameterTypeInformation extends ElementTypeInformation {
   ParameterElement get element => super.element;
+  FunctionElement get declaration => element.functionDeclaration;
 
   ParameterTypeInformation._internal(ParameterElement element,
                                      TypeInformationSystem types)
@@ -522,9 +528,10 @@
 
   // TODO(herhut): Cleanup into one conditional.
   TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
-    if (!inferrer.compiler.backend.canBeUsedForGlobalOptimizations(element)) {
-      // Do not infer types for fields and parameters being assigned
-      // by synthesized calls.
+    if (!inferrer.backend.canBeUsedForGlobalOptimizations(element) ||
+        inferrer.annotations.assumeDynamic(declaration)) {
+      // Do not infer types for parameters that have a correspondign annotation
+      // or that are assigned by synthesized calls.
       giveUp(inferrer);
       return safeType(inferrer);
     }
@@ -567,7 +574,8 @@
   TypeMask potentiallyNarrowType(TypeMask mask,
                                  TypeGraphInferrerEngine inferrer) {
     Compiler compiler = inferrer.compiler;
-    if (!compiler.trustTypeAnnotations) {
+    if (!compiler.trustTypeAnnotations &&
+        !inferrer.annotations.trustTypeAnnotations(declaration)) {
       return mask;
     }
     // When type assertions are enabled (aka checked mode), we have to always
diff --git a/pkg/compiler/lib/src/io/code_output.dart b/pkg/compiler/lib/src/io/code_output.dart
index bd97af0..5f13198 100644
--- a/pkg/compiler/lib/src/io/code_output.dart
+++ b/pkg/compiler/lib/src/io/code_output.dart
@@ -6,7 +6,7 @@
 
 import 'dart:async';
 
-import 'source_map_builder.dart';
+import 'source_information.dart';
 
 class CodeOutputMarker {
   final int offsetDelta;
diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
new file mode 100644
index 0000000..c0e6e0a
--- /dev/null
+++ b/pkg/compiler/lib/src/io/source_information.dart
@@ -0,0 +1,164 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.source_information;
+
+import '../dart2jslib.dart' show SourceSpan;
+import '../elements/elements.dart' show AstElement;
+import '../scanner/scannerlib.dart' show Token;
+import '../tree/tree.dart' show Node;
+import '../js/js.dart' show JavaScriptNodeSourceInformation;
+import 'code_output.dart';
+import 'source_file.dart';
+
+/// Interface for passing source information, for instance for use in source
+/// maps, through the backend.
+abstract class SourceInformation extends JavaScriptNodeSourceInformation {
+  SourceSpan get sourceSpan;
+  void beginMapping(CodeOutput output);
+  void endMapping(CodeOutput output);
+}
+
+/// Source information that contains start source position and optionally an
+/// end source position.
+class StartEndSourceInformation implements SourceInformation {
+  final SourceFileLocation startPosition;
+  final SourceFileLocation endPosition;
+
+  StartEndSourceInformation(this.startPosition, [this.endPosition]);
+
+  SourceSpan get sourceSpan {
+    Uri uri = Uri.parse(startPosition.sourceFile.filename);
+    int begin = startPosition.offset;
+    int end = endPosition == null ? begin : endPosition.offset;
+    return new SourceSpan(uri, begin, end);
+  }
+
+  void beginMapping(CodeBuffer output) {
+    output.beginMappedRange();
+    output.setSourceLocation(startPosition);
+  }
+
+  void endMapping(CodeBuffer output) {
+    if (endPosition != null) {
+      output.setSourceLocation(endPosition);
+    }
+    output.endMappedRange();
+  }
+
+  int get hashCode {
+    return (startPosition.hashCode * 17 +
+            endPosition.hashCode * 19)
+           & 0x7FFFFFFF;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! StartEndSourceInformation) return false;
+    return startPosition == other.startPosition &&
+           endPosition == other.endPosition;
+  }
+
+  // TODO(johnniwinther): Remove this method. Source information should be
+  // computed based on the element by provided from statements and expressions.
+  static StartEndSourceInformation computeSourceInformation(
+      AstElement element) {
+
+    AstElement implementation = element.implementation;
+    SourceFile sourceFile = implementation.compilationUnit.script.file;
+    String name = element.name;
+    Node node = implementation.node;
+    Token beginToken;
+    Token endToken;
+    if (node == null) {
+      // Synthesized node. Use the enclosing element for the location.
+      beginToken = endToken = element.position;
+    } else {
+      beginToken = node.getBeginToken();
+      endToken = node.getEndToken();
+    }
+    // TODO(podivilov): find the right sourceFile here and remove offset
+    // checks below.
+    SourceFileLocation sourcePosition, endSourcePosition;
+    if (beginToken.charOffset < sourceFile.length) {
+      sourcePosition =
+          new TokenSourceFileLocation(sourceFile, beginToken, name);
+    }
+    if (endToken.charOffset < sourceFile.length) {
+      endSourcePosition =
+          new TokenSourceFileLocation(sourceFile, endToken, name);
+    }
+    return new StartEndSourceInformation(sourcePosition, endSourcePosition);
+  }
+
+  String toString() {
+    StringBuffer sb = new StringBuffer();
+    sb.write('${startPosition.getSourceUrl()}:');
+    sb.write('[${startPosition.getLine()},${startPosition.getColumn()}]');
+    if (endPosition != null) {
+      sb.write('-[${endPosition.getLine()},${endPosition.getColumn()}]');
+    }
+    return sb.toString();
+  }
+}
+
+// TODO(johnniwinther): Refactor this class to use getters.
+abstract class SourceFileLocation {
+  SourceFile sourceFile;
+
+  SourceFileLocation(this.sourceFile) {
+    assert(isValid());
+  }
+
+  int line;
+
+  int get offset;
+
+  String getSourceUrl() => sourceFile.filename;
+
+  int getLine() {
+    if (line == null) line = sourceFile.getLine(offset);
+    return line;
+  }
+
+  int getColumn() => sourceFile.getColumn(getLine(), offset);
+
+  String getSourceName();
+
+  bool isValid() => offset < sourceFile.length;
+
+  int get hashCode {
+    return getSourceUrl().hashCode * 17 +
+           offset.hashCode * 17 +
+           getSourceName().hashCode * 23;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! SourceFileLocation) return false;
+    return getSourceUrl() == other.getSourceUrl() &&
+           offset == other.offset &&
+           getSourceName() == other.getSourceName();
+  }
+
+  String toString() => '${getSourceUrl()}:[${getLine()},${getColumn()}]';
+}
+
+class TokenSourceFileLocation extends SourceFileLocation {
+  final Token token;
+  final String name;
+
+  TokenSourceFileLocation(SourceFile sourceFile, this.token, this.name)
+    : super(sourceFile);
+
+  int get offset => token.charOffset;
+
+  String getSourceName() {
+    return name;
+  }
+
+  String toString() {
+    return '${super.toString()}:$name';
+  }
+}
diff --git a/pkg/compiler/lib/src/io/source_map_builder.dart b/pkg/compiler/lib/src/io/source_map_builder.dart
index 117e298..ed546f2 100644
--- a/pkg/compiler/lib/src/io/source_map_builder.dart
+++ b/pkg/compiler/lib/src/io/source_map_builder.dart
@@ -5,10 +5,9 @@
 library dart2js.source_map_builder;
 
 import '../util/util.dart';
-import '../scanner/scannerlib.dart' show Token;
 import '../util/uri_extras.dart' show relativize;
 import 'line_column_provider.dart';
-import 'source_file.dart';
+import 'source_information.dart' show SourceFileLocation;
 
 class SourceMapBuilder {
   static const int VLQ_BASE_SHIFT = 5;
@@ -230,42 +229,3 @@
 
   SourceMapEntry(this.sourceLocation, this.targetOffset);
 }
-
-abstract class SourceFileLocation {
-  SourceFile sourceFile;
-
-  SourceFileLocation(this.sourceFile) {
-    assert(isValid());
-  }
-
-  int line;
-
-  int get offset;
-
-  String getSourceUrl() => sourceFile.filename;
-
-  int getLine() {
-    if (line == null) line = sourceFile.getLine(offset);
-    return line;
-  }
-
-  int getColumn() => sourceFile.getColumn(getLine(), offset);
-
-  String getSourceName();
-
-  bool isValid() => offset < sourceFile.length;
-}
-
-class TokenSourceFileLocation extends SourceFileLocation {
-  final Token token;
-  final String name;
-
-  TokenSourceFileLocation(SourceFile sourceFile, this.token, this.name)
-    : super(sourceFile);
-
-  int get offset => token.charOffset;
-
-  String getSourceName() {
-    return name;
-  }
-}
diff --git a/pkg/compiler/lib/src/js/builder.dart b/pkg/compiler/lib/src/js/builder.dart
index 3eeca5e..72b4507 100644
--- a/pkg/compiler/lib/src/js/builder.dart
+++ b/pkg/compiler/lib/src/js/builder.dart
@@ -5,7 +5,7 @@
 // Utilities for building JS ASTs at runtime.  Contains a builder class
 // and a parser that parses part of the language.
 
-part of js;
+part of js_ast;
 
 
 /**
@@ -349,8 +349,8 @@
 ArrayInitializer numArray(Iterable<int> list) => js.numArray(list);
 ArrayInitializer stringArray(Iterable<String> list) => js.stringArray(list);
 Call propertyCall(Expression receiver,
-                    String fieldName,
-                    List<Expression> arguments) {
+                  String fieldName,
+                  List<Expression> arguments) {
   return js.propertyCall(receiver, fieldName, arguments);
 }
 
@@ -716,6 +716,8 @@
         return new LiteralNull();
       } else if (last == "function") {
         return parseFunctionExpression();
+      } else if (last == "this") {
+        return new This();
       } else {
         return new VariableUse(last);
       }
@@ -1116,9 +1118,12 @@
 
       if (lastToken == 'default') error("Default outside switch.");
 
+      if (lastToken == 'yield') return parseYield();
+
       if (lastToken == 'with') {
         error('Not implemented in mini parser');
       }
+
     }
 
     bool checkForInterpolatedStatement = lastCategory == HASH;
@@ -1153,6 +1158,13 @@
     return new Return(expression);
   }
 
+  Statement parseYield() {
+    bool hasStar = acceptString('*');
+    Expression expression = parseExpression();
+    expectSemicolon();
+    return new DartYield(expression, hasStar);
+  }
+
   Statement parseThrow() {
     if (skippedNewline) error('throw expression must be on same line');
     Expression expression = parseExpression();
diff --git a/pkg/compiler/lib/src/js/characters.dart b/pkg/compiler/lib/src/js/characters.dart
new file mode 100644
index 0000000..ae6740f
--- /dev/null
+++ b/pkg/compiler/lib/src/js/characters.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_character_codes;
+
+const int $EOF = 0;
+const int $STX = 2;
+const int $BS  = 8;
+const int $TAB = 9;
+const int $LF = 10;
+const int $VTAB = 11;
+const int $FF = 12;
+const int $CR = 13;
+const int $SPACE = 32;
+const int $BANG = 33;
+const int $DQ = 34;
+const int $HASH = 35;
+const int $$ = 36;
+const int $PERCENT = 37;
+const int $AMPERSAND = 38;
+const int $SQ = 39;
+const int $OPEN_PAREN = 40;
+const int $CLOSE_PAREN = 41;
+const int $STAR = 42;
+const int $PLUS = 43;
+const int $COMMA = 44;
+const int $MINUS = 45;
+const int $PERIOD = 46;
+const int $SLASH = 47;
+const int $0 = 48;
+const int $1 = 49;
+const int $2 = 50;
+const int $3 = 51;
+const int $4 = 52;
+const int $5 = 53;
+const int $6 = 54;
+const int $7 = 55;
+const int $8 = 56;
+const int $9 = 57;
+const int $COLON = 58;
+const int $SEMICOLON = 59;
+const int $LT = 60;
+const int $EQ = 61;
+const int $GT = 62;
+const int $QUESTION = 63;
+const int $AT = 64;
+const int $A = 65;
+const int $B = 66;
+const int $C = 67;
+const int $D = 68;
+const int $E = 69;
+const int $F = 70;
+const int $G = 71;
+const int $H = 72;
+const int $I = 73;
+const int $J = 74;
+const int $K = 75;
+const int $L = 76;
+const int $M = 77;
+const int $N = 78;
+const int $O = 79;
+const int $P = 80;
+const int $Q = 81;
+const int $R = 82;
+const int $S = 83;
+const int $T = 84;
+const int $U = 85;
+const int $V = 86;
+const int $W = 87;
+const int $X = 88;
+const int $Y = 89;
+const int $Z = 90;
+const int $OPEN_SQUARE_BRACKET = 91;
+const int $BACKSLASH = 92;
+const int $CLOSE_SQUARE_BRACKET = 93;
+const int $CARET = 94;
+const int $_ = 95;
+const int $BACKPING = 96;
+const int $a = 97;
+const int $b = 98;
+const int $c = 99;
+const int $d = 100;
+const int $e = 101;
+const int $f = 102;
+const int $g = 103;
+const int $h = 104;
+const int $i = 105;
+const int $j = 106;
+const int $k = 107;
+const int $l = 108;
+const int $m = 109;
+const int $n = 110;
+const int $o = 111;
+const int $p = 112;
+const int $q = 113;
+const int $r = 114;
+const int $s = 115;
+const int $t = 116;
+const int $u = 117;
+const int $v = 118;
+const int $w = 119;
+const int $x = 120;
+const int $y = 121;
+const int $z = 122;
+const int $OPEN_CURLY_BRACKET = 123;
+const int $BAR = 124;
+const int $CLOSE_CURLY_BRACKET = 125;
+const int $TILDE = 126;
+const int $DEL = 127;
+const int $NBSP = 160;
+const int $LS = 0x2028;
+const int $PS = 0x2029;
+
+const int $FIRST_SURROGATE = 0xd800;
+const int $LAST_SURROGATE = 0xdfff;
+const int $LAST_CODE_POINT = 0x10ffff;
diff --git a/pkg/compiler/lib/src/js/js.dart b/pkg/compiler/lib/src/js/js.dart
index dc67462..a5bbec4 100644
--- a/pkg/compiler/lib/src/js/js.dart
+++ b/pkg/compiler/lib/src/js/js.dart
@@ -1,22 +1,64 @@
-// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
 library js;
 
-import 'precedence.dart';
-import '../util/characters.dart' as charCodes;
-import '../util/util.dart';
+// TODO(sra): This will become a package import.
+import 'js_ast.dart';
+export 'js_ast.dart';
+
 import '../io/code_output.dart' show CodeBuffer;
+import '../io/source_information.dart' show SourceInformation;
 import '../js_emitter/js_emitter.dart' show USE_NEW_EMITTER;
-
-// TODO(floitsch): remove this dependency (currently necessary for the
-// CodeBuffer).
 import '../dart2jslib.dart' as leg;
+import '../util/util.dart' show NO_LOCATION_SPANNABLE;
+import '../dump_info.dart' show DumpInfoTask;
 
-import '../dump_info.dart';
 
-part 'nodes.dart';
-part 'builder.dart';
-part 'printer.dart';
-part 'template.dart';
+CodeBuffer prettyPrint(Node node, leg.Compiler compiler,
+                       {DumpInfoTask monitor,
+                        bool allowVariableMinification: true}) {
+  JavaScriptPrintingOptions options = new JavaScriptPrintingOptions(
+      shouldCompressOutput: compiler.enableMinification,
+      minifyLocalVariables: allowVariableMinification,
+      preferSemicolonToNewlineInMinifiedOutput: USE_NEW_EMITTER);
+  Dart2JSJavaScriptPrintingContext context =
+      new Dart2JSJavaScriptPrintingContext(compiler, monitor);
+  Printer printer = new Printer(options, context);
+  printer.visit(node);
+  return context.outBuffer;
+}
+
+class Dart2JSJavaScriptPrintingContext implements JavaScriptPrintingContext {
+  final leg.Compiler compiler;
+  final DumpInfoTask monitor;
+  final CodeBuffer outBuffer = new CodeBuffer();
+
+  Dart2JSJavaScriptPrintingContext(leg.Compiler this.compiler,
+      DumpInfoTask this.monitor);
+
+  void error(String message) {
+    compiler.internalError(NO_LOCATION_SPANNABLE, message);
+  }
+
+  void emit(String string) {
+    outBuffer.add(string);
+  }
+
+  void enterNode(Node node) {
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      sourceInformation.beginMapping(outBuffer);
+    }
+    if (monitor != null) monitor.enteringAst(node, outBuffer.length);
+  }
+
+  void exitNode(Node node) {
+    if (monitor != null) monitor.exitingAst(node, outBuffer.length);
+    SourceInformation sourceInformation = node.sourceInformation;
+    if (sourceInformation != null) {
+      sourceInformation.endMapping(outBuffer);
+    }
+  }
+}
diff --git a/pkg/compiler/lib/src/js/js_ast.dart b/pkg/compiler/lib/src/js/js_ast.dart
new file mode 100644
index 0000000..ee8289e
--- /dev/null
+++ b/pkg/compiler/lib/src/js/js_ast.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library js_ast;
+
+import 'precedence.dart';
+import 'characters.dart' as charCodes;
+
+part 'nodes.dart';
+part 'builder.dart';
+part 'printer.dart';
+part 'template.dart';
diff --git a/pkg/compiler/lib/src/js/nodes.dart b/pkg/compiler/lib/src/js/nodes.dart
index e5b57f6..92446fa 100644
--- a/pkg/compiler/lib/src/js/nodes.dart
+++ b/pkg/compiler/lib/src/js/nodes.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js;
+part of js_ast;
 
 abstract class NodeVisitor<T> {
   T visitProgram(Program node);
@@ -27,8 +27,8 @@
   T visitFunctionDeclaration(FunctionDeclaration node);
   T visitLabeledStatement(LabeledStatement node);
   T visitLiteralStatement(LiteralStatement node);
+  T visitDartYield(DartYield node);
 
-  T visitBlob(Blob node);
   T visitLiteralExpression(LiteralExpression node);
   T visitVariableDeclarationList(VariableDeclarationList node);
   T visitAssignment(Assignment node);
@@ -108,7 +108,6 @@
   T visitDefault(Default node) => visitNode(node);
 
   T visitExpression(Expression node) => visitNode(node);
-  T visitBlob(Blob node) => visitExpression(node);
   T visitVariableReference(VariableReference node) => visitExpression(node);
 
   T visitLiteralExpression(LiteralExpression node) => visitExpression(node);
@@ -169,14 +168,17 @@
   T visitComment(Comment node) => null;
 
   T visitAwait(Await node) => visitExpression(node);
+  T visitDartYield(DartYield node) => visitStatement(node);
 }
 
-abstract class Node {
-  get sourcePosition => _sourcePosition;
-  get endSourcePosition => _endSourcePosition;
+/// This tag interface has no behaviour but must be implemented by any class
+/// that is to be stored on a [Node] as source information.
+abstract class JavaScriptNodeSourceInformation {}
 
-  var _sourcePosition;
-  var _endSourcePosition;
+abstract class Node {
+  JavaScriptNodeSourceInformation get sourceInformation => _sourceInformation;
+
+  JavaScriptNodeSourceInformation _sourceInformation;
 
   accept(NodeVisitor visitor);
   void visitChildren(NodeVisitor visitor);
@@ -187,24 +189,18 @@
 
   // Returns a node equivalent to [this], but with new source position and end
   // source position.
-  Node withPosition(var sourcePosition, var endSourcePosition) {
-    if (sourcePosition == _sourcePosition &&
-        endSourcePosition == _endSourcePosition) {
+  Node withSourceInformation(
+      JavaScriptNodeSourceInformation sourceInformation) {
+    if (sourceInformation == _sourceInformation) {
       return this;
     }
     Node clone = _clone();
     // TODO(sra): Should existing data be 'sticky' if we try to overwrite with
     // `null`?
-    clone._sourcePosition = sourcePosition;
-    clone._endSourcePosition = endSourcePosition;
+    clone._sourceInformation = sourceInformation;
     return clone;
   }
 
-  // Returns a node equivalent to [this], but with new [this.sourcePositions],
-  // keeping the existing [endPosition]
-  Node withLocation(var sourcePosition) =>
-      withPosition(sourcePosition, this.endSourcePosition);
-
   VariableUse asVariableUse() => null;
 
   bool get isCommaOperator => false;
@@ -227,9 +223,6 @@
 
 abstract class Statement extends Node {
   Statement toStatement() => this;
-
-  Statement withPosition(var sourcePosition, var endSourcePosition) =>
-      super.withPosition(sourcePosition, endSourcePosition);
 }
 
 class Block extends Statement {
@@ -532,32 +525,28 @@
   LiteralStatement _clone() => new LiteralStatement(code);
 }
 
+// Not a real JavaScript node, but represents the yield statement from a dart
+// program translated to JavaScript.
+class DartYield extends Statement {
+  final Expression expression;
+
+  final bool hasStar;
+
+  DartYield(this.expression, this.hasStar);
+
+  accept(NodeVisitor visitor) => visitor.visitDartYield(this);
+
+  void visitChildren(NodeVisitor visitor) {
+    expression.accept(visitor);
+  }
+
+  DartYield _clone() => new DartYield(expression, hasStar);
+}
+
 abstract class Expression extends Node {
   int get precedenceLevel;
 
   Statement toStatement() => new ExpressionStatement(this);
-
-  Expression withPosition(var sourcePosition, var endSourcePosition) =>
-      super.withPosition(sourcePosition, endSourcePosition);
-}
-
-/// Wrap a CodeBuffer as an expression.
-class Blob extends Expression {
-  // TODO(ahe): This class is an aid to convert everything to ASTs, remove when
-  // not needed anymore.
-
-  final CodeBuffer buffer;
-
-  Blob(this.buffer);
-
-  accept(NodeVisitor visitor) => visitor.visitBlob(this);
-
-  void visitChildren(NodeVisitor visitor) {}
-
-  Blob _clone() => new Blob(buffer);
-
-  int get precedenceLevel => PRIMARY;
-
 }
 
 class LiteralExpression extends Expression {
@@ -862,7 +851,7 @@
     body.accept(visitor);
   }
 
-  Fun _clone() => new Fun(params, body);
+  Fun _clone() => new Fun(params, body, asyncModifier: asyncModifier);
 
   int get precedenceLevel => CALL;
 }
@@ -870,11 +859,25 @@
 class AsyncModifier {
   final bool isAsync;
   final bool isYielding;
+  final String description;
 
-  const AsyncModifier.sync() : isAsync = false, isYielding = false;
-  const AsyncModifier.async() : isAsync = true, isYielding = false;
-  const AsyncModifier.asyncStar() : isAsync = true, isYielding = true;
-  const AsyncModifier.syncStar() : isAsync = false, isYielding = true;
+  const AsyncModifier.sync()
+      : isAsync = false,
+        isYielding = false,
+        description = "sync";
+  const AsyncModifier.async()
+      : isAsync = true,
+        isYielding = false,
+        description = "async";
+  const AsyncModifier.asyncStar()
+      : isAsync = true,
+        isYielding = true,
+        description = "async*";
+  const AsyncModifier.syncStar()
+      : isAsync = false,
+        isYielding = true,
+        description = "sync*";
+  toString() => description;
 }
 
 class PropertyAccess extends Expression {
@@ -928,9 +931,12 @@
   /**
    * Constructs a LiteralString from a string value.
    *
-   * The constructor does not add the required quotes.  If [value] is
-   * not surrounded by quotes, the resulting object is invalid as a JS
-   * value.
+   * The constructor does not add the required quotes.  If [value] is not
+   * surrounded by quotes and property escaped, the resulting object is invalid
+   * as a JS value.
+   *
+   * TODO(sra): Introduce variants for known valid strings that don't allocate a
+   * new string just to add quotes.
    */
   LiteralString(this.value);
 
@@ -939,7 +945,7 @@
 }
 
 class LiteralNumber extends Literal {
-  final String value;
+  final String value;  // Must be a valid JavaScript number literal.
 
   LiteralNumber(this.value);
 
@@ -1108,7 +1114,7 @@
 /**
  * An asynchronous await.
  *
- * Not part of javascript. We desugar this expression before outputting.
+ * Not part of JavaScript. We desugar this expression before outputting.
  * Should only occur in a [Fun] with `asyncModifier` async or asyncStar.
  */
 class Await extends Expression {
diff --git a/pkg/compiler/lib/src/js/printer.dart b/pkg/compiler/lib/src/js/printer.dart
index 19d6c3f..6ee3f3e 100644
--- a/pkg/compiler/lib/src/js/printer.dart
+++ b/pkg/compiler/lib/src/js/printer.dart
@@ -2,32 +2,77 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js;
+part of js_ast;
 
-class Printer extends Indentation implements NodeVisitor {
+
+class JavaScriptPrintingOptions {
   final bool shouldCompressOutput;
-  leg.DiagnosticListener diagnosticListener;
-  CodeBuffer outBuffer;
-  bool inForInit = false;
-  bool atStatementBegin = false;
+  final bool minifyLocalVariables;
+  final bool preferSemicolonToNewlineInMinifiedOutput;
+
+  JavaScriptPrintingOptions(
+      {this.shouldCompressOutput: false,
+       this.minifyLocalVariables: false,
+       this.preferSemicolonToNewlineInMinifiedOutput: false});
+}
+
+
+/// An environment in which JavaScript printing is done.  Provides emitting of
+/// text and pre- and post-visit callbacks.
+abstract class JavaScriptPrintingContext {
+  /// Signals an error.  This should happen only for serious internal errors.
+  void error(String message) { throw message; }
+
+  /// Adds [string] to the output.
+  void emit(String string);
+
+  /// Callback immediately before printing [node].  Whitespace may be printed
+  /// after this callback before the first non-whitespace character for [node].
+  void enterNode(Node node) {}
+  /// Callback after printing the last character representing [node].
+  void exitNode(Node node) {}
+}
+
+/// A simple implementation of [JavaScriptPrintingContext] suitable for tests.
+class SimpleJavaScriptPrintingContext extends JavaScriptPrintingContext {
+  final StringBuffer buffer = new StringBuffer();
+
+  void emit(String string) {
+    buffer.write(string);
+  }
+
+  String getText() => buffer.toString();
+}
+
+
+class Printer implements NodeVisitor {
+  final JavaScriptPrintingOptions options;
+  final JavaScriptPrintingContext context;
+  final bool shouldCompressOutput;
   final DanglingElseVisitor danglingElseVisitor;
   final LocalNamer localNamer;
+
+  bool inForInit = false;
+  bool atStatementBegin = false;
   bool pendingSemicolon = false;
   bool pendingSpace = false;
-  DumpInfoTask monitor = null;
+
+  // The current indentation level.
+  int _indentLevel = 0;
+  // A cache of all indentation strings used so far.
+  List<String> _indentList = <String>[""];
 
   static final identifierCharacterRegExp = new RegExp(r'^[a-zA-Z_0-9$]');
   static final expressionContinuationRegExp = new RegExp(r'^[-+([]');
 
-  Printer(leg.DiagnosticListener diagnosticListener, DumpInfoTask monitor,
-          { bool enableMinification: false, allowVariableMinification: true })
-      : shouldCompressOutput = enableMinification,
-        monitor = monitor,
-        diagnosticListener = diagnosticListener,
-        outBuffer = new CodeBuffer(),
-        danglingElseVisitor = new DanglingElseVisitor(diagnosticListener),
-        localNamer = determineRenamer(enableMinification,
-                                      allowVariableMinification);
+  Printer(JavaScriptPrintingOptions options,
+          JavaScriptPrintingContext context)
+      : options = options,
+        context = context,
+        shouldCompressOutput = options.shouldCompressOutput,
+        danglingElseVisitor = new DanglingElseVisitor(context),
+        localNamer = determineRenamer(options.shouldCompressOutput,
+                                      options.minifyLocalVariables);
 
   static LocalNamer determineRenamer(bool shouldCompressOutput,
                                      bool allowVariableMinification) {
@@ -35,6 +80,25 @@
         ? new MinifyRenamer() : new IdentityNamer();
   }
 
+
+  // The current indentation string.
+  String get indentation {
+    // Lazily add new indentation strings as required.
+    while (_indentList.length <= _indentLevel) {
+      _indentList.add(_indentList.last + "  ");
+    }
+    return _indentList[_indentLevel];
+  }
+
+  void indentMore() {
+    _indentLevel++;
+  }
+
+  void indentLess() {
+    _indentLevel--;
+  }
+
+
   /// Always emit a newline, even under `enableMinification`.
   void forceLine() {
     out("\n");
@@ -58,7 +122,7 @@
     if (str != "") {
       if (pendingSemicolon) {
         if (!shouldCompressOutput) {
-          outBuffer.add(";");
+          context.emit(";");
         } else if (str != "}") {
           // We want to output newline instead of semicolon because it makes
           // the raw stack traces much easier to read and it also makes line-
@@ -71,20 +135,21 @@
           // If we're using the new emitter where most pretty printed code
           // is escaped in strings, it is a lot easier to deal with semicolons
           // than newlines because the former doesn't need escaping.
-          if (USE_NEW_EMITTER || expressionContinuationRegExp.hasMatch(str)) {
-            outBuffer.add(";");
+          if (options.preferSemicolonToNewlineInMinifiedOutput ||
+              expressionContinuationRegExp.hasMatch(str)) {
+            context.emit(";");
           } else {
-            outBuffer.add("\n");
+            context.emit("\n");
           }
         }
       }
       if (pendingSpace &&
           (!shouldCompressOutput || identifierCharacterRegExp.hasMatch(str))) {
-        outBuffer.add(" ");
+        context.emit(" ");
       }
       pendingSpace = false;
       pendingSemicolon = false;
-      outBuffer.add(str);
+      context.emit(str);
       lastAddedString = str;
     }
   }
@@ -111,30 +176,10 @@
     }
   }
 
-  void beginSourceRange(Node node) {
-    if (node.sourcePosition != null) {
-      outBuffer.beginMappedRange();
-      outBuffer.setSourceLocation(node.sourcePosition);
-    }
-  }
-
-  void endSourceRange(Node node) {
-    if (node.endSourcePosition != null) {
-      outBuffer.setSourceLocation(node.endSourcePosition);
-    }
-    if (node.sourcePosition != null) {
-      outBuffer.endMappedRange();
-    }
-  }
-
   visit(Node node) {
-    beginSourceRange(node);
-    if (monitor != null) monitor.enteringAst(node, outBuffer.length);
-
+    context.enterNode(node);
     node.accept(this);
-
-    if (monitor != null) monitor.exitingAst(node, outBuffer.length);
-    endSourceRange(node);
+    context.exitNode(node);
   }
 
   visitCommaSeparated(List<Node> nodes, int hasRequiredType,
@@ -159,10 +204,6 @@
     visitAll(program.body);
   }
 
-  visitBlob(Blob node) {
-    outBuffer.addBuffer(node.buffer);
-  }
-
   bool blockBody(Node body, {bool needsSeparation, bool needsNewline}) {
     if (body is Block) {
       spaceOut();
@@ -176,16 +217,18 @@
     } else {
       lineOut();
     }
-    indentBlock(() => visit(body));
+    indentMore();
+    visit(body);
+    indentLess();
     return false;
   }
 
   void blockOutWithoutBraces(Node node) {
     if (node is Block) {
-      beginSourceRange(node);
+      context.enterNode(node);
       Block block = node;
       block.statements.forEach(blockOutWithoutBraces);
-      endSourceRange(node);
+      context.exitNode(node);
     } else {
       visit(node);
     }
@@ -193,13 +236,15 @@
 
   void blockOut(Block node, bool shouldIndent, bool needsNewline) {
     if (shouldIndent) indent();
-    beginSourceRange(node);
+    context.enterNode(node);
     out("{");
     lineOut();
-    indentBlock(() => node.statements.forEach(blockOutWithoutBraces));
+    indentMore();
+    node.statements.forEach(blockOutWithoutBraces);
+    indentLess();
     indent();
     out("}");
-    endSourceRange(node);
+    context.exitNode(node);
     if (needsNewline) lineOut();
   }
 
@@ -355,6 +400,19 @@
     outSemicolonLn();
   }
 
+  visitDartYield(DartYield node) {
+    if (node.hasStar) {
+      outIndent("yield*");
+    } else {
+      outIndent("yield");
+    }
+    pendingSpace = true;
+    visitNestedExpression(node.expression, EXPRESSION,
+                          newInForInit: false, newAtStatementBegin: false);
+    outSemicolonLn();
+  }
+
+
   visitThrow(Throw node) {
     outIndent("throw");
     pendingSpace = true;
@@ -398,7 +456,9 @@
     out(")");
     spaceOut();
     outLn("{");
-    indentBlock(() => visitAll(node.cases));
+    indentMore();
+    visitAll(node.cases);
+    indentLess();
     outIndentLn("}");
   }
 
@@ -409,14 +469,18 @@
                           newInForInit: false, newAtStatementBegin: false);
     outLn(":");
     if (!node.body.statements.isEmpty) {
-      indentBlock(() => blockOutWithoutBraces(node.body));
+      indentMore();
+      blockOutWithoutBraces(node.body);
+      indentLess();
     }
   }
 
   visitDefault(Default node) {
     outIndentLn("default:");
     if (!node.body.statements.isEmpty) {
-      indentBlock(() => blockOutWithoutBraces(node.body));
+      indentMore();
+      blockOutWithoutBraces(node.body);
+      indentLess();
     }
   }
 
@@ -633,8 +697,7 @@
         rightPrecedenceRequirement = UNARY;
         break;
       default:
-        diagnosticListener
-            .internalError(NO_LOCATION_SPANNABLE, "Forgot operator: $op");
+        context.error("Forgot operator: $op");
     }
 
     visitNestedExpression(left, leftPrecedenceRequirement,
@@ -871,8 +934,7 @@
     List<String> parts = template.split('#');
     int inputsLength = inputs == null ? 0 : inputs.length;
     if (parts.length != inputsLength + 1) {
-      diagnosticListener.internalError(NO_LOCATION_SPANNABLE,
-          'Wrong number of arguments for JS: $template');
+      context.error('Wrong number of arguments for JS: $template');
     }
     // Code that uses JS must take care of operator precedences, and
     // put parenthesis if needed.
@@ -999,15 +1061,14 @@
  * as then-statement in an [If] that has an else branch.
  */
 class DanglingElseVisitor extends BaseVisitor<bool> {
-  leg.DiagnosticListener diagnosticListener;
+  JavaScriptPrintingContext context;
 
-  DanglingElseVisitor(this.diagnosticListener);
+  DanglingElseVisitor(this.context);
 
   bool visitProgram(Program node) => false;
 
   bool visitNode(Statement node) {
-    diagnosticListener
-        .internalError(NO_LOCATION_SPANNABLE, "Forgot node: $node");
+    context.error("Forgot node: $node");
     return null;
   }
 
@@ -1046,18 +1107,6 @@
 }
 
 
-CodeBuffer prettyPrint(Node node, leg.Compiler compiler,
-                       {DumpInfoTask monitor,
-                        bool allowVariableMinification: true}) {
-  Printer printer =
-      new Printer(compiler, monitor,
-                  enableMinification: compiler.enableMinification,
-                  allowVariableMinification: allowVariableMinification);
-  printer.visit(node);
-  return printer.outBuffer;
-}
-
-
 abstract class LocalNamer {
   String getName(String oldName);
   String declareVariable(String oldName);
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
new file mode 100644
index 0000000..656b1af
--- /dev/null
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -0,0 +1,2149 @@
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library rewrite_async;
+
+// TODO(sigurdm): Throws in catch-handlers are handled wrong.
+// TODO(sigurdm): Avoid using variables in templates. It could blow up memory
+// use.
+
+import "dart:math" show max;
+import 'dart:collection';
+
+import "js.dart" as js;
+
+import '../util/util.dart';
+import '../dart2jslib.dart' show DiagnosticListener;
+
+import "../helpers/helpers.dart";
+
+/// Rewrites a [js.Fun] with async/sync*/async* functions and await and yield
+/// (with dart-like semantics) to an equivalent function without these.
+/// await-for is not handled and must be rewritten before. (Currently handled
+/// in ssa/builder.dart).
+///
+/// When generating the input to this, special care must be taken that
+/// parameters to sync* functions that are mutated in the body must be boxed.
+/// (Currently handled in closure.dart).
+///
+/// Look at [visitFun], [visitDartYield] and [visitAwait] for more explanation.
+class AsyncRewriter extends js.NodeVisitor {
+
+  // Local variables are hoisted to the top of the function, so they are
+  // collected here.
+  List<js.VariableDeclaration> localVariables =
+      new List<js.VariableDeclaration>();
+
+  Map<js.Node, int> continueLabels = new Map<js.Node, int>();
+  Map<js.Node, int> breakLabels = new Map<js.Node, int>();
+  Map<js.Node, int> finallyLabels = new Map<js.Node, int>();
+  int exitLabel;
+
+  // A stack of all enclosing jump targets (including the function for
+  // representing the target of a return, and all enclosing try-blocks that have
+  // finally part, this way ensuring all the finally blocks between a jump and
+  // its target are run before the jump.
+  List<js.Node> targetsAndTries = new List<js.Node>();
+
+  List<int> continueStack = new List<int>();
+  List<int> breakStack = new List<int>();
+  List<int> returnStack = new List<int>();
+
+  List<Pair<String, String>> variableRenamings =
+      new List<Pair<String, String>>();
+
+  PreTranslationAnalysis analysis;
+
+  List<int> errorHandlerLabels = new List<int>();
+
+  final Function safeVariableName;
+
+  // All the <x>Name variables are names of Javascript variables used in the
+  // transformed code.
+
+  /// Contains the result of an awaited expression, or a conditional or
+  /// lazy boolean operator.
+  ///
+  /// For example a conditional expression is roughly translated like:
+  /// [[cond ? a : b]]
+  ///
+  /// Becomes:
+  ///
+  /// while true { // outer while loop
+  ///   switch (goto) { // Simulates goto
+  ///     ...
+  ///       goto = [[cond]] ? thenLabel : elseLabel
+  ///       break;
+  ///     case thenLabel:
+  ///       result = [[a]];
+  ///       goto = joinLabel;
+  ///     case elseLabel:
+  ///       result = [[b]];
+  ///     case joinLabel:
+  ///       // Now the result of computing the condition is in result.
+  ///     ....
+  ///   }
+  /// }
+  ///
+  /// It is a parameter to the [helperName] function, so that [thenHelper] and
+  /// [streamHelper] can call [helperName] with the result of an awaited Future.
+  String resultName;
+
+  /// The name of the inner function that is scheduled to do each await/yield,
+  /// and called to do a new iteration for sync*.
+  String helperName;
+
+  /// The Completer that will finish an async function.
+  ///
+  /// Not used for sync* or async* functions.
+  String completerName;
+
+  /// The StreamController that controls an async* function.
+  ///
+  /// Not used for async and sync* functions
+  String controllerName;
+
+  /// Used to simulate a goto.
+  ///
+  /// To "goto" a label, the label is assigned to this
+  /// variable, and break out of the switch to take another iteration in the
+  /// while loop. See [addGoto]
+  String gotoName;
+
+  /// The label of the current error handler.
+  String handlerName;
+
+  /// Current caught error.
+  String errorName;
+
+  /// A stack of labels of finally blocks to visit, and the label to go to after
+  /// the last.
+  String nextName;
+
+  /// The current returned value (a finally block may overwrite it).
+  String returnValueName;
+
+  /// The label of the outer loop.
+  ///
+  /// Used if there are untransformed loops containing break or continues to
+  /// targets outside the loop.
+  String outerLabelName;
+
+  /// If javascript `this` is used, it is accessed via this variable, in the
+  /// [helperName] function.
+  String selfName;
+
+  // These expressions are hooks for communicating with the runtime.
+
+  /// The function called by an async function to simulate an await or return.
+  ///
+  /// For an await it is called with:
+  ///
+  /// - The value to await
+  /// - The [helperName]
+  /// - The [completerName]
+  /// - A JavaScript function that is executed if the future completed with
+  ///   an error. That function is responsible for executing the right error
+  ///   handler and/or finally blocks).
+  ///
+  /// For a return it is called with:
+  ///
+  /// - The value to complete the completer with.
+  /// - null
+  /// - The [completerName]
+  /// - null.
+  final js.Expression thenHelper;
+
+  /// The function called by an async* function to simulate an await, yield or
+  /// yield*.
+  ///
+  /// For an await/yield/yield* it is called with:
+  ///
+  /// - The value to await/yieldExpression(value to yield)/
+  /// yieldStarExpression(stream to yield)
+  /// - The [helperName]
+  /// - The [controllerName]
+  /// - A JavaScript function that is executed if the future completed with
+  ///   an error. That function is responsible for executing the right error
+  ///   handler and/or finally blocks).
+  ///
+  /// For a return it is called with:
+  ///
+  /// - null
+  /// - null
+  /// - The [controllerName]
+  /// - null.
+  final js.Expression streamHelper;
+
+  /// Contructor used to initialize the [completerName] variable.
+  ///
+  /// Specific to async methods.
+  final js.Expression newCompleter;
+
+  /// Contructor used to initialize the [controllerName] variable.
+  ///
+  /// Specific to async* methods.
+  final js.Expression newController;
+
+  /// Used to get the `Stream` out of the [controllerName] variable.
+  ///
+  /// Specific to async* methods.
+  final js.Expression streamOfController;
+
+  /// Contructor creating the Iterable for a sync* method. Called with
+  /// [helperName].
+  final js.Expression newIterable;
+
+  /// A JS Expression that creates a marker showing that iteration is over.
+  ///
+  /// Called without arguments.
+  final js.Expression endOfIteration;
+
+  /// A JS Expression that creates a marker indicating a 'yield' statement.
+  ///
+  /// Called with the value to yield.
+  final js.Expression yieldExpression;
+
+  /// A JS Expression that creates a marker indication a 'yield*' statement.
+  ///
+  /// Called with the stream to yield from.
+  final js.Expression yieldStarExpression;
+
+  final DiagnosticListener diagnosticListener;
+  // For error reporting only.
+  Spannable get spannable {
+    return (_spannable == null) ? NO_LOCATION_SPANNABLE : _spannable;
+  }
+
+  Spannable _spannable;
+
+  int _currentLabel = 0;
+
+  // The highest temporary variable index currently in use.
+  int currentTempVarIndex = 0;
+  // The highest temporary variable index ever in use in this function.
+  int tempVarHighWaterMark = 0;
+  Map<int, js.Expression> tempVarNames = new Map<int, js.Expression>();
+
+  js.AsyncModifier async;
+
+  bool get isSync => async == const js.AsyncModifier.sync();
+  bool get isAsync => async == const js.AsyncModifier.async();
+  bool get isSyncStar => async == const js.AsyncModifier.syncStar();
+  bool get isAsyncStar => async == const js.AsyncModifier.asyncStar();
+
+  AsyncRewriter(this.diagnosticListener,
+                spannable,
+                {this.thenHelper,
+                 this.streamHelper,
+                 this.streamOfController,
+                 this.newCompleter,
+                 this.newController,
+                 this.endOfIteration,
+                 this.newIterable,
+                 this.yieldExpression,
+                 this.yieldStarExpression,
+                 this.safeVariableName})
+      : _spannable = spannable;
+
+  /// Main entry point.
+  /// Rewrites a sync*/async/async* function to an equivalent normal function.
+  ///
+  /// [spannable] can be passed to have a location for error messages.
+  js.Fun rewrite(js.Fun node, [Spannable spannable]) {
+    _spannable = spannable;
+
+    async = node.asyncModifier;
+    assert(!isSync);
+
+    analysis = new PreTranslationAnalysis(unsupported);
+    analysis.analyze(node);
+
+    // To avoid name collisions with existing names, the fresh names are
+    // generated after the analysis.
+    resultName = freshName("result");
+    completerName = freshName("completer");
+    controllerName = freshName("controller");
+    helperName = freshName("helper");
+    gotoName = freshName("goto");
+    handlerName = freshName("handler");
+    errorName = freshName("error");
+    nextName = freshName("next");
+    returnValueName = freshName("returnValue");
+    outerLabelName = freshName("outer");
+    selfName = freshName("self");
+
+    return node.accept(this);
+  }
+
+  js.Expression get currentErrorHandler {
+    return errorHandlerLabels.isEmpty
+        ? new js.LiteralNull()
+        : js.number(errorHandlerLabels.last);
+  }
+
+  int allocateTempVar() {
+    assert(tempVarHighWaterMark >= currentTempVarIndex);
+    currentTempVarIndex++;
+    tempVarHighWaterMark = max(currentTempVarIndex, tempVarHighWaterMark);
+    return currentTempVarIndex;
+  }
+
+  js.VariableUse useTempVar(int i) {
+    return tempVarNames.putIfAbsent(
+        i, () => new js.VariableUse(freshName("temp$i")));
+  }
+
+  /// Generates a variable name with [safeVariableName] based on [originalName]
+  /// with a suffix to guarantee it does not collide with already used names.
+  String freshName(String originalName) {
+    String safeName = safeVariableName(originalName);
+    String result = safeName;
+    int counter = 1;
+    while (analysis.usedNames.contains(result)) {
+      result = "$safeName$counter";
+      ++counter;
+    }
+    analysis.usedNames.add(result);
+    return result;
+  }
+
+  /// All the pieces are collected in this map, to create a switch with a case
+  /// for each label.
+  ///
+  /// The order is important, therefore the type is explicitly LinkedHashMap.
+  LinkedHashMap<int, List<js.Statement>> labelledParts =
+      new LinkedHashMap<int, List<js.Statement>>();
+
+  /// Description of each label for readability of the non-minified output.
+  Map<int, String> labelComments = new Map<int, String>();
+
+  /// True if the function has any try blocks containing await.
+  bool hasTryBlocks = false;
+
+  /// True if any return, break or continue passes through a finally.
+  bool hasJumpThroughFinally = false;
+
+  /// True if the traversion currently is inside a loop or switch for which
+  /// [shouldTransform] is false.
+  bool insideUntranslatedBreakable = false;
+
+  /// True if a label is used to break to an outer switch-statement.
+  bool hasJumpThoughOuterLabel = false;
+
+  /// True if there is a catch-handler protected by a finally with no enclosing
+  /// catch-handlers.
+  bool needsRethrow = false;
+
+  /// Buffer for collecting translated statements belonging to the same switch
+  /// case.
+  List<js.Statement> currentStatementBuffer;
+
+  // Labels will become cases in the big switch expression, and `goto label`
+  // is expressed by assigning to the switch key [gotoName] and breaking out of
+  // the switch.
+
+  int newLabel([String comment]) {
+    int result = _currentLabel;
+    _currentLabel++;
+    if (comment != null) {
+      labelComments[result] = comment;
+    }
+    return result;
+  }
+
+  /// Begins outputting statements to a new buffer with label [label].
+  ///
+  /// Each buffer ends up as its own case part in the big state-switch.
+  void beginLabel(int label) {
+    assert(!labelledParts.containsKey(label));
+    currentStatementBuffer = new List<js.Statement>();
+    labelledParts[label] = currentStatementBuffer;
+    addStatement(new js.Comment(labelComments[label]));
+  }
+
+  /// Returns a statement assigning to the variable named [gotoName].
+  /// This should be followed by a break for the goto to be executed. Use
+  /// [gotoWithBreak] or [addGoto] for this.
+  js.Statement setGotoVariable(int label) {
+    return new js.ExpressionStatement(
+        new js.Assignment(new js.VariableUse(gotoName), js.number(label)));
+  }
+
+  /// Returns a block that has a goto to [label] including the break.
+  ///
+  /// Also inserts a comment describing the label if available.
+  js.Block gotoAndBreak(int label) {
+    List<js.Statement> statements = new List<js.Statement>();
+    if (labelComments.containsKey(label)) {
+      statements.add(new js.Comment("goto ${labelComments[label]}"));
+    }
+    statements.add(setGotoVariable(label));
+    if (insideUntranslatedBreakable) {
+      hasJumpThoughOuterLabel = true;
+      statements.add(new js.Break(outerLabelName));
+    } else {
+      statements.add(new js.Break(null));
+    }
+    return new js.Block(statements);
+  }
+
+  /// Adds a goto to [label] including the break.
+  ///
+  /// Also inserts a comment describing the label if available.
+  void addGoto(int label) {
+    if (labelComments.containsKey(label)) {
+      addStatement(new js.Comment("goto ${labelComments[label]}"));
+    }
+    addStatement(setGotoVariable(label));
+
+    addBreak();
+  }
+
+  void addStatement(js.Statement node) {
+    currentStatementBuffer.add(node);
+  }
+
+  void addExpressionStatement(js.Expression node) {
+    addStatement(new js.ExpressionStatement(node));
+  }
+
+  /// True if there is an await or yield in [node] or some subexpression.
+  bool shouldTransform(js.Node node) {
+    return analysis.hasAwaitOrYield.contains(node);
+  }
+
+  void unsupported(js.Node node) {
+    throw new UnsupportedError(
+        "Node $node cannot be transformed by the await-sync transformer");
+  }
+
+  void unreachable(js.Node node) {
+    diagnosticListener.internalError(
+        spannable, "Internal error, trying to visit $node");
+  }
+
+  visitStatement(js.Statement node) {
+    node.accept(this);
+  }
+
+  /// Visits [node] to ensure its sideeffects are performed, but throwing away
+  /// the result.
+  ///
+  /// If the return value of visiting [node] is an expression guaranteed to have
+  /// no side effect, it is dropped.
+  void visitExpressionIgnoreResult(js.Expression node) {
+    js.Expression result = node.accept(this);
+    if (!(result is js.Literal || result is js.VariableUse)) {
+      addExpressionStatement(result);
+    }
+  }
+
+  js.Expression visitExpression(js.Expression node) {
+    return node.accept(this);
+  }
+
+
+  /// Calls [fn] with the value of evaluating [node1] and [node2].
+  ///
+  /// Both nodes are evaluated in order.
+  ///
+  /// If node2 must be transformed (see [shouldTransform]), then the evaluation
+  /// of node1 is added to the current statement-list and the result is stored
+  /// in a temporary variable. The evaluation of node2 is then free to emit
+  /// statements without affecting the result of node1.
+  ///
+  /// This is necessary, because await or yield expressions have to emit
+  /// statements, and these statements could affect the value of node1.
+  ///
+  /// For example:
+  ///
+  /// - _storeIfNecessary(someLiteral) returns someLiteral.
+  /// - _storeIfNecessary(someVariable)
+  ///   inserts: var tempX = someVariable
+  ///   returns: tempX
+  ///   where tempX is a fresh temporary variable.
+  js.Expression _storeIfNecessary(js.Expression result) {
+    // Note that RegExes, js.ArrayInitializer and js.ObjectInitializer are not
+    // [js.Literal]s.
+    if (result is js.Literal) return result;
+    js.Expression tempVar = useTempVar(allocateTempVar());
+    addExpressionStatement(new js.Assignment(tempVar, result));
+    return tempVar;
+  }
+
+  withExpression(js.Expression node, fn(js.Expression result), {bool store}) {
+    int oldTempVarIndex = currentTempVarIndex;
+    js.Expression visited = visitExpression(node);
+    if (store) {
+      visited = _storeIfNecessary(visited);
+    }
+    var result = fn(visited);
+    currentTempVarIndex = oldTempVarIndex;
+    return result;
+  }
+
+  /// Calls [fn] with the value of evaluating [node1] and [node2].
+  ///
+  /// If `shouldTransform(node2)` the first expression is stored in a temporary
+  /// variable.
+  ///
+  /// This is because node1 must be evaluated before visiting node2,
+  /// because the evaluation of an await or yield cannot be expressed as
+  /// an expression, visiting node2 it will output statements that
+  /// might have an influence on the value of node1.
+  withExpression2(js.Expression node1, js.Expression node2,
+      fn(js.Expression result1, js.Expression result2)) {
+    int oldTempVarIndex = currentTempVarIndex;
+    js.Expression r1 = visitExpression(node1);
+    if (shouldTransform(node2)) {
+      r1 = _storeIfNecessary(r1);
+    }
+    js.Expression r2 = visitExpression(node2);
+    var result = fn(r1, r2);
+    currentTempVarIndex = oldTempVarIndex;
+    return result;
+  }
+
+  /// Calls [fn] with the value of evaluating all [nodes].
+  ///
+  /// All results before the last node where `shouldTransform(node)` are stored
+  /// in temporary variables.
+  ///
+  /// See more explanation on [withExpression2].
+  ///
+  /// If any of the nodes are null, they are ignored, and a null is passed to
+  /// [fn] in that place.
+  withExpressions(List<js.Expression> nodes, fn(List<js.Expression> results)) {
+    int oldTempVarIndex = currentTempVarIndex;
+    // Find last occurence of a 'transform' expression in [nodes].
+    // All expressions before that must be stored in temp-vars.
+    int lastTransformIndex = 0;
+    for (int i = nodes.length - 1; i >= 0; --i) {
+      if (nodes[i] == null) continue;
+      if (shouldTransform(nodes[i])) {
+        lastTransformIndex = i;
+        break;
+      }
+    }
+    List<js.Node> visited = nodes.take(lastTransformIndex).map((js.Node node) {
+      return node == null ? null : _storeIfNecessary(visitExpression(node));
+    }).toList();
+    visited.addAll(nodes.skip(lastTransformIndex).map((js.Node node) {
+      return node == null ? null : visitExpression(node);
+    }));
+    var result = fn(visited);
+    currentTempVarIndex = oldTempVarIndex;
+    return result;
+  }
+
+  /// Emits the return block that all returns should jump to (after going
+  /// through all the enclosing finally blocks). The jump to here is made in
+  /// [visitReturn].
+  ///
+  /// Returning from an async method calls the [thenHelper] with the result.
+  /// (the result might have been stored in [returnValueName] by some finally
+  /// block).
+  ///
+  /// Returning from a sync* function returns an [endOfIteration] marker.
+  ///
+  /// Returning from an async* function calls the [streamHelper] with an
+  /// [endOfIteration] marker.
+  void addExit() {
+    if (analysis.hasExplicitReturns || isAsyncStar) {
+      beginLabel(exitLabel);
+    } else {
+      addStatement(new js.Comment("implicit return"));
+    }
+    switch (async) {
+      case const js.AsyncModifier.async():
+        String returnValue =
+            analysis.hasExplicitReturns ? returnValueName : "null";
+        addStatement(js.js.statement(
+            "return #thenHelper($returnValue, null, $completerName, null)", {
+          "thenHelper": thenHelper
+        }));
+        break;
+      case const js.AsyncModifier.syncStar():
+        addStatement(new js.Return(new js.Call(endOfIteration, [])));
+        break;
+      case const js.AsyncModifier.asyncStar():
+        addStatement(js.js.statement(
+            "return #streamHelper(null, null, $controllerName, null)", {
+          "streamHelper": streamHelper
+        }));
+        break;
+      default:
+        diagnosticListener.internalError(
+            spannable, "Internal error, unexpected asyncmodifier $async");
+    }
+  }
+
+  /// The initial call to [thenHelper]/[streamHelper].
+  ///
+  /// There is no value to await/yield, so the first argument is `null` and
+  /// also the errorCallback is `null`.
+  ///
+  /// Returns the [Future]/[Stream] coming from [completerName]/
+  /// [controllerName].
+  js.Statement generateInitializer() {
+    if (isAsync) {
+      return js.js.statement(
+          "return #thenHelper(null, $helperName, $completerName, null);", {
+        "thenHelper": thenHelper
+      });
+    } else if (isAsyncStar) {
+      return js.js.statement(
+          "return #streamOfController($controllerName);", {
+        "streamOfController": streamOfController
+      });
+    } else {
+      throw diagnosticListener.internalError(
+          spannable, "Unexpected asyncModifier: $async");
+    }
+  }
+
+  /// Rewrites an async/sync*/async* function to a normal Javascript function.
+  ///
+  /// The control flow is flattened by simulating 'goto' using a switch in a
+  /// loop and a state variable [gotoName] inside a helper-function that can be
+  /// called back by [thenHelper]/[streamHelper]/the [Iterator].
+  ///
+  /// Local variables are hoisted outside the helper.
+  ///
+  /// Awaits in async/async* are translated to code that remembers the current
+  /// location (so the function can resume from where it was) followed by a call
+  /// to the [thenHelper]. The helper sets up the waiting for the awaited value
+  /// and returns a future which is immediately returned by the translated
+  /// await.
+  /// Yields in async* are translated to a call to the [streamHelper]. They,
+  /// too, need to be prepared to be interrupted in case the stream is paused or
+  /// canceled. (Currently we always suspend - this is different from the spec,
+  /// see `streamHelper` in `js_helper.dart`).
+  ///
+  /// Yield/yield* in a sync* function is translated to a return of the value,
+  /// wrapped into a "IterationMarker" that signals the type (yield or yield*).
+  /// Sync* functions are executed on demand (when the user requests a value) by
+  /// the Iterable that knows how to handle these values.
+  ///
+  /// Simplified examples (not the exact translation, but intended to show the
+  /// ideas):
+  ///
+  /// function (x, y, z) async {
+  ///   var p = await foo();
+  ///   return bar(p);
+  /// }
+  ///
+  /// Becomes:
+  ///
+  /// function(x, y, z) {
+  ///   var goto = 0, returnValue, completer = new Completer(), p;
+  ///   function helper(result) {
+  ///     while (true) {
+  ///       switch (goto) {
+  ///         case 0:
+  ///           goto = 1 // Remember where to continue when the future succeeds.
+  ///           return thenHelper(foo(), helper, completer, null);
+  ///         case 1:
+  ///           p = result;
+  ///           returnValue = bar(p);
+  ///           goto = 2;
+  ///           break;
+  ///         case 2:
+  ///           return thenHelper(returnValue, null, completer, null)
+  ///       }
+  ///     }
+  ///     return thenHelper(null, helper, completer, null);
+  ///   }
+  /// }
+  ///
+  /// Try/catch is implemented by maintaining [handlerName] to contain the label
+  /// of the current handler. The switch is nested inside a try/catch that will
+  /// redirect the flow to the current handler.
+  ///
+  /// A `finally` clause is compiled similar to normal code, with the additional
+  /// complexity that `finally` clauses need to know where to jump to after the
+  /// clause is done. In the translation, each flow-path that enters a `finally`
+  /// sets up the variable [nextName] with a stack of finally-blocks and a final
+  /// jump-target (exit, catch, ...).
+  ///
+  /// function (x, y, z) async {
+  ///   try {
+  ///     try {
+  ///       throw "error";
+  ///     } finally {
+  ///       finalize1();
+  ///     }
+  ///   } catch (e) {
+  ///     handle(e);
+  ///   } finally {
+  ///     finalize2();
+  ///   }
+  /// }
+  ///
+  /// Translates into (besides the fact that structures not containing
+  /// await/yield/yield* are left intact):
+  ///
+  /// function(x, y, z) {
+  ///   var goto = 0;
+  ///   var returnValue;
+  ///   var completer = new Completer();
+  ///   var handler = null;
+  ///   var p;
+  ///   // The result can be either the result of an awaited future, or an
+  ///   // error if the future completed with an error.
+  ///   function helper(result) {
+  ///     while (true) {
+  ///       try {
+  ///         switch (goto) {
+  ///           case 0:
+  ///             handler = 4; // The outer catch-handler
+  ///             handler = 1; // The inner (implicit) catch-handler
+  ///             throw "error";
+  ///             next = [3];
+  ///             // After the finally (2) continue normally after the try.
+  ///             goto = 2;
+  ///             break;
+  ///           case 1: // (implicit) catch handler for inner try.
+  ///             next = [3]; // destination after the finally.
+  ///             // fall-though to the finally handler.
+  ///           case 2: // finally for inner try
+  ///             handler = 4; // catch-handler for outer try.
+  ///             finalize1();
+  ///             goto = next.pop();
+  ///             break;
+  ///           case 3: // exiting inner try.
+  ///             next = [6];
+  ///             goto = 5; // finally handler for outer try.
+  ///             break;
+  ///           case 4: // catch handler for outer try.
+  ///             e = result;
+  ///             handle(e);
+  ///             // Fall through to finally.
+  ///           case 5: // finally handler for outer try.
+  ///             handler = null;
+  ///             finalize2();
+  ///             goto = next.pop();
+  ///             break;
+  ///           case 6: // Exiting outer try.
+  ///           case 7: // return
+  ///             return thenHelper(returnValue, null, completer, null);
+  ///         }
+  ///       } catch (error) {
+  ///         result = error;
+  ///         goto = handler;
+  ///       }
+  ///     }
+  ///     return thenHelper(null, helper, completer, null);
+  ///   }
+  /// }
+  ///
+  @override
+  js.Expression visitFun(js.Fun node) {
+    if (isSync) return node;
+
+    beginLabel(newLabel("Function start"));
+    // AsyncStar needs a returnlabel for its handling of cancelation. See
+    // [visitDartYield].
+    exitLabel =
+        analysis.hasExplicitReturns || isAsyncStar ? newLabel("return") : null;
+    js.Statement body = node.body;
+    targetsAndTries.add(node);
+    visitStatement(body);
+    targetsAndTries.removeLast();
+    addExit();
+
+    List<js.SwitchClause> clauses = labelledParts.keys.map((label) {
+      return new js.Case(js.number(label), new js.Block(labelledParts[label]));
+    }).toList();
+    js.Statement helperBody =
+        new js.Switch(new js.VariableUse(gotoName), clauses);
+    if (hasJumpThoughOuterLabel) {
+      helperBody = js.js.statement("$outerLabelName: #", [helperBody]);
+    }
+    if (hasTryBlocks) {
+      helperBody = js.js.statement("""
+          try {
+            #body
+          } catch ($errorName){
+            if ($handlerName === null)
+              throw $errorName;
+            $resultName = $errorName;
+            $gotoName = $handlerName;
+          }""", {"body": helperBody});
+    }
+    List<js.VariableInitialization> inits = <js.VariableInitialization>[];
+
+    js.VariableInitialization makeInit(String name, js.Expression initValue) {
+      return new js.VariableInitialization(
+          new js.VariableDeclaration(name), initValue);
+    }
+
+    inits.add(makeInit(gotoName, js.number(0)));
+    if (isAsync) {
+      inits.add(makeInit(completerName, new js.New(newCompleter, [])));
+    } else if (isAsyncStar) {
+      inits.add(makeInit(controllerName,
+          new js.Call(newController, [new js.VariableUse(helperName)])));
+    }
+    if (hasTryBlocks) {
+      inits.add(makeInit(handlerName, new js.LiteralNull()));
+    }
+    if (hasJumpThroughFinally) {
+      inits.add(makeInit(nextName, null));
+    }
+    if (analysis.hasExplicitReturns && isAsync) {
+      inits.add(makeInit(returnValueName, null));
+    }
+    if (analysis.hasThis && !isSyncStar) {
+      // Sync* functions must remember `this` on the level of the outer
+      // function.
+      inits.add(makeInit(selfName, new js.This()));
+    }
+    inits.addAll(localVariables.map((js.VariableDeclaration decl) {
+      return new js.VariableInitialization(decl, null);
+    }));
+    inits.addAll(new Iterable.generate(tempVarHighWaterMark,
+        (int i) => makeInit(useTempVar(i + 1).name, null)));
+    js.VariableDeclarationList varDecl = new js.VariableDeclarationList(inits);
+    if (isSyncStar) {
+      return js.js("""
+          function (#params) {
+            if (#needsThis)
+              var $selfName = this;
+            return new #newIterable(function () {
+              #varDecl;
+              return function $helperName($resultName) {
+                while (true)
+                  #helperBody;
+              };
+            });
+          }
+          """, {
+        "params": node.params,
+        "needsThis": analysis.hasThis,
+        "helperBody": helperBody,
+        "varDecl": varDecl,
+        "newIterable": newIterable
+      });
+    }
+    return js.js("""
+        function (#params) {
+          #varDecl;
+          function $helperName($resultName) {
+            while (true)
+              #helperBody;
+          }
+          #init;
+        }""", {
+      "params": node.params,
+      "helperBody": helperBody,
+      "varDecl": varDecl,
+      "init": generateInitializer()
+    });
+  }
+
+  @override
+  js.Expression visitAccess(js.PropertyAccess node) {
+    return withExpression2(node.receiver, node.selector,
+        (receiver, selector) => new js.PropertyAccess(receiver, selector));
+  }
+
+  @override
+  js.Expression visitArrayHole(js.ArrayHole node) {
+    return node;
+  }
+
+  @override
+  js.Expression visitArrayInitializer(js.ArrayInitializer node) {
+    return withExpressions(node.elements, (elements) {
+      return new js.ArrayInitializer(elements);
+    });
+  }
+
+  @override
+  js.Expression visitAssignment(js.Assignment node) {
+    if (!shouldTransform(node)) {
+      return new js.Assignment.compound(visitExpression(node.leftHandSide),
+          node.op, visitExpression(node.value));
+    }
+    js.Expression leftHandSide = node.leftHandSide;
+    if (leftHandSide is js.VariableUse) {
+      return withExpression(node.value, (js.Expression value) {
+        return new js.Assignment(leftHandSide, value);
+      }, store: false);
+    } else if (leftHandSide is js.PropertyAccess) {
+      return withExpressions([
+        leftHandSide.receiver,
+        leftHandSide.selector,
+        node.value
+      ], (evaluated) {
+        return new js.Assignment.compound(
+            new js.PropertyAccess(evaluated[0], evaluated[1]), node.op,
+            evaluated[2]);
+      });
+    } else {
+      throw "Unexpected assignment left hand side $leftHandSide";
+    }
+  }
+
+  /// An await is translated to a call to [thenHelper]/[streamHelper].
+  ///
+  /// See the comments of [visitFun] for an example.
+  @override
+  js.Expression visitAwait(js.Await node) {
+    assert(isAsync || isAsyncStar);
+    int afterAwait = newLabel("returning from await.");
+    withExpression(node.expression, (js.Expression value) {
+      addStatement(setGotoVariable(afterAwait));
+      js.Expression errorCallback = errorHandlerLabels.isEmpty
+          ? new js.LiteralNull()
+          : js.js("""
+            function($errorName) {
+              $gotoName = #currentHandler;
+              $helperName($errorName);
+            }""", {"currentHandler": currentErrorHandler});
+
+      addStatement(js.js.statement("""
+          return #thenHelper(#value,
+                             $helperName,
+                             ${isAsync ? completerName : controllerName},
+                             #errorCallback);
+          """, {
+        "thenHelper": isAsync ? thenHelper : streamHelper,
+        "value": value,
+        "errorCallback": errorCallback
+      }));
+    }, store: false);
+    beginLabel(afterAwait);
+    return new js.VariableUse(resultName);
+  }
+
+  /// Checks if [node] is the variable named [resultName].
+  ///
+  /// [resultName] is used to hold the result of a transformed computation
+  /// for example the result of awaiting, or the result of a conditional or
+  /// short-circuiting expression.
+  /// If the subexpression of some transformed node already is transformed and
+  /// visiting it returns [resultName], it is not redundantly assigned to itself
+  /// again.
+  bool isResult(js.Expression node) {
+    return node is js.VariableUse && node.name == resultName;
+  }
+
+  @override
+  js.Expression visitBinary(js.Binary node) {
+    if (shouldTransform(node.right) && (node.op == "||" || node.op == "&&")) {
+      int thenLabel = newLabel("then");
+      int joinLabel = newLabel("join");
+      withExpression(node.left, (js.Expression left) {
+        js.Statement assignLeft = isResult(left)
+            ? new js.Block.empty()
+            : new js.ExpressionStatement(
+                new js.Assignment(new js.VariableUse(resultName), left));
+        if (node.op == "||") {
+          addStatement(new js.If(left, gotoAndBreak(thenLabel), assignLeft));
+        } else {
+          assert(node.op == "&&");
+          addStatement(new js.If(left, assignLeft, gotoAndBreak(thenLabel)));
+        }
+      }, store: true);
+      addGoto(joinLabel);
+      beginLabel(thenLabel);
+      withExpression(node.right, (js.Expression value) {
+        if (!isResult(value)) {
+          addExpressionStatement(
+              new js.Assignment(new js.VariableUse(resultName), value));
+        }
+      }, store: false);
+      beginLabel(joinLabel);
+      return new js.VariableUse(resultName);
+    }
+
+    return withExpression2(node.left, node.right,
+        (left, right) => new js.Binary(node.op, left, right));
+  }
+
+  @override
+  void visitBlock(js.Block node) {
+    for (js.Statement statement in node.statements) {
+      visitStatement(statement);
+    }
+  }
+
+  @override
+  void visitBreak(js.Break node) {
+    js.Node target = analysis.targets[node];
+    if (!shouldTransform(target)) {
+      addStatement(node);
+      return;
+    }
+    translateJump(target, breakLabels[target]);
+  }
+
+  @override
+  js.Expression visitCall(js.Call node) {
+    bool storeTarget = node.arguments.any(shouldTransform);
+    return withExpression(node.target, (target) {
+      return withExpressions(node.arguments, (List<js.Expression> arguments) {
+        return new js.Call(target, arguments);
+      });
+    }, store: storeTarget);
+  }
+
+  @override
+  void visitCase(js.Case node) {
+    return unreachable(node);
+  }
+
+  @override
+  void visitCatch(js.Catch node) {
+    return unreachable(node);
+  }
+
+  @override
+  void visitComment(js.Comment node) {
+    addStatement(node);
+  }
+
+  @override
+  js.Expression visitConditional(js.Conditional node) {
+    if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
+      return withExpression(node.condition, (js.Expression condition) {
+        return new js.Conditional(condition, node.then, node.otherwise);
+      });
+    }
+    int thenLabel = newLabel("then");
+    int joinLabel = newLabel("join");
+    int elseLabel = newLabel("else");
+    withExpression(node.condition, (js.Expression condition) {
+      addExpressionStatement(new js.Assignment(new js.VariableUse(gotoName),
+          new js.Conditional(
+              condition, js.number(thenLabel), js.number(elseLabel))));
+    }, store: false);
+    addBreak();
+    beginLabel(thenLabel);
+    withExpression(node.then, (js.Expression value) {
+      if (!isResult(value)) {
+        addExpressionStatement(
+            new js.Assignment(new js.VariableUse(resultName), value));
+      }
+    }, store: false);
+    addGoto(joinLabel);
+    beginLabel(elseLabel);
+    withExpression(node.otherwise, (js.Expression value) {
+      if (!isResult(value)) {
+        addExpressionStatement(
+            new js.Assignment(new js.VariableUse(resultName), value));
+      }
+    }, store: false);
+    beginLabel(joinLabel);
+    return new js.VariableUse(resultName);
+  }
+
+  @override
+  void visitContinue(js.Continue node) {
+    js.Node target = analysis.targets[node];
+    if (!shouldTransform(target)) {
+      addStatement(node);
+      return;
+    }
+    translateJump(target, continueLabels[target]);
+  }
+
+  /// Emits a break statement that exits the big switch statement.
+  void addBreak() {
+    if (insideUntranslatedBreakable) {
+      hasJumpThoughOuterLabel = true;
+      addStatement(new js.Break(outerLabelName));
+    } else {
+      addStatement(new js.Break(null));
+    }
+  }
+
+  /// Common code for handling break, continue, return.
+  ///
+  /// It is necessary to run all nesting finally-handlers between the jump and
+  /// the target. For that [nextName] is used as a stack of places to go.
+  ///
+  /// See also [visitFun].
+  void translateJump(js.Node target, int targetLabel) {
+    // Compute a stack of all the 'finally' nodes that must be visited before
+    // the jump.
+    // The bottom of the stack is the label where the jump goes to.
+    List<int> jumpStack = new List<int>();
+    for (js.Node node in targetsAndTries.reversed) {
+      if (node is js.Try) {
+        assert(node.finallyPart != null);
+        jumpStack.add(finallyLabels[node]);
+      } else if (node == target) {
+        jumpStack.add(targetLabel);
+        break;
+      }
+      // Ignore other nodes.
+    }
+    jumpStack = jumpStack.reversed.toList();
+    // As the program jumps directly to the top of the stack, it is taken off
+    // now.
+    int firstTarget = jumpStack.removeLast();
+    if (jumpStack.isNotEmpty) {
+      hasJumpThroughFinally = true;
+      js.Expression jsJumpStack = new js.ArrayInitializer(
+          jumpStack.map((int label) => js.number(label)).toList());
+      addStatement(js.js.statement("$nextName = #", [jsJumpStack]));
+    }
+    addGoto(firstTarget);
+  }
+
+  @override
+  void visitDefault(js.Default node) => unreachable(node);
+
+  @override
+  void visitDo(js.Do node) {
+    if (!shouldTransform(node)) {
+      bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable;
+      insideUntranslatedBreakable = true;
+      withExpression(node.condition, (js.Expression condition) {
+        addStatement(new js.Do(translateInBlock(node.body), condition));
+      }, store: false);
+      insideUntranslatedBreakable = oldInsideUntranslatedBreakable;
+      return;
+    }
+    int startLabel = newLabel("do body");
+
+    int continueLabel = newLabel("do condition");
+    continueLabels[node] = continueLabel;
+
+    int afterLabel = newLabel("after do");
+    breakLabels[node] = afterLabel;
+
+    beginLabel(startLabel);
+
+    targetsAndTries.add(node);
+    visitStatement(node.body);
+    targetsAndTries.removeLast();
+
+    beginLabel(continueLabel);
+    withExpression(node.condition, (js.Expression condition) {
+      addStatement(new js.If.noElse(condition, gotoAndBreak(startLabel)));
+    }, store: false);
+    beginLabel(afterLabel);
+  }
+
+  @override
+  void visitEmptyStatement(js.EmptyStatement node) {
+    addStatement(node);
+  }
+
+  void visitExpressionInStatementContext(js.Expression node) {
+    if (node is js.VariableDeclarationList) {
+      // Treat js.VariableDeclarationList as a statement.
+      visitVariableDeclarationList(node);
+    } else {
+      visitExpressionIgnoreResult(node);
+    }
+  }
+
+  @override
+  void visitExpressionStatement(js.ExpressionStatement node) {
+    visitExpressionInStatementContext(node.expression);
+  }
+
+  @override
+  void visitFor(js.For node) {
+    if (!shouldTransform(node)) {
+      bool oldInsideUntranslated = insideUntranslatedBreakable;
+      insideUntranslatedBreakable = true;
+      // Note that node.init, node.condition, node.update all can be null, but
+      // withExpressions handles that.
+      withExpressions([
+        node.init,
+        node.condition,
+        node.update
+      ], (List<js.Expression> transformed) {
+        addStatement(new js.For(transformed[0], transformed[1], transformed[2],
+            translateInBlock(node.body)));
+      });
+      insideUntranslatedBreakable = oldInsideUntranslated;
+      return;
+    }
+
+    if (node.init != null) {
+      visitExpressionInStatementContext(node.init);
+    }
+    int startLabel = newLabel("for condition");
+    // If there is no update, continuing the loop is the same as going to the
+    // start.
+    int continueLabel =
+        (node.update == null) ? startLabel : newLabel("for update");
+    continueLabels[node] = continueLabel;
+    int afterLabel = newLabel("after for");
+    breakLabels[node] = afterLabel;
+    beginLabel(startLabel);
+    js.Expression condition = node.condition;
+    if (condition == null ||
+        (condition is js.LiteralBool && condition.value == true)) {
+      addStatement(new js.Comment("trivial condition"));
+    } else {
+      withExpression(condition, (js.Expression condition) {
+        addStatement(new js.If.noElse(
+            new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
+      }, store: false);
+    }
+    targetsAndTries.add(node);
+    visitStatement(node.body);
+    targetsAndTries.removeLast();
+    if (node.update != null) {
+      beginLabel(continueLabel);
+      visitExpressionIgnoreResult(node.update);
+    }
+    addGoto(startLabel);
+    beginLabel(afterLabel);
+  }
+
+  @override
+  void visitForIn(js.ForIn node) {
+    // The dart output currently never uses for-in loops.
+    throw "Javascript for-in not implemented yet in the await transformation";
+  }
+
+  @override
+  void visitFunctionDeclaration(js.FunctionDeclaration node) {
+    unsupported(node);
+  }
+
+  // Only used for code where `!shouldTransform(node)`.
+  js.Block translateInBlock(js.Statement node) {
+    assert(!shouldTransform(node));
+    List<js.Statement> oldBuffer = currentStatementBuffer;
+    currentStatementBuffer = new List();
+    List<js.Statement> resultBuffer = currentStatementBuffer;
+    visitStatement(node);
+    currentStatementBuffer = oldBuffer;
+    return new js.Block(resultBuffer);
+  }
+
+  @override
+  void visitIf(js.If node) {
+    if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
+      withExpression(node.condition, (js.Expression condition) {
+        addStatement(new js.If(condition, translateInBlock(node.then),
+            translateInBlock(node.otherwise)));
+      }, store: false);
+      return;
+    }
+    int thenLabel = newLabel("then");
+    int joinLabel = newLabel("join");
+    int elseLabel =
+        node.otherwise is js.EmptyStatement ? joinLabel : newLabel("else");
+
+    withExpression(node.condition, (js.Expression condition) {
+      addExpressionStatement(
+          new js.Assignment(
+              new js.VariableUse(gotoName),
+              new js.Conditional(
+                  condition,
+                  js.number(thenLabel),
+                  js.number(elseLabel))));
+    }, store: false);
+    addBreak();
+    beginLabel(thenLabel);
+    visitStatement(node.then);
+    if (node.otherwise is! js.EmptyStatement) {
+      addGoto(joinLabel);
+      beginLabel(elseLabel);
+      visitStatement(node.otherwise);
+    }
+    beginLabel(joinLabel);
+  }
+
+  @override
+  visitInterpolatedExpression(js.InterpolatedExpression node) {
+    return unsupported(node);
+  }
+
+  @override
+  visitInterpolatedLiteral(js.InterpolatedLiteral node) => unsupported(node);
+
+  @override
+  visitInterpolatedParameter(js.InterpolatedParameter node) {
+    return unsupported(node);
+  }
+
+  @override
+  visitInterpolatedSelector(js.InterpolatedSelector node) {
+    return unsupported(node);
+  }
+
+  @override
+  visitInterpolatedStatement(js.InterpolatedStatement node) {
+    return unsupported(node);
+  }
+
+  @override
+  void visitLabeledStatement(js.LabeledStatement node) {
+    if (!shouldTransform(node)) {
+      addStatement(
+          new js.LabeledStatement(node.label, translateInBlock(node.body)));
+      return;
+    }
+    int breakLabel = newLabel("break ${node.label}");
+    int continueLabel = newLabel("continue ${node.label}");
+    breakLabels[node] = breakLabel;
+    continueLabels[node] = continueLabel;
+
+    beginLabel(continueLabel);
+    targetsAndTries.add(node);
+    visitStatement(node.body);
+    targetsAndTries.removeLast();
+    beginLabel(breakLabel);
+  }
+
+  @override
+  js.Expression visitLiteralBool(js.LiteralBool node) => node;
+
+  @override
+  visitLiteralExpression(js.LiteralExpression node) => unsupported(node);
+
+  @override
+  js.Expression visitLiteralNull(js.LiteralNull node) => node;
+
+  @override
+  js.Expression visitLiteralNumber(js.LiteralNumber node) => node;
+
+  @override
+  visitLiteralStatement(js.LiteralStatement node) => unsupported(node);
+
+  @override
+  js.Expression visitLiteralString(js.LiteralString node) => node;
+
+  @override
+  visitNamedFunction(js.NamedFunction node) {
+    unsupported(node);
+  }
+
+  @override
+  js.Expression visitNew(js.New node) {
+    bool storeTarget = node.arguments.any(shouldTransform);
+    return withExpression(node.target, (target) {
+      return withExpressions(node.arguments, (List<js.Expression> arguments) {
+        return new js.New(target, arguments);
+      });
+    }, store: storeTarget);
+  }
+
+  @override
+  js.Expression visitObjectInitializer(js.ObjectInitializer node) {
+    return withExpressions(
+        node.properties.map((js.Property property) => property.value).toList(),
+        (List<js.Node> values) {
+      List<js.Property> properties = new List.generate(values.length, (int i) {
+        return new js.Property(node.properties[i].name, values[i]);
+      });
+      return new js.ObjectInitializer(properties);
+    });
+  }
+
+  @override
+  visitParameter(js.Parameter node) => unreachable(node);
+
+  @override
+  js.Expression visitPostfix(js.Postfix node) {
+    if (node.op == "++" || node.op == "--") {
+      js.Expression argument = node.argument;
+      if (argument is js.VariableUse) {
+        return new js.Postfix(node.op, argument);
+      } else if (argument is js.PropertyAccess) {
+        return withExpression2(argument.receiver, argument.selector,
+            (receiver, selector) {
+          return new js.Postfix(
+              node.op, new js.PropertyAccess(receiver, selector));
+        });
+      } else {
+        throw "Unexpected postfix ${node.op} "
+            "operator argument ${node.argument}";
+      }
+    }
+    return withExpression(node.argument,
+        (js.Expression argument) => new js.Postfix(node.op, argument),
+        store: false);
+  }
+
+  @override
+  js.Expression visitPrefix(js.Prefix node) {
+    if (node.op == "++" || node.op == "--") {
+      js.Expression argument = node.argument;
+      if (argument is js.VariableUse) {
+        return new js.Prefix(node.op, argument);
+      } else if (argument is js.PropertyAccess) {
+        return withExpression2(argument.receiver, argument.selector,
+            (receiver, selector) {
+          return new js.Prefix(
+              node.op, new js.PropertyAccess(receiver, selector));
+        });
+      } else {
+        throw "Unexpected prefix ${node.op} operator "
+            "argument ${node.argument}";
+      }
+    }
+    return withExpression(node.argument,
+        (js.Expression argument) => new js.Prefix(node.op, argument),
+        store: false);
+  }
+
+  @override
+  visitProgram(js.Program node) => unsupported(node);
+
+  @override
+  js.Property visitProperty(js.Property node) {
+    return withExpression(
+        node.value, (js.Expression value) => new js.Property(node.name, value),
+        store: false);
+  }
+
+  @override
+  js.Expression visitRegExpLiteral(js.RegExpLiteral node) => node;
+
+  @override
+  void visitReturn(js.Return node) {
+    assert(node.value == null || !isSyncStar && !isAsyncStar);
+    js.Node target = analysis.targets[node];
+    if (node.value != null) {
+      withExpression(node.value, (js.Expression value) {
+        addStatement(js.js.statement("$returnValueName = #", [value]));
+      }, store: false);
+    }
+    translateJump(target, exitLabel);
+  }
+
+  @override
+  void visitSwitch(js.Switch node) {
+    if (!node.cases.any(shouldTransform)) {
+      // If only the key has an await, translation can be simplified.
+      bool oldInsideUntranslated = insideUntranslatedBreakable;
+      insideUntranslatedBreakable = true;
+      withExpression(node.key, (js.Expression key) {
+        List<js.SwitchClause> cases = node.cases.map((js.SwitchClause clause) {
+          if (clause is js.Case) {
+            return new js.Case(
+                clause.expression, translateInBlock(clause.body));
+          } else if (clause is js.Default) {
+            return new js.Default(translateInBlock(clause.body));
+          }
+        }).toList();
+        addStatement(new js.Switch(key, cases));
+      }, store: false);
+      insideUntranslatedBreakable = oldInsideUntranslated;
+      return;
+    }
+    int before = newLabel("switch");
+    int after = newLabel("after switch");
+    breakLabels[node] = after;
+
+    beginLabel(before);
+    List<int> labels = new List<int>(node.cases.length);
+
+    bool anyCaseExpressionTransformed = node.cases.any(
+        (js.SwitchClause x) => x is js.Case && shouldTransform(x.expression));
+    if (anyCaseExpressionTransformed) {
+      int defaultIndex = null; // Null means no default was found.
+      // If there is an await in one of the keys, a chain of ifs has to be used.
+
+      withExpression(node.key, (js.Expression key) {
+        int i = 0;
+        for (js.SwitchClause clause in node.cases) {
+          if (clause is js.Default) {
+            // The goto for the default case is added after all non-default
+            // clauses have been handled.
+            defaultIndex = i;
+            labels[i] = newLabel("default");
+            continue;
+          } else if (clause is js.Case) {
+            labels[i] = newLabel("case");
+            withExpression(clause.expression, (expression) {
+              addStatement(new js.If.noElse(
+                  new js.Binary("===", key, expression),
+                  gotoAndBreak(labels[i])));
+            }, store: false);
+          }
+          i++;
+        }
+      }, store: true);
+
+      if (defaultIndex == null) {
+        addGoto(after);
+      } else {
+        addGoto(labels[defaultIndex]);
+      }
+    } else {
+      bool hasDefault = false;
+      int i = 0;
+      List<js.SwitchClause> clauses = new List<js.SwitchClause>();
+      for (js.SwitchClause clause in node.cases) {
+        if (clause is js.Case) {
+          labels[i] = newLabel("case");
+          clauses.add(new js.Case(clause.expression, gotoAndBreak(labels[i])));
+        } else if (i is js.Default) {
+          labels[i] = newLabel("default");
+          clauses.add(new js.Default(gotoAndBreak(labels[i])));
+          hasDefault = true;
+        } else {
+          diagnosticListener.internalError(
+              spannable, "Unknown clause type $clause");
+        }
+        i++;
+      }
+      withExpression(node.key, (js.Expression key) {
+        addStatement(new js.Switch(key, clauses));
+      }, store: false);
+      if (!hasDefault) {
+        addGoto(after);
+      }
+    }
+
+    targetsAndTries.add(node);
+    for (int i = 0; i < labels.length; i++) {
+      beginLabel(labels[i]);
+      visitStatement(node.cases[i].body);
+    }
+    beginLabel(after);
+    targetsAndTries.removeLast();
+  }
+
+  @override
+  js.Expression visitThis(js.This node) {
+    return new js.VariableUse(selfName);
+  }
+
+  @override
+  void visitThrow(js.Throw node) {
+    withExpression(node.expression, (js.Expression expression) {
+      addStatement(new js.Throw(expression));
+    }, store: false);
+  }
+
+  setErrorHandler() {
+    addExpressionStatement(new js.Assignment(
+        new js.VariableUse(handlerName), currentErrorHandler));
+  }
+
+  @override
+  void visitTry(js.Try node) {
+    if (!shouldTransform(node)) {
+      js.Block body = translateInBlock(node.body);
+      js.Catch catchPart = (node.catchPart == null)
+          ? null
+          : new js.Catch(node.catchPart.declaration,
+              translateInBlock(node.catchPart.body));
+      js.Block finallyPart = (node.finallyPart == null)
+          ? null
+          : translateInBlock(node.finallyPart);
+      addStatement(new js.Try(body, catchPart, finallyPart));
+      return;
+    }
+    hasTryBlocks = true;
+    int handlerLabel = newLabel("catch");
+    int finallyLabel = newLabel("finally");
+    int afterFinallyLabel = newLabel("after finally");
+    errorHandlerLabels.add(handlerLabel);
+    // Set the error handler here. It must be cleared on every path out;
+    // normal and error exit.
+    setErrorHandler();
+    if (node.finallyPart != null) {
+      finallyLabels[node] = finallyLabel;
+      targetsAndTries.add(node);
+    }
+    visitStatement(node.body);
+    errorHandlerLabels.removeLast();
+    addStatement(
+        js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+    if (node.finallyPart == null) {
+      setErrorHandler();
+      addGoto(afterFinallyLabel);
+    } else {
+      // The handler is set as the first thing in the finally block.
+      addGoto(finallyLabel);
+    }
+    beginLabel(handlerLabel);
+    if (node.catchPart != null) {
+      setErrorHandler();
+      // The catch declaration name can shadow outer variables, so a fresh name
+      // is needed to avoid collisions.  See Ecma 262, 3rd edition,
+      // section 12.14.
+      String errorRename = freshName(node.catchPart.declaration.name);
+      localVariables.add(new js.VariableDeclaration(errorRename));
+      variableRenamings
+          .add(new Pair(node.catchPart.declaration.name, errorRename));
+      addExpressionStatement(new js.Assignment(
+          new js.VariableUse(errorRename), new js.VariableUse(resultName)));
+      visitStatement(node.catchPart.body);
+      variableRenamings.removeLast();
+    }
+    if (node.finallyPart != null) {
+      targetsAndTries.removeLast();
+      setErrorHandler();
+      // This belongs to the catch-part, but is only needed if there is a
+      // `finally`. Therefore it is in this branch.
+      // This is needed even if there is no explicit catch-branch, because
+      // if an exception is raised the finally part has to be run.
+      addStatement(
+          js.js.statement("$nextName = [#];", [js.number(afterFinallyLabel)]));
+      beginLabel(finallyLabel);
+      setErrorHandler();
+      visitStatement(node.finallyPart);
+      addStatement(new js.Comment("// goto the next finally handler"));
+      addStatement(js.js.statement("$gotoName = $nextName.pop();"));
+      addBreak();
+    }
+    beginLabel(afterFinallyLabel);
+  }
+
+  @override
+  visitVariableDeclaration(js.VariableDeclaration node) {
+    unreachable(node);
+  }
+
+  @override
+  void visitVariableDeclarationList(js.VariableDeclarationList node) {
+    // Declaration of local variables is hoisted outside the helper but the
+    // initialization is done here.
+    for (js.VariableInitialization initialization in node.declarations) {
+      js.VariableDeclaration declaration = initialization.declaration;
+      localVariables.add(declaration);
+      if (initialization.value != null) {
+        withExpression(initialization.value, (js.Expression value) {
+          addStatement(new js.ExpressionStatement(
+              new js.Assignment(new js.VariableUse(declaration.name), value)));
+        }, store: false);
+      }
+    }
+  }
+
+  @override
+  void visitVariableInitialization(js.VariableInitialization node) {
+    unreachable(node);
+  }
+
+  @override
+  js.Expression visitVariableUse(js.VariableUse node) {
+    Pair<String, String> renaming = variableRenamings.lastWhere(
+        (Pair renaming) => renaming.a == node.name, orElse: () => null);
+    if (renaming == null) return node;
+    return new js.VariableUse(renaming.b);
+  }
+
+  @override
+  void visitWhile(js.While node) {
+    if (!shouldTransform(node)) {
+      bool oldInsideUntranslated = insideUntranslatedBreakable;
+      insideUntranslatedBreakable = true;
+      withExpression(node.condition, (js.Expression condition) {
+        addStatement(new js.While(condition, translateInBlock(node.body)));
+      }, store: false);
+      insideUntranslatedBreakable = oldInsideUntranslated;
+      return;
+    }
+    int continueLabel = newLabel("while condition");
+    continueLabels[node] = continueLabel;
+    beginLabel(continueLabel);
+
+    int afterLabel = newLabel("after while");
+    breakLabels[node] = afterLabel;
+    js.Expression condition = node.condition;
+    // If the condition is `true`, a test is not needed.
+    if (!(condition is js.LiteralBool && condition.value == true)) {
+      withExpression(node.condition, (js.Expression condition) {
+        addStatement(new js.If.noElse(
+            new js.Prefix("!", condition), gotoAndBreak(afterLabel)));
+      }, store: false);
+    }
+    targetsAndTries.add(node);
+    visitStatement(node.body);
+    targetsAndTries.removeLast();
+    addGoto(continueLabel);
+    beginLabel(afterLabel);
+  }
+
+  /// Translates a yield/yield* in an sync*.
+  ///
+  /// `yield` in a sync* function just returns [value].
+  /// `yield*` wraps [value] in a [yieldStarExpression] and returns it.
+  void addSyncYield(js.DartYield node, js.Expression expression) {
+    assert(isSyncStar);
+    if (node.hasStar) {
+      addStatement(
+          new js.Return(new js.Call(yieldStarExpression, [expression])));
+    } else {
+      addStatement(new js.Return(expression));
+    }
+  }
+
+  /// Translates a yield/yield* in an async* function.
+  ///
+  /// yield/yield* in an async* function is translated much like the `await` is
+  /// translated in [visitAwait], only the object is wrapped in a
+  /// [yieldExpression]/[yieldStarExpression] to let [streamHelper] distinguish.
+  ///
+  /// Because there is no Future that can fail (as there is in await) null is
+  /// passed as the errorCallback.
+  void addAsyncYield(js.DartYield node, js.Expression expression) {
+    assert(isAsyncStar);
+    // Find all the finally blocks that should be performed if the stream is
+    // canceled during the yield.
+    // At the bottom of the stack is the return label.
+    List<int> enclosingFinallyLabels = <int>[exitLabel];
+    enclosingFinallyLabels.addAll(targetsAndTries
+        .where((js.Node node) => node is js.Try)
+        .map((js.Try node) => finallyLabels[node]));
+    int destinationOnCancel = enclosingFinallyLabels.removeLast();
+    js.ArrayInitializer finallyListInitializer = new js.ArrayInitializer(
+        enclosingFinallyLabels.map(js.number).toList());
+    addStatement(js.js.statement("""
+        return #streamHelper(#yieldExpression(#expression),
+            $helperName, $controllerName, function () {
+              if (#notEmptyFinallyList)
+                $nextName = #finallyList;
+              $gotoName = #destinationOnCancel;
+              $helperName();
+            });""", {
+      "streamHelper": streamHelper,
+      "yieldExpression": node.hasStar ? yieldStarExpression : yieldExpression,
+      "expression": expression,
+      "notEmptyFinallyList": enclosingFinallyLabels.isNotEmpty,
+      "finallyList": finallyListInitializer,
+      "destinationOnCancel": js.number(destinationOnCancel)
+    }));
+  }
+
+  @override
+  void visitDartYield(js.DartYield node) {
+    assert(isSyncStar || isAsyncStar);
+    int label = newLabel("after yield");
+    // Don't do a break here for the goto, but instead a return in either
+    // addSynYield or addAsyncYield.
+    withExpression(node.expression, (js.Expression expression) {
+      addStatement(setGotoVariable(label));
+      if (isSyncStar) {
+        addSyncYield(node, expression);
+      } else {
+        addAsyncYield(node, expression);
+      }
+    }, store: false);
+    beginLabel(label);
+  }
+}
+
+/// Finds out
+///
+/// - which expressions have yield or await nested in them.
+/// - targets of jumps
+/// - a set of used names.
+/// - if any [This]-expressions are used.
+class PreTranslationAnalysis extends js.NodeVisitor<bool> {
+  Set<js.Node> hasAwaitOrYield = new Set<js.Node>();
+
+  Map<js.Node, js.Node> targets = new Map<js.Node, js.Node>();
+  List<js.Node> loopsAndSwitches = new List<js.Node>();
+  List<js.LabeledStatement> labelledStatements =
+      new List<js.LabeledStatement>();
+  Set<String> usedNames = new Set<String>();
+
+  bool hasExplicitReturns = false;
+
+  bool hasThis = false;
+
+  // The function currently being analyzed.
+  js.Fun currentFunction;
+
+  // For error messages.
+  final Function unsupported;
+
+  PreTranslationAnalysis(void this.unsupported(js.Node node));
+
+  bool visit(js.Node node) {
+    bool containsAwait = node.accept(this);
+    if (containsAwait) {
+      hasAwaitOrYield.add(node);
+    }
+    return containsAwait;
+  }
+
+  analyze(js.Fun node) {
+    currentFunction = node;
+    node.params.forEach(visit);
+    visit(node.body);
+  }
+
+  @override
+  bool visitAccess(js.PropertyAccess node) {
+    bool receiver = visit(node.receiver);
+    bool selector = visit(node.selector);
+    return receiver || selector;
+  }
+
+  @override
+  bool visitArrayHole(js.ArrayHole node) {
+    return false;
+  }
+
+  @override
+  bool visitArrayInitializer(js.ArrayInitializer node) {
+    bool containsAwait = false;
+    for (js.Expression element in node.elements) {
+      if (visit(element)) containsAwait = true;
+    }
+    return containsAwait;
+  }
+
+  @override
+  bool visitAssignment(js.Assignment node) {
+    bool leftHandSide = visit(node.leftHandSide);
+    bool value = (node.value == null) ? false : visit(node.value);
+    return leftHandSide || value;
+  }
+
+  @override
+  bool visitAwait(js.Await node) {
+    visit(node.expression);
+    return true;
+  }
+
+  @override
+  bool visitBinary(js.Binary node) {
+    bool left = visit(node.left);
+    bool right = visit(node.right);
+    return left || right;
+  }
+
+  @override
+  bool visitBlock(js.Block node) {
+    bool containsAwait = false;
+    for (js.Statement statement in node.statements) {
+      if (visit(statement)) containsAwait = true;
+    }
+    return containsAwait;
+  }
+
+  @override
+  bool visitBreak(js.Break node) {
+    if (node.targetLabel != null) {
+      targets[node] = labelledStatements.lastWhere(
+          (js.LabeledStatement statement) {
+        return statement.label == node.targetLabel;
+      });
+    } else {
+      targets[node] = loopsAndSwitches.last;
+    }
+    return false;
+  }
+
+  @override
+  bool visitCall(js.Call node) {
+    bool containsAwait = visit(node.target);
+    for (js.Expression argument in node.arguments) {
+      if (visit(argument)) containsAwait = true;
+    }
+    return containsAwait;
+  }
+
+  @override
+  bool visitCase(js.Case node) {
+    bool expression = visit(node.expression);
+    bool body = visit(node.body);
+    return expression || body;
+  }
+
+  @override
+  bool visitCatch(js.Catch node) {
+    bool declaration = visit(node.declaration);
+    bool body = visit(node.body);
+    return declaration || body;
+  }
+
+  @override
+  bool visitComment(js.Comment node) {
+    return false;
+  }
+
+  @override
+  bool visitConditional(js.Conditional node) {
+    bool condition = visit(node.condition);
+    bool then = visit(node.then);
+    bool otherwise = visit(node.otherwise);
+    return condition || then || otherwise;
+  }
+
+  @override
+  bool visitContinue(js.Continue node) {
+    if (node.targetLabel != null) {
+      targets[node] = labelledStatements.lastWhere(
+          (js.LabeledStatement stm) => stm.label == node.targetLabel);
+    } else {
+      targets[node] =
+          loopsAndSwitches.lastWhere((js.Node node) => node is! js.Switch);
+    }
+    assert(() {
+      js.Node target = targets[node];
+      return target is js.Loop ||
+          (target is js.LabeledStatement && target.body is js.Loop);
+    });
+    return false;
+  }
+
+  @override
+  bool visitDefault(js.Default node) {
+    return visit(node.body);
+  }
+
+  @override
+  bool visitDo(js.Do node) {
+    loopsAndSwitches.add(node);
+    bool body = visit(node.body);
+    bool condition = visit(node.condition);
+    loopsAndSwitches.removeLast();
+    return body || condition;
+  }
+
+  @override
+  bool visitEmptyStatement(js.EmptyStatement node) {
+    return false;
+  }
+
+  @override
+  bool visitExpressionStatement(js.ExpressionStatement node) {
+    return visit(node.expression);
+  }
+
+  @override
+  bool visitFor(js.For node) {
+    bool init = (node.init == null) ? false : visit(node.init);
+    bool condition = (node.condition == null) ? false : visit(node.condition);
+    bool update = (node.update == null) ? false : visit(node.update);
+    loopsAndSwitches.add(node);
+    bool body = visit(node.body);
+    loopsAndSwitches.removeLast();
+    return init || condition || update || body;
+  }
+
+  @override
+  bool visitForIn(js.ForIn node) {
+    bool object = visit(node.object);
+    loopsAndSwitches.add(node);
+    bool body = visit(node.body);
+    loopsAndSwitches.removeLast();
+    return object || body;
+  }
+
+  @override
+  bool visitFun(js.Fun node) {
+    return false;
+  }
+
+  @override
+  bool visitFunctionDeclaration(js.FunctionDeclaration node) {
+    return false;
+  }
+
+  @override
+  bool visitIf(js.If node) {
+    bool condition = visit(node.condition);
+    bool then = visit(node.then);
+    bool otherwise = visit(node.otherwise);
+    return condition || then || otherwise;
+  }
+
+  @override
+  bool visitInterpolatedExpression(js.InterpolatedExpression node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitInterpolatedLiteral(js.InterpolatedLiteral node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitInterpolatedParameter(js.InterpolatedParameter node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitInterpolatedSelector(js.InterpolatedSelector node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitInterpolatedStatement(js.InterpolatedStatement node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitLabeledStatement(js.LabeledStatement node) {
+    usedNames.add(node.label);
+    labelledStatements.add(node);
+    bool containsAwait = visit(node.body);
+    labelledStatements.removeLast();
+    return containsAwait;
+  }
+
+  @override
+  bool visitLiteralBool(js.LiteralBool node) {
+    return false;
+  }
+
+  @override
+  bool visitLiteralExpression(js.LiteralExpression node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitLiteralNull(js.LiteralNull node) {
+    return false;
+  }
+
+  @override
+  bool visitLiteralNumber(js.LiteralNumber node) {
+    return false;
+  }
+
+  @override
+  bool visitLiteralStatement(js.LiteralStatement node) {
+    return unsupported(node);
+  }
+
+  @override
+  bool visitLiteralString(js.LiteralString node) {
+    return false;
+  }
+
+  @override
+  bool visitNamedFunction(js.NamedFunction node) {
+    return false;
+  }
+
+  @override
+  bool visitNew(js.New node) {
+    return visitCall(node);
+  }
+
+  @override
+  bool visitObjectInitializer(js.ObjectInitializer node) {
+    bool containsAwait = false;
+    for (js.Property property in node.properties) {
+      if (visit(property)) containsAwait = true;
+    }
+    return containsAwait;
+  }
+
+  @override
+  bool visitParameter(js.Parameter node) {
+    usedNames.add(node.name);
+    return false;
+  }
+
+  @override
+  bool visitPostfix(js.Postfix node) {
+    return visit(node.argument);
+  }
+
+  @override
+  bool visitPrefix(js.Prefix node) {
+    return visit(node.argument);
+  }
+
+  @override
+  bool visitProgram(js.Program node) {
+    throw "Unexpected";
+  }
+
+  @override
+  bool visitProperty(js.Property node) {
+    return visit(node.value);
+  }
+
+  @override
+  bool visitRegExpLiteral(js.RegExpLiteral node) {
+    return false;
+  }
+
+  @override
+  bool visitReturn(js.Return node) {
+    hasExplicitReturns = true;
+    targets[node] = currentFunction;
+    if (node.value == null) return false;
+    return visit(node.value);
+  }
+
+  @override
+  bool visitSwitch(js.Switch node) {
+    loopsAndSwitches.add(node);
+    bool result = visit(node.key);
+    for (js.SwitchClause clause in node.cases) {
+      if (visit(clause)) result = true;
+    }
+    loopsAndSwitches.removeLast();
+    return result;
+  }
+
+  @override
+  bool visitThis(js.This node) {
+    hasThis = true;
+    return false;
+  }
+
+  @override
+  bool visitThrow(js.Throw node) {
+    return visit(node.expression);
+  }
+
+  @override
+  bool visitTry(js.Try node) {
+    bool body = visit(node.body);
+    bool catchPart = (node.catchPart == null) ? false : visit(node.catchPart);
+    bool finallyPart =
+        (node.finallyPart == null) ? false : visit(node.finallyPart);
+    return body || catchPart || finallyPart;
+  }
+
+  @override
+  bool visitVariableDeclaration(js.VariableDeclaration node) {
+    usedNames.add(node.name);
+    return false;
+  }
+
+  @override
+  bool visitVariableDeclarationList(js.VariableDeclarationList node) {
+    bool result = false;
+    for (js.VariableInitialization init in node.declarations) {
+      if (visit(init)) result = true;
+    }
+    return result;
+  }
+
+  @override
+  bool visitVariableInitialization(js.VariableInitialization node) {
+    return visitAssignment(node);
+  }
+
+  @override
+  bool visitVariableUse(js.VariableUse node) {
+    usedNames.add(node.name);
+    return false;
+  }
+
+  @override
+  bool visitWhile(js.While node) {
+    loopsAndSwitches.add(node);
+    bool condition = visit(node.condition);
+    bool body = visit(node.body);
+    loopsAndSwitches.removeLast();
+    return condition || body;
+  }
+
+  @override
+  bool visitDartYield(js.DartYield node) {
+    visit(node.expression);
+    return true;
+  }
+}
diff --git a/pkg/compiler/lib/src/js/template.dart b/pkg/compiler/lib/src/js/template.dart
index ce57d09..7740431 100644
--- a/pkg/compiler/lib/src/js/template.dart
+++ b/pkg/compiler/lib/src/js/template.dart
@@ -2,7 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-part of js;
+part of js_ast;
 
 class TemplateManager {
   Map<String, Template> expressionTemplates = new Map<String, Template>();
@@ -435,6 +435,11 @@
     return (arguments) => new Return(makeExpression(arguments));
   }
 
+  Instantiator visitDartYield(DartYield node) {
+    Instantiator makeExpression = visit(node.expression);
+    return (arguments) => new DartYield(makeExpression(arguments), node.hasStar);
+  }
+
   Instantiator visitThrow(Throw node) {
     Instantiator makeExpression = visit(node.expression);
     return (arguments) => new Throw(makeExpression(arguments));
@@ -487,12 +492,13 @@
         new FunctionDeclaration(makeName(arguments), makeFunction(arguments));
   }
 
-  Instantiator visitLabeledStatement(LabeledStatement node) =>
-      TODO('visitLabeledStatement');
+  Instantiator visitLabeledStatement(LabeledStatement node) {
+    Instantiator makeBody = visit(node.body);
+    return (arguments) => new LabeledStatement(node.label, makeBody(arguments));
+  }
+
   Instantiator visitLiteralStatement(LiteralStatement node) =>
       TODO('visitLiteralStatement');
-  Instantiator visitBlob(Blob node) =>
-      TODO('visitBlob');
   Instantiator visitLiteralExpression(LiteralExpression node) =>
       TODO('visitLiteralExpression');
 
@@ -701,12 +707,12 @@
 }
 
 /**
- * InterpolatedNodeAnalysis extract [InterpolatedNode]s from AST.
+ * InterpolatedNodeAnalysis determines which AST trees contain
+ * [InterpolatedNode]s, and the names of the named interpolated nodes.
  */
 class InterpolatedNodeAnalysis extends BaseVisitor {
-  final Setlet<Node> containsInterpolatedNode = new Setlet<Node>();
-  final List<InterpolatedNode> interpolatedNodes = <InterpolatedNode>[];
-  final Setlet<String> holeNames = new Setlet<String>();
+  final Set<Node> containsInterpolatedNode = new Set<Node>();
+  final Set<String> holeNames = new Set<String>();
   int count = 0;
 
   InterpolatedNodeAnalysis();
@@ -726,7 +732,6 @@
   }
 
   visitInterpolatedNode(InterpolatedNode node) {
-    interpolatedNodes.add(node);
     containsInterpolatedNode.add(node);
     if (node.isNamed) holeNames.add(node.nameOrPosition);
     ++count;
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index b3ec3fd..e396899 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -943,6 +943,7 @@
       Element e = findHelper('boolConversionCheck');
       if (e != null) enqueue(world, e, registry);
     }
+
     if (TRACE_CALLS) {
       traceHelper = findHelper('traceHelper');
       assert(traceHelper != null);
@@ -1599,6 +1600,71 @@
     return findHelper("throwCyclicInit");
   }
 
+  Element getThenHelper() {
+    return findHelper("thenHelper");
+  }
+
+  Element getYieldStar() {
+    ClassElement classElement = findHelper("IterationMarker");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupLocalMember("yieldStar");
+  }
+
+  Element getYieldSingle() {
+    ClassElement classElement = findHelper("IterationMarker");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupLocalMember("yieldSingle");
+  }
+
+  Element getStreamHelper() {
+    return findHelper("streamHelper");
+  }
+
+  Element getStreamOfController() {
+    return findHelper("streamOfController");
+  }
+
+  Element getEndOfIteration() {
+    ClassElement classElement = findHelper("IterationMarker");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupLocalMember("endOfIteration");
+  }
+
+  Element getSyncStarIterable() {
+    ClassElement classElement = findHelper("SyncStarIterable");
+    classElement.ensureResolved(compiler);
+    return classElement;
+  }
+
+  Element getSyncStarIterableConstructor() {
+    ClassElement classElement = getSyncStarIterable();
+    classElement.ensureResolved(compiler);
+    return classElement.lookupConstructor("");
+  }
+
+  Element getCompleterConstructor() {
+    ClassElement classElement = find(compiler.asyncLibrary, "Completer");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupConstructor("");
+  }
+
+  Element getASyncStarController() {
+    ClassElement classElement = findHelper("AsyncStarStreamController");
+    classElement.ensureResolved(compiler);
+    return classElement;
+  }
+
+  Element getASyncStarControllerConstructor() {
+    ClassElement classElement = getASyncStarController();
+    return classElement.lookupConstructor("");
+  }
+
+  Element getStreamIteratorConstructor() {
+    ClassElement classElement = find(compiler.asyncLibrary, "StreamIterator");
+    classElement.ensureResolved(compiler);
+    return classElement.lookupConstructor("");
+  }
+
   bool isNullImplementation(ClassElement cls) {
     return cls == jsNullClass;
   }
@@ -2334,6 +2400,29 @@
     String extension = addExtension ? ".part.js" : "";
     return "${outName}_$name$extension";
   }
+
+  void registerAsyncMarker(FunctionElement element,
+                           Enqueuer enqueuer,
+                           Registry registry) {
+    if (element.asyncMarker == AsyncMarker.ASYNC) {
+      enqueue(enqueuer, getThenHelper(), registry);
+      enqueue(enqueuer, getCompleterConstructor(), registry);
+      enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+    } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
+      enqueuer.registerInstantiatedClass(getSyncStarIterable(), registry);
+      enqueue(enqueuer, getSyncStarIterableConstructor(), registry);
+      enqueue(enqueuer, getEndOfIteration(), registry);
+      enqueue(enqueuer, getYieldStar(), registry);
+    } else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
+      enqueuer.registerInstantiatedClass(getASyncStarController(), registry);
+      enqueue(enqueuer, getStreamHelper(), registry);
+      enqueue(enqueuer, getStreamOfController(), registry);
+      enqueue(enqueuer, getYieldSingle(), registry);
+      enqueue(enqueuer, getYieldStar(), registry);
+      enqueue(enqueuer, getASyncStarControllerConstructor(), registry);
+      enqueue(enqueuer, getStreamIteratorConstructor(), registry);
+    }
+  }
 }
 
 /// Handling of special annotations for tests.
diff --git a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
index 1237350..b773f95 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/codegen.dart
@@ -135,8 +135,27 @@
 
   @override
   js.Expression visitConcatenateStrings(tree_ir.ConcatenateStrings node) {
-    return giveup(node);
-    // TODO: implement visitConcatenateStrings
+    js.Expression addStrings(js.Expression left, js.Expression right) {
+      return new js.Binary('+', left, right);
+    }
+
+    js.Expression toString(tree_ir.Expression input) {
+      bool useDirectly = input is tree_ir.Constant &&
+          (input.expression.value.isString ||
+           input.expression.value.isInt ||
+           input.expression.value.isBool);
+      js.Expression value = visitExpression(input);
+      if (useDirectly) {
+        return value;
+      } else {
+        Element convertToString = glue.getStringConversion();
+        registry.registerStaticUse(convertToString);
+        js.Expression access = glue.staticFunctionAccess(convertToString);
+        return (new js.Call(access, <js.Expression>[value]));
+      }
+    }
+
+    return node.arguments.map(toString).reduce(addStrings);
   }
 
   @override
@@ -188,16 +207,6 @@
     }
   }
 
-  List<js.Expression> compileStaticArgumentList(
-      Selector selector,
-      Element target, /* TODO(karlklose): this should be the signature. */
-      List<tree_ir.Expression> arguments) {
-    return selector.makeArgumentsList(
-        target.implementation,
-        visitArguments(arguments),
-        compileConstant);
-  }
-
   @override
   js.Expression visitInvokeConstructor(tree_ir.InvokeConstructor node) {
     checkStaticTargetIsValid(node, node.target);
@@ -206,8 +215,7 @@
     registry.registerInstantiatedClass(node.target.enclosingClass);
     Selector selector = node.selector;
     FunctionElement target = node.target;
-    List<js.Expression> arguments =
-        compileStaticArgumentList(selector, target, node.arguments);
+    List<js.Expression> arguments = visitArguments(node.arguments);
     return buildStaticInvoke(selector, target, arguments);
   }
 
@@ -259,8 +267,7 @@
     }
     Selector selector = node.selector;
     FunctionElement target = node.target;
-    List<js.Expression> arguments =
-        compileStaticArgumentList(selector, target, node.arguments);
+    List<js.Expression> arguments = visitArguments(node.arguments);
     return buildStaticInvoke(selector, target, arguments);
   }
 
diff --git a/pkg/compiler/lib/src/js_backend/codegen/glue.dart b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
index 2b86147..0c8310c 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/glue.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/glue.dart
@@ -30,6 +30,10 @@
     return _emitter.constantReference(value);
   }
 
+  Element getStringConversion() {
+    return _backend.getStringInterpolationHelper();
+  }
+
   reportInternalError(String message) {
     _compiler.internalError(_compiler.currentElement, message);
   }
diff --git a/pkg/compiler/lib/src/js_backend/codegen/task.dart b/pkg/compiler/lib/src/js_backend/codegen/task.dart
index 4797173..dbfb871 100644
--- a/pkg/compiler/lib/src/js_backend/codegen/task.dart
+++ b/pkg/compiler/lib/src/js_backend/codegen/task.dart
@@ -11,17 +11,14 @@
 
 import '../js_backend.dart';
 import '../../dart2jslib.dart';
-import '../../io/source_file.dart';
 import '../../cps_ir/cps_ir_nodes.dart' as cps;
 import '../../cps_ir/cps_ir_builder.dart';
 import '../../tree_ir/tree_ir_nodes.dart' as tree_ir;
-import '../../tree/tree.dart' as ast;
 import '../../types/types.dart' show TypeMask, UnionTypeMask, FlatTypeMask,
     ForwardingTypeMask;
-import '../../scanner/scannerlib.dart' as scanner;
 import '../../elements/elements.dart';
 import '../../js/js.dart' as js;
-import '../../io/source_map_builder.dart';
+import '../../io/source_information.dart' show StartEndSourceInformation;
 import '../../tree_ir/tree_ir_builder.dart' as tree_builder;
 import '../../dart_backend/backend_ast_emitter.dart' as backend_ast_emitter;
 import '../../cps_ir/optimizers.dart';
@@ -207,36 +204,7 @@
   }
 
   js.Node attachPosition(js.Node node, AstElement element) {
-    // TODO(sra): Attaching positions might be cleaner if the source position
-    // was on a wrapping node.
-    SourceFile sourceFile = sourceFileOfElement(element);
-    String name = element.name;
-    AstElement implementation = element.implementation;
-    ast.Node expression = implementation.node;
-    scanner.Token beginToken;
-    scanner.Token endToken;
-    if (expression == null) {
-      // Synthesized node. Use the enclosing element for the location.
-      beginToken = endToken = element.position;
-    } else {
-      beginToken = expression.getBeginToken();
-      endToken = expression.getEndToken();
-    }
-    // TODO(podivilov): find the right sourceFile here and remove offset
-    // checks below.
-    var sourcePosition, endSourcePosition;
-    if (beginToken.charOffset < sourceFile.length) {
-      sourcePosition =
-          new TokenSourceFileLocation(sourceFile, beginToken, name);
-    }
-    if (endToken.charOffset < sourceFile.length) {
-      endSourcePosition =
-          new TokenSourceFileLocation(sourceFile, endToken, name);
-    }
-    return node.withPosition(sourcePosition, endSourcePosition);
-  }
-
-  SourceFile sourceFileOfElement(Element element) {
-    return element.implementation.compilationUnit.script.file;
+    return node.withSourceInformation(
+        StartEndSourceInformation.computeSourceInformation(element));
   }
 }
diff --git a/pkg/compiler/lib/src/js_backend/patch_resolver.dart b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
index d538fe5..84d67cc 100644
--- a/pkg/compiler/lib/src/js_backend/patch_resolver.dart
+++ b/pkg/compiler/lib/src/js_backend/patch_resolver.dart
@@ -26,7 +26,6 @@
       });
       checkMatchingPatchSignatures(element, patch);
       element = patch;
-      ResolverTask.processAsyncMarker(compiler, element);
     } else {
       compiler.reportError(
          element, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
diff --git a/pkg/compiler/lib/src/js_emitter/js_emitter.dart b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
index f4f172c..d92af17 100644
--- a/pkg/compiler/lib/src/js_emitter/js_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/js_emitter.dart
@@ -92,11 +92,12 @@
 part 'code_emitter_task.dart';
 part 'helpers.dart';
 part 'interceptor_stub_generator.dart';
+part 'main_call_stub_generator.dart';
 part 'metadata_collector.dart';
 part 'native_emitter.dart';
 part 'native_generator.dart';
 part 'parameter_stub_generator.dart';
-part 'type_test_generator.dart';
+part 'runtime_type_generator.dart';
 part 'type_test_registry.dart';
 
 part 'old_emitter/class_builder.dart';
diff --git a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
new file mode 100644
index 0000000..4748854
--- /dev/null
+++ b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart2js.js_emitter;
+
+class MainCallStubGenerator {
+  final Compiler compiler;
+  final JavaScriptBackend backend;
+  final CodeEmitterTask emitterTask;
+
+  MainCallStubGenerator(this.compiler, this.backend, this.emitterTask);
+
+  /// Returns the code equivalent to:
+  ///   `function(args) { $.startRootIsolate(X.main$closure(), args); }`
+  jsAst.Expression _buildIsolateSetupClosure(Element appMain,
+                                            Element isolateMain) {
+    jsAst.Expression mainAccess =
+        emitterTask.isolateStaticClosureAccess(appMain);
+    // Since we pass the closurized version of the main method to
+    // the isolate method, we must make sure that it exists.
+    return js('function(a){ #(#, a); }',
+        [emitterTask.staticFunctionAccess(isolateMain), mainAccess]);
+  }
+
+
+  jsAst.Statement generateInvokeMain() {
+    Element main = compiler.mainFunction;
+    jsAst.Expression mainCallClosure = null;
+    if (compiler.hasIsolateSupport) {
+      Element isolateMain =
+        backend.isolateHelperLibrary.find(JavaScriptBackend.START_ROOT_ISOLATE);
+      mainCallClosure = _buildIsolateSetupClosure(main, isolateMain);
+    } else if (compiler.hasIncrementalSupport) {
+      mainCallClosure = js(
+          'function() { return #(); }',
+          emitterTask.staticFunctionAccess(main));
+    } else {
+      mainCallClosure = emitterTask.staticFunctionAccess(main);
+    }
+
+    jsAst.Expression currentScriptAccess =
+        emitterTask.generateEmbeddedGlobalAccess(embeddedNames.CURRENT_SCRIPT);
+
+    // This code finds the currently executing script by listening to the
+    // onload event of all script tags and getting the first script which
+    // finishes. Since onload is called immediately after execution this should
+    // not substantially change execution order.
+    return js.statement('''
+      (function (callback) {
+        if (typeof document === "undefined") {
+          callback(null);
+          return;
+        }
+        if (document.currentScript) {
+          callback(document.currentScript);
+          return;
+        }
+
+        var scripts = document.scripts;
+        function onLoad(event) {
+          for (var i = 0; i < scripts.length; ++i) {
+            scripts[i].removeEventListener("load", onLoad, false);
+          }
+          callback(event.target);
+        }
+        for (var i = 0; i < scripts.length; ++i) {
+          scripts[i].addEventListener("load", onLoad, false);
+        }
+      })(function(currentScript) {
+        #currentScript = currentScript;
+
+        if (typeof dartMainRunner === "function") {
+          dartMainRunner(#mainCallClosure, []);
+        } else {
+          #mainCallClosure([]);
+        }
+      })''',
+      {'currentScript': currentScriptAccess,
+       'mainCallClosure': mainCallClosure});
+  }
+}
diff --git a/pkg/compiler/lib/src/js_emitter/model.dart b/pkg/compiler/lib/src/js_emitter/model.dart
index 313fb80..96e0da9 100644
--- a/pkg/compiler/lib/src/js_emitter/model.dart
+++ b/pkg/compiler/lib/src/js_emitter/model.dart
@@ -4,7 +4,7 @@
 
 library dart2js.new_js_emitter.model;
 
-import '../js/js.dart' as js show Expression;
+import '../js/js.dart' as js show Expression, Statement;
 import '../constants/values.dart' show ConstantValue;
 
 import '../deferred_load.dart' show OutputUnit;
@@ -17,6 +17,7 @@
   final List<Fragment> fragments;
   final bool outputContainsConstantList;
   final bool outputContainsNativeClasses;
+  final bool hasIsolateSupport;
   /// A map from load id to the list of fragments that need to be loaded.
   final Map<String, List<Fragment>> loadMap;
 
@@ -33,9 +34,11 @@
           this.typeToInterceptorMap,
           this._metadataCollector,
           {this.outputContainsNativeClasses,
-           this.outputContainsConstantList}) {
+           this.outputContainsConstantList,
+           this.hasIsolateSupport}) {
     assert(outputContainsNativeClasses != null);
     assert(outputContainsConstantList != null);
+    assert(hasIsolateSupport != null);
   }
 
   /// A list of pretty-printed JavaScript expressions.
@@ -103,12 +106,12 @@
  * other [DeferredFragment]s.
  */
 class MainFragment extends Fragment {
-  final js.Expression main;
+  final js.Statement invokeMain;
   final List<Holder> holders;
 
   MainFragment(OutputUnit outputUnit,
                String outputFileName,
-               this.main,
+               this.invokeMain,
                List<Library> libraries,
                List<StaticField> staticNonFinalFields,
                List<StaticField> staticLazilyInitializedFields,
@@ -209,6 +212,9 @@
   /// Stub methods for this class that are call stubs for getters.
   final List<StubMethod> callStubs;
 
+  /// Stub methods for this class handling reads to type variables.
+  final List<StubMethod> typeVariableReaderStubs;
+
   /// noSuchMethod stubs in the special case that the class is Object.
   final List<StubMethod> noSuchMethodStubs;
   final List<Field> staticFieldsForReflection;
@@ -231,6 +237,7 @@
         this.fields,
         this.staticFieldsForReflection,
         this.callStubs,
+        this.typeVariableReaderStubs,
         this.noSuchMethodStubs,
         this.isChecks,
         this.functionTypeIndex,
@@ -262,6 +269,7 @@
                    List<Field> instanceFields,
                    List<Field> staticFieldsForReflection,
                    List<StubMethod> callStubs,
+                   List<StubMethod> typeVariableReaderStubs,
                    List<StubMethod> isChecks,
                    int functionTypeIndex,
                    {bool onlyForRti,
@@ -272,6 +280,7 @@
               instanceFields,
               staticFieldsForReflection,
               callStubs,
+              typeVariableReaderStubs,
               const <StubMethod>[],
               isChecks, functionTypeIndex,
               onlyForRti: onlyForRti,
diff --git a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
index 6e37f27..de9ea11 100644
--- a/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/new_emitter/model_emitter.dart
@@ -17,6 +17,7 @@
     NativeEmitter;
 
 import 'package:_internal/compiler/js_lib/shared/embedded_names.dart' show
+    CREATE_NEW_ISOLATE,
     DEFERRED_LIBRARY_URIS,
     DEFERRED_LIBRARY_HASHES,
     GET_TYPE_FROM_NAME,
@@ -33,7 +34,6 @@
 import '../model.dart';
 
 
-
 class ModelEmitter {
   final Compiler compiler;
   final Namer namer;
@@ -62,14 +62,12 @@
   int emitProgram(Program program) {
     List<Fragment> fragments = program.fragments;
     MainFragment mainFragment = fragments.first;
-    js.Statement mainAst = emitMainFragment(program);
-    String mainCode = js.prettyPrint(mainAst, compiler).getText();
-    compiler.outputProvider(mainFragment.outputFileName, 'js')
-        ..add(buildGeneratedBy(compiler))
-        ..add(mainCode)
-        ..close();
-    int totalSize = mainCode.length;
 
+    int totalSize = 0;
+
+    // We have to emit the deferred fragments first, since we need their
+    // deferred hash (which depends on the output) when emitting the main
+    // fragment.
     fragments.skip(1).forEach((DeferredFragment deferredUnit) {
       js.Expression ast =
           emitDeferredFragment(deferredUnit, mainFragment.holders);
@@ -79,10 +77,19 @@
           ..add(code)
           ..close();
     });
+
+    js.Statement mainAst = emitMainFragment(program);
+    String mainCode = js.prettyPrint(mainAst, compiler).getText();
+    compiler.outputProvider(mainFragment.outputFileName, 'js')
+        ..add(buildGeneratedBy(compiler))
+        ..add(mainCode)
+        ..close();
+    totalSize += mainCode.length;
+
     return totalSize;
   }
 
-  js.LiteralString unparse(Compiler compiler, js.Expression value) {
+  js.LiteralString unparse(Compiler compiler, js.Node value) {
     String text = js.prettyPrint(value, compiler).getText();
     if (value is js.Fun) text = '($text)';
     return js.js.escapedString(text);
@@ -117,7 +124,7 @@
          emitStaticNonFinalFields(fragment.staticNonFinalFields),
        'operatorIsPrefix': js.string(namer.operatorIsPrefix),
        'eagerClasses': emitEagerClassInitializations(fragment.libraries),
-       'main': fragment.main,
+       'invokeMain': fragment.invokeMain,
        'code': code};
 
     holes.addAll(nativeHoles(program));
@@ -201,9 +208,7 @@
     List<js.Property> globals = <js.Property>[];
 
     if (program.loadMap.isNotEmpty) {
-      globals.addAll(emitLoadUrisAndHashes(program.loadMap));
-      globals.add(emitIsHunkLoadedFunction());
-      globals.add(emitInitializeLoadedHunk());
+      globals.addAll(emitEmbeddedGlobalsForDeferredLoading(program.loadMap));
     }
 
     if (program.typeToInterceptorMap != null) {
@@ -211,6 +216,14 @@
                                   program.typeToInterceptorMap));
     }
 
+    if (program.hasIsolateSupport) {
+      String isolateName = namer.currentIsolate;
+      globals.add(
+          new js.Property(js.string(CREATE_NEW_ISOLATE),
+                          js.js('function () { return $isolateName; }')));
+      // TODO(floitsch): add remaining isolate functions.
+    }
+
     globals.add(emitMangledGlobalNames());
 
     globals.add(emitGetTypeFromName());
@@ -253,12 +266,24 @@
                            new js.ObjectInitializer(names));
   }
 
-  List<js.Property> emitLoadUrisAndHashes(Map<String, List<Fragment>> loadMap) {
-    js.ArrayInitializer outputUris(List<Fragment> fragments) {
+  js.Statement emitDeferredInitializerGlobal(Map loadMap) {
+    if (loadMap.isEmpty) return new js.Block.empty();
+
+    return js.js.statement("""
+  if (typeof($deferredInitializersGlobal) === 'undefined')
+    var $deferredInitializersGlobal = Object.create(null);""");
+  }
+
+  Iterable<js.Property> emitEmbeddedGlobalsForDeferredLoading(
+      Map<String, List<Fragment>> loadMap) {
+
+    List<js.Property> globals = <js.Property>[];
+
+    js.ArrayInitializer fragmentUris(List<Fragment> fragments) {
       return js.stringArray(fragments.map((DeferredFragment fragment) =>
-          "${fragment.outputFileName}$deferredExtension"));
+          "${fragment.outputFileName}.$deferredExtension"));
     }
-    js.ArrayInitializer outputHashes(List<Fragment> fragments) {
+    js.ArrayInitializer fragmentHashes(List<Fragment> fragments) {
       // TODO(floitsch): the hash must depend on the generated code.
       return js.numArray(
           fragments.map((DeferredFragment fragment) => fragment.hashCode));
@@ -269,38 +294,41 @@
     int count = 0;
     loadMap.forEach((String loadId, List<Fragment> fragmentList) {
       uris[count] =
-          new js.Property(js.string(loadId), outputUris(fragmentList));
+          new js.Property(js.string(loadId), fragmentUris(fragmentList));
       hashes[count] =
-          new js.Property(js.string(loadId), outputHashes(fragmentList));
+          new js.Property(js.string(loadId), fragmentHashes(fragmentList));
       count++;
     });
 
-    return <js.Property>[
-         new js.Property(js.string(DEFERRED_LIBRARY_URIS),
-                         new js.ObjectInitializer(uris)),
-         new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
-                         new js.ObjectInitializer(hashes))
-         ];
-  }
+    globals.add(new js.Property(js.string(DEFERRED_LIBRARY_URIS),
+                                new js.ObjectInitializer(uris)));
+    globals.add(new js.Property(js.string(DEFERRED_LIBRARY_HASHES),
+                                new js.ObjectInitializer(hashes)));
 
-  js.Statement emitDeferredInitializerGlobal(Map loadMap) {
-    if (loadMap.isEmpty) return new js.Block.empty();
-
-    return js.js.statement("""
-  if (typeof($deferredInitializersGlobal) === 'undefined')
-    var $deferredInitializersGlobal = Object.create(null);""");
-  }
-
-  js.Property emitIsHunkLoadedFunction() {
-    js.Expression function =
+    js.Expression isHunkLoadedFunction =
         js.js("function(hash) { return !!$deferredInitializersGlobal[hash]; }");
-    return new js.Property(js.string(IS_HUNK_LOADED), function);
-  }
+    globals.add(new js.Property(js.string(IS_HUNK_LOADED),
+                                isHunkLoadedFunction));
 
-  js.Property emitInitializeLoadedHunk() {
-    js.Expression function =
-        js.js("function(hash) { eval($deferredInitializersGlobal[hash]); }");
-    return new js.Property(js.string(INITIALIZE_LOADED_HUNK), function);
+    js.Expression isHunkInitializedFunction =
+        js.js("function(hash) { return false; }");
+    globals.add(new js.Property(js.string(IS_HUNK_INITIALIZED),
+                                isHunkInitializedFunction));
+
+    /// See [emitEmbeddedGlobalsForDeferredLoading] for the format of the
+    /// deferred hunk.
+    js.Expression initializeLoadedHunkFunction =
+        js.js("""
+          function(hash) {
+            var hunk = $deferredInitializersGlobal[hash];
+            $setupProgramName(hunk[0]);
+            eval(hunk[1]);
+          }""");
+
+    globals.add(new js.Property(js.string(INITIALIZE_LOADED_HUNK),
+                                initializeLoadedHunkFunction));
+
+    return globals;
   }
 
   js.Property emitGetTypeFromName() {
@@ -323,14 +351,30 @@
                                      List<Holder> holders) {
     // TODO(floitsch): initialize eager classes.
     // TODO(floitsch): the hash must depend on the output.
-    int hash = this.hashCode;
-    if (fragment.constants.isNotEmpty) {
-      throw new UnimplementedError("constants in deferred units");
-    }
-    js.ArrayInitializer content =
-        new js.ArrayInitializer(fragment.libraries.map(emitLibrary)
-                                                  .toList(growable: false));
-    return js.js("$deferredInitializersGlobal[$hash] = #", content);
+    int hash = fragment.hashCode;
+
+    List<js.Expression> deferredCode =
+        fragment.libraries.map(emitLibrary).toList();
+
+    deferredCode.add(
+        emitLazilyInitializedStatics(fragment.staticLazilyInitializedFields));
+
+    js.ArrayInitializer deferredArray = new js.ArrayInitializer(deferredCode);
+
+    // This is the code that must be evaluated after all deferred classes have
+    // been setup.
+    js.Statement immediateCode = js.js.statement('''{
+          #constants;
+          #eagerClasses;
+        }''',
+        {'constants': emitConstants(fragment.constants),
+         'eagerClasses': emitEagerClassInitializations(fragment.libraries)});
+
+    js.LiteralString immediateString = unparse(compiler, immediateCode);
+    js.ArrayInitializer hunk =
+        new js.ArrayInitializer([deferredArray, immediateString]);
+
+    return js.js("$deferredInitializersGlobal[$hash] = #", hunk);
   }
 
   js.Block emitConstants(List<Constant> constants) {
@@ -466,7 +510,9 @@
   // This string should be referenced wherever JavaScript code makes assumptions
   // on the mixin format.
   static final String mixinFormatDescription =
-      "Mixins have no constructor, but a reference to their mixin class.";
+      "Mixins have a reference to their mixin class at the place of the usual"
+      "constructor. If they are instantiated the constructor follows the"
+      "reference.";
 
   js.Expression emitClass(Class cls) {
     List elements = [js.string(cls.superclassName),
@@ -476,17 +522,21 @@
       MixinApplication mixin = cls;
       elements.add(js.string(mixin.mixinClass.name));
       elements.add(js.number(mixin.mixinClass.holder.index));
+      if (cls.isDirectlyInstantiated) {
+        elements.add(_generateConstructor(cls));
+      }
     } else {
       elements.add(_generateConstructor(cls));
     }
     Iterable<Method> methods = cls.methods;
     Iterable<Method> isChecks = cls.isChecks;
     Iterable<Method> callStubs = cls.callStubs;
+    Iterable<Method> typeVariableReaderStubs = cls.typeVariableReaderStubs;
     Iterable<Method> noSuchMethodStubs = cls.noSuchMethodStubs;
     Iterable<Method> gettersSetters = _generateGettersSetters(cls);
     Iterable<Method> allMethods =
-        [methods, isChecks, callStubs, noSuchMethodStubs, gettersSetters]
-            .expand((x) => x);
+        [methods, isChecks, callStubs, typeVariableReaderStubs,
+         noSuchMethodStubs, gettersSetters].expand((x) => x);
     elements.addAll(allMethods.expand(emitInstanceMethod));
 
     return unparse(compiler, new js.ArrayInitializer(elements));
@@ -503,12 +553,12 @@
   /// facilitate the generation of tearOffs at runtime. The format is an array
   /// with the following fields:
   ///
+  /// [InstanceMethod.aliasName] (optional).
   /// [Method.code]
   /// [DartMethod.callName]
-  /// [DartMethod.tearOffName]
-  /// [JavaScriptBackend.isInterceptedMethod]
-  /// functionType
-  /// [InstanceMethod.aliasName]
+  /// isInterceptedMethod (optional, present if [DartMethod.needsTearOff]).
+  /// [DartMethod.tearOffName] (optional, present if [DartMethod.needsTearOff]).
+  /// functionType (optional, present if [DartMethod.needsTearOff]).
   ///
   /// followed by
   ///
@@ -520,25 +570,40 @@
   static final String parseFunctionDescriptorBoilerplate = r"""
 function parseFunctionDescriptor(proto, name, descriptor) {
   if (descriptor instanceof Array) {
-    proto[name] = descriptor[0];
-    var funs = [descriptor[0]];
-    funs[0].$callName = descriptor[1];
-    for (var pos = 6; pos < descriptor.length; pos += 3) {
+    // 'pos' points to the last read entry.
+    var f, pos = -1;
+    var aliasOrFunction = descriptor[++pos];
+    if (typeof aliasOrFunction == "string") {
+      // Install the alias for super calls on the prototype chain.
+      proto[aliasOrFunction] = f = descriptor[++pos];
+    } else {
+      f = aliasOrFunction;
+    }
+
+    proto[name] = f;
+    var funs = [f];
+    f.$callName = descriptor[++pos];
+
+    var isInterceptedOrParameterStubName = descriptor[pos + 1];
+    var isIntercepted, tearOffName, reflectionInfo;
+    if (typeof isInterceptedOrParameterStubName == "boolean") {
+      isIntercepted = descriptor[++pos];
+      tearOffName = descriptor[++pos];
+      reflectionInfo = descriptor[++pos];
+    }
+
+    for (++pos; pos < descriptor.length; pos += 3) {
       var stub = descriptor[pos + 2];
       stub.$callName = descriptor[pos + 1];
       proto[descriptor[pos]] = stub;
       funs.push(stub);
     }
-    if (descriptor[2] != null) {
-      var isIntercepted = descriptor[3];
-      var reflectionInfo = descriptor[4];
-      proto[descriptor[2]] = 
+
+    if (tearOffName) {
+      proto[tearOffName] =
           tearOff(funs, reflectionInfo, false, name, isIntercepted);
     }
-    // Install the alias for super calls on the prototype chain.
-    if (descriptor[5] != null) {
-      proto[descriptor[5]] = descriptor[0];
-    }
+
   } else {
     proto[name] = descriptor;
   }
@@ -571,19 +636,22 @@
       if (method.needsTearOff || method.aliasName != null) {
         /// See [parseFunctionDescriptorBoilerplate] for a full description of
         /// the format.
-        // [name, [function, callName, tearOffName, isIntercepted, functionType,
-        //     aliasName, stub1_name, stub1_callName, stub1_code, ...]
-        bool isIntercepted = backend.isInterceptedMethod(method.element);
-        var data = [method.code];
-        data.add(js.string(method.callName));
-        data.add(js.string(method.tearOffName));
-        data.add(new js.LiteralBool(isIntercepted));
-        data.add(_generateFunctionType(method.type));
+        // [name, [aliasName, function, callName, isIntercepted, tearOffName,
+        // functionType, stub1_name, stub1_callName, stub1_code, ...]
+        var data = [];
         if (method.aliasName != null) {
           data.add(js.string(method.aliasName));
-        } else {
-          data.add(new js.LiteralNull());
         }
+        data.add(method.code);
+        data.add(js.string(method.callName));
+
+        if (method.needsTearOff) {
+          bool isIntercepted = backend.isInterceptedMethod(method.element);
+          data.add(new js.LiteralBool(isIntercepted));
+          data.add(js.string(method.tearOffName));
+          data.add(_generateFunctionType(method.type));
+        }
+
         data.addAll(method.parameterStubs.expand(makeNameCallNameCodeTriplet));
         return [js.string(method.name), new js.ArrayInitializer(data)];
       } else {
@@ -637,6 +705,8 @@
     return output;
   }
 
+  static final String setupProgramName = "setupProgram";
+
   static final String boilerplate = """
 {
 // Declare deferred-initializer global.
@@ -650,7 +720,7 @@
   // Counter to generate unique names for tear offs.
   var functionCounter = 0;
 
-  function setupProgram() {
+  function $setupProgramName(program) {
     for (var i = 0; i < program.length - 1; i++) {
       setupLibrary(program[i]);
     }
@@ -800,18 +870,28 @@
     descriptor = compile(name, descriptor);
     var prototype = determinePrototype(descriptor);
     var constructor;
+    var functionsIndex;
     // $mixinFormatDescription.
     if (typeof descriptor[2] !== 'function') {
-      constructor = compileMixinConstructor(name, prototype, descriptor);
-      for (var i = 4; i < descriptor.length; i += 2) {
-        parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
+      fillPrototypeWithMixedIn(descriptor[2], descriptor[3], prototype);
+      // descriptor[4] contains the constructor if the mixin application is
+      // directly instantiated.
+      if (typeof descriptor[4] === 'function') {
+        constructor = descriptor[4];
+        functionsIndex = 5;
+      } else {
+        constructor = function() {};
+        functionsIndex = 4;
       }
     } else {
       constructor = descriptor[2];
-      for (var i = 3; i < descriptor.length; i += 2) {
-        parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
-      }
+      functionsIndex = 3;
     }
+
+    for (var i = functionsIndex; i < descriptor.length; i += 2) {
+      parseFunctionDescriptor(prototype, descriptor[i], descriptor[i + 1]);
+    }
+
     constructor.builtin\$cls = name;  // Needed for RTI.
     constructor.prototype = prototype;
     prototype[#operatorIsPrefix + name] = constructor;
@@ -819,10 +899,7 @@
     return constructor;
   }
 
-  function compileMixinConstructor(name, prototype, descriptor) {
-    // $mixinFormatDescription.
-    var mixinName = descriptor[2];
-    var mixinHolderIndex = descriptor[3];
+  function fillPrototypeWithMixedIn(mixinName, mixinHolderIndex, prototype) {
     var mixin = holders[mixinHolderIndex][mixinName].ensureResolved();
     var mixinPrototype = mixin.prototype;
 
@@ -832,10 +909,6 @@
       var p = mixinProperties[i];
       prototype[p] = mixinPrototype[p];
     }
-    // Since this is a mixin application the constructor will actually never
-    // be invoked. We only use its prototype for the application's subclasses. 
-    var constructor = function() {};
-    return constructor;
   }
 
   function determinePrototype(descriptor) {
@@ -880,7 +953,7 @@
     }
   }
 
-  setupProgram();
+  $setupProgramName(program);
 
   // Initialize constants.
   #constants;
@@ -905,9 +978,9 @@
   #eagerClasses;
 
   var end = Date.now();
-  print('Setup: ' + (end - start) + ' ms.');
+  // print('Setup: ' + (end - start) + ' ms.');
 
-  #main();  // Start main.
+  #invokeMain;  // Start main.
 
 }(Date.now(), #code)
 }""";
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart
index 2cc8254..3be27cf 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/class_builder.dart
@@ -20,7 +20,6 @@
 
   ClassBuilder(this.element, this.namer);
 
-  // Has the same signature as [DefineStubFunction].
   jsAst.Property addProperty(String name, jsAst.Expression value) {
     jsAst.Property property = new jsAst.Property(js.string(name), value);
     properties.add(property);
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
index 216b7d0..0193ba2 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/class_emitter.dart
@@ -39,7 +39,8 @@
     emitCheckedClassSetters(cls, builder);
     emitClassGettersSettersForCSP(cls, builder);
     emitInstanceMembers(cls, builder);
-    emitCallStubs(cls, builder);
+    emitStubs(cls.callStubs, builder);
+    emitStubs(cls.typeVariableReaderStubs, builder);
     emitRuntimeTypeInformation(cls, builder);
     emitNativeInfo(cls, builder);
 
@@ -51,8 +52,6 @@
       builder.addProperty(namer.getterNameFromAccessorName(name), function);
     }
 
-    emitTypeVariableReaders(classElement, builder);
-
     emitClassBuilderWithReflectionData(cls, builder, enclosingBuilder);
   }
   /**
@@ -213,8 +212,8 @@
     }
   }
 
-  void emitCallStubs(Class cls, ClassBuilder builder) {
-    for (Method method in cls.callStubs) {
+  void emitStubs(Iterable<StubMethod> stubs, ClassBuilder builder) {
+    for (Method method in stubs) {
       jsAst.Property property = builder.addProperty(method.name, method.code);
       compiler.dumpInfoTask.registerElementAst(method.element, property);
     }
@@ -553,45 +552,4 @@
       builder.addProperty('+$reflectionName', reflectable);
     }
   }
-
-  void emitTypeVariableReaders(ClassElement cls, ClassBuilder builder) {
-    List typeVariables = [];
-    ClassElement superclass = cls;
-    while (superclass != null) {
-      for (TypeVariableType parameter in superclass.typeVariables) {
-        if (backend.emitter.readTypeVariables.contains(parameter.element)) {
-          emitTypeVariableReader(cls, builder, parameter.element);
-        }
-      }
-      superclass = superclass.superclass;
-    }
-  }
-
-  void emitTypeVariableReader(ClassElement cls,
-                              ClassBuilder builder,
-                              TypeVariableElement element) {
-    String name = namer.readTypeVariableName(element);
-    int index = RuntimeTypes.getTypeVariableIndex(element);
-    jsAst.Expression computeTypeVariable;
-
-    Substitution substitution =
-        backend.rti.computeSubstitution(
-            cls, element.typeDeclaration, alwaysGenerateFunction: true);
-    if (substitution != null) {
-      computeTypeVariable =
-          js(r'#.apply(null, this.$builtinTypeInfo)',
-             substitution.getCodeForVariable(index, backend.rti));
-    } else {
-      // TODO(ahe): These can be generated dynamically.
-      computeTypeVariable =
-          js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]',
-              js.number(index));
-    }
-    jsAst.Expression convertRtiToRuntimeType = emitter
-        .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType'));
-    compiler.dumpInfoTask.registerElementAst(element,
-        builder.addProperty(name,
-            js('function () { return #(#) }',
-                [convertRtiToRuntimeType, computeTypeVariable])));
-  }
 }
diff --git a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
index 25d4b43..a575e1c 100644
--- a/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/old_emitter/emitter.dart
@@ -366,6 +366,12 @@
     }
 
     if (hasIsolateSupport) {
+      jsAst.Expression createNewIsolateFunctionAccess =
+          generateEmbeddedGlobalAccess(embeddedNames.CREATE_NEW_ISOLATE);
+      var createIsolateAssignment =
+          js('# = function() { return new ${namer.isolateName}(); }',
+             createNewIsolateFunctionAccess);
+
       jsAst.Expression classIdExtractorAccess =
           generateEmbeddedGlobalAccess(embeddedNames.CLASS_ID_EXTRACTOR);
       var classIdExtractorAssignment =
@@ -402,7 +408,8 @@
         return o;
       }''', [ initializeEmptyInstanceAccess, allClassesAccess ]);
 
-      result.addAll([classIdExtractorAssignment,
+      result.addAll([createIsolateAssignment,
+                     classIdExtractorAssignment,
                      classFieldsExtractorAssignment,
                      instanceFromClassIdAssignment,
                      initializeEmptyInstanceAssignment]);
@@ -861,8 +868,8 @@
         cachedEmittedConstants.add(constantValue);
       }
       jsAst.Expression init = buildConstantInitializer(constantValue);
-      constantOutput.addBuffer(jsAst.prettyPrint(init, compiler,
-                                         monitor: compiler.dumpInfoTask));
+      constantOutput.addBuffer(
+          jsAst.prettyPrint(init, compiler, monitor: compiler.dumpInfoTask));
       constantOutput.add('$N');
     }
     if (compiler.hasIncrementalSupport && isMainFragment) {
@@ -914,32 +921,8 @@
                       backend.rti.getFunctionThatReturnsNullName]);
   }
 
-  /// Returns the code equivalent to:
-  ///   `function(args) { $.startRootIsolate(X.main$closure(), args); }`
-  jsAst.Expression buildIsolateSetupClosure(Element appMain,
-                                            Element isolateMain) {
-    jsAst.Expression mainAccess = isolateStaticClosureAccess(appMain);
-    // Since we pass the closurized version of the main method to
-    // the isolate method, we must make sure that it exists.
-    return js('function(a){ #(#, a); }',
-        [backend.emitter.staticFunctionAccess(isolateMain), mainAccess]);
-  }
-
-  emitMain(CodeOutput output) {
+  emitMain(CodeOutput output, jsAst.Statement invokeMain) {
     if (compiler.isMockCompilation) return;
-    Element main = compiler.mainFunction;
-    jsAst.Expression mainCallClosure = null;
-    if (compiler.hasIsolateSupport) {
-      Element isolateMain =
-        backend.isolateHelperLibrary.find(JavaScriptBackend.START_ROOT_ISOLATE);
-      mainCallClosure = buildIsolateSetupClosure(main, isolateMain);
-    } else if (compiler.hasIncrementalSupport) {
-      mainCallClosure = js(
-          'function() { return #(); }',
-          backend.emitter.staticFunctionAccess(main));
-    } else {
-      mainCallClosure = backend.emitter.staticFunctionAccess(main);
-    }
 
     if (NativeGenerator.needsIsolateAffinityTagInitialization(backend)) {
       jsAst.Statement nativeBoilerPlate =
@@ -951,47 +934,8 @@
           nativeBoilerPlate, compiler, monitor: compiler.dumpInfoTask));
     }
 
-    jsAst.Expression currentScriptAccess =
-        generateEmbeddedGlobalAccess(embeddedNames.CURRENT_SCRIPT);
-
-    addComment('BEGIN invoke [main].', output);
-    // This code finds the currently executing script by listening to the
-    // onload event of all script tags and getting the first script which
-    // finishes. Since onload is called immediately after execution this should
-    // not substantially change execution order.
-    jsAst.Statement invokeMain = js.statement('''
-(function (callback) {
-  if (typeof document === "undefined") {
-    callback(null);
-    return;
-  }
-  if (document.currentScript) {
-    callback(document.currentScript);
-    return;
-  }
-
-  var scripts = document.scripts;
-  function onLoad(event) {
-    for (var i = 0; i < scripts.length; ++i) {
-      scripts[i].removeEventListener("load", onLoad, false);
-    }
-    callback(event.target);
-  }
-  for (var i = 0; i < scripts.length; ++i) {
-    scripts[i].addEventListener("load", onLoad, false);
-  }
-})(function(currentScript) {
-  #currentScript = currentScript;
-
-  if (typeof dartMainRunner === "function") {
-    dartMainRunner(#mainCallClosure, []);
-  } else {
-    #mainCallClosure([]);
-  }
-})''', {'currentScript': currentScriptAccess,
-        'mainCallClosure': mainCallClosure});
-
     output.add(';');
+    addComment('BEGIN invoke [main].', output);
     output.addBuffer(jsAst.prettyPrint(invokeMain,
                      compiler, monitor: compiler.dumpInfoTask));
     output.add(N);
@@ -1358,7 +1302,7 @@
 
   void emitMainOutputUnit(Program program,
                           Map<OutputUnit, String> deferredLoadHashes) {
-    Fragment mainFragment = program.fragments.first;
+    MainFragment mainFragment = program.fragments.first;
     OutputUnit mainOutputUnit = mainFragment.outputUnit;
 
     LineColumnCollector lineColumnCollector;
@@ -1572,7 +1516,7 @@
     jsAst.FunctionDeclaration precompiledFunctionAst =
         buildCspPrecompiledFunctionFor(mainOutputUnit);
     emitInitFunction(mainOutput);
-    emitMain(mainOutput);
+    emitMain(mainOutput, mainFragment.invokeMain);
     mainOutput.add('})()\n');
 
     if (compiler.useContentSecurityPolicy) {
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder.dart
index a6d6fe8..7036bb7 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder.dart
@@ -19,8 +19,9 @@
     ClassStubGenerator,
     CodeEmitterTask,
     InterceptorStubGenerator,
+    MainCallStubGenerator,
     ParameterStubGenerator,
-    TypeTestGenerator,
+    RuntimeTypeGenerator,
     TypeTestProperties;
 
 import '../universe/universe.dart' show Universe;
@@ -122,7 +123,8 @@
         _buildTypeToInterceptorMap(),
         _task.metadataCollector,
         outputContainsNativeClasses: containsNativeClasses,
-        outputContainsConstantList: _task.outputContainsConstantList);
+        outputContainsConstantList: _task.outputContainsConstantList,
+        hasIsolateSupport: _compiler.hasIsolateSupport);
   }
 
   void _markEagerClasses() {
@@ -152,7 +154,7 @@
     MainFragment result = new MainFragment(
         librariesMap.outputUnit,
         "",  // The empty string is the name for the main output file.
-        backend.emitter.staticFunctionAccess(_compiler.mainFunction),
+        _buildInvokeMain(),
         _buildLibraries(librariesMap),
         _buildStaticNonFinalFields(librariesMap),
         _buildStaticLazilyInitializedFields(librariesMap),
@@ -162,6 +164,12 @@
     return result;
   }
 
+  js.Statement _buildInvokeMain() {
+    MainCallStubGenerator generator =
+        new MainCallStubGenerator(_compiler, backend, backend.emitter);
+    return generator.generateInvokeMain();
+  }
+
   DeferredFragment _buildDeferredOutput(MainFragment mainOutput,
                                       LibrariesMap librariesMap) {
     DeferredFragment result = new DeferredFragment(
@@ -290,7 +298,7 @@
     String name = namer.getNameOfClass(element);
 
     return new Class(
-        element, name, null, [], instanceFields, [], [], [], [], null,
+        element, name, null, [], instanceFields, [], [], [], [], [], null,
         isDirectlyInstantiated: true,
         onlyForRti: false,
         isNative: element.isNative);
@@ -304,6 +312,8 @@
 
     ClassStubGenerator classStubGenerator =
         new ClassStubGenerator(_compiler, namer, backend);
+    RuntimeTypeGenerator runtimeTypeGenerator =
+        new RuntimeTypeGenerator(_compiler, _task, namer);
 
     void visitMember(ClassElement enclosing, Element member) {
       assert(invariant(element, member.isDeclaration));
@@ -329,6 +339,9 @@
       }
     }
 
+    List<StubMethod> typeVariableReaderStubs =
+        runtimeTypeGenerator.generateTypeVariableReaderStubs(element);
+
     List<StubMethod> noSuchMethodStubs = <StubMethod>[];
     if (element == _compiler.objectClass) {
       Map<String, Selector> selectors =
@@ -353,10 +366,8 @@
     List<Field> staticFieldsForReflection =
         onlyForRti ? const <Field>[] : _buildFields(element, true);
 
-    TypeTestGenerator generator =
-        new TypeTestGenerator(_compiler, _task, namer);
     TypeTestProperties typeTests =
-        generator.generateIsTests(
+        runtimeTypeGenerator.generateIsTests(
             element,
             storeFunctionTypeInMetadata: _storeFunctionTypesInMetadata);
 
@@ -381,6 +392,7 @@
                                     instanceFields,
                                     staticFieldsForReflection,
                                     callStubs,
+                                    typeVariableReaderStubs,
                                     isChecks,
                                     typeTests.functionTypeIndex,
                                     isDirectlyInstantiated: isInstantiated,
@@ -390,6 +402,7 @@
                          name, holder, methods, instanceFields,
                          staticFieldsForReflection,
                          callStubs,
+                         typeVariableReaderStubs,
                          noSuchMethodStubs,
                          isChecks,
                          typeTests.functionTypeIndex,
diff --git a/pkg/compiler/lib/src/js_emitter/type_test_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
similarity index 84%
rename from pkg/compiler/lib/src/js_emitter/type_test_generator.dart
rename to pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index bb2b0b9..9abed6d 100644
--- a/pkg/compiler/lib/src/js_emitter/type_test_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -20,12 +20,12 @@
   final Map<String, jsAst.Node> properties = <String, jsAst.Node>{};
 }
 
-class TypeTestGenerator {
+class RuntimeTypeGenerator {
   final Compiler compiler;
   final CodeEmitterTask emitterTask;
   final Namer namer;
 
-  TypeTestGenerator(this.compiler, this.emitterTask, this.namer);
+  RuntimeTypeGenerator(this.compiler, this.emitterTask, this.namer);
 
   JavaScriptBackend get backend => compiler.backend;
   TypeTestRegistry get typeTestRegistry => emitterTask.typeTestRegistry;
@@ -264,4 +264,48 @@
                                  generateSubstitution, alreadyGenerated);
     }
   }
+
+  List<StubMethod> generateTypeVariableReaderStubs(ClassElement classElement) {
+    List<StubMethod> stubs = <StubMethod>[];
+    List typeVariables = [];
+    ClassElement superclass = classElement;
+    while (superclass != null) {
+        for (TypeVariableType parameter in superclass.typeVariables) {
+          if (backend.emitter.readTypeVariables.contains(parameter.element)) {
+            stubs.add(
+                _generateTypeVariableReader(classElement, parameter.element));
+          }
+        }
+        superclass = superclass.superclass;
+      }
+
+    return stubs;
+  }
+
+  StubMethod _generateTypeVariableReader(ClassElement cls,
+                                         TypeVariableElement element) {
+    String name = namer.readTypeVariableName(element);
+    int index = RuntimeTypes.getTypeVariableIndex(element);
+    jsAst.Expression computeTypeVariable;
+
+    Substitution substitution =
+        backend.rti.computeSubstitution(
+            cls, element.typeDeclaration, alwaysGenerateFunction: true);
+    if (substitution != null) {
+      computeTypeVariable =
+          js(r'#.apply(null, this.$builtinTypeInfo)',
+             substitution.getCodeForVariable(index, backend.rti));
+    } else {
+      // TODO(ahe): These can be generated dynamically.
+      computeTypeVariable =
+          js(r'this.$builtinTypeInfo && this.$builtinTypeInfo[#]',
+              js.number(index));
+    }
+    jsAst.Expression convertRtiToRuntimeType = backend.emitter
+         .staticFunctionAccess(backend.findHelper('convertRtiToRuntimeType'));
+
+    return new StubMethod(name,
+                          js('function () { return #(#) }',
+                             [convertRtiToRuntimeType, computeTypeVariable]));
+  }
 }
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index af2b302..bd92e97 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -492,15 +492,11 @@
   }
 
   static void processAsyncMarker(Compiler compiler,
-                                 BaseFunctionElementX element) {
+                                 BaseFunctionElementX element,
+                                 Registry registry) {
     FunctionExpression functionExpression = element.node;
     AsyncModifier asyncModifier = functionExpression.asyncModifier;
     if (asyncModifier != null) {
-      if (!compiler.enableAsyncAwait) {
-        compiler.reportError(asyncModifier,
-            MessageKind.EXPERIMENTAL_ASYNC_AWAIT,
-            {'modifier': element.asyncMarker});
-      }
 
       if (asyncModifier.isAsynchronous) {
         element.asyncMarker = asyncModifier.isYielding
@@ -530,6 +526,7 @@
               {'modifier': element.asyncMarker});
         }
       }
+      registry.registerAsyncMarker(element);
     }
   }
 
@@ -556,6 +553,7 @@
       ResolutionRegistry registry = visitor.registry;
       registry.defineFunction(tree, element);
       visitor.setupFunction(tree, element);
+      processAsyncMarker(compiler, element, registry);
 
       if (element.isGenerativeConstructor) {
         // Even if there is no initializer list we still have to do the
@@ -630,7 +628,6 @@
       } else {
         element.parseNode(compiler);
         element.computeType(compiler);
-        processAsyncMarker(compiler, element);
         FunctionElementX implementation = element;
         if (element.isExternal) {
           implementation = compiler.backend.resolveExternalFunction(element);
@@ -2478,7 +2475,7 @@
     LocalFunctionElementX function = new LocalFunctionElementX(
         name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
         enclosingElement);
-    ResolverTask.processAsyncMarker(compiler, function);
+    ResolverTask.processAsyncMarker(compiler, function, registry);
     function.functionSignatureCache = SignatureResolver.analyze(
         compiler,
         node.parameters,
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index eeaa2a8..317efbb 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -367,4 +367,8 @@
   bool isAssert(Send node) {
     return mapping.isAssert(node);
   }
+
+  void registerAsyncMarker(FunctionElement element) {
+    backend.registerAsyncMarker(element, world, this);
+  }
 }
diff --git a/pkg/compiler/lib/src/scanner/parser.dart b/pkg/compiler/lib/src/scanner/parser.dart
index fb49196..00e599f 100644
--- a/pkg/compiler/lib/src/scanner/parser.dart
+++ b/pkg/compiler/lib/src/scanner/parser.dart
@@ -1512,15 +1512,6 @@
     return token;
   }
 
-  /// `async*` and `sync*` are parsed a two tokens, [token] and [star]. This
-  /// method checks that there is no whitespace between [token] and [star].
-  void checkStarredModifier(Token token, Token star, String name) {
-    if (star.charOffset > token.charOffset + token.charCount) {
-      listener.reportError(new TokenPair(token, star),
-          MessageKind.INVALID_STARRED_KEYWORD, {'keyword': name});
-    }
-  }
-
   Token parseAsyncModifier(Token token) {
     Token async;
     Token star;
@@ -1534,7 +1525,6 @@
         yieldIsKeyword = true;
         star = token;
         token = token.next;
-        checkStarredModifier(async, star, 'async*');
       }
     } else if (optional('sync', token)) {
       async = token;
@@ -1543,8 +1533,6 @@
         yieldIsKeyword = true;
         star = token;
         token = token.next;
-
-        checkStarredModifier(async, star, 'sync*');
       } else {
         listener.reportError(async,
             MessageKind.INVALID_SYNC_MODIFIER);
@@ -1617,7 +1605,6 @@
     if (optional('*', token)) {
       starToken = token;
       token = token.next;
-      checkStarredModifier(begin, starToken, 'yield*');
     }
     token = parseExpression(token);
     listener.endYieldStatement(begin, starToken, token);
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 43798cd..13350ca 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -19,7 +19,54 @@
   js.Fun compile(CodegenWorkItem work) {
     HGraph graph = builder.build(work);
     optimizer.optimize(work, graph);
-    return generator.generateCode(work, graph);
+    Element element = work.element;
+    js.Expression result = generator.generateCode(work, graph);
+    if (element is FunctionElement) {
+      JavaScriptBackend backend = builder.backend;
+
+      AsyncRewriter rewriter = null;
+      if (element.asyncMarker == AsyncMarker.ASYNC) {
+        rewriter = new AsyncRewriter(
+            backend.compiler,
+            backend.compiler.currentElement,
+            thenHelper:
+                backend.emitter.staticFunctionAccess(backend.getThenHelper()),
+            newCompleter: backend.emitter.staticFunctionAccess(
+                backend.getCompleterConstructor()),
+            safeVariableName: backend.namer.safeVariableName);
+      } else if (element.asyncMarker == AsyncMarker.SYNC_STAR) {
+        rewriter = new AsyncRewriter(
+            backend.compiler,
+            backend.compiler.currentElement,
+            endOfIteration: backend.emitter.staticFunctionAccess(
+                backend.getEndOfIteration()),
+            newIterable: backend.emitter.staticFunctionAccess(
+                backend.getSyncStarIterableConstructor()),
+            yieldStarExpression: backend.emitter.staticFunctionAccess(
+                backend.getYieldStar()),
+            safeVariableName: backend.namer.safeVariableName);
+      }
+      else if (element.asyncMarker == AsyncMarker.ASYNC_STAR) {
+        rewriter = new AsyncRewriter(
+            backend.compiler,
+            backend.compiler.currentElement,
+            streamHelper: backend.emitter.staticFunctionAccess(
+                backend.getStreamHelper()),
+            streamOfController: backend.emitter.staticFunctionAccess(
+                backend.getStreamOfController()),
+            newController: backend.emitter.staticFunctionAccess(
+                backend.getASyncStarControllerConstructor()),
+            safeVariableName: backend.namer.safeVariableName,
+            yieldExpression: backend.emitter.staticFunctionAccess(
+                backend.getYieldSingle()),
+            yieldStarExpression: backend.emitter.staticFunctionAccess(
+                backend.getYieldStar()));
+      }
+      if (rewriter != null) {
+        result = rewriter.rewrite(result);
+      }
+    }
+    return result;
   }
 
   Iterable<CompilerTask> get tasks {
@@ -362,7 +409,7 @@
   bool isAccessedDirectly(Local local) {
     assert(local != null);
     return !redirectionMapping.containsKey(local)
-        && !closureData.usedVariablesInTry.contains(local);
+        && !closureData.variablesUsedInTryOrGenerator.contains(local);
   }
 
   bool isStoredInClosureField(Local local) {
@@ -379,8 +426,8 @@
     return redirectionMapping.containsKey(local);
   }
 
-  bool isUsedInTry(Local local) {
-    return closureData.usedVariablesInTry.contains(local);
+  bool isUsedInTryOrGenerator(Local local) {
+    return closureData.variablesUsedInTryOrGenerator.contains(local);
   }
 
   /**
@@ -422,7 +469,7 @@
       builder.add(lookup);
       return lookup;
     } else {
-      assert(isUsedInTry(local));
+      assert(isUsedInTryOrGenerator(local));
       HLocalValue localValue = getLocal(local);
       HInstruction instruction = new HLocalGet(
           local, localValue, builder.backend.dynamicType);
@@ -478,7 +525,7 @@
       HInstruction box = readLocal(redirect.box);
       builder.add(new HFieldSet(redirect, box, value));
     } else {
-      assert(isUsedInTry(local));
+      assert(isUsedInTryOrGenerator(local));
       HLocalValue localValue = getLocal(local);
       builder.add(new HLocalSet(local, localValue, value));
     }
@@ -1916,10 +1963,10 @@
         }
         Selector selector = new Selector.callDefaultConstructor();
         List<HInstruction> arguments =
-            selector.makeArgumentsList2(const Link<ast.Node>(),
-                                        target.implementation,
-                                        null,
-                                        handleConstantForOptionalParameter);
+            selector.makeArgumentsList(const Link<ast.Node>(),
+                                       target.implementation,
+                                       null,
+                                       handleConstantForOptionalParameter);
         inlineSuperOrRedirect(target,
                               arguments,
                               constructors,
@@ -2446,11 +2493,21 @@
 
   HInstruction attachPosition(HInstruction target, ast.Node node) {
     if (generateSourceMap && node != null) {
-      target.sourcePosition = sourceFileLocationForBeginToken(node);
+      target.sourceInformation = sourceInformationForBeginToken(node);
     }
     return target;
   }
 
+  SourceInformation sourceInformationForBeginToken(ast.Node node) {
+    return new StartEndSourceInformation(sourceFileLocationForBeginToken(node));
+  }
+
+  SourceInformation sourceInformationForBeginEndToken(ast.Node node) {
+    return new StartEndSourceInformation(
+        sourceFileLocationForBeginToken(node),
+        sourceFileLocationForEndToken(node));
+  }
+
   SourceFileLocation sourceFileLocationForBeginToken(ast.Node node) =>
       sourceFileLocationForToken(node, node.getBeginToken());
 
@@ -2734,8 +2791,7 @@
               wrapExpressionGraph(updateGraph),
               conditionBlock.loopInformation.target,
               conditionBlock.loopInformation.labels,
-              sourceFileLocationForBeginToken(loop),
-              sourceFileLocationForEndToken(loop));
+              sourceInformationForBeginEndToken(loop));
 
       startBlock.setBlockFlow(info, current);
       loopInfo.loopBlockInformation = info;
@@ -2952,8 +3008,7 @@
               null,
               loopEntryBlock.loopInformation.target,
               loopEntryBlock.loopInformation.labels,
-              sourceFileLocationForBeginToken(node),
-              sourceFileLocationForEndToken(node));
+              sourceInformationForBeginEndToken(node));
       loopEntryBlock.setBlockFlow(loopBlockInfo, current);
       loopInfo.loopBlockInformation = loopBlockInfo;
     } else {
@@ -3504,10 +3559,10 @@
       return pop();
     }
 
-    return selector.makeArgumentsList2(arguments,
-                                       element,
-                                       compileArgument,
-                                       handleConstantForOptionalParameter);
+    return selector.makeArgumentsList(arguments,
+                                      element,
+                                      compileArgument,
+                                      handleConstantForOptionalParameter);
   }
 
   void addGenericSendArgumentsToList(Link<ast.Node> link, List<HInstruction> list) {
@@ -3831,16 +3886,6 @@
                       effects: sideEffects));
   }
 
-  void handleForeignCreateIsolate(ast.Send node) {
-    if (!node.arguments.isEmpty) {
-      compiler.internalError(node.argumentsNode, 'Too many arguments.');
-    }
-    String constructorName = backend.namer.isolateName;
-    push(new HForeign(js.js.parseForeignJS("new $constructorName()"),
-                      backend.dynamicType,
-                      <HInstruction>[]));
-  }
-
   void handleForeignDartObjectJsConstructorFunction(ast.Send node) {
     if (!node.arguments.isEmpty) {
       compiler.internalError(node.argumentsNode, 'Too many arguments.');
@@ -3875,8 +3920,6 @@
       handleForeignRawFunctionRef(node, 'RAW_DART_FUNCTION_REF');
     } else if (name == 'JS_SET_CURRENT_ISOLATE') {
       handleForeignSetCurrentIsolate(node);
-    } else if (name == 'JS_CREATE_ISOLATE') {
-      handleForeignCreateIsolate(node);
     } else if (name == 'JS_OPERATOR_IS_PREFIX') {
       // TODO(floitsch): this should be a JS_NAME.
       stack.add(addConstantString(backend.namer.operatorIsPrefix));
@@ -5164,14 +5207,17 @@
   }
 
   visitYield(ast.Yield node) {
-    // Dummy implementation.
     visit(node.expression);
-    pop();
+    HInstruction yielded = pop();
+    add(new HYield(yielded, node.hasStar));
   }
 
   visitAwait(ast.Await node) {
-    // Dummy implementation.
     visit(node.expression);
+    HInstruction awaited = pop();
+    // TODO(herhut): Improve this type.
+    push(new HAwait(awaited, new TypeMask.subclass(compiler.objectClass,
+                                                   compiler.world)));
   }
 
   visitTypeAnnotation(ast.TypeAnnotation node) {
@@ -5315,7 +5361,78 @@
     return new JumpHandler(this, element);
   }
 
+  buildAsyncForIn(ast.ForIn node) {
+    assert(node.isAsync);
+    // The async-for is implemented with a StreamIterator.
+    HInstruction streamIterator;
+
+    visit(node.expression);
+    HInstruction expression = pop();
+    pushInvokeStatic(node,
+                     backend.getStreamIteratorConstructor(),
+                     [expression, graph.addConstantNull(compiler)]);
+    streamIterator = pop();
+
+    void buildInitializer() {}
+
+    HInstruction buildCondition() {
+      Selector selector = elements.getMoveNextSelector(node);
+      pushInvokeDynamic(node, selector, [streamIterator]);
+      HInstruction future = pop();
+      push(new HAwait(future, new TypeMask.subclass(compiler.objectClass,
+                                                    compiler.world)));
+      return popBoolified();
+    }
+    void buildBody() {
+      Selector call = elements.getCurrentSelector(node);
+      pushInvokeDynamic(node, call, [streamIterator]);
+
+      ast.Node identifier = node.declaredIdentifier;
+      Element variable = elements.getForInVariable(node);
+      Selector selector = elements.getSelector(identifier);
+
+      HInstruction value = pop();
+      if (identifier.asSend() != null
+          && Elements.isInstanceSend(identifier, elements)) {
+        HInstruction receiver = generateInstanceSendReceiver(identifier);
+        assert(receiver != null);
+        generateInstanceSetterWithCompiledReceiver(
+            null,
+            receiver,
+            value,
+            selector: selector,
+            location: identifier);
+      } else {
+        generateNonInstanceSetter(
+            null, variable, value, location: identifier);
+      }
+      pop(); // Pop the value pushed by the setter call.
+
+      visit(node.body);
+    }
+
+    void buildUpdate() {};
+
+    buildProtectedByFinally(() {
+      handleLoop(node,
+                 buildInitializer,
+                 buildCondition,
+                 buildUpdate,
+                 buildBody);
+    }, () {
+      pushInvokeDynamic(node, new Selector.call("cancel", null, 0),
+          [streamIterator]);
+      push(new HAwait(pop(), new TypeMask.subclass(compiler.objectClass,
+          compiler.world)));
+      pop();
+    });
+  }
+
   visitForIn(ast.ForIn node) {
+    if (node.isAsync) {
+      return buildAsyncForIn(node);
+    }
+
     // Generate a structure equivalent to:
     //   Iterator<E> $iter = <iterable>.iterator;
     //   while ($iter.moveNext()) {
@@ -5851,6 +5968,85 @@
     compiler.internalError(node, 'SsaFromAstMixin.visitCaseMatch.');
   }
 
+  /// Calls [buildTry] inside a synthetic try block with [buildFinally] in the
+  /// finally block.
+  void buildProtectedByFinally(void buildTry(), void buildFinally()) {
+    HBasicBlock enterBlock = openNewBlock();
+    HTry tryInstruction = new HTry();
+    close(tryInstruction);
+    bool oldInTryStatement = inTryStatement;
+    inTryStatement = true;
+
+    HBasicBlock startTryBlock;
+    HBasicBlock endTryBlock;
+    HBasicBlock startFinallyBlock;
+    HBasicBlock endFinallyBlock;
+
+    startTryBlock = graph.addNewBlock();
+    open(startTryBlock);
+    buildTry();
+    // We use a [HExitTry] instead of a [HGoto] for the try block
+    // because it will have two successors: the join block, and
+    // the finally block.
+    if (!isAborted()) endTryBlock = close(new HExitTry());
+    SubGraph bodyGraph = new SubGraph(startTryBlock, lastOpenedBlock);
+
+    SubGraph finallyGraph = null;
+
+    startFinallyBlock = graph.addNewBlock();
+    open(startFinallyBlock);
+    buildFinally();
+    if (!isAborted()) endFinallyBlock = close(new HGoto());
+    tryInstruction.finallyBlock = startFinallyBlock;
+    finallyGraph = new SubGraph(startFinallyBlock, lastOpenedBlock);
+
+    HBasicBlock exitBlock = graph.addNewBlock();
+
+    void addExitTrySuccessor(HBasicBlock successor) {
+      // Iterate over all blocks created inside this try/catch, and
+      // attach successor information to blocks that end with
+      // [HExitTry].
+      for (int i = startTryBlock.id; i < successor.id; i++) {
+        HBasicBlock block = graph.blocks[i];
+        var last = block.last;
+        if (last is HExitTry) {
+          block.addSuccessor(successor);
+        }
+      }
+    }
+
+    // Setup all successors. The entry block that contains the [HTry]
+    // has 1) the body 2) the finally, and 4) the exit
+    // blocks as successors.
+    enterBlock.addSuccessor(startTryBlock);
+    enterBlock.addSuccessor(startFinallyBlock);
+    enterBlock.addSuccessor(exitBlock);
+
+    // The body has the finally block as successor.
+    if (endTryBlock != null) {
+      endTryBlock.addSuccessor(startFinallyBlock);
+      endTryBlock.addSuccessor(exitBlock);
+    }
+
+    // The finally block has the exit block as successor.
+    endFinallyBlock.addSuccessor(exitBlock);
+
+    // If a block inside try/catch aborts (eg with a return statement),
+    // we explicitely mark this block a predecessor of the catch
+    // block and the finally block.
+    addExitTrySuccessor(startFinallyBlock);
+
+    open(exitBlock);
+    enterBlock.setBlockFlow(
+        new HTryBlockInformation(
+          wrapStatementGraph(bodyGraph),
+          null, // No catch-variable.
+          null, // No catchGraph.
+          wrapStatementGraph(finallyGraph)),
+        exitBlock);
+    inTryStatement = oldInTryStatement;
+  }
+
   visitTryStatement(ast.TryStatement node) {
     // Save the current locals. The catch block and the finally block
     // must not reuse the existing locals handler. None of the variables
@@ -6222,6 +6418,7 @@
         new InlineWeeder(maxInliningNodes, useMaxInliningNodes, allowLoops);
     weeder.visit(functionExpression.initializers);
     weeder.visit(functionExpression.body);
+    weeder.visit(functionExpression.asyncModifier);
     return !weeder.tooDifficult;
   }
 
@@ -6248,6 +6445,13 @@
     }
   }
 
+  @override
+  void visitAsyncModifier(ast.AsyncModifier node) {
+    if (node.isYielding || node.isAsynchronous) {
+      tooDifficult = true;
+    }
+  }
+
   void visitFunctionExpression(ast.Node node) {
     if (!registerNode()) return;
     tooDifficult = true;
diff --git a/pkg/compiler/lib/src/ssa/codegen.dart b/pkg/compiler/lib/src/ssa/codegen.dart
index 0d4b389..21387ea 100644
--- a/pkg/compiler/lib/src/ssa/codegen.dart
+++ b/pkg/compiler/lib/src/ssa/codegen.dart
@@ -16,43 +16,23 @@
 
 
   js.Node attachPosition(js.Node node, AstElement element) {
-    // TODO(sra): Attaching positions might be cleaner if the source position
-    // was on a wrapping node.
-    SourceFile sourceFile = sourceFileOfElement(element);
-    String name = element.name;
-    AstElement implementation = element.implementation;
-    ast.Node expression = implementation.node;
-    Token beginToken;
-    Token endToken;
-    if (expression == null) {
-      // Synthesized node. Use the enclosing element for the location.
-      beginToken = endToken = element.position;
-    } else {
-      beginToken = expression.getBeginToken();
-      endToken = expression.getEndToken();
-    }
-    // TODO(podivilov): find the right sourceFile here and remove offset
-    // checks below.
-    var sourcePosition, endSourcePosition;
-    if (beginToken.charOffset < sourceFile.length) {
-      sourcePosition =
-          new TokenSourceFileLocation(sourceFile, beginToken, name);
-    }
-    if (endToken.charOffset < sourceFile.length) {
-      endSourcePosition =
-          new TokenSourceFileLocation(sourceFile, endToken, name);
-    }
-    return node.withPosition(sourcePosition, endSourcePosition);
-  }
-
-  SourceFile sourceFileOfElement(Element element) {
-    return element.implementation.compilationUnit.script.file;
+    return node.withSourceInformation(
+        StartEndSourceInformation.computeSourceInformation(element));
   }
 
   js.Fun buildJavaScriptFunction(FunctionElement element,
                                  List<js.Parameter> parameters,
                                  js.Block body) {
-    return attachPosition(new js.Fun(parameters, body), element);
+    js.AsyncModifier asyncModifier = element.asyncMarker.isAsync
+        ? (element.asyncMarker.isYielding
+            ? const js.AsyncModifier.asyncStar()
+            : const js.AsyncModifier.async())
+        : (element.asyncMarker.isYielding
+            ? const js.AsyncModifier.syncStar()
+            : const js.AsyncModifier.sync());
+
+    return attachPosition(
+        new js.Fun(parameters, body, asyncModifier: asyncModifier), element);
   }
 
   js.Expression generateCode(CodegenWorkItem work, HGraph graph) {
@@ -75,10 +55,13 @@
 
   js.Expression generateMethod(CodegenWorkItem work, HGraph graph) {
     return measure(() {
+      FunctionElement element = work.element;
+      if (element.asyncMarker != AsyncMarker.SYNC) {
+        work.registry.registerAsyncMarker(element);
+      }
       SsaCodeGenerator codegen = new SsaCodeGenerator(backend, work);
       codegen.visitGraph(graph);
       compiler.tracer.traceGraph("codegen", graph);
-      FunctionElement element = work.element;
       return buildJavaScriptFunction(element, codegen.parameters, codegen.body);
     });
   }
@@ -241,13 +224,12 @@
   }
 
   js.Node attachLocation(js.Node jsNode, HInstruction instruction) {
-    return jsNode.withLocation(instruction.sourcePosition);
+    return attachSourceInformation(jsNode, instruction.sourceInformation);
   }
 
-  js.Node attachLocationRange(js.Node jsNode,
-                              SourceFileLocation sourcePosition,
-                              SourceFileLocation endSourcePosition) {
-    return jsNode.withPosition(sourcePosition, endSourcePosition);
+  js.Node attachSourceInformation(js.Node jsNode,
+                                  SourceInformation sourceInformation) {
+    return jsNode.withSourceInformation(sourceInformation);
   }
 
   void preGenerateMethod(HGraph graph) {
@@ -956,8 +938,7 @@
         compiler.internalError(condition.conditionExpression,
             'Unexpected loop kind: ${info.kind}.');
     }
-    js.Statement result =
-        attachLocationRange(loop, info.sourcePosition, info.endSourcePosition);
+    js.Statement result = attachSourceInformation(loop, info.sourceInformation);
     if (info.kind == HLoopBlockInformation.SWITCH_CONTINUE_LOOP) {
       String continueLabelString =
           backend.namer.implicitContinueLabelName(info.target);
@@ -1969,6 +1950,16 @@
     }
   }
 
+  visitAwait(HAwait node) {
+    use(node.inputs[0]);
+    push(new js.Await(pop()), node);
+  }
+
+  visitYield(HYield node) {
+    use(node.inputs[0]);
+    pushStatement(new js.DartYield(pop(), node.hasStar), node);
+  }
+
   visitRangeConversion(HRangeConversion node) {
     // Range conversion instructions are removed by the value range
     // analyzer.
@@ -2047,7 +2038,15 @@
     if (helperName == 'wrapException') {
       pushStatement(new js.Throw(value));
     } else {
-      pushStatement(new js.Return(value));
+      Element element = work.element;
+      if (element is FunctionElement && element.asyncMarker.isYielding) {
+        // `return <expr>;` is illegal in a sync* or async* function.
+        // To have the the async-translator working, we avoid introducing
+        // `return` nodes.
+        pushStatement(new js.ExpressionStatement(value));
+      } else {
+        pushStatement(new js.Return(value));
+      }
     }
   }
 
diff --git a/pkg/compiler/lib/src/ssa/codegen_helpers.dart b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
index 88e5505..c298e06 100644
--- a/pkg/compiler/lib/src/ssa/codegen_helpers.dart
+++ b/pkg/compiler/lib/src/ssa/codegen_helpers.dart
@@ -34,8 +34,8 @@
         if (replacement.sourceElement == null) {
           replacement.sourceElement = instruction.sourceElement;
         }
-        if (replacement.sourcePosition == null) {
-          replacement.sourcePosition = instruction.sourcePosition;
+        if (replacement.sourceInformation == null) {
+          replacement.sourceInformation = instruction.sourceInformation;
         }
         if (!replacement.isInBasicBlock()) {
           // The constant folding can return an instruction that is already
diff --git a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
index 3a0f467..d8213e2 100644
--- a/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
+++ b/pkg/compiler/lib/src/ssa/interceptor_simplifier.dart
@@ -300,7 +300,7 @@
         if (backend.mayGenerateInstanceofCheck(user.typeExpression)) {
           HInstruction instanceofCheck = new HIs.instanceOf(
               user.typeExpression, user.expression, user.instructionType);
-          instanceofCheck.sourcePosition = user.sourcePosition;
+          instanceofCheck.sourceInformation = user.sourceInformation;
           instanceofCheck.sourceElement = user.sourceElement;
           return replaceUserWith(instanceofCheck);
         }
@@ -313,7 +313,7 @@
         inputs[0] = nullConstant;
         HOneShotInterceptor oneShotInterceptor = new HOneShotInterceptor(
             user.selector, inputs, user.instructionType, interceptedClasses);
-        oneShotInterceptor.sourcePosition = user.sourcePosition;
+        oneShotInterceptor.sourceInformation = user.sourceInformation;
         oneShotInterceptor.sourceElement = user.sourceElement;
         return replaceUserWith(oneShotInterceptor);
       }
diff --git a/pkg/compiler/lib/src/ssa/nodes.dart b/pkg/compiler/lib/src/ssa/nodes.dart
index 7337b7b..e6db5e3 100644
--- a/pkg/compiler/lib/src/ssa/nodes.dart
+++ b/pkg/compiler/lib/src/ssa/nodes.dart
@@ -6,6 +6,7 @@
 
 abstract class HVisitor<R> {
   R visitAdd(HAdd node);
+  R visitAwait(HAwait node);
   R visitBitAnd(HBitAnd node);
   R visitBitNot(HBitNot node);
   R visitBitOr(HBitOr node);
@@ -71,6 +72,7 @@
   R visitTry(HTry node);
   R visitTypeConversion(HTypeConversion node);
   R visitTypeKnown(HTypeKnown node);
+  R visitYield(HYield node);
   R visitReadTypeVariable(HReadTypeVariable node);
   R visitFunctionType(HFunctionType node);
   R visitVoidType(HVoidType node);
@@ -354,6 +356,8 @@
   visitVoidType(HVoidType node) => visitInstruction(node);
   visitInterfaceType(HInterfaceType node) => visitInstruction(node);
   visitDynamicType(HDynamicType node) => visitInstruction(node);
+  visitAwait(HAwait node) => visitInstruction(node);
+  visitYield(HYield node) => visitInstruction(node);
 }
 
 class SubGraph {
@@ -759,7 +763,7 @@
 
 abstract class HInstruction implements Spannable {
   Entity sourceElement;
-  SourceFileLocation sourcePosition;
+  SourceInformation sourceInformation;
 
   final int id;
   static int idCounter;
@@ -2234,6 +2238,26 @@
   bool canThrow() => true;
 }
 
+class HAwait extends HInstruction {
+  HAwait(HInstruction value, TypeMask type)
+      : super(<HInstruction>[value], type);
+  toString() => 'await';
+  accept(HVisitor visitor) => visitor.visitAwait(this);
+  // An await will throw if its argument is not a real future.
+  bool canThrow() => true;
+  SideEffects sideEffects = new SideEffects();
+}
+
+class HYield extends HInstruction {
+  HYield(HInstruction value, this.hasStar)
+      : super(<HInstruction>[value], const TypeMask.nonNullEmpty());
+  bool hasStar;
+  toString() => 'yield';
+  accept(HVisitor visitor) => visitor.visitYield(this);
+  bool canThrow() => false;
+  SideEffects sideEffects = new SideEffects();
+}
+
 class HThrow extends HControlFlow {
   final bool isRethrow;
   HThrow(value, {this.isRethrow: false}) : super(<HInstruction>[value]);
@@ -2882,8 +2906,7 @@
   final HExpressionInformation updates;
   final JumpTarget target;
   final List<LabelDefinition> labels;
-  final SourceFileLocation sourcePosition;
-  final SourceFileLocation endSourcePosition;
+  final SourceInformation sourceInformation;
 
   HLoopBlockInformation(this.kind,
                         this.initializer,
@@ -2892,8 +2915,7 @@
                         this.updates,
                         this.target,
                         this.labels,
-                        this.sourcePosition,
-                        this.endSourcePosition) {
+                        this.sourceInformation) {
     assert(
         (kind == DO_WHILE_LOOP ? body.start : condition.start).isLoopHeader());
   }
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 9aa51f0..04ac400 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -167,8 +167,8 @@
         if (replacement.sourceElement == null) {
           replacement.sourceElement = instruction.sourceElement;
         }
-        if (replacement.sourcePosition == null) {
-          replacement.sourcePosition = instruction.sourcePosition;
+        if (replacement.sourceInformation == null) {
+          replacement.sourceInformation = instruction.sourceInformation;
         }
         if (!replacement.isInBasicBlock()) {
           // The constant folding can return an instruction that is already
diff --git a/pkg/compiler/lib/src/ssa/ssa.dart b/pkg/compiler/lib/src/ssa/ssa.dart
index 2b56162..3e80b8e 100644
--- a/pkg/compiler/lib/src/ssa/ssa.dart
+++ b/pkg/compiler/lib/src/ssa/ssa.dart
@@ -18,19 +18,20 @@
          VariableElementX,
          ConstructorBodyElementX;
 import '../helpers/helpers.dart';
+import '../io/source_file.dart';
+import '../io/source_information.dart';
 import '../js/js.dart' as js;
 import '../js_backend/js_backend.dart';
 import '../js_emitter/js_emitter.dart' show CodeEmitterTask, NativeEmitter;
 import '../native/native.dart' as native;
 import '../scanner/scannerlib.dart'
     show PartialFunctionElement, Token, PLUS_TOKEN;
-import '../io/source_file.dart';
-import '../io/source_map_builder.dart';
 import '../tree/tree.dart' as ast;
 import '../types/types.dart';
 import '../types/constants.dart' show computeTypeMask;
 import '../universe/universe.dart';
 import '../util/util.dart';
+import '../js/rewrite_async.dart';
 
 part 'builder.dart';
 part 'codegen.dart';
diff --git a/pkg/compiler/lib/src/ssa/ssa_tracer.dart b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
index 09d8069..103ecae 100644
--- a/pkg/compiler/lib/src/ssa/ssa_tracer.dart
+++ b/pkg/compiler/lib/src/ssa/ssa_tracer.dart
@@ -519,4 +519,12 @@
   String visitDynamicType(HDynamicType node) {
     return "DynamicType";
   }
+
+  String visitAwait(HAwait node) {
+    return "await ${temporaryId(node.inputs[0])}";
+  }
+
+  String visitYield(HYield node) {
+    return "yield${node.hasStar ? "*" : ""} ${temporaryId(node.inputs[0])}";
+  }
 }
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index 1d9c690..d7dbda7 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -408,7 +408,7 @@
     if (node.starToken != null) {
       write(node.starToken.value);
     }
-    space();
+    write(' ');
     visit(node.expression);
     write(node.endToken.value);
   }
diff --git a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
index a688778..038ecf1 100644
--- a/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
+++ b/pkg/compiler/lib/src/tree_ir/tree_ir_nodes.dart
@@ -181,6 +181,8 @@
   final FunctionElement target;
   final List<Expression> arguments;
   final Selector selector;
+  /// TODO(karlklose): get rid of this field.  Instead use the constant's
+  /// expression to find the constructor to be called in dart2dart.
   final values.ConstantValue constant;
 
   InvokeConstructor(this.type, this.target, this.selector, this.arguments,
@@ -197,9 +199,8 @@
 /// Calls [toString] on each argument and concatenates the results.
 class ConcatenateStrings extends Expression {
   final List<Expression> arguments;
-  final values.ConstantValue constant;
 
-  ConcatenateStrings(this.arguments, [this.constant]);
+  ConcatenateStrings(this.arguments);
 
   accept(ExpressionVisitor visitor) => visitor.visitConcatenateStrings(this);
   accept1(ExpressionVisitor1 visitor, arg) {
diff --git a/pkg/compiler/lib/src/universe/universe.dart b/pkg/compiler/lib/src/universe/universe.dart
index a7ddbb0..3deffcb 100644
--- a/pkg/compiler/lib/src/universe/universe.dart
+++ b/pkg/compiler/lib/src/universe/universe.dart
@@ -506,49 +506,7 @@
    *
    * Invariant: [element] must be the implementation element.
    */
-  /*<S, T>*/ List/*<T>*/ makeArgumentsList(
-        FunctionElement element,
-        List/*<T>*/ compiledArguments,
-        /*T*/ compileDefaultValue(ParameterElement element)) {
-    assert(invariant(element, element.isImplementation));
-    List/*<T>*/ result = new List();
-    FunctionSignature parameters = element.functionSignature;
-    int i = 0;
-    parameters.forEachRequiredParameter((ParameterElement element) {
-      result.add(compiledArguments[i]);
-      ++i;
-    });
-
-    if (!parameters.optionalParametersAreNamed) {
-      parameters.forEachOptionalParameter((ParameterElement element) {
-        if (i < compiledArguments.length) {
-          result.add(compiledArguments[i]);
-          ++i;
-        } else {
-          result.add(compileDefaultValue(element));
-        }
-      });
-    } else {
-      int offset = i;
-      // Iterate over the optional parameters of the signature, and try to
-      // find them in [compiledNamedArguments]. If found, we use the
-      // value in the temporary list, otherwise the default value.
-      parameters.orderedOptionalParameters
-          .forEach((ParameterElement element) {
-        int foundIndex = namedArguments.indexOf(element.name);
-        if (foundIndex != -1) {
-          result.add(compiledArguments[offset + foundIndex]);
-        } else {
-          result.add(compileDefaultValue(element));
-        }
-      });
-    }
-    return result;
-  }
-
-  /// This is a version of [makeArgumentsList] that works for a `Link`
-  /// representation of arguments.
-  /*<T>*/ List/*<T>*/ makeArgumentsList2(
+  /*<T>*/ List/*<T>*/ makeArgumentsList(
       Link<Node> arguments,
       FunctionElement element,
       /*T*/ compileArgument(Node argument),
@@ -593,7 +551,6 @@
     return result;
   }
 
-
   /**
    * Fills [list] with the arguments in the order expected by
    * [callee], and where [caller] is a synthesized element
@@ -661,10 +618,10 @@
                                           namedParameters);
 
     if (!selector.applies(callee, world)) return false;
-    list.addAll(selector.makeArgumentsList2(nodes,
-                                            callee,
-                                            internalCompileArgument,
-                                            compileConstant));
+    list.addAll(selector.makeArgumentsList(nodes,
+                                           callee,
+                                           internalCompileArgument,
+                                           compileConstant));
 
     return true;
   }
diff --git a/pkg/compiler/lib/src/use_unused_api.dart b/pkg/compiler/lib/src/use_unused_api.dart
index 909b000..77f0bc9 100644
--- a/pkg/compiler/lib/src/use_unused_api.dart
+++ b/pkg/compiler/lib/src/use_unused_api.dart
@@ -51,10 +51,10 @@
   useSetlet(null);
   useImmutableEmptySet(null);
   useElementVisitor(new ElementVisitor());
-  useJs(new js.Program(null));
-  useJs(new js.Blob(null));
-  useJs(new js.NamedFunction(null, null));
-  useJs(new js.ArrayHole());
+  useJsNode(new js.Program(null));
+  useJsNode(new js.NamedFunction(null, null));
+  useJsNode(new js.ArrayHole());
+  useJsOther(new js.SimpleJavaScriptPrintingContext());
   useJsBackend(null);
   useConcreteTypesInferrer(null);
   useColor();
@@ -170,10 +170,14 @@
     ..visitWarnOnUseElement(null);
 }
 
-useJs(js.Node node) {
+useJsNode(js.Node node) {
   node.asVariableUse();
 }
 
+useJsOther(js.SimpleJavaScriptPrintingContext context) {
+  context.getText();
+}
+
 useJsBackend(js_backend.JavaScriptBackend backend) {
   backend.assembleCode(null);
   backend.annotations.noInlining(null);
diff --git a/pkg/compiler/lib/src/warnings.dart b/pkg/compiler/lib/src/warnings.dart
index e21429c..75334ea 100644
--- a/pkg/compiler/lib/src/warnings.dart
+++ b/pkg/compiler/lib/src/warnings.dart
@@ -2075,19 +2075,6 @@
     " require a preamble file located in:\n"
     "  <sdk>/lib/_internal/compiler/js_lib/preambles.");
 
-  static const MessageKind EXPERIMENTAL_ASYNC_AWAIT = const MessageKind(
-      "Experimental language feature 'async/await' is not supported.");
-
-  static const MessageKind INVALID_STARRED_KEYWORD = const MessageKind(
-      "Invalid '#{keyword}' keyword.",
-      options: const ['--enable-async'],
-      howToFix: "Try removing whitespace between '#{keyword}' and '*'.",
-      examples: const [
-        "main() async * {}",
-        "main() sync * {}",
-        "main() async* { yield * null; }"
-      ]);
-
   static const MessageKind INVALID_SYNC_MODIFIER = const MessageKind(
       "Invalid modifier 'sync'.",
       options: const ['--enable-async'],
diff --git a/pkg/dart2js_incremental/lib/library_updater.dart b/pkg/dart2js_incremental/lib/library_updater.dart
index 217abdb..bc269e2 100644
--- a/pkg/dart2js_incremental/lib/library_updater.dart
+++ b/pkg/dart2js_incremental/lib/library_updater.dart
@@ -995,9 +995,13 @@
   }
 
   String prettyPrintJs(jsAst.Node node) {
-    jsAst.Printer printer = new jsAst.Printer(compiler, null);
+    jsAst.JavaScriptPrintingOptions options =
+        new jsAst.JavaScriptPrintingOptions();
+    jsAst.JavaScriptPrintingContext context =
+        new jsAst.Dart2JSJavaScriptPrintingContext(compiler, null);
+    jsAst.Printer printer = new jsAst.Printer(options, context);
     printer.blockOutWithoutBraces(node);
-    return printer.outBuffer.getText();
+    return context.outBuffer.getText();
   }
 
   String callNameFor(FunctionElement element) {
diff --git