Version 1.13.0-dev.6.0

Merge commit '3abd6ad7583fa0e87158fddbdc7668c851874e5f' into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e6e2695..2f9aadf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,26 +1,40 @@
 ## 1.13.0
 
+### Core library changes
+* `dart:async`
+  * `StreamTransformer` instances created with `fromHandlers` with no
+    `handleError` callback now forward stack traces along with errors to the
+    resulting streams.
+
 * `dart:core`
   * `Uri` added `removeFragment` method.
   * `String.allMatches` (implementing `Pattern.allMatches`) is now lazy,
     as all `allMatches` implementations are intended to be.
+  * `Resource` is deprecated in favor of the resource package.
+    See https://pub.dartlang.org/packages/resource to learn more. This is
+    the last release to contain the Resource class.
 
 * `dart:io`
   * `HttpClient` no longer sends URI fragments in the request. This is not
     allowed by the HTTP protocol.
     The `HttpServer` still gracefully receives fragments, but discards them
     before delivering the request.
-
-* `dart:async`
-  * `StreamTransformer`s created with `fromHandlers` with no `handleError`
-    callback now forward stack traces along with errors to the resulting
-    streams.
+  * Removed server socket references. The use of server socket references
+    was deprecated back in 1.9. Use the `shared` flag when creating listening
+    sockets and `HttpServer` to distribute accepted sockets between isolates.
 
 ### Tool changes
 
 * `docgen` and 'dartdocgen' no longer ship in the sdk. The `docgen` sources have
    been removed from the repository.
 
+* This is the last release to ship the VM's "legacy debug protocol".
+  We intend to remove the legacy debug protocol in Dart VM 1.14.
+
+* The VM's Service Protocol has been updated to version 3.0 to take care
+  of a number of issues uncovered by the first few non-observatory
+  clients.  This is a potentially breaking change for clients.
+
 ## 1.12.0
 
 ### Language changes
diff --git a/DEPS b/DEPS
index 9cb65e6..ac30916 100644
--- a/DEPS
+++ b/DEPS
@@ -38,7 +38,7 @@
 
   # Revisions of /third_party/* dependencies.
   "7zip_rev" : "@19997",
-  "analyzer_cli_rev" : "@0b89a16c0566f36676fa8f2016eb2c332178f616",
+  "analyzer_cli_rev" : "@c8a60be821be07df64cde2efb8f87b462a91a521",
   "args_tag": "@0.13.0",
   "async_tag": "@1.2.0",
   "barback_tag" : "@0.15.2+7",
@@ -50,8 +50,8 @@
   "collection_rev": "@1da9a07f32efa2ba0c391b289e2037391e31da0e",
   "crypto_rev" : "@2df57a1e26dd88e8d0614207d4b062c73209917d",
   "csslib_tag" : "@0.12.0",
-  "dart2js_info_rev" : "@bad01369f1f605ab688d505c135db54de927318f",
-  "dartdoc_rev" : "@786426c4bbea96729d5eab2add744def41a5a690",
+  "dart2js_info_rev" : "@ffd03ee45f7459efd3039ff565b4d0aa2e7cd9e7",
+  "dartdoc_rev" : "@d51211b7c0a30862a691aa6dc0631009bd926004",
   "dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
   "dart_style_tag": "@0.2.0",
   "dev_compiler_rev": "@0.1.8",
diff --git a/codereview.settings b/codereview.settings
index 3e78887..ada9e3c 100644
--- a/codereview.settings
+++ b/codereview.settings
@@ -1,4 +1,4 @@
 # This file is used by gcl to get repository specific information.
-CODE_REVIEW_SERVER: http://codereview.chromium.org/
+CODE_REVIEW_SERVER: http://codereview.chromium.org
 VIEW_VC: https://github.com/dart-lang/sdk/commit/
 CC_LIST: reviews@dartlang.org
diff --git a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
index fd50e13..6f7a3c6 100644
--- a/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/analysis_timing_tests.dart
@@ -7,43 +7,82 @@
 import 'dart:async';
 import 'dart:io';
 
+import 'package:analysis_server/src/protocol.dart';
 import 'package:args/args.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
 
 import '../../test/utils.dart';
 import 'performance_tests.dart';
 
-const String SOURCE_OPTION = 'source';
-
 /**
- * Pass in the directory of the source to be analyzed as option --source
+ * Pass in the directory of the source to be analyzed as option `--source`,
+ * optionally specify a priority file with `--priority` and the specific
+ * test to run with `--test`.  If no test is specified, the default is
+ * `analysis`.
  */
-main(List<String> arguements) {
+main(List<String> arguments) {
   initializeTestEnvironment();
   ArgParser parser = _createArgParser();
-  var args = parser.parse(arguements);
+  var args = parser.parse(arguments);
   if (args[SOURCE_OPTION] == null) {
     print('path to source directory must be specified');
     exit(1);
   }
   source = args[SOURCE_OPTION];
-  defineReflectiveTests(AnalysisTimingIntegrationTest);
+  priorityFile = args[PRIORITY_FILE_OPTION];
+  testName = args[TEST_NAME_OPTION] ?? DEFAULT_TEST;
+
+  switch (testName) {
+    case 'analysis':
+      defineReflectiveTests(AnalysisTimingIntegrationTest);
+      break;
+    case 'highlighting':
+      defineReflectiveTests(HighlightingTimingIntegrationTest);
+      break;
+    case 'navigation':
+      defineReflectiveTests(NavigationTimingIntegrationTest);
+      break;
+    case 'outline':
+      defineReflectiveTests(OutlineTimingIntegrationTest);
+      break;
+    default:
+      print('unrecognized test name $testName');
+      exit(1);
+  }
 }
 
+const DEFAULT_TEST = 'analysis';
+const PRIORITY_FILE_OPTION = 'priority';
+const SOURCE_OPTION = 'source';
+const TEST_NAME_OPTION = 'test';
+
+String priorityFile;
 String source;
+String testName;
+
+ArgParser _createArgParser() => new ArgParser()
+  ..addOption(TEST_NAME_OPTION, help: 'test name (defaults to `analysis`)')
+  ..addOption(SOURCE_OPTION, help: 'full path to source directory for analysis')
+  ..addOption(PRIORITY_FILE_OPTION,
+      help: '(optional) full path to a priority file');
+
+class AbstractTimingTest extends AbstractAnalysisServerPerformanceTest {
+  @override
+  Future setUp() => super.setUp().then((_) {
+        sourceDirectory = new Directory(source);
+        subscribeToStatusNotifications();
+      });
+}
 
 @reflectiveTest
-class AnalysisTimingIntegrationTest
-    extends AbstractAnalysisServerPerformanceTest {
+class AnalysisTimingIntegrationTest extends AbstractTimingTest {
   test_detect_analysis_done() {
-    sourceDirectory = new Directory(source);
-    subscribeToStatusNotifications();
-    return _runAndTimeAnalysis();
-  }
-
-  Future _runAndTimeAnalysis() {
     stopwatch.start();
     setAnalysisRoot();
+    if (priorityFile != null) {
+      sendAnalysisSetPriorityFiles([priorityFile]);
+    }
     return analysisFinished.then((_) {
       print('analysis completed in ${stopwatch.elapsed}');
       stopwatch.reset();
@@ -51,9 +90,67 @@
   }
 }
 
-ArgParser _createArgParser() {
-  ArgParser parser = new ArgParser();
-  parser.addOption('source',
-      help: 'full path to source directory for analysis');
-  return parser;
+@reflectiveTest
+class HighlightingTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'highlighting';
+
+  @override
+  Stream get eventStream => onAnalysisHighlights;
+
+  @override
+  AnalysisService get service => AnalysisService.HIGHLIGHTS;
+}
+
+@reflectiveTest
+class NavigationTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'navigation';
+
+  @override
+  Stream get eventStream => onAnalysisNavigation;
+
+  @override
+  AnalysisService get service => AnalysisService.NAVIGATION;
+}
+
+@reflectiveTest
+class OutlineTimingIntegrationTest extends PriorityFileTimer {
+  @override
+  String get description => 'outline';
+
+  @override
+  Stream get eventStream => onAnalysisOutline;
+
+  @override
+  AnalysisService get service => AnalysisService.OUTLINE;
+}
+
+abstract class PriorityFileTimer extends AbstractTimingTest {
+  String get description;
+  Stream get eventStream;
+  AnalysisService get service;
+
+  Future test_timing() {
+    expect(priorityFile, isNotNull,
+        reason: 'A priority file must be specified for $description testing.');
+    stopwatch.start();
+
+    Duration elapsed;
+    eventStream.listen((_) {
+      elapsed = stopwatch.elapsed;
+    });
+
+    setAnalysisRoot();
+    sendAnalysisSetSubscriptions({
+      service: [priorityFile]
+    });
+
+    sendAnalysisSetPriorityFiles([priorityFile]);
+
+    return analysisFinished.then((_) {
+      print('$description completed in ${elapsed}');
+      stopwatch.reset();
+    });
+  }
 }
diff --git a/pkg/analysis_server/benchmark/perf/performance_tests.dart b/pkg/analysis_server/benchmark/perf/performance_tests.dart
index a926e33..3dd1842 100644
--- a/pkg/analysis_server/benchmark/perf/performance_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/performance_tests.dart
@@ -25,9 +25,8 @@
    * Send the server an 'analysis.setAnalysisRoots' command directing it to
    * analyze [sourceDirectory].
    */
-  Future setAnalysisRoot() {
-    return sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
-  }
+  Future setAnalysisRoot() =>
+      sendAnalysisSetAnalysisRoots([sourceDirectory.path], []);
 
   /**
    * Enable [SERVER_STATUS] notifications so that [analysisFinished]
@@ -69,7 +68,5 @@
    * After every test, the server is stopped.
    */
   @override
-  Future tearDown() {
-    return shutdownIfNeeded();
-  }
+  Future tearDown() => shutdownIfNeeded();
 }
diff --git a/pkg/analysis_server/doc/api.html b/pkg/analysis_server/doc/api.html
index 52b4419..69a9f87 100644
--- a/pkg/analysis_server/doc/api.html
+++ b/pkg/analysis_server/doc/api.html
@@ -61,7 +61,7 @@
 </style></head>
   <body>
     <h1>Analysis Server API Specification</h1>
-    <h1 style="color:#999999">Version 1.9.0</h1>
+    <h1 style="color:#999999">Version 1.12.0</h1>
     <p>
       This document contains a specification of the API provided by the
       analysis server.  The API in this document is currently under
@@ -1200,6 +1200,8 @@
   "event": "analysis.outline"
   "params": {
     "<b>file</b>": <a href="#type_FilePath">FilePath</a>
+    "<b>kind</b>": <a href="#type_FileKind">FileKind</a>
+    "<b>libraryName</b>": <span style="color:#999999">optional</span> String
     "<b>outline</b>": <a href="#type_Outline">Outline</a>
   }
 }</pre></div>
@@ -1218,6 +1220,21 @@
             <p>
               The file with which the outline is associated.
             </p>
+          </dd><dt class="field"><b><i>kind ( <a href="#type_FileKind">FileKind</a> )</i></b></dt><dd>
+            
+            <p>
+              The kind of the file.
+            </p>
+          </dd><dt class="field"><b><i>libraryName ( <span style="color:#999999">optional</span> String )</i></b></dt><dd>
+            
+            <p>
+              The name of the library defined by the file using a "library"
+              directive, or referenced by a "part of" directive. If both
+              "library" and "part of" directives are present, then the
+              "library" directive takes precedence.
+              This field will be omitted if the file has neither "library"
+              nor "part of" directives.
+            </p>
           </dd><dt class="field"><b><i>outline ( <a href="#type_Outline">Outline</a> )</i></b></dt><dd>
             
             <p>
@@ -2309,6 +2326,7 @@
       
       
       
+      
     <dl><dt class="typeDefinition"><a name="type_AddContentOverlay">AddContentOverlay: object</a></dt><dd>
         <p>
           A directive to begin overlaying the contents of a file.  The
@@ -2362,6 +2380,20 @@
               the error. The field is omitted if there is no correction
               message associated with the error code.
             </p>
+          </dd><dt class="field"><b><i>hasFix ( <span style="color:#999999">optional</span> bool )</i></b></dt><dd>
+            
+            <p>
+              A hint to indicate to interested clients that this error has
+              an associated fix (or fixes).  The absence of this field implies
+              there are not known to be fixes.  Note that since the operation
+              to calculate whether fixes apply needs to be performant it is
+              possible that complicated tests will be skipped and a false
+              negative returned.  For this reason, this attribute should be
+              treated as a "hint".  Despite the possibility of false negatives,
+              no false positives should be returned.  If a client sees this
+              flag set they can proceed with the confidence that there are in
+              fact associated fixes.
+            </p>
           </dd></dl></dd><dt class="typeDefinition"><a name="type_AnalysisErrorFixes">AnalysisErrorFixes: object</a></dt><dd>
         <p>
           A list of fixes associated with a specific error
@@ -2775,7 +2807,12 @@
           domain.
         </p>
         
-      <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
+      <dl><dt class="value">LAUNCH_DATA</dt></dl></dd><dt class="typeDefinition"><a name="type_FileKind">FileKind: String</a></dt><dd>
+        <p>
+          An enumeration of the kinds of files.
+        </p>
+        
+      <dl><dt class="value">LIBRARY</dt><dt class="value">PART</dt></dl></dd><dt class="typeDefinition"><a name="type_FilePath">FilePath: String</a></dt><dd>
         
         <p>
           The absolute path of a file.
@@ -3918,16 +3955,28 @@
         </p>
       <h4>Feedback</h4><p>none</p><h4>Options</h4><p>none</p></dd><dt class="refactoring">EXTRACT_LOCAL_VARIABLE</dt><dd>
         <p>
-          Create a local variable initialized by a specified
-          expression.
+          Create a local variable initialized by the expression that covers
+          the specified selection.
         </p>
         <p>
-          It is an error if the range contains anything other than a
-          complete expression (no partial expressions are allowed).
+          It is an error if the selection range is not covered by a
+          complete expression.
         </p>
         
         
-      <h4>Feedback</h4><dl><dt class="field"><b><i>names ( List&lt;String&gt; )</i></b></dt><dd>
+      <h4>Feedback</h4><dl><dt class="field"><b><i>coveringExpressionOffsets ( List&lt;int&gt; )</i></b></dt><dd>
+            
+            <p>
+              The offsets of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </dd><dt class="field"><b><i>coveringExpressionLengths ( List&lt;int&gt; )</i></b></dt><dd>
+            
+            <p>
+              The lengths of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </dd><dt class="field"><b><i>names ( List&lt;String&gt; )</i></b></dt><dd>
             
             <p>
               The proposed names for the local variable.
@@ -4202,7 +4251,7 @@
       TBD
     </p>
     <h2 class="domain"><a name="index">Index</a></h2>
-    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
+    <h3>Domains</h3><h4>server (<a href="#domain_server">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_server.getVersion">getVersion</a></li><li><a href="#request_server.shutdown">shutdown</a></li><li><a href="#request_server.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_server.connected">connected</a></li><li><a href="#notification_server.error">error</a></li><li><a href="#notification_server.status">status</a></li></ul></div></div><h4>analysis (<a href="#domain_analysis">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_analysis.getErrors">getErrors</a></li><li><a href="#request_analysis.getHover">getHover</a></li><li><a href="#request_analysis.getLibraryDependencies">getLibraryDependencies</a></li><li><a href="#request_analysis.getNavigation">getNavigation</a></li><li><a href="#request_analysis.reanalyze">reanalyze</a></li><li><a href="#request_analysis.setAnalysisRoots">setAnalysisRoots</a></li><li><a href="#request_analysis.setGeneralSubscriptions">setGeneralSubscriptions</a></li><li><a href="#request_analysis.setPriorityFiles">setPriorityFiles</a></li><li><a href="#request_analysis.setSubscriptions">setSubscriptions</a></li><li><a href="#request_analysis.updateContent">updateContent</a></li><li><a href="#request_analysis.updateOptions">updateOptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_analysis.analyzedFiles">analyzedFiles</a></li><li><a href="#notification_analysis.errors">errors</a></li><li><a href="#notification_analysis.flushResults">flushResults</a></li><li><a href="#notification_analysis.folding">folding</a></li><li><a href="#notification_analysis.highlights">highlights</a></li><li><a href="#notification_analysis.implemented">implemented</a></li><li><a href="#notification_analysis.invalidate">invalidate</a></li><li><a href="#notification_analysis.navigation">navigation</a></li><li><a href="#notification_analysis.occurrences">occurrences</a></li><li><a href="#notification_analysis.outline">outline</a></li><li><a href="#notification_analysis.overrides">overrides</a></li></ul></div></div><h4>completion (<a href="#domain_completion">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_completion.getSuggestions">getSuggestions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_completion.results">results</a></li></ul></div></div><h4>search (<a href="#domain_search">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_search.findElementReferences">findElementReferences</a></li><li><a href="#request_search.findMemberDeclarations">findMemberDeclarations</a></li><li><a href="#request_search.findMemberReferences">findMemberReferences</a></li><li><a href="#request_search.findTopLevelDeclarations">findTopLevelDeclarations</a></li><li><a href="#request_search.getTypeHierarchy">getTypeHierarchy</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_search.results">results</a></li></ul></div></div><h4>edit (<a href="#domain_edit">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_edit.format">format</a></li><li><a href="#request_edit.getAssists">getAssists</a></li><li><a href="#request_edit.getAvailableRefactorings">getAvailableRefactorings</a></li><li><a href="#request_edit.getFixes">getFixes</a></li><li><a href="#request_edit.getRefactoring">getRefactoring</a></li><li><a href="#request_edit.sortMembers">sortMembers</a></li><li><a href="#request_edit.organizeDirectives">organizeDirectives</a></li></ul></div><h4>execution (<a href="#domain_execution">↑</a>)</h4><div class="subindex"><h5>Requests</h5><ul><li><a href="#request_execution.createContext">createContext</a></li><li><a href="#request_execution.deleteContext">deleteContext</a></li><li><a href="#request_execution.mapUri">mapUri</a></li><li><a href="#request_execution.setSubscriptions">setSubscriptions</a></li></ul><h5>Notifications</h5><div class="subindex"><ul><li><a href="#notification_execution.launchData">launchData</a></li></ul></div></div><h3>Types (<a href="#types">↑</a>)</h3><div class="subindex"><ul><li><a href="#type_AddContentOverlay">AddContentOverlay</a></li><li><a href="#type_AnalysisError">AnalysisError</a></li><li><a href="#type_AnalysisErrorFixes">AnalysisErrorFixes</a></li><li><a href="#type_AnalysisErrorSeverity">AnalysisErrorSeverity</a></li><li><a href="#type_AnalysisErrorType">AnalysisErrorType</a></li><li><a href="#type_AnalysisOptions">AnalysisOptions</a></li><li><a href="#type_AnalysisService">AnalysisService</a></li><li><a href="#type_AnalysisStatus">AnalysisStatus</a></li><li><a href="#type_ChangeContentOverlay">ChangeContentOverlay</a></li><li><a href="#type_CompletionId">CompletionId</a></li><li><a href="#type_CompletionSuggestion">CompletionSuggestion</a></li><li><a href="#type_CompletionSuggestionKind">CompletionSuggestionKind</a></li><li><a href="#type_Element">Element</a></li><li><a href="#type_ElementKind">ElementKind</a></li><li><a href="#type_ExecutableFile">ExecutableFile</a></li><li><a href="#type_ExecutableKind">ExecutableKind</a></li><li><a href="#type_ExecutionContextId">ExecutionContextId</a></li><li><a href="#type_ExecutionService">ExecutionService</a></li><li><a href="#type_FileKind">FileKind</a></li><li><a href="#type_FilePath">FilePath</a></li><li><a href="#type_FoldingKind">FoldingKind</a></li><li><a href="#type_FoldingRegion">FoldingRegion</a></li><li><a href="#type_GeneralAnalysisService">GeneralAnalysisService</a></li><li><a href="#type_HighlightRegion">HighlightRegion</a></li><li><a href="#type_HighlightRegionType">HighlightRegionType</a></li><li><a href="#type_HoverInformation">HoverInformation</a></li><li><a href="#type_ImplementedClass">ImplementedClass</a></li><li><a href="#type_ImplementedMember">ImplementedMember</a></li><li><a href="#type_LinkedEditGroup">LinkedEditGroup</a></li><li><a href="#type_LinkedEditSuggestion">LinkedEditSuggestion</a></li><li><a href="#type_LinkedEditSuggestionKind">LinkedEditSuggestionKind</a></li><li><a href="#type_Location">Location</a></li><li><a href="#type_NavigationRegion">NavigationRegion</a></li><li><a href="#type_NavigationTarget">NavigationTarget</a></li><li><a href="#type_Occurrences">Occurrences</a></li><li><a href="#type_Outline">Outline</a></li><li><a href="#type_Override">Override</a></li><li><a href="#type_OverriddenMember">OverriddenMember</a></li><li><a href="#type_Position">Position</a></li><li><a href="#type_PubStatus">PubStatus</a></li><li><a href="#type_RefactoringKind">RefactoringKind</a></li><li><a href="#type_RefactoringMethodParameter">RefactoringMethodParameter</a></li><li><a href="#type_RefactoringFeedback">RefactoringFeedback</a></li><li><a href="#type_RefactoringOptions">RefactoringOptions</a></li><li><a href="#type_RefactoringMethodParameterKind">RefactoringMethodParameterKind</a></li><li><a href="#type_RefactoringProblem">RefactoringProblem</a></li><li><a href="#type_RefactoringProblemSeverity">RefactoringProblemSeverity</a></li><li><a href="#type_RemoveContentOverlay">RemoveContentOverlay</a></li><li><a href="#type_RequestError">RequestError</a></li><li><a href="#type_RequestErrorCode">RequestErrorCode</a></li><li><a href="#type_SearchId">SearchId</a></li><li><a href="#type_SearchResult">SearchResult</a></li><li><a href="#type_SearchResultKind">SearchResultKind</a></li><li><a href="#type_ServerService">ServerService</a></li><li><a href="#type_SourceChange">SourceChange</a></li><li><a href="#type_SourceEdit">SourceEdit</a></li><li><a href="#type_SourceFileEdit">SourceFileEdit</a></li><li><a href="#type_TypeHierarchyItem">TypeHierarchyItem</a></li></ul></div><h3>Refactorings (<a href="#refactorings">↑</a>)</h3><div class="subindex"><ul><li><a href="#refactoring_CONVERT_GETTER_TO_METHOD">CONVERT_GETTER_TO_METHOD</a></li><li><a href="#refactoring_CONVERT_METHOD_TO_GETTER">CONVERT_METHOD_TO_GETTER</a></li><li><a href="#refactoring_EXTRACT_LOCAL_VARIABLE">EXTRACT_LOCAL_VARIABLE</a></li><li><a href="#refactoring_EXTRACT_METHOD">EXTRACT_METHOD</a></li><li><a href="#refactoring_INLINE_LOCAL_VARIABLE">INLINE_LOCAL_VARIABLE</a></li><li><a href="#refactoring_INLINE_METHOD">INLINE_METHOD</a></li><li><a href="#refactoring_MOVE_FILE">MOVE_FILE</a></li><li><a href="#refactoring_RENAME">RENAME</a></li></ul></div>
   
 
 </body></html>
\ No newline at end of file
diff --git a/pkg/analysis_server/lib/analysis/index_core.dart b/pkg/analysis_server/lib/analysis/index_core.dart
index aac9d8a..58e996e 100644
--- a/pkg/analysis_server/lib/analysis/index_core.dart
+++ b/pkg/analysis_server/lib/analysis/index_core.dart
@@ -12,6 +12,16 @@
 import 'package:analyzer/src/generated/source.dart';
 
 /**
+ * Return the integer value that corresponds to the given [string]. The value of
+ * [string] may be `null`.
+ *
+ * Clients are not expected to implement this signature. A function of this type
+ * is provided by the framework to clients in order to implement the method
+ * [IndexableObjectKind.encodeHash].
+ */
+typedef int StringToInt(String string);
+
+/**
  * An object that can have a [Relationship] with various [Location]s in a code
  * base. The object is abstractly represented by a [kind] and an [offset] within
  * a [source].
@@ -29,17 +39,6 @@
   IndexableObjectKind get kind;
 
   /**
-   * Return the length of the indexable object within its source.
-   */
-  int get length;
-
-  /**
-   * Return the name of this element.
-   */
-  // TODO(brianwilkerson) Remove the need for this getter.
-  String get name;
-
-  /**
    * Return the offset of the indexable object within its source.
    */
   int get offset;
@@ -88,6 +87,27 @@
   IndexableObject decode(AnalysisContext context, String filePath, int offset);
 
   /**
+   * Returns the hash value that corresponds to the given [indexable].
+   *
+   * This hash is used to remember buckets with relations of the given
+   * [indexable]. Usually the name of the indexable object is encoded
+   * using [stringToInt] and mixed with other information to produce the final
+   * result.
+   *
+   * Clients must ensure that the same value is returned for the same object.
+   *
+   * Returned values must have good selectivity, e.g. if it is possible that
+   * there are many different objects with the same name, then additional
+   * information should be mixed in, for example the hash of the source that
+   * declares the given [indexable].
+   *
+   * Clients don't have to use name to compute this result, so if an indexable
+   * object does not have a name, some other value may be returned, but it still
+   * must be always the same for the same object and have good selectivity.
+   */
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable);
+
+  /**
    * Return the object kind with the given [index].
    */
   static IndexableObjectKind getKind(int index) {
@@ -121,20 +141,6 @@
   void contributeTo(IndexStore store, AnalysisContext context, Object object);
 }
 
-// A sketch of what the driver routine might look like:
-//
-//void buildIndexForSource(AnalysisContext context, Source source) {
-//  IndexStoreImpl store;
-//  store.aboutToIndex(context, source);
-//  try {
-//    for (IndexContributor contributor in contributors) {
-//      contributor.contributeTo(store, context, source);
-//    }
-//  } finally {
-//    store.doneIndexing();
-//  }
-//}
-
 /**
  * An object that stores information about the relationships between locations
  * in a code base.
diff --git a/pkg/analysis_server/lib/analysis/navigation_core.dart b/pkg/analysis_server/lib/analysis/navigation_core.dart
index e2f56f8..2e2623d 100644
--- a/pkg/analysis_server/lib/analysis/navigation_core.dart
+++ b/pkg/analysis_server/lib/analysis/navigation_core.dart
@@ -25,8 +25,7 @@
 }
 
 /**
- * An object that [NavigationContributor]s use to record navigation regions
- * into.
+ * An object that [NavigationContributor]s use to record navigation regions.
  *
  * Clients are not expected to subtype this class.
  */
diff --git a/pkg/analysis_server/lib/plugin/occurrences.dart b/pkg/analysis_server/lib/plugin/occurrences.dart
index 5339ccc..eaabc26 100644
--- a/pkg/analysis_server/lib/plugin/occurrences.dart
+++ b/pkg/analysis_server/lib/plugin/occurrences.dart
@@ -5,6 +5,23 @@
 /**
  * Support for client code that extends the analysis server by adding new
  * occurrences contributors.
+ *
+ * Plugins can register occurrences contributors. The registered contributors
+ * will be used to get occurrence information any time the server is about to
+ * send an 'analysis.occurrences' notification.
+ *
+ * If a plugin wants to add occurrence information, it should implement the
+ * class [OccurrencesContributor] and then register the contributor by including
+ * code like the following in the plugin's registerExtensions method:
+ *
+ *     @override
+ *     void registerExtensions(RegisterExtension registerExtension) {
+ *       ...
+ *       registerExtension(
+ *           OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID,
+ *           new MyOccurrencesContributor());
+ *       ...
+ *     }
  */
 library analysis_server.plugin.occurrences;
 
@@ -14,8 +31,8 @@
 
 /**
  * The identifier of the extension point that allows plugins to register
- * element occurrences. The object used as an extension must be
- * a [OccurrencesContributor].
+ * occurrence information. The object used as an extension must be an
+ * [OccurrencesContributor].
  */
 final String OCCURRENCES_CONTRIBUTOR_EXTENSION_POINT_ID = Plugin.join(
     ServerPlugin.UNIQUE_IDENTIFIER,
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index cee3508..8cb08b0 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -70,7 +70,7 @@
    * The version of the analysis server. The value should be replaced
    * automatically during the build.
    */
-  static final String VERSION = '1.9.0';
+  static final String VERSION = '1.12.0';
 
   /**
    * The number of milliseconds to perform operations before inserting
@@ -1002,7 +1002,9 @@
               case AnalysisService.OUTLINE:
                 AnalysisContext context = dartUnit.element.context;
                 LineInfo lineInfo = context.getLineInfo(source);
-                sendAnalysisNotificationOutline(this, file, lineInfo, dartUnit);
+                SourceKind kind = context.getKindOf(source);
+                sendAnalysisNotificationOutline(
+                    this, file, lineInfo, kind, dartUnit);
                 break;
               case AnalysisService.OVERRIDES:
                 sendAnalysisNotificationOverrides(this, file, dartUnit);
@@ -1221,8 +1223,15 @@
               if (dartUnits != null) {
                 AnalysisErrorInfo errorInfo = context.getErrors(source);
                 for (var dartUnit in dartUnits) {
-                  scheduleNotificationOperations(this, file, errorInfo.lineInfo,
-                      context, null, dartUnit, errorInfo.errors);
+                  scheduleNotificationOperations(
+                      this,
+                      source,
+                      file,
+                      errorInfo.lineInfo,
+                      context,
+                      null,
+                      dartUnit,
+                      errorInfo.errors);
                   scheduleIndexOperation(this, file, context, dartUnit);
                 }
               } else {
diff --git a/pkg/analysis_server/lib/src/computer/computer_hover.dart b/pkg/analysis_server/lib/src/computer/computer_hover.dart
index c09668b..8d870c0 100644
--- a/pkg/analysis_server/lib/src/computer/computer_hover.dart
+++ b/pkg/analysis_server/lib/src/computer/computer_hover.dart
@@ -111,9 +111,7 @@
           }
         }
         // documentation
-        String dartDoc = element.computeDocumentationComment();
-        dartDoc = _removeDartDocDelimiters(dartDoc);
-        hover.dartdoc = dartDoc;
+        hover.dartdoc = _computeDocumentation(element);
       }
       // parameter
       hover.parameter = _safeToString(expression.bestParameterElement);
@@ -127,5 +125,13 @@
     return null;
   }
 
+  String _computeDocumentation(Element element) {
+    if (element is ParameterElement) {
+      element = element.enclosingElement;
+    }
+    String dartDoc = element.computeDocumentationComment();
+    return _removeDartDocDelimiters(dartDoc);
+  }
+
   static _safeToString(obj) => obj != null ? obj.toString() : null;
 }
diff --git a/pkg/analysis_server/lib/src/constants.dart b/pkg/analysis_server/lib/src/constants.dart
index 391e41c..a32ad98 100644
--- a/pkg/analysis_server/lib/src/constants.dart
+++ b/pkg/analysis_server/lib/src/constants.dart
@@ -137,6 +137,7 @@
 const String FILES = 'files';
 const String FIXES = 'fixes';
 const String FLAGS = 'flags';
+const String HAS_FIX = 'hasFix';
 const String HIERARCHY_ITEMS = 'hierarchyItems';
 const String HOVERS = 'hovers';
 const String ID = 'id';
diff --git a/pkg/analysis_server/lib/src/domain_completion.dart b/pkg/analysis_server/lib/src/domain_completion.dart
index 81d7bf2..970e189 100644
--- a/pkg/analysis_server/lib/src/domain_completion.dart
+++ b/pkg/analysis_server/lib/src/domain_completion.dart
@@ -6,12 +6,12 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/context_manager.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
index 0891156..f96f42f 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/implemented_dart.dart
@@ -22,6 +22,15 @@
 
   compute() async {
     for (ClassElement type in unitElement.types) {
+      // always include Object and its members
+      if (type.supertype == null) {
+        _addImplementedClass(type);
+        type.accessors.forEach(_addImplementedMember);
+        type.fields.forEach(_addImplementedMember);
+        type.methods.forEach(_addImplementedMember);
+        continue;
+      }
+      // analyze ancestors
       subtypes = await getSubClasses(searchEngine, type);
       if (subtypes.isNotEmpty) {
         _addImplementedClass(type);
diff --git a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
index 8b87629..f1b9100 100644
--- a/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
+++ b/pkg/analysis_server/lib/src/domains/analysis/navigation_dart.dart
@@ -74,6 +74,9 @@
   }
 
   void _addRegionForNode(AstNode node, Element element) {
+    if (node == null) {
+      return;
+    }
     int offset = node.offset;
     int length = node.length;
     _addRegion(offset, length, element);
@@ -92,6 +95,30 @@
   _DartNavigationComputerVisitor(this.computer);
 
   @override
+  visitAnnotation(Annotation node) {
+    Element element = node.element;
+    if (element is ConstructorElement && element.isSynthetic) {
+      element = element.enclosingElement;
+    }
+    Identifier name = node.name;
+    if (name is PrefixedIdentifier) {
+      // use constructor in: @PrefixClass.constructorName
+      Element prefixElement = name.prefix.staticElement;
+      if (prefixElement is ClassElement) {
+        prefixElement = element;
+      }
+      computer._addRegionForNode(name.prefix, prefixElement);
+      // always constructor
+      computer._addRegionForNode(name.identifier, element);
+    } else {
+      computer._addRegionForNode(name, element);
+    }
+    computer._addRegionForNode(node.constructorName, element);
+    // arguments
+    _safelyVisit(node.arguments);
+  }
+
+  @override
   visitAssignmentExpression(AssignmentExpression node) {
     _safelyVisit(node.leftHandSide);
     computer._addRegionForToken(node.operator, node.bestElement);
diff --git a/pkg/analysis_server/lib/src/edit/edit_domain.dart b/pkg/analysis_server/lib/src/edit/edit_domain.dart
index cb7b513..f6c298d 100644
--- a/pkg/analysis_server/lib/src/edit/edit_domain.dart
+++ b/pkg/analysis_server/lib/src/edit/edit_domain.dart
@@ -557,7 +557,8 @@
       List<CompilationUnit> units = server.getResolvedCompilationUnits(file);
       if (units.isNotEmpty) {
         refactoring = new ExtractLocalRefactoring(units[0], offset, length);
-        feedback = new ExtractLocalVariableFeedback([], [], []);
+        feedback = new ExtractLocalVariableFeedback(
+            <int>[], <int>[], <String>[], <int>[], <int>[]);
       }
     }
     if (kind == RefactoringKind.EXTRACT_METHOD) {
@@ -565,8 +566,8 @@
       if (units.isNotEmpty) {
         refactoring = new ExtractMethodRefactoring(
             searchEngine, units[0], offset, length);
-        feedback = new ExtractMethodFeedback(
-            offset, length, '', [], false, [], [], []);
+        feedback = new ExtractMethodFeedback(offset, length, '', <String>[],
+            false, <RefactoringMethodParameter>[], <int>[], <int>[]);
       }
     }
     if (kind == RefactoringKind.INLINE_LOCAL_VARIABLE) {
diff --git a/pkg/analysis_server/lib/src/generated_protocol.dart b/pkg/analysis_server/lib/src/generated_protocol.dart
index c396864..4c95b37e 100644
--- a/pkg/analysis_server/lib/src/generated_protocol.dart
+++ b/pkg/analysis_server/lib/src/generated_protocol.dart
@@ -3158,12 +3158,18 @@
  *
  * {
  *   "file": FilePath
+ *   "kind": FileKind
+ *   "libraryName": optional String
  *   "outline": Outline
  * }
  */
 class AnalysisOutlineParams implements HasToJson {
   String _file;
 
+  FileKind _kind;
+
+  String _libraryName;
+
   Outline _outline;
 
   /**
@@ -3180,6 +3186,39 @@
   }
 
   /**
+   * The kind of the file.
+   */
+  FileKind get kind => _kind;
+
+  /**
+   * The kind of the file.
+   */
+  void set kind(FileKind value) {
+    assert(value != null);
+    this._kind = value;
+  }
+
+  /**
+   * The name of the library defined by the file using a "library" directive,
+   * or referenced by a "part of" directive. If both "library" and "part of"
+   * directives are present, then the "library" directive takes precedence.
+   * This field will be omitted if the file has neither "library" nor "part of"
+   * directives.
+   */
+  String get libraryName => _libraryName;
+
+  /**
+   * The name of the library defined by the file using a "library" directive,
+   * or referenced by a "part of" directive. If both "library" and "part of"
+   * directives are present, then the "library" directive takes precedence.
+   * This field will be omitted if the file has neither "library" nor "part of"
+   * directives.
+   */
+  void set libraryName(String value) {
+    this._libraryName = value;
+  }
+
+  /**
    * The outline associated with the file.
    */
   Outline get outline => _outline;
@@ -3192,8 +3231,10 @@
     this._outline = value;
   }
 
-  AnalysisOutlineParams(String file, Outline outline) {
+  AnalysisOutlineParams(String file, FileKind kind, Outline outline, {String libraryName}) {
     this.file = file;
+    this.kind = kind;
+    this.libraryName = libraryName;
     this.outline = outline;
   }
 
@@ -3208,13 +3249,23 @@
       } else {
         throw jsonDecoder.missingKey(jsonPath, "file");
       }
+      FileKind kind;
+      if (json.containsKey("kind")) {
+        kind = new FileKind.fromJson(jsonDecoder, jsonPath + ".kind", json["kind"]);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "kind");
+      }
+      String libraryName;
+      if (json.containsKey("libraryName")) {
+        libraryName = jsonDecoder._decodeString(jsonPath + ".libraryName", json["libraryName"]);
+      }
       Outline outline;
       if (json.containsKey("outline")) {
         outline = new Outline.fromJson(jsonDecoder, jsonPath + ".outline", json["outline"]);
       } else {
         throw jsonDecoder.missingKey(jsonPath, "outline");
       }
-      return new AnalysisOutlineParams(file, outline);
+      return new AnalysisOutlineParams(file, kind, outline, libraryName: libraryName);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "analysis.outline params", json);
     }
@@ -3228,6 +3279,10 @@
   Map<String, dynamic> toJson() {
     Map<String, dynamic> result = {};
     result["file"] = file;
+    result["kind"] = kind.toJson();
+    if (libraryName != null) {
+      result["libraryName"] = libraryName;
+    }
     result["outline"] = outline.toJson();
     return result;
   }
@@ -3243,6 +3298,8 @@
   bool operator==(other) {
     if (other is AnalysisOutlineParams) {
       return file == other.file &&
+          kind == other.kind &&
+          libraryName == other.libraryName &&
           outline == other.outline;
     }
     return false;
@@ -3252,6 +3309,8 @@
   int get hashCode {
     int hash = 0;
     hash = _JenkinsSmiHash.combine(hash, file.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, kind.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, libraryName.hashCode);
     hash = _JenkinsSmiHash.combine(hash, outline.hashCode);
     return _JenkinsSmiHash.finish(hash);
   }
@@ -7288,6 +7347,7 @@
  *   "location": Location
  *   "message": String
  *   "correction": optional String
+ *   "hasFix": optional bool
  * }
  */
 class AnalysisError implements HasToJson {
@@ -7301,6 +7361,8 @@
 
   String _correction;
 
+  bool _hasFix;
+
   /**
    * The severity of the error.
    */
@@ -7371,12 +7433,39 @@
     this._correction = value;
   }
 
-  AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction}) {
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  bool get hasFix => _hasFix;
+
+  /**
+   * A hint to indicate to interested clients that this error has an associated
+   * fix (or fixes). The absence of this field implies there are not known to
+   * be fixes. Note that since the operation to calculate whether fixes apply
+   * needs to be performant it is possible that complicated tests will be
+   * skipped and a false negative returned. For this reason, this attribute
+   * should be treated as a "hint". Despite the possibility of false negatives,
+   * no false positives should be returned. If a client sees this flag set they
+   * can proceed with the confidence that there are in fact associated fixes.
+   */
+  void set hasFix(bool value) {
+    this._hasFix = value;
+  }
+
+  AnalysisError(AnalysisErrorSeverity severity, AnalysisErrorType type, Location location, String message, {String correction, bool hasFix}) {
     this.severity = severity;
     this.type = type;
     this.location = location;
     this.message = message;
     this.correction = correction;
+    this.hasFix = hasFix;
   }
 
   factory AnalysisError.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
@@ -7412,7 +7501,11 @@
       if (json.containsKey("correction")) {
         correction = jsonDecoder._decodeString(jsonPath + ".correction", json["correction"]);
       }
-      return new AnalysisError(severity, type, location, message, correction: correction);
+      bool hasFix;
+      if (json.containsKey("hasFix")) {
+        hasFix = jsonDecoder._decodeBool(jsonPath + ".hasFix", json["hasFix"]);
+      }
+      return new AnalysisError(severity, type, location, message, correction: correction, hasFix: hasFix);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "AnalysisError", json);
     }
@@ -7427,6 +7520,9 @@
     if (correction != null) {
       result["correction"] = correction;
     }
+    if (hasFix != null) {
+      result["hasFix"] = hasFix;
+    }
     return result;
   }
 
@@ -7440,7 +7536,8 @@
           type == other.type &&
           location == other.location &&
           message == other.message &&
-          correction == other.correction;
+          correction == other.correction &&
+          hasFix == other.hasFix;
     }
     return false;
   }
@@ -7453,6 +7550,7 @@
     hash = _JenkinsSmiHash.combine(hash, location.hashCode);
     hash = _JenkinsSmiHash.combine(hash, message.hashCode);
     hash = _JenkinsSmiHash.combine(hash, correction.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, hasFix.hashCode);
     return _JenkinsSmiHash.finish(hash);
   }
 }
@@ -9511,6 +9609,55 @@
 }
 
 /**
+ * FileKind
+ *
+ * enum {
+ *   LIBRARY
+ *   PART
+ * }
+ */
+class FileKind implements Enum {
+  static const LIBRARY = const FileKind._("LIBRARY");
+
+  static const PART = const FileKind._("PART");
+
+  /**
+   * A list containing all of the enum values that are defined.
+   */
+  static const List<FileKind> VALUES = const <FileKind>[LIBRARY, PART];
+
+  final String name;
+
+  const FileKind._(this.name);
+
+  factory FileKind(String name) {
+    switch (name) {
+      case "LIBRARY":
+        return LIBRARY;
+      case "PART":
+        return PART;
+    }
+    throw new Exception('Illegal enum value: $name');
+  }
+
+  factory FileKind.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {
+    if (json is String) {
+      try {
+        return new FileKind(json);
+      } catch(_) {
+        // Fall through
+      }
+    }
+    throw jsonDecoder.mismatch(jsonPath, "FileKind", json);
+  }
+
+  @override
+  String toString() => "FileKind.$name";
+
+  String toJson() => name;
+}
+
+/**
  * FoldingKind
  *
  * enum {
@@ -14573,12 +14720,18 @@
  * extractLocalVariable feedback
  *
  * {
+ *   "coveringExpressionOffsets": List<int>
+ *   "coveringExpressionLengths": List<int>
  *   "names": List<String>
  *   "offsets": List<int>
  *   "lengths": List<int>
  * }
  */
 class ExtractLocalVariableFeedback extends RefactoringFeedback implements HasToJson {
+  List<int> _coveringExpressionOffsets;
+
+  List<int> _coveringExpressionLengths;
+
   List<String> _names;
 
   List<int> _offsets;
@@ -14586,6 +14739,36 @@
   List<int> _lengths;
 
   /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionOffsets => _coveringExpressionOffsets;
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionOffsets(List<int> value) {
+    assert(value != null);
+    this._coveringExpressionOffsets = value;
+  }
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  List<int> get coveringExpressionLengths => _coveringExpressionLengths;
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from
+   * the down most to the up most.
+   */
+  void set coveringExpressionLengths(List<int> value) {
+    assert(value != null);
+    this._coveringExpressionLengths = value;
+  }
+
+  /**
    * The proposed names for the local variable.
    */
   List<String> get names => _names;
@@ -14632,7 +14815,9 @@
     this._lengths = value;
   }
 
-  ExtractLocalVariableFeedback(List<String> names, List<int> offsets, List<int> lengths) {
+  ExtractLocalVariableFeedback(List<int> coveringExpressionOffsets, List<int> coveringExpressionLengths, List<String> names, List<int> offsets, List<int> lengths) {
+    this.coveringExpressionOffsets = coveringExpressionOffsets;
+    this.coveringExpressionLengths = coveringExpressionLengths;
     this.names = names;
     this.offsets = offsets;
     this.lengths = lengths;
@@ -14643,6 +14828,18 @@
       json = {};
     }
     if (json is Map) {
+      List<int> coveringExpressionOffsets;
+      if (json.containsKey("coveringExpressionOffsets")) {
+        coveringExpressionOffsets = jsonDecoder._decodeList(jsonPath + ".coveringExpressionOffsets", json["coveringExpressionOffsets"], jsonDecoder._decodeInt);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "coveringExpressionOffsets");
+      }
+      List<int> coveringExpressionLengths;
+      if (json.containsKey("coveringExpressionLengths")) {
+        coveringExpressionLengths = jsonDecoder._decodeList(jsonPath + ".coveringExpressionLengths", json["coveringExpressionLengths"], jsonDecoder._decodeInt);
+      } else {
+        throw jsonDecoder.missingKey(jsonPath, "coveringExpressionLengths");
+      }
       List<String> names;
       if (json.containsKey("names")) {
         names = jsonDecoder._decodeList(jsonPath + ".names", json["names"], jsonDecoder._decodeString);
@@ -14661,7 +14858,7 @@
       } else {
         throw jsonDecoder.missingKey(jsonPath, "lengths");
       }
-      return new ExtractLocalVariableFeedback(names, offsets, lengths);
+      return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
     } else {
       throw jsonDecoder.mismatch(jsonPath, "extractLocalVariable feedback", json);
     }
@@ -14669,6 +14866,8 @@
 
   Map<String, dynamic> toJson() {
     Map<String, dynamic> result = {};
+    result["coveringExpressionOffsets"] = coveringExpressionOffsets;
+    result["coveringExpressionLengths"] = coveringExpressionLengths;
     result["names"] = names;
     result["offsets"] = offsets;
     result["lengths"] = lengths;
@@ -14681,7 +14880,9 @@
   @override
   bool operator==(other) {
     if (other is ExtractLocalVariableFeedback) {
-      return _listEqual(names, other.names, (String a, String b) => a == b) &&
+      return _listEqual(coveringExpressionOffsets, other.coveringExpressionOffsets, (int a, int b) => a == b) &&
+          _listEqual(coveringExpressionLengths, other.coveringExpressionLengths, (int a, int b) => a == b) &&
+          _listEqual(names, other.names, (String a, String b) => a == b) &&
           _listEqual(offsets, other.offsets, (int a, int b) => a == b) &&
           _listEqual(lengths, other.lengths, (int a, int b) => a == b);
     }
@@ -14691,6 +14892,8 @@
   @override
   int get hashCode {
     int hash = 0;
+    hash = _JenkinsSmiHash.combine(hash, coveringExpressionOffsets.hashCode);
+    hash = _JenkinsSmiHash.combine(hash, coveringExpressionLengths.hashCode);
     hash = _JenkinsSmiHash.combine(hash, names.hashCode);
     hash = _JenkinsSmiHash.combine(hash, offsets.hashCode);
     hash = _JenkinsSmiHash.combine(hash, lengths.hashCode);
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 198955c..973b831 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -77,6 +77,7 @@
  */
 void scheduleNotificationOperations(
     AnalysisServer server,
+    Source source,
     String file,
     LineInfo lineInfo,
     AnalysisContext context,
@@ -99,12 +100,10 @@
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.NAVIGATION, file)) {
-      Source source = resolvedDartUnit.element.source;
       server.scheduleOperation(new NavigationOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OCCURRENCES, file)) {
-      Source source = resolvedDartUnit.element.source;
       server.scheduleOperation(new OccurrencesOperation(context, source));
     }
     if (server.hasAnalysisSubscription(
@@ -116,8 +115,9 @@
   if (dartUnit != null) {
     if (server.hasAnalysisSubscription(
         protocol.AnalysisService.OUTLINE, file)) {
-      server.scheduleOperation(
-          new _DartOutlineOperation(context, file, lineInfo, dartUnit));
+      SourceKind sourceKind = context.getKindOf(source);
+      server.scheduleOperation(new _DartOutlineOperation(
+          context, file, lineInfo, sourceKind, dartUnit));
     }
   }
   // errors
@@ -213,11 +213,23 @@
 }
 
 void sendAnalysisNotificationOutline(AnalysisServer server, String file,
-    LineInfo lineInfo, CompilationUnit dartUnit) {
+    LineInfo lineInfo, SourceKind sourceKind, CompilationUnit dartUnit) {
   _sendNotification(server, () {
+    // compute FileKind
+    protocol.FileKind fileKind = protocol.FileKind.LIBRARY;
+    if (sourceKind == SourceKind.LIBRARY) {
+      fileKind = protocol.FileKind.LIBRARY;
+    } else if (sourceKind == SourceKind.PART) {
+      fileKind = protocol.FileKind.PART;
+    }
+    // compute library name
+    String libraryName = _computeLibraryName(dartUnit);
+    // compute Outline
     var computer = new DartUnitOutlineComputer(file, lineInfo, dartUnit);
-    var outline = computer.compute();
-    var params = new protocol.AnalysisOutlineParams(file, outline);
+    protocol.Outline outline = computer.compute();
+    // send notification
+    var params = new protocol.AnalysisOutlineParams(file, fileKind, outline,
+        libraryName: libraryName);
     server.sendNotification(params.toNotification());
   });
 }
@@ -241,6 +253,20 @@
   context.analysisOptions = options;
 }
 
+String _computeLibraryName(CompilationUnit unit) {
+  for (Directive directive in unit.directives) {
+    if (directive is LibraryDirective && directive.name != null) {
+      return directive.name.name;
+    }
+  }
+  for (Directive directive in unit.directives) {
+    if (directive is PartOfDirective && directive.libraryName != null) {
+      return directive.libraryName.name;
+    }
+  }
+  return null;
+}
+
 /**
  * Runs the given notification producing function [f], catching exceptions.
  */
@@ -371,8 +397,8 @@
       // Dart
       CompilationUnit parsedDartUnit = notice.parsedDartUnit;
       CompilationUnit resolvedDartUnit = notice.resolvedDartUnit;
-      scheduleNotificationOperations(server, file, notice.lineInfo, context,
-          parsedDartUnit, resolvedDartUnit, notice.errors);
+      scheduleNotificationOperations(server, source, file, notice.lineInfo,
+          context, parsedDartUnit, resolvedDartUnit, notice.errors);
       // done
       server.fileAnalyzed(notice);
     }
@@ -455,14 +481,15 @@
 
 class _DartOutlineOperation extends _DartNotificationOperation {
   final LineInfo lineInfo;
+  final SourceKind sourceKind;
 
-  _DartOutlineOperation(
-      AnalysisContext context, String file, this.lineInfo, CompilationUnit unit)
+  _DartOutlineOperation(AnalysisContext context, String file, this.lineInfo,
+      this.sourceKind, CompilationUnit unit)
       : super(context, file, unit);
 
   @override
   void perform(AnalysisServer server) {
-    sendAnalysisNotificationOutline(server, file, lineInfo, unit);
+    sendAnalysisNotificationOutline(server, file, lineInfo, sourceKind, unit);
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/plugin/server_plugin.dart b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
index b88d009..4e227b4 100644
--- a/pkg/analysis_server/lib/src/plugin/server_plugin.dart
+++ b/pkg/analysis_server/lib/src/plugin/server_plugin.dart
@@ -8,7 +8,6 @@
 import 'package:analysis_server/analysis/index_core.dart';
 import 'package:analysis_server/analysis/navigation_core.dart';
 import 'package:analysis_server/analysis/occurrences_core.dart';
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/edit/assist/assist_core.dart';
 import 'package:analysis_server/edit/fix/fix_core.dart';
 import 'package:analysis_server/plugin/analyzed_files.dart';
@@ -26,6 +25,7 @@
 import 'package:analysis_server/src/domains/analysis/occurrences_dart.dart';
 import 'package:analysis_server/src/edit/edit_domain.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:analysis_server/src/search/search_domain.dart';
 import 'package:analysis_server/src/services/correction/assist_internal.dart';
 import 'package:analysis_server/src/services/correction/fix_internal.dart';
diff --git a/pkg/analysis_server/lib/src/protocol_server.dart b/pkg/analysis_server/lib/src/protocol_server.dart
index a9dd5dd..705b7aa 100644
--- a/pkg/analysis_server/lib/src/protocol_server.dart
+++ b/pkg/analysis_server/lib/src/protocol_server.dart
@@ -5,6 +5,7 @@
 library protocol.server;
 
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/services/correction/fix.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart'
     as engine;
 import 'package:analyzer/src/generated/ast.dart' as engine;
@@ -92,8 +93,9 @@
   var type = new AnalysisErrorType(errorCode.type.name);
   String message = error.message;
   String correction = error.correction;
+  bool fix = hasFix(error.errorCode);
   return new AnalysisError(severity, type, location, message,
-      correction: correction);
+      correction: correction, hasFix: fix);
 }
 
 /**
diff --git a/pkg/analysis_server/lib/plugin/completion.dart b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
similarity index 90%
rename from pkg/analysis_server/lib/plugin/completion.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion.dart
index 9b1c4b5..9a71bc0 100644
--- a/pkg/analysis_server/lib/plugin/completion.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion.dart
@@ -23,10 +23,10 @@
  *       ...
  *     }
  */
-library analysis_server.plugin.completion;
+library analysis_server.src.provisional.completion.completion;
 
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:plugin/plugin.dart';
 
 /**
diff --git a/pkg/analysis_server/lib/completion/completion_core.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/completion_core.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_core.dart
index 5003faf..f38d541 100644
--- a/pkg/analysis_server/lib/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_core.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.
 
-library analysis_server.completion.completion_core;
+library analysis_server.src.provisional.completion.completion_core;
 
 import 'package:analysis_server/src/protocol.dart';
 import 'package:analyzer/file_system/file_system.dart';
diff --git a/pkg/analysis_server/lib/completion/completion_dart.dart b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
similarity index 91%
rename from pkg/analysis_server/lib/completion/completion_dart.dart
rename to pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
index 1ddd5a0..488f30d 100644
--- a/pkg/analysis_server/lib/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/completion_dart.dart
@@ -2,14 +2,14 @@
 // 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 analysis_server.completion.completion_dart;
+library analysis_server.src.provisional.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
 
 /**
  * An object used to produce completions for a specific error within a Dart
@@ -66,9 +66,10 @@
   bool get isResolved;
 
   /**
-   * Return the compilation unit in which the completion was requested.
+   * Return the completion target.  This determines what part of the parse tree
+   * will receive the newly inserted text.
    */
-  CompilationUnit get unit;
+  CompletionTarget get target;
 
   /**
    * Cached information from a prior code completion operation.
@@ -76,10 +77,9 @@
   //DartCompletionCache get cache;
 
   /**
-   * Return the completion target.  This determines what part of the parse tree
-   * will receive the newly inserted text.
+   * Return the compilation unit in which the completion was requested.
    */
-  CompletionTarget get target;
+  CompilationUnit get unit;
 
   /**
    * Information about the types of suggestions that should be included.
diff --git a/pkg/analysis_server/lib/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
similarity index 97%
rename from pkg/analysis_server/lib/completion/dart/completion_target.dart
rename to pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index a1f315b..b24c610 100644
--- a/pkg/analysis_server/lib/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -1,3 +1,9 @@
+// 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 analysis_server.src.provisional.completion.dart.completion_target;
+
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/scanner.dart';
diff --git a/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
new file mode 100644
index 0000000..f1c9f94
--- /dev/null
+++ b/pkg/analysis_server/lib/src/provisional/refactoring/refactoring_core.dart
@@ -0,0 +1,102 @@
+// 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 analysis_server.edit.refactoring.refactoring_core;
+
+import 'dart:async';
+
+import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/source.dart';
+
+/**
+ * Abstract interface for all refactorings.
+ */
+abstract class Refactoring {
+  /**
+   * Return the ids of source edits that are not known to be valid.
+   *
+   * An edit is not known to be valid if there was insufficient type information
+   * for the server to be able to determine whether or not the code needs to be
+   * modified, such as when a member is being renamed and there is a reference
+   * to a member from an unknown type. This field will be omitted if the change
+   * field is omitted or if there are no potential edits for the refactoring.
+   */
+  List<String> get potentialEditIds;
+
+  /**
+   * Return the human readable name of this refactoring.
+   */
+  String get refactoringName;
+
+  /**
+   * Checks all conditions - [checkInitialConditions] and
+   * [checkFinalConditions] to decide if refactoring can be performed.
+   */
+  Future<RefactoringStatus> checkAllConditions();
+
+  /**
+   * Validates environment to check if this refactoring can be performed.
+   *
+   * This check may be slow, because many refactorings use search engine.
+   */
+  Future<RefactoringStatus> checkFinalConditions();
+
+  /**
+   * Validates arguments to check if this refactoring can be performed.
+   *
+   * This check should be quick because it is used often as arguments change.
+   */
+  Future<RefactoringStatus> checkInitialConditions();
+
+  /**
+   * Return the [Change] to apply to perform this refactoring.
+   */
+  Future<SourceChange> createChange();
+
+  /**
+   * Return `true` if the [Change] created by refactoring may be unsafe,
+   * so we want user to review the [Change] to ensure that he understands it.
+   */
+  bool requiresPreview();
+}
+
+/**
+ *
+ *
+ * Clients are expected to subtype this class when implementing plugins.
+ */
+abstract class RefactoringContributor {
+  /**
+   *
+   */
+  Refactoring createRefactoring(AnalysisContext context, RefactoringKind kind,
+      Source source, int offset, int length);
+
+  /**
+   *
+   */
+  List<RefactoringKind> getAvailableRefactorings(
+      AnalysisContext context, Source source, int offset, int length);
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringKind {
+  factory RefactoringKind(String name, bool requiresOptions) {
+  } // TODO(brianwilkerson) Redirect to impl class.
+  bool get requiresOptions;
+}
+
+/**
+ *
+ *
+ * Clients are not expected to subtype this class.
+ */
+abstract class RefactoringStatus {
+  // TODO(brianwilkerson) Fill this in.
+}
diff --git a/pkg/analysis_server/lib/src/server/driver.dart b/pkg/analysis_server/lib/src/server/driver.dart
index c5eb6bf..883f50c4e 100644
--- a/pkg/analysis_server/lib/src/server/driver.dart
+++ b/pkg/analysis_server/lib/src/server/driver.dart
@@ -206,6 +206,11 @@
   static const String CLIENT_VERSION = "client-version";
 
   /**
+   * The name of the option used to disable the use of the new task model.
+   */
+  static const String DISABLE_NEW_TASK_MODEL = "disable-new-task-model";
+
+  /**
    * The name of the option used to enable incremental resolution of API
    * changes.
    */
@@ -218,11 +223,6 @@
   static const String ENABLE_INSTRUMENTATION_OPTION = "enable-instrumentation";
 
   /**
-   * The name of the option used to enable the use of the new task model.
-   */
-  static const String ENABLE_NEW_TASK_MODEL = "enable-new-task-model";
-
-  /**
    * The name of the option used to set the file read mode.
    */
   static const String FILE_READ_MODE = "file-read-mode";
@@ -395,9 +395,7 @@
     //
     // Enable the new task model, if appropriate.
     //
-    if (results[ENABLE_NEW_TASK_MODEL]) {
-      AnalysisEngine.instance.useTaskModel = true;
-    }
+    AnalysisEngine.instance.useTaskModel = !results[DISABLE_NEW_TASK_MODEL];
     //
     // Process all of the plugins so that extensions are registered.
     //
@@ -470,6 +468,11 @@
     parser.addOption(CLIENT_ID,
         help: "an identifier used to identify the client");
     parser.addOption(CLIENT_VERSION, help: "the version of the client");
+    parser.addFlag(DISABLE_NEW_TASK_MODEL,
+        help: "disable the use of the new task model",
+        defaultsTo: false,
+        hide: true,
+        negatable: false);
     parser.addFlag(ENABLE_INCREMENTAL_RESOLUTION_API,
         help: "enable using incremental resolution for API changes",
         defaultsTo: false,
@@ -478,11 +481,6 @@
         help: "enable sending instrumentation information to a server",
         defaultsTo: false,
         negatable: false);
-    parser.addFlag(ENABLE_NEW_TASK_MODEL,
-        help: "enable the use of the new task model",
-        defaultsTo: false,
-        hide: true,
-        negatable: false);
     parser.addFlag(HELP_OPTION,
         help: "print this help message without starting a server",
         defaultsTo: false,
diff --git a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
index 61194fc..4f7780d 100644
--- a/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/arglist_contributor.dart
@@ -141,23 +141,20 @@
           }
         }
       }
-      if (parent is InstanceCreationExpression) {
-        ConstructorName constructorName = parent.constructorName;
-        if (constructorName != null) {
-          String name = constructorName.toSource();
-          if (name.length > 0) {
-            /*
-             * If a local declaration is found, then return null
-             * indicating that suggestions were added
-             * and no further action is necessary
-             */
-            if (new _LocalArgSuggestionBuilder(request, request.offset, name)
-                .visit(node)) {
-              return null;
-            }
-            return new _ArgSuggestionBuilder(request, name);
-          }
+      String constructorName;
+      if (parent is Annotation && parent.name != null) {
+        constructorName = parent.name.toSource();
+      }
+      if (parent is InstanceCreationExpression &&
+          parent.constructorName != null) {
+        constructorName = parent.constructorName.toSource();
+      }
+      if (constructorName != null && constructorName.length > 0) {
+        if (new _LocalArgSuggestionBuilder(
+            request, request.offset, constructorName).visit(node)) {
+          return null;
         }
+        return new _ArgSuggestionBuilder(request, constructorName);
       }
     }
     return null;
diff --git a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
index 2b391ca..e3c44ce 100644
--- a/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
+++ b/pkg/analysis_server/lib/src/services/completion/common_usage_computer.dart
@@ -4,10 +4,10 @@
 
 library services.completion.computer.dart.relevance;
 
-import 'package:analysis_server/completion/completion_dart.dart';
 import 'package:analysis_server/src/protocol_server.dart' as protocol;
 import 'package:analysis_server/src/protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
     show DART_RELEVANCE_COMMON_USAGE;
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_core.dart b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
index a8ed44b..68fa732 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_core.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_core.dart
@@ -4,7 +4,7 @@
 
 library analysis_server.src.services.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
 import 'package:analyzer/file_system/file_system.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
index 4304295..1cfff04 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_dart.dart
@@ -4,9 +4,9 @@
 
 library analysis_server.src.services.completion.completion_dart;
 
-import 'package:analysis_server/completion/completion_core.dart';
-import 'package:analysis_server/completion/completion_dart.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart';
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/completion_core.dart';
 import 'package:analyzer/src/generated/ast.dart';
 
diff --git a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
index ebc5054..178d76c 100644
--- a/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
+++ b/pkg/analysis_server/lib/src/services/completion/completion_manager.dart
@@ -6,10 +6,10 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/search/search_engine.dart';
 import 'package:analyzer/file_system/file_system.dart';
@@ -273,11 +273,9 @@
   CompletionResultImpl(this.replacementOffset, this.replacementLength,
       this.suggestions, this.last);
 
-  @override
-  // TODO(brianwilkerson) Figure out whether this is correct.
-  bool get hasNewSuggestions => suggestions.isNotEmpty;
-
-  @override
+  /**
+   * Return `true` if this is the last completion result that will be produced.
+   */
   bool get isLast => last;
 }
 
diff --git a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
index 737a837..3a5217b 100644
--- a/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
+++ b/pkg/analysis_server/lib/src/services/completion/contribution_sorter.dart
@@ -4,8 +4,8 @@
 
 library services.completion.sorter;
 
-import 'package:analysis_server/completion/completion_dart.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
 
 /**
  * The abstract class `ContributionSorter` defines the behavior of objects
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 ae177f2..2f19c64 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
@@ -6,12 +6,13 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
-import 'package:analysis_server/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
+    as newApi;
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/arglist_contributor.dart';
 import 'package:analysis_server/src/services/completion/combinator_contributor.dart';
 import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
@@ -182,7 +183,10 @@
       });
       contributionSorter.sort(
           new OldRequestWrapper(request), request.suggestions);
-      sendResults(request, todo.isEmpty);
+
+      if (todo.isEmpty) {
+        sendResults(request, todo.isEmpty);
+      }
       return todo;
     });
   }
diff --git a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
index 11d0631..410eb81 100644
--- a/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/inherited_contributor.dart
@@ -4,11 +4,11 @@
 
 library services.completion.computer.dart.invocation;
 
-import 'package:analysis_server/completion/completion_dart.dart';
 import 'package:analysis_server/src/protocol_server.dart'
     show CompletionSuggestion, CompletionSuggestionKind, SourceChange;
 import 'package:analysis_server/src/protocol_server.dart' as protocol
     hide CompletionSuggestion, CompletionSuggestionKind;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart'
     show DART_RELEVANCE_HIGH;
 import 'package:analysis_server/utilities/change_builder_dart.dart';
diff --git a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
index 6aa3536..fe9ef14 100644
--- a/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/keyword_contributor.dart
@@ -1,4 +1,5 @@
 // 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.
 
@@ -70,6 +71,9 @@
       }
     }
     _addStatementKeywords(node);
+    if (_inCatchClause(node)) {
+      _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
+    }
   }
 
   @override
@@ -446,7 +450,6 @@
       Keyword.VOID,
       Keyword.WHILE
     ]);
-    _addSuggestion(Keyword.RETHROW, DART_RELEVANCE_KEYWORD - 1);
   }
 
   void _addSuggestion(Keyword keyword,
@@ -481,6 +484,9 @@
     return body != null && body.isAsynchronous;
   }
 
+  bool _inCatchClause(Block node) =>
+      node.getAncestor((p) => p is CatchClause) != null;
+
   bool _inClassMemberBody(AstNode node) {
     while (true) {
       AstNode body = node.getAncestor((n) => n is FunctionBody);
diff --git a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
index 6fdb2b6..181f259 100644
--- a/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/local_reference_contributor.dart
@@ -351,9 +351,20 @@
 class _LocalVisitor extends LocalDeclarationVisitor {
   final DartCompletionRequest request;
   final OpType optype;
+  int privateMemberRelevance = DART_RELEVANCE_DEFAULT;
 
   _LocalVisitor(this.request, int offset, this.optype) : super(offset) {
     includeLocalInheritedTypes = !optype.inStaticMethodBody;
+    if (request.replacementLength > 0) {
+      var contents = request.context.getContents(request.source);
+      if (contents != null &&
+          contents.data != null &&
+          contents.data.startsWith('_', request.replacementOffset)) {
+        // If user typed identifier starting with '_'
+        // then do not suppress the relevance of private members
+        privateMemberRelevance = null;
+      }
+    }
   }
 
   @override
@@ -554,6 +565,10 @@
         id, isDeprecated, relevance, typeName,
         classDecl: classDecl);
     if (suggestion != null) {
+      if (privateMemberRelevance != null &&
+          suggestion.completion.startsWith('_')) {
+        suggestion.relevance = privateMemberRelevance;
+      }
       request.addSuggestion(suggestion);
       suggestion.element = createElement(request.source, elemKind, id,
           isAbstract: isAbstract,
diff --git a/pkg/analysis_server/lib/src/services/completion/optype.dart b/pkg/analysis_server/lib/src/services/completion/optype.dart
index 5a04322..dc38919 100644
--- a/pkg/analysis_server/lib/src/services/completion/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/optype.dart
@@ -4,7 +4,7 @@
 
 library services.completion.dart.optype;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/scanner.dart';
 
@@ -295,6 +295,16 @@
   }
 
   @override
+  void visitFieldFormalParameter(FieldFormalParameter node) {
+    if (entity == node.identifier) {
+      optype.isPrefixed = true;
+    } else {
+      optype.includeReturnValueSuggestions = true;
+      optype.includeTypeNameSuggestions = true;
+    }
+  }
+
+  @override
   void visitForEachStatement(ForEachStatement node) {
     if (identical(entity, node.identifier)) {
       optype.includeTypeNameSuggestions = true;
@@ -449,16 +459,6 @@
   }
 
   @override
-  void visitFieldFormalParameter(FieldFormalParameter node) {
-    if (entity == node.identifier) {
-      optype.isPrefixed = true;
-    } else {
-      optype.includeReturnValueSuggestions = true;
-      optype.includeTypeNameSuggestions = true;
-    }
-  }
-
-  @override
   void visitNormalFormalParameter(NormalFormalParameter node) {
     optype.includeReturnValueSuggestions = true;
     optype.includeTypeNameSuggestions = true;
diff --git a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
index cb32012..6d19260 100644
--- a/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/uri_contributor.dart
@@ -48,13 +48,22 @@
   }
 
   @override
+  visitExportDirective(ExportDirective node) {
+    visitNamespaceDirective(node);
+  }
+
+  @override
   visitImportDirective(ImportDirective node) {
+    visitNamespaceDirective(node);
+  }
+
+  visitNamespaceDirective(NamespaceDirective node) {
     StringLiteral uri = node.uri;
     if (uri is SimpleStringLiteral) {
       int offset = request.offset;
       if (uri.offset < offset &&
           (offset < uri.end || offset == uri.offset + 1)) {
-        // Handle degenerate case where import is only line in file
+        // Handle degenerate case where import or export is only line in file
         // and there is no semicolon
         visitSimpleStringLiteral(uri);
       }
@@ -64,7 +73,7 @@
   @override
   visitSimpleStringLiteral(SimpleStringLiteral node) {
     AstNode parent = node.parent;
-    if (parent is ImportDirective && parent.uri == node) {
+    if (parent is NamespaceDirective && parent.uri == node) {
       String partial = node.literal.lexeme.substring(
           node.contentsOffset - node.offset, request.offset - node.offset);
       request.replacementOffset = node.contentsOffset;
diff --git a/pkg/analysis_server/lib/src/services/correction/fix.dart b/pkg/analysis_server/lib/src/services/correction/fix.dart
index e1f81f6..d00a24f 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/error.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
 
 /**
  * Compute and return the fixes available for the given [error]. The error was
@@ -38,6 +39,63 @@
 }
 
 /**
+ * Return true if this [errorCode] is likely to have a fix associated with it.
+ */
+bool hasFix(ErrorCode errorCode) => errorCode ==
+        StaticWarningCode.UNDEFINED_CLASS_BOOLEAN ||
+    errorCode == StaticWarningCode.CONCRETE_CLASS_WITH_ABSTRACT_MEMBER ||
+    errorCode == StaticWarningCode.EXTRA_POSITIONAL_ARGUMENTS ||
+    errorCode == StaticWarningCode.NEW_WITH_UNDEFINED_CONSTRUCTOR ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_ONE ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_TWO ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_THREE ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FOUR ||
+    errorCode ==
+        StaticWarningCode.NON_ABSTRACT_CLASS_INHERITS_ABSTRACT_MEMBER_FIVE_PLUS ||
+    errorCode == StaticWarningCode.CAST_TO_NON_TYPE ||
+    errorCode == StaticWarningCode.TYPE_TEST_WITH_UNDEFINED_NAME ||
+    errorCode == StaticWarningCode.UNDEFINED_CLASS ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_1 ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_2 ||
+    errorCode == StaticWarningCode.FINAL_NOT_INITIALIZED_CONSTRUCTOR_3_PLUS ||
+    errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER ||
+    errorCode ==
+        CompileTimeErrorCode.CONST_INITIALIZED_WITH_NON_CONSTANT_VALUE ||
+    errorCode == CompileTimeErrorCode.INVALID_ANNOTATION ||
+    errorCode == CompileTimeErrorCode.NO_DEFAULT_SUPER_CONSTRUCTOR_EXPLICIT ||
+    errorCode == CompileTimeErrorCode.PART_OF_NON_PART ||
+    errorCode ==
+        CompileTimeErrorCode.UNDEFINED_CONSTRUCTOR_IN_INITIALIZER_DEFAULT ||
+    errorCode == CompileTimeErrorCode.URI_DOES_NOT_EXIST ||
+    errorCode == HintCode.DEAD_CODE ||
+    errorCode == HintCode.DIVISION_OPTIMIZATION ||
+    errorCode == HintCode.TYPE_CHECK_IS_NOT_NULL ||
+    errorCode == HintCode.TYPE_CHECK_IS_NULL ||
+    errorCode == HintCode.UNDEFINED_GETTER ||
+    errorCode == HintCode.UNDEFINED_SETTER ||
+    errorCode == HintCode.UNNECESSARY_CAST ||
+    errorCode == HintCode.UNUSED_CATCH_CLAUSE ||
+    errorCode == HintCode.UNUSED_CATCH_STACK ||
+    errorCode == HintCode.UNUSED_IMPORT ||
+    errorCode == HintCode.UNDEFINED_METHOD ||
+    errorCode == ParserErrorCode.EXPECTED_TOKEN ||
+    errorCode == ParserErrorCode.GETTER_WITH_PARAMETERS ||
+    errorCode == ParserErrorCode.VAR_AS_TYPE_NAME ||
+    errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE ||
+    errorCode == StaticTypeWarningCode.INSTANCE_ACCESS_TO_STATIC_MEMBER ||
+    errorCode == StaticTypeWarningCode.INVOCATION_OF_NON_FUNCTION ||
+    errorCode == StaticTypeWarningCode.NON_TYPE_AS_TYPE_ARGUMENT ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_FUNCTION ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_GETTER ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_METHOD ||
+    errorCode == StaticTypeWarningCode.UNDEFINED_SETTER;
+
+/**
  * An enumeration of possible quick fix kinds.
  */
 class DartFixKind {
diff --git a/pkg/analysis_server/lib/src/services/index/index.dart b/pkg/analysis_server/lib/src/services/index/index.dart
index 3a44b4f..5767b4c 100644
--- a/pkg/analysis_server/lib/src/services/index/index.dart
+++ b/pkg/analysis_server/lib/src/services/index/index.dart
@@ -82,9 +82,6 @@
   IndexableObjectKind get kind => IndexableNameKind.INSTANCE;
 
   @override
-  int get length => 0;
-
-  @override
   int get offset {
     return -1;
   }
@@ -127,6 +124,12 @@
     throw new UnsupportedError(
         'Indexable names cannot be decoded through their kind');
   }
+
+  @override
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+    String name = (indexable as IndexableName).name;
+    return stringToInt(name);
+  }
 }
 
 /**
diff --git a/pkg/analysis_server/lib/src/services/index/index_contributor.dart b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
index ae1ec69..44ce967 100644
--- a/pkg/analysis_server/lib/src/services/index/index_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/index/index_contributor.dart
@@ -778,8 +778,8 @@
   void _recordTopLevelElementDefinition(Element element) {
     if (element != null) {
       IndexableElement indexable = new IndexableElement(element);
-      int offset = indexable.offset;
-      int length = indexable.length;
+      int offset = element.nameOffset;
+      int length = element.nameLength;
       LocationImpl location = new LocationImpl(indexable, offset, length);
       recordRelationshipElement(
           _libraryElement, IndexConstants.DEFINES, location);
diff --git a/pkg/analysis_server/lib/src/services/index/indexable_element.dart b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
index 8df94c0..a2d3d64 100644
--- a/pkg/analysis_server/lib/src/services/index/indexable_element.dart
+++ b/pkg/analysis_server/lib/src/services/index/indexable_element.dart
@@ -10,6 +10,7 @@
 import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/utilities_general.dart';
 
 /**
  * A wrapper around an [Element] that implements the [IndexableObject] interface.
@@ -36,12 +37,6 @@
   IndexableObjectKind get kind => IndexableElementKind.forElement(element);
 
   @override
-  int get length => element.nameLength;
-
-  @override
-  String get name => element.displayName;
-
-  @override
   int get offset {
     if (element is ConstructorElement) {
       return element.enclosingElement.nameOffset;
@@ -67,7 +62,7 @@
   /**
    * A table mapping element kinds to the corresponding indexable element kind.
    */
-  static Map<ElementKind, IndexableElementKind> _kindMap =
+  static final Map<ElementKind, IndexableElementKind> _kindMap =
       new HashMap<ElementKind, IndexableElementKind>();
 
   /**
@@ -75,7 +70,7 @@
    * of constructors associated with a class) to the indexable element kind used
    * to represent it.
    */
-  static Map<int, IndexableElementKind> _constructorKinds =
+  static final Map<int, IndexableElementKind> _constructorKinds =
       new HashMap<int, IndexableElementKind>();
 
   @override
@@ -145,6 +140,22 @@
     return null;
   }
 
+  @override
+  int encodeHash(StringToInt stringToInt, IndexableObject indexable) {
+    Element element = (indexable as IndexableElement).element;
+    String elementName = element.displayName;
+    int elementNameId = stringToInt(elementName);
+    if (indexable is IndexableElement) {
+      LibraryElement libraryElement = indexable.element.library;
+      if (libraryElement != null) {
+        String libraryPath = libraryElement.source.fullName;
+        int libraryPathId = stringToInt(libraryPath);
+        return JenkinsSmiHash.combine(libraryPathId, elementNameId);
+      }
+    }
+    return elementNameId;
+  }
+
   /**
    * Return the indexable element kind representing the given [element].
    */
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 07925f3..c865aa4 100644
--- a/pkg/analysis_server/lib/src/services/index/store/codec.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/codec.dart
@@ -8,11 +8,8 @@
 
 import 'package:analysis_server/analysis/index_core.dart';
 import 'package:analysis_server/src/services/index/index.dart';
-import 'package:analysis_server/src/services/index/indexable_element.dart';
-import 'package:analyzer/src/generated/element.dart';
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_general.dart';
 
 /**
  * A helper that encodes/decodes [AnalysisContext]s from/to integers.
@@ -79,7 +76,6 @@
    */
   IndexableObject decode(
       AnalysisContext context, int fileId, int offset, int kindId) {
-    String filePath = _stringCodec.decode(fileId);
     IndexableObjectKind kind = IndexableObjectKind.getKind(kindId);
     if (kind == null) {
       return null;
@@ -87,6 +83,7 @@
       String name = _stringCodec.decode(offset);
       return new IndexableName(name);
     }
+    String filePath = _stringCodec.decode(fileId);
     return kind.decode(context, filePath, offset);
   }
 
@@ -113,11 +110,7 @@
       String name = indexable.name;
       return _stringCodec.encode(name);
     }
-    int offset = indexable.offset;
-    if (offset < 0) {
-      return _stringCodec.encode(indexable.name);
-    }
-    return offset;
+    return indexable.offset;
   }
 
   /**
@@ -132,19 +125,7 @@
    * Returns an integer that corresponds to the name of [indexable].
    */
   int encodeHash(IndexableObject indexable) {
-    // TODO(brianwilkerson) Consider moving this to IndexableObjectKind so that
-    // we don't have to break encapsulation.
-    String elementName = indexable.name; // was: indexable.displayName;
-    int elementNameId = _stringCodec.encode(elementName);
-    if (indexable is IndexableElement) {
-      LibraryElement libraryElement = indexable.element.library;
-      if (libraryElement != null) {
-        String libraryPath = libraryElement.source.fullName;
-        int libraryPathId = _stringCodec.encode(libraryPath);
-        return JenkinsSmiHash.combine(libraryPathId, elementNameId);
-      }
-    }
-    return elementNameId;
+    return indexable.kind.encodeHash(_stringCodec.encode, indexable);
   }
 }
 
diff --git a/pkg/analysis_server/lib/src/services/index/store/split_store.dart b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
index 9c51d6a..57b1734 100644
--- a/pkg/analysis_server/lib/src/services/index/store/split_store.dart
+++ b/pkg/analysis_server/lib/src/services/index/store/split_store.dart
@@ -1005,8 +1005,8 @@
       nodeDeclarations[_currentNodeNameId] = declarations;
     }
     // record LocationData
-    declarations
-        .add(new _TopElementData(_elementCodec, new IndexableElement(element)));
+    declarations.add(new _TopElementData(
+        _elementCodec, element.displayName, new IndexableElement(element)));
   }
 
   @override
@@ -1154,12 +1154,9 @@
   final int elementId3;
 
   factory _TopElementData(
-      ElementCodec elementCodec, IndexableObject indexable) {
-    return new _TopElementData._(
-        indexable.name,
-        elementCodec.encode1(indexable),
-        elementCodec.encode2(indexable),
-        elementCodec.encode3(indexable));
+      ElementCodec elementCodec, String name, IndexableObject indexable) {
+    return new _TopElementData._(name, elementCodec.encode1(indexable),
+        elementCodec.encode2(indexable), elementCodec.encode3(indexable));
   }
 
   _TopElementData._(
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename.dart b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
index bd97527..a9bdb74 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename.dart
@@ -17,6 +17,7 @@
 import 'package:analyzer/src/generated/engine.dart';
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:path/path.dart' as pathos;
 
 /**
  * Returns `true` if two given [Element]s are [LocalElement]s and have
@@ -52,6 +53,18 @@
   return librarySourcesOfSource.contains(librarySourceOfElement);
 }
 
+bool isElementInPubCache(Element element) {
+  Source source = element.source;
+  String path = source.fullName;
+  return isPathInPubCache(path);
+}
+
+bool isElementInSdkOrPubCache(Element element) {
+  Source source = element.source;
+  String path = source.fullName;
+  return source.isInSystemLibrary || isPathInPubCache(path);
+}
+
 /**
  * Checks if the given [Element] is in the given [AnalysisContext].
  */
@@ -59,6 +72,23 @@
   return element.context == context;
 }
 
+bool isPathInPubCache(String path) {
+  List<String> parts = pathos.split(path);
+  if (parts.contains('.pub-cache')) {
+    return true;
+  }
+  for (int i = 0; i < parts.length - 1; i++) {
+    if (parts[i] == 'Pub' && parts[i + 1] == 'Cache') {
+      return true;
+    }
+    if (parts[i] == 'third_party' &&
+        (parts[i + 1] == 'pkg' || parts[i + 1] == 'pkg_tested')) {
+      return true;
+    }
+  }
+  return false;
+}
+
 /**
  * Checks if the given unqualified [SearchMatch] intersects with visibility
  * range of [localElement].
@@ -145,6 +175,13 @@
           getElementQualifiedName(element));
       result.addFatalError(message);
     }
+    if (isElementInPubCache(element)) {
+      String message = format(
+          "The {0} '{1}' is defined in a pub package, so cannot be renamed.",
+          getElementKindName(element),
+          getElementQualifiedName(element));
+      result.addFatalError(message);
+    }
     return new Future.value(result);
   }
 
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 e0f9a77..4d70e06 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
@@ -100,6 +100,11 @@
       if (reference.isResolved) {
         continue;
       }
+      // ignore references from SDK and pub cache
+      if (isElementInSdkOrPubCache(reference.element)) {
+        print('ignore: $reference');
+        continue;
+      }
       // check the element being renamed is accessible
       {
         LibraryElement whereLibrary = reference.element.library;
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index abf8f00..c85db7b 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -323,6 +323,7 @@
       results.add(COMPILATION_UNIT_CONSTANTS);
       results.add(COMPILATION_UNIT_ELEMENT);
       results.add(HINTS);
+      results.add(LINTS);
       results.add(INFER_STATIC_VARIABLE_TYPES_ERRORS);
       results.add(INFERABLE_STATIC_VARIABLES_IN_UNIT);
       results.add(LIBRARY_UNIT_ERRORS);
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 0029437..95fcbe5 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -6,7 +6,7 @@
 environment:
   sdk: '>=1.9.0 <2.0.0'
 dependencies:
-  analyzer: '>=0.26.1+3 <0.27.0'
+  analyzer: '>=0.26.1+7 <0.27.0'
   args: '>=0.13.0 <0.14.0'
   dart_style: '>=0.2.0 <0.3.0'
   logging: any
diff --git a/pkg/analysis_server/test/analysis/get_hover_test.dart b/pkg/analysis_server/test/analysis/get_hover_test.dart
index bda7c91..61520dc 100644
--- a/pkg/analysis_server/test/analysis/get_hover_test.dart
+++ b/pkg/analysis_server/test/analysis/get_hover_test.dart
@@ -168,6 +168,31 @@
     });
   }
 
+  test_expression_parameter() {
+    addTestFile('''
+library my.library;
+class A {
+  /// The method documentation.
+  m(int p) {
+  }
+}
+''');
+    return prepareHover('p) {').then((HoverInformation hover) {
+      // element
+      expect(hover.containingLibraryName, isNull);
+      expect(hover.containingLibraryPath, isNull);
+      expect(hover.containingClassDescription, isNull);
+      expect(hover.dartdoc, 'The method documentation.');
+      expect(hover.elementDescription, 'int p');
+      expect(hover.elementKind, 'parameter');
+      // types
+      expect(hover.staticType, 'int');
+      expect(hover.propagatedType, isNull);
+      // no parameter
+      expect(hover.parameter, isNull);
+    });
+  }
+
   test_expression_syntheticGetter() {
     addTestFile('''
 library my.library;
diff --git a/pkg/analysis_server/test/analysis/notification_errors_test.dart b/pkg/analysis_server/test/analysis/notification_errors_test.dart
index e03a380..aa841e3 100644
--- a/pkg/analysis_server/test/analysis/notification_errors_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_errors_test.dart
@@ -7,6 +7,7 @@
 import 'package:analysis_server/src/constants.dart';
 import 'package:analysis_server/src/domain_analysis.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analyzer/src/generated/engine.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 import 'package:unittest/unittest.dart';
 
@@ -35,6 +36,24 @@
     server.handlers = [new AnalysisDomainHandler(server),];
   }
 
+  test_importError() {
+    createProject();
+
+    addTestFile('''
+import 'does_not_exist.dart';
+''');
+    return waitForTasksFinished().then((_) {
+      List<AnalysisError> errors = filesErrors[testFile];
+      // Verify that we are generating only 1 error for the bad URI.
+      // https://github.com/dart-lang/sdk/issues/23754
+      expect(errors, hasLength(1));
+      AnalysisError error = errors[0];
+      expect(error.severity, AnalysisErrorSeverity.ERROR);
+      expect(error.type, AnalysisErrorType.COMPILE_TIME_ERROR);
+      expect(error.message, startsWith('Target of URI does not exist'));
+    });
+  }
+
   test_notInAnalysisRoot() {
     createProject();
     String otherFile = '/other.dart';
diff --git a/pkg/analysis_server/test/analysis/notification_implemented_test.dart b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
index a26ff56..fc72b72 100644
--- a/pkg/analysis_server/test/analysis/notification_implemented_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_implemented_test.dart
@@ -37,6 +37,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedClasses == null) {
+      fail('No notification of impemented classes was received');
+    }
     for (ImplementedClass clazz in implementedClasses) {
       if (clazz.offset == offset && clazz.length == length) {
         return;
@@ -57,6 +60,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedMembers == null) {
+      fail('No notification of impemented members was received');
+    }
     for (ImplementedMember member in implementedMembers) {
       if (member.offset == offset && member.length == length) {
         return;
@@ -77,6 +83,9 @@
     if (length == -1) {
       length = findIdentifierLength(search);
     }
+    if (implementedMembers == null) {
+      fail('No notification of impemented members was received');
+    }
     for (ImplementedMember member in implementedMembers) {
       if (member.offset == offset) {
         fail('Unexpected implemented member at $offset'
@@ -90,16 +99,12 @@
     return createLocalMemoryIndex();
   }
 
+  /**
+   * Subscribe for `IMPLEMENTED` and wait for the notification.
+   */
   Future prepareImplementedElements() {
-    addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
-    Future waitForNotification(int times) {
-      if (times == 0 || implementedClasses != null) {
-        return new Future.value();
-      }
-      return new Future.delayed(
-          Duration.ZERO, () => waitForNotification(times - 1));
-    }
-    return waitForNotification(100);
+    subscribeForImplemented();
+    return waitForImplementedElements();
   }
 
   void processNotification(Notification notification) {
@@ -117,6 +122,10 @@
     createProject();
   }
 
+  void subscribeForImplemented() {
+    addAnalysisSubscription(AnalysisService.IMPLEMENTED, testFile);
+  }
+
   test_afterAnalysis() async {
     addTestFile('''
 class A {}
@@ -127,6 +136,25 @@
     assertHasImplementedClass('A {');
   }
 
+  test_afterIncrementalResolution() async {
+    subscribeForImplemented();
+    addTestFile('''
+class A {}
+class B extends A {}
+''');
+    await prepareImplementedElements();
+    assertHasImplementedClass('A {');
+    // add a space
+    implementedClasses = null;
+    testCode = '''
+class A  {}
+class B extends A {}
+''';
+    server.updateContent('1', {testFile: new AddContentOverlay(testCode)});
+    await waitForImplementedElements();
+    assertHasImplementedClass('A  {');
+  }
+
   test_class_extended() async {
     addTestFile('''
 class A {}
@@ -286,4 +314,15 @@
     await prepareImplementedElements();
     assertHasImplementedMember('f(_) {} // A');
   }
+
+  Future waitForImplementedElements() {
+    Future waitForNotification(int times) {
+      if (times == 0 || implementedClasses != null) {
+        return new Future.value();
+      }
+      return new Future.delayed(
+          new Duration(milliseconds:1), () => waitForNotification(times - 1));
+    }
+    return waitForNotification(30000);
+  }
 }
diff --git a/pkg/analysis_server/test/analysis/notification_navigation_test.dart b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
index fee0d6f..6ef6b57 100644
--- a/pkg/analysis_server/test/analysis/notification_navigation_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_navigation_test.dart
@@ -215,6 +215,113 @@
     });
   }
 
+  test_annotationConstructor_implicit() async {
+    addTestFile('''
+class A {
+}
+@A()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegionString('A()', 'A'.length);
+    assertHasTarget('A {');
+  }
+
+  test_annotationConstructor_importPrefix() async {
+    addFile(
+        '$testFolder/my_annotation.dart',
+        r'''
+library an;
+class MyAnnotation {
+  const MyAnnotation();
+  const MyAnnotation.named();
+}
+''');
+    addTestFile('''
+import 'my_annotation.dart' as man;
+@man.MyAnnotation()
+@man.MyAnnotation.named()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('MyAnnotation()');
+    assertHasRegion('MyAnnotation.named()');
+    assertHasRegion('named()');
+    {
+      assertHasRegion('man.MyAnnotation()');
+      assertHasTarget('man;');
+    }
+    {
+      assertHasRegion('man.MyAnnotation.named()');
+      assertHasTarget('man;');
+    }
+  }
+
+  test_annotationConstructor_named() async {
+    addTestFile('''
+class A {
+  const A.named(p);
+}
+@A.named(0)
+main() {
+}
+''');
+    await prepareNavigation();
+    {
+      assertHasRegion('A.named(0)');
+      assertHasTarget('named(p);');
+    }
+    {
+      assertHasRegion('named(0)');
+      assertHasTarget('named(p);');
+    }
+  }
+
+  test_annotationConstructor_unnamed() async {
+    addTestFile('''
+class A {
+  const A();
+}
+@A()
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegionString('A()', 'A'.length);
+    assertHasTarget('A();', 0);
+  }
+
+  test_annotationField() async {
+    addTestFile('''
+const myan = new Object();
+@myan // ref
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('myan // ref');
+    assertHasTarget('myan = new Object();');
+  }
+
+  test_annotationField_importPrefix() async {
+    addFile(
+        '$testFolder/mayn.dart',
+        r'''
+library an;
+const myan = new Object();
+''');
+    addTestFile('''
+import 'mayn.dart' as man;
+@man.myan // ref
+main() {
+}
+''');
+    await prepareNavigation();
+    assertHasRegion('myan // ref');
+  }
+
   test_class_fromSDK() {
     addTestFile('''
 int V = 42;
diff --git a/pkg/analysis_server/test/analysis/notification_outline_test.dart b/pkg/analysis_server/test/analysis/notification_outline_test.dart
index fdac6b5..4840a2e 100644
--- a/pkg/analysis_server/test/analysis/notification_outline_test.dart
+++ b/pkg/analysis_server/test/analysis/notification_outline_test.dart
@@ -21,6 +21,8 @@
 
 @reflectiveTest
 class _AnalysisNotificationOutlineTest extends AbstractAnalysisTest {
+  FileKind fileKind;
+  String libraryName;
   Outline outline;
 
   Future prepareOutline() {
@@ -32,6 +34,8 @@
     if (notification.event == ANALYSIS_OUTLINE) {
       var params = new AnalysisOutlineParams.fromNotification(notification);
       if (params.file == testFile) {
+        fileKind = params.kind;
+        libraryName = params.libraryName;
         outline = params.outline;
       }
     }
@@ -311,6 +315,43 @@
     });
   }
 
+  test_libraryName_hasLibraryDirective() async {
+    addTestFile('''
+library my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_hasLibraryPartOfDirectives() async {
+    addTestFile('''
+part of lib.in.part.of;
+library my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_hasPartOfDirective() async {
+    addTestFile('''
+part of my.lib;
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.PART);
+    expect(libraryName, 'my.lib');
+  }
+
+  test_libraryName_noDirectives() async {
+    addTestFile('''
+class A {}
+''');
+    await prepareOutline();
+    expect(fileKind, FileKind.LIBRARY);
+    expect(libraryName, isNull);
+  }
+
   test_localFunctions() {
     addTestFile('''
 class A {
diff --git a/pkg/analysis_server/test/analysis/test_all.dart b/pkg/analysis_server/test/analysis/test_all.dart
index a14781f..468d420 100644
--- a/pkg/analysis_server/test/analysis/test_all.dart
+++ b/pkg/analysis_server/test/analysis/test_all.dart
@@ -27,7 +27,7 @@
  */
 main() {
   initializeTestEnvironment();
-  group('search', () {
+  group('analysis', () {
     get_errors_test.main();
     get_hover_test.main();
     get_navigation_test.main();
diff --git a/pkg/analysis_server/test/completion_test.dart b/pkg/analysis_server/test/completion_test.dart
index d602bde..7fc8d23 100644
--- a/pkg/analysis_server/test/completion_test.dart
+++ b/pkg/analysis_server/test/completion_test.dart
@@ -2851,7 +2851,7 @@
 
     // test analysis of untyped fields and top-level vars
     buildTests('test035', '''class Y {final x='hi';mth() {x.!1length;}}''',
-        <String>["1+length"]);
+        <String>["1+length"], failingTests: '1');
 
     // TODO(scheglov) decide what to do with Type for untyped field (not
     // supported by the new store)
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index 1202ef3..c1ccc99 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -6,9 +6,6 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
-import 'package:analysis_server/completion/completion_dart.dart' as newApi;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/channel/channel.dart';
 import 'package:analysis_server/src/constants.dart';
@@ -17,6 +14,10 @@
 import 'package:analysis_server/src/domain_completion.dart';
 import 'package:analysis_server/src/plugin/server_plugin.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
+import 'package:analysis_server/src/provisional/completion/completion_dart.dart'
+    as newApi;
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/contribution_sorter.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
diff --git a/pkg/analysis_server/test/edit/organize_directives_test.dart b/pkg/analysis_server/test/edit/organize_directives_test.dart
index deb4ed9..821e4a4 100644
--- a/pkg/analysis_server/test/edit/organize_directives_test.dart
+++ b/pkg/analysis_server/test/edit/organize_directives_test.dart
@@ -65,6 +65,28 @@
         response, isResponseFailure('0', RequestErrorCode.FILE_NOT_ANALYZED));
   }
 
+  Future test_OK_remove_duplicateImports_withSamePrefix() {
+    addTestFile('''
+library lib;
+
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}
+''');
+    return _assertOrganized(r'''
+library lib;
+
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}
+''');
+  }
+
   Future test_OK_remove_unresolvedDirectives() {
     addFile('$testFolder/existing_part1.dart', 'part of lib;');
     addFile('$testFolder/existing_part2.dart', 'part of lib;');
diff --git a/pkg/analysis_server/test/integration/integration_test_methods.dart b/pkg/analysis_server/test/integration/integration_test_methods.dart
index 836f884..8ab5dca 100644
--- a/pkg/analysis_server/test/integration/integration_test_methods.dart
+++ b/pkg/analysis_server/test/integration/integration_test_methods.dart
@@ -829,6 +829,18 @@
    *
    *   The file with which the outline is associated.
    *
+   * kind ( FileKind )
+   *
+   *   The kind of the file.
+   *
+   * libraryName ( optional String )
+   *
+   *   The name of the library defined by the file using a "library" directive,
+   *   or referenced by a "part of" directive. If both "library" and "part of"
+   *   directives are present, then the "library" directive takes precedence.
+   *   This field will be omitted if the file has neither "library" nor "part
+   *   of" directives.
+   *
    * outline ( Outline )
    *
    *   The outline associated with the file.
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index ed2d62a..6e7273e 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -597,7 +597,7 @@
       {bool debugServer: false,
       int diagnosticPort,
       bool profileServer: false,
-      bool newTaskModel: false,
+      bool newTaskModel: true,
       bool useAnalysisHighlight2: false}) {
     if (_process != null) {
       throw new Exception('Process already started');
@@ -627,9 +627,11 @@
     if (useAnalysisHighlight2) {
       arguments.add('--useAnalysisHighlight2');
     }
-    if (newTaskModel) {
-      arguments.add('--${analysisServer.Driver.ENABLE_NEW_TASK_MODEL}');
+    if (!newTaskModel) {
+      arguments.add('--${analysisServer.Driver.DISABLE_NEW_TASK_MODEL}');
     }
+    print('Launching $serverPath');
+    print('$dartBinary ${arguments.join(' ')}');
     return Process.start(dartBinary, arguments).then((Process process) {
       _process = process;
       process.exitCode.then((int code) {
diff --git a/pkg/analysis_server/test/integration/protocol_matchers.dart b/pkg/analysis_server/test/integration/protocol_matchers.dart
index 4d2bc54..347976e 100644
--- a/pkg/analysis_server/test/integration/protocol_matchers.dart
+++ b/pkg/analysis_server/test/integration/protocol_matchers.dart
@@ -468,13 +468,18 @@
  *
  * {
  *   "file": FilePath
+ *   "kind": FileKind
+ *   "libraryName": optional String
  *   "outline": Outline
  * }
  */
 final Matcher isAnalysisOutlineParams = new LazyMatcher(() => new MatchesJsonObject(
   "analysis.outline params", {
     "file": isFilePath,
+    "kind": isFileKind,
     "outline": isOutline
+  }, optionalFields: {
+    "libraryName": isString
   }));
 
 /**
@@ -1024,6 +1029,7 @@
  *   "location": Location
  *   "message": String
  *   "correction": optional String
+ *   "hasFix": optional bool
  * }
  */
 final Matcher isAnalysisError = new LazyMatcher(() => new MatchesJsonObject(
@@ -1033,7 +1039,8 @@
     "location": isLocation,
     "message": isString
   }, optionalFields: {
-    "correction": isString
+    "correction": isString,
+    "hasFix": isBool
   }));
 
 /**
@@ -1379,6 +1386,19 @@
 ]);
 
 /**
+ * FileKind
+ *
+ * enum {
+ *   LIBRARY
+ *   PART
+ * }
+ */
+final Matcher isFileKind = new MatchesEnum("FileKind", [
+  "LIBRARY",
+  "PART"
+]);
+
+/**
  * FilePath
  *
  * String
@@ -2221,6 +2241,8 @@
  * extractLocalVariable feedback
  *
  * {
+ *   "coveringExpressionOffsets": List<int>
+ *   "coveringExpressionLengths": List<int>
  *   "names": List<String>
  *   "offsets": List<int>
  *   "lengths": List<int>
@@ -2228,6 +2250,8 @@
  */
 final Matcher isExtractLocalVariableFeedback = new LazyMatcher(() => new MatchesJsonObject(
   "extractLocalVariable feedback", {
+    "coveringExpressionOffsets": isListOf(isInt),
+    "coveringExpressionLengths": isListOf(isInt),
     "names": isListOf(isString),
     "offsets": isListOf(isInt),
     "lengths": isListOf(isInt)
diff --git a/pkg/analysis_server/test/protocol_server_test.dart b/pkg/analysis_server/test/protocol_server_test.dart
index 7abbe3f..d770e35 100644
--- a/pkg/analysis_server/test/protocol_server_test.dart
+++ b/pkg/analysis_server/test/protocol_server_test.dart
@@ -72,7 +72,8 @@
         START_COLUMN: 2
       },
       MESSAGE: 'my message',
-      CORRECTION: 'my correction'
+      CORRECTION: 'my correction',
+      HAS_FIX : false
     });
   }
 
@@ -89,7 +90,8 @@
         START_LINE: 3,
         START_COLUMN: 2
       },
-      MESSAGE: 'my message'
+      MESSAGE: 'my message',
+      HAS_FIX : false
     });
   }
 
@@ -106,7 +108,8 @@
         START_LINE: -1,
         START_COLUMN: -1
       },
-      MESSAGE: 'my message'
+      MESSAGE: 'my message',
+      HAS_FIX : false
     });
   }
 }
diff --git a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
index 433448b..959b027 100644
--- a/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/arglist_contributor_test.dart
@@ -90,6 +90,17 @@
     contributor = new ArgListContributor();
   }
 
+  test_Annotation_local_constructor_named_param() {
+    //
+    addTestSource('''
+class A { A({int one, String two: 'defaultValue'}) { } }
+@A(^) main() { }''');
+    computeFast();
+    return computeFull((bool result) {
+      assertSuggestArguments(namedArguments: ['one', 'two']);
+    });
+  }
+
   test_ArgumentList_getter() {
     addTestSource('class A {int get foo => 7; main() {foo(^)}');
     computeFast();
diff --git a/pkg/analysis_server/test/services/completion/completion_computer_test.dart b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
index 0cdeff9..dddf75e 100644
--- a/pkg/analysis_server/test/services/completion/completion_computer_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_computer_test.dart
@@ -6,10 +6,10 @@
 
 import 'dart:async';
 
-import 'package:analysis_server/completion/completion_core.dart'
-    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/analysis_server.dart';
 import 'package:analysis_server/src/protocol.dart';
+import 'package:analysis_server/src/provisional/completion/completion_core.dart'
+    show CompletionRequest, CompletionResult;
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/index/index.dart';
@@ -94,26 +94,24 @@
       switch (++count) {
         case 1:
           contributor1.assertCalls(context, source, 0, searchEngine);
+          expect(contributor1.fastCount, equals(1));
+          expect(contributor1.fullCount, equals(0));
           contributor2.assertCalls(context, source, 0, searchEngine);
-          expect(isLast, isFalse);
-          expect(r.suggestions, hasLength(1));
-          expect(r.suggestions, contains(suggestion1));
-          resolveLibrary();
-          break;
-        case 2:
-          contributor1.assertFull(0);
-          contributor2.assertFull(1);
+          expect(contributor2.fastCount, equals(1));
+          expect(contributor2.fullCount, equals(1));
           expect(isLast, isTrue);
           expect(r.suggestions, hasLength(2));
           expect(r.suggestions, contains(suggestion1));
           expect(r.suggestions, contains(suggestion2));
+          resolveLibrary();
           break;
         default:
           fail('unexpected');
       }
     }, onDone: () {
       done = true;
-      expect(count, equals(2));
+      // There is only one notification
+      expect(count, equals(1));
     });
     return pumpEventQueue().then((_) {
       expect(done, isTrue);
@@ -134,7 +132,11 @@
       switch (++count) {
         case 1:
           contributor1.assertCalls(context, source, 0, searchEngine);
+          expect(contributor1.fastCount, equals(1));
+          expect(contributor1.fullCount, equals(0));
           contributor2.assertCalls(context, source, 0, searchEngine);
+          expect(contributor2.fastCount, equals(1));
+          expect(contributor2.fullCount, equals(0));
           expect(isLast, isTrue);
           expect(r.suggestions, hasLength(2));
           expect(r.suggestions, contains(suggestion1));
@@ -170,14 +172,11 @@
 
   MockCompletionContributor(this.fastSuggestion, this.fullSuggestion);
 
-  assertCalls(AnalysisContext context, Source source, int offset,
-      SearchEngine searchEngine) {
+  assertCalls(AnalysisContext context, Source source, int offset, SearchEngine searchEngine) {
     expect(request.context, equals(context));
     expect(request.source, equals(source));
     expect(request.offset, equals(offset));
     expect(request.searchEngine, equals(searchEngine));
-    expect(this.fastCount, equals(1));
-    expect(this.fullCount, equals(0));
   }
 
   assertFull(int fullCount) {
diff --git a/pkg/analysis_server/test/services/completion/completion_target_test.dart b/pkg/analysis_server/test/services/completion/completion_target_test.dart
index 6d0e52f..169874b 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.completion.target;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/source.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
diff --git a/pkg/analysis_server/test/services/completion/completion_test_util.dart b/pkg/analysis_server/test/services/completion/completion_test_util.dart
index 94d9058..e9b24b4 100644
--- a/pkg/analysis_server/test/services/completion/completion_test_util.dart
+++ b/pkg/analysis_server/test/services/completion/completion_test_util.dart
@@ -10,9 +10,9 @@
 import 'package:analysis_server/src/protocol.dart' as protocol
     show Element, ElementKind;
 import 'package:analysis_server/src/protocol.dart' hide Element, ElementKind;
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/common_usage_computer.dart';
 import 'package:analysis_server/src/services/completion/completion_manager.dart';
-import 'package:analysis_server/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_cache.dart';
 import 'package:analysis_server/src/services/completion/dart_completion_manager.dart';
 import 'package:analysis_server/src/services/completion/imported_reference_contributor.dart';
@@ -1357,7 +1357,8 @@
       //assertSuggestImportedTopLevelVar('T3', 'int', COMPLETION_RELEVANCE_LOW);
       assertNotSuggested('_T4');
       assertSuggestLocalTopLevelVar('T5', 'int');
-      assertSuggestLocalTopLevelVar('_T6', null);
+      assertSuggestLocalTopLevelVar('_T6', null,
+          relevance: DART_RELEVANCE_DEFAULT);
       assertNotSuggested('==');
       assertSuggestLocalGetter('T7', 'String');
       assertSuggestLocalSetter('T8');
@@ -3473,7 +3474,8 @@
         expect(getterF.element.isDeprecated, isTrue);
         expect(getterF.element.isPrivate, isFalse);
       }
-      CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null);
+      CompletionSuggestion getterG = assertSuggestLocalGetter('_g', null,
+          relevance: DART_RELEVANCE_DEFAULT);
       if (getterG != null) {
         expect(getterG.element.isDeprecated, isFalse);
         expect(getterG.element.isPrivate, isTrue);
@@ -3528,7 +3530,8 @@
     return computeFull((bool result) {
       expect(request.replacementOffset, completionOffset);
       expect(request.replacementLength, 0);
-      CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z');
+      CompletionSuggestion methodA = assertSuggestLocalMethod('_a', 'A', 'Z',
+          relevance: DART_RELEVANCE_DEFAULT);
       if (methodA != null) {
         expect(methodA.element.isDeprecated, isFalse);
         expect(methodA.element.isPrivate, isTrue);
diff --git a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
index bf3c027..882efd9 100644
--- a/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/keyword_contributor_test.dart
@@ -85,7 +85,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -107,7 +106,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -130,7 +128,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SUPER,
     Keyword.SWITCH,
@@ -153,7 +150,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -171,7 +167,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -191,7 +186,6 @@
     Keyword.FOR,
     Keyword.IF,
     Keyword.NEW,
-    Keyword.RETHROW,
     Keyword.RETURN,
     Keyword.SWITCH,
     Keyword.THROW,
@@ -613,6 +607,16 @@
         relevance: DART_RELEVANCE_KEYWORD);
   }
 
+  test_catch() {
+    addTestSource('main() {try {} catch (e) {^}}}');
+    expect(computeFast(), isTrue);
+    var keywords = <Keyword>[];
+    keywords.addAll(STMT_START_OUTSIDE_CLASS);
+    keywords.add(Keyword.RETHROW);
+    assertSuggestKeywords(keywords,
+        relevance: DART_RELEVANCE_KEYWORD);
+  }
+
   test_for_break_continue2() {
     addTestSource('class A {foo() {for (int x in myList) {^}}}');
     expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
index cb29f97..94c0717 100644
--- a/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/local_reference_contributor_test.dart
@@ -793,6 +793,20 @@
     assertSuggestMethod('m', 'B', null, relevance: DART_RELEVANCE_LOCAL_METHOD);
   }
 
+  test_prioritization_private() {
+    addTestSource('main() {var ab; var _ab; _^}');
+    expect(computeFast(), isTrue);
+    assertSuggestLocalVariable('ab', null);
+    assertSuggestLocalVariable('_ab', null);
+  }
+
+  test_prioritization_public() {
+    addTestSource('main() {var ab; var _ab; a^}');
+    expect(computeFast(), isTrue);
+    assertSuggestLocalVariable('ab', null);
+    assertSuggestLocalVariable('_ab', null, relevance: DART_RELEVANCE_DEFAULT);
+  }
+
   test_shadowed_name() {
     addTestSource('var a; class A { var a; m() { ^ } }');
     expect(computeFast(), isTrue);
diff --git a/pkg/analysis_server/test/services/completion/optype_test.dart b/pkg/analysis_server/test/services/completion/optype_test.dart
index e2c654c..a2bf5c8 100644
--- a/pkg/analysis_server/test/services/completion/optype_test.dart
+++ b/pkg/analysis_server/test/services/completion/optype_test.dart
@@ -4,7 +4,7 @@
 
 library test.services.completion.contributor.dart.optype;
 
-import 'package:analysis_server/completion/dart/completion_target.dart';
+import 'package:analysis_server/src/provisional/completion/dart/completion_target.dart';
 import 'package:analysis_server/src/services/completion/optype.dart';
 import 'package:analyzer/src/generated/ast.dart';
 import 'package:analyzer/src/generated/engine.dart';
diff --git a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
index 9742dbd..4a046a1 100644
--- a/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/uri_contributor_test.dart
@@ -186,6 +186,16 @@
         csKind: CompletionSuggestionKind.IMPORT);
   }
 
+  test_export_package2() {
+    addPackageSource('foo', 'foo.dart', 'library foo;');
+    addPackageSource('foo', 'baz/too.dart', 'library too;');
+    addPackageSource('bar', 'bar.dart', 'library bar;');
+    addTestSource('export "package:foo/baz/^" import');
+    computeFast();
+    assertSuggest('package:foo/baz/too.dart',
+        csKind: CompletionSuggestionKind.IMPORT);
+  }
+
   test_import_package_missing_lib() {
     var pkgSrc = addPackageSource('bar', 'bar.dart', 'library bar;');
     provider.deleteFolder(dirname(pkgSrc.fullName));
diff --git a/pkg/analysis_server/test/services/correction/organize_directives_test.dart b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
index 6c817b5..833cc49 100644
--- a/pkg/analysis_server/test/services/correction/organize_directives_test.dart
+++ b/pkg/analysis_server/test/services/correction/organize_directives_test.dart
@@ -22,6 +22,29 @@
 class OrganizeDirectivesTest extends AbstractSingleUnitTest {
   List<AnalysisError> testErrors;
 
+  void test_keep_duplicateImports_withDifferentPrefix() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+  async1.Future f;
+  async2.Stream s;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async1;
+import 'dart:async' as async2;
+
+main() {
+  async1.Future f;
+  async2.Stream s;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
   void test_remove_duplicateImports() {
     _computeUnitAndErrors(r'''
 import 'dart:async';
@@ -42,6 +65,46 @@
         removeUnused: true);
   }
 
+  void test_remove_duplicateImports_differentText_uri() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import "dart:async" as async;
+
+main() {
+  async.Future f;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
+  void test_remove_duplicateImports_withSamePrefix() {
+    _computeUnitAndErrors(r'''
+import 'dart:async' as async;
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''');
+    // validate change
+    _assertOrganize(
+        r'''
+import 'dart:async' as async;
+
+main() {
+  async.Future f;
+}''',
+        removeUnresolved: true,
+        removeUnused: true);
+  }
+
   void test_remove_unresolvedDirectives() {
     addSource('/existing_part1.dart', 'part of lib;');
     addSource('/existing_part2.dart', 'part of lib;');
diff --git a/pkg/analysis_server/test/services/index/store/codec_test.dart b/pkg/analysis_server/test/services/index/store/codec_test.dart
index 43dbe33..5e6d180 100644
--- a/pkg/analysis_server/test/services/index/store/codec_test.dart
+++ b/pkg/analysis_server/test/services/index/store/codec_test.dart
@@ -93,7 +93,7 @@
       int id2 = codec.encode2(indexable);
       int id3 = codec.encode3(indexable);
       expect(id1, isNonNegative);
-      expect(id2, isNonNegative);
+      expect(id2, -1);
       expect(id3, IndexableElementKind.forElement(element).index);
       validateDecode(id1, id2, id3, element);
     }
@@ -106,7 +106,7 @@
       int id2 = codec.encode2(indexable);
       int id3 = codec.encode3(indexable);
       expect(id1, isNonNegative);
-      expect(id2, isNonNegative);
+      expect(id2, -1);
       expect(id3, IndexableElementKind.forElement(element).index);
       validateDecode(id1, id2, id3, element);
     }
@@ -260,6 +260,7 @@
     expect(id1, -1);
     expect(id2, isNonNegative);
     expect(id3, IndexableNameKind.INSTANCE.index);
+    expect(codec.decode(context, id1, id2, id3), indexable);
   }
 
   void test_encode_LibraryElement() {
@@ -274,7 +275,7 @@
     int id2 = codec.encode2(indexable);
     int id3 = codec.encode3(indexable);
     expect(id1, isNonNegative);
-    expect(id2, isNonNegative);
+    expect(id2, -1);
     expect(id3, IndexableElementKind.forElement(element).index);
     validateDecode(id1, id2, id3, element);
   }
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 3f0ee70..d0b312b 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
@@ -582,6 +582,43 @@
     assertPotentialEdits(['test(); // 1', 'test(); // 2']);
   }
 
+  test_createChange_MethodElement_potential_inPubCache() async {
+    String pkgLib = '/.pub-cache/lib.dart';
+    indexUnit(
+        pkgLib,
+        r'''
+processObj(p) {
+  p.test();
+}
+''');
+    indexTestUnit('''
+import '$pkgLib';
+class A {
+  test() {}
+}
+main(var a) {
+  a.test();
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test() {}');
+    expect(refactoring.refactoringName, 'Rename Method');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    await assertSuccessfulRefactoring('''
+import '/.pub-cache/lib.dart';
+class A {
+  newName() {}
+}
+main(var a) {
+  a.newName();
+}
+''');
+    SourceFileEdit fileEdit = refactoringChange.getFileEdit(pkgLib);
+    expect(fileEdit, isNull);
+  }
+
   test_createChange_MethodElement_potential_private_otherLibrary() async {
     indexUnit(
         '/lib.dart',
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 4c799d1..8e38f8f 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
@@ -224,6 +224,48 @@
     assertRefactoringStatusOK(status);
   }
 
+  test_checkInitialConditions_inPubCache_posix() async {
+    addSource(
+        '/.pub-cache/lib.dart',
+        r'''
+class A {}
+''');
+    indexTestUnit('''
+import '/.pub-cache/lib.dart';
+main() {
+  A a;
+}
+''');
+    createRenameRefactoringAtString('A a');
+    // check status
+    refactoring.newName = 'NewName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            "The class 'A' is defined in a pub package, so cannot be renamed.");
+  }
+
+  test_checkInitialConditions_inPubCache_windows() async {
+    addSource(
+        '/Pub/Cache/lib.dart',
+        r'''
+class A {}
+''');
+    indexTestUnit('''
+import '/Pub/Cache/lib.dart';
+main() {
+  A a;
+}
+''');
+    createRenameRefactoringAtString('A a');
+    // check status
+    refactoring.newName = 'NewName';
+    RefactoringStatus status = await refactoring.checkInitialConditions();
+    assertRefactoringStatus(status, RefactoringProblemSeverity.FATAL,
+        expectedMessage:
+            "The class 'A' is defined in a pub package, so cannot be renamed.");
+  }
+
   test_checkInitialConditions_inSDK() async {
     indexTestUnit('''
 main() {
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
index c85d882..baf27c0 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/AnalysisError.java
@@ -72,14 +72,26 @@
   private final String correction;
 
   /**
+   * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+   * absence of this field implies there are not known to be fixes. Note that since the operation to
+   * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+   * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+   * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+   * client sees this flag set they can proceed with the confidence that there are in fact associated
+   * fixes.
+   */
+  private final Boolean hasFix;
+
+  /**
    * Constructor for {@link AnalysisError}.
    */
-  public AnalysisError(String severity, String type, Location location, String message, String correction) {
+  public AnalysisError(String severity, String type, Location location, String message, String correction, Boolean hasFix) {
     this.severity = severity;
     this.type = type;
     this.location = location;
     this.message = message;
     this.correction = correction;
+    this.hasFix = hasFix;
   }
 
   @Override
@@ -91,7 +103,8 @@
         ObjectUtilities.equals(other.type, type) &&
         ObjectUtilities.equals(other.location, location) &&
         ObjectUtilities.equals(other.message, message) &&
-        ObjectUtilities.equals(other.correction, correction);
+        ObjectUtilities.equals(other.correction, correction) &&
+        ObjectUtilities.equals(other.hasFix, hasFix);
     }
     return false;
   }
@@ -102,7 +115,8 @@
     Location location = Location.fromJson(jsonObject.get("location").getAsJsonObject());
     String message = jsonObject.get("message").getAsString();
     String correction = jsonObject.get("correction") == null ? null : jsonObject.get("correction").getAsString();
-    return new AnalysisError(severity, type, location, message, correction);
+    Boolean hasFix = jsonObject.get("hasFix") == null ? null : jsonObject.get("hasFix").getAsBoolean();
+    return new AnalysisError(severity, type, location, message, correction, hasFix);
   }
 
   public static List<AnalysisError> fromJsonArray(JsonArray jsonArray) {
@@ -127,6 +141,19 @@
   }
 
   /**
+   * A hint to indicate to interested clients that this error has an associated fix (or fixes). The
+   * absence of this field implies there are not known to be fixes. Note that since the operation to
+   * calculate whether fixes apply needs to be performant it is possible that complicated tests will
+   * be skipped and a false negative returned. For this reason, this attribute should be treated as a
+   * "hint". Despite the possibility of false negatives, no false positives should be returned. If a
+   * client sees this flag set they can proceed with the confidence that there are in fact associated
+   * fixes.
+   */
+  public Boolean getHasFix() {
+    return hasFix;
+  }
+
+  /**
    * The location associated with the error.
    */
   public Location getLocation() {
@@ -163,6 +190,7 @@
     builder.append(location);
     builder.append(message);
     builder.append(correction);
+    builder.append(hasFix);
     return builder.toHashCode();
   }
 
@@ -175,6 +203,9 @@
     if (correction != null) {
       jsonObject.addProperty("correction", correction);
     }
+    if (hasFix != null) {
+      jsonObject.addProperty("hasFix", hasFix);
+    }
     return jsonObject;
   }
 
@@ -191,7 +222,9 @@
     builder.append("message=");
     builder.append(message + ", ");
     builder.append("correction=");
-    builder.append(correction);
+    builder.append(correction + ", ");
+    builder.append("hasFix=");
+    builder.append(hasFix);
     builder.append("]");
     return builder.toString();
   }
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
index c329329..e00506d 100644
--- a/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
+++ b/pkg/analysis_server/tool/spec/generated/java/types/ExtractLocalVariableFeedback.java
@@ -42,6 +42,18 @@
   public static final List<ExtractLocalVariableFeedback> EMPTY_LIST = Lists.newArrayList();
 
   /**
+   * The offsets of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  private final int[] coveringExpressionOffsets;
+
+  /**
+   * The lengths of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  private final int[] coveringExpressionLengths;
+
+  /**
    * The proposed names for the local variable.
    */
   private final List<String> names;
@@ -61,7 +73,9 @@
   /**
    * Constructor for {@link ExtractLocalVariableFeedback}.
    */
-  public ExtractLocalVariableFeedback(List<String> names, int[] offsets, int[] lengths) {
+  public ExtractLocalVariableFeedback(int[] coveringExpressionOffsets, int[] coveringExpressionLengths, List<String> names, int[] offsets, int[] lengths) {
+    this.coveringExpressionOffsets = coveringExpressionOffsets;
+    this.coveringExpressionLengths = coveringExpressionLengths;
     this.names = names;
     this.offsets = offsets;
     this.lengths = lengths;
@@ -72,6 +86,8 @@
     if (obj instanceof ExtractLocalVariableFeedback) {
       ExtractLocalVariableFeedback other = (ExtractLocalVariableFeedback) obj;
       return
+        Arrays.equals(other.coveringExpressionOffsets, coveringExpressionOffsets) &&
+        Arrays.equals(other.coveringExpressionLengths, coveringExpressionLengths) &&
         ObjectUtilities.equals(other.names, names) &&
         Arrays.equals(other.offsets, offsets) &&
         Arrays.equals(other.lengths, lengths);
@@ -80,10 +96,12 @@
   }
 
   public static ExtractLocalVariableFeedback fromJson(JsonObject jsonObject) {
+    int[] coveringExpressionOffsets = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionOffsets").getAsJsonArray());
+    int[] coveringExpressionLengths = JsonUtilities.decodeIntArray(jsonObject.get("coveringExpressionLengths").getAsJsonArray());
     List<String> names = JsonUtilities.decodeStringList(jsonObject.get("names").getAsJsonArray());
     int[] offsets = JsonUtilities.decodeIntArray(jsonObject.get("offsets").getAsJsonArray());
     int[] lengths = JsonUtilities.decodeIntArray(jsonObject.get("lengths").getAsJsonArray());
-    return new ExtractLocalVariableFeedback(names, offsets, lengths);
+    return new ExtractLocalVariableFeedback(coveringExpressionOffsets, coveringExpressionLengths, names, offsets, lengths);
   }
 
   public static List<ExtractLocalVariableFeedback> fromJsonArray(JsonArray jsonArray) {
@@ -99,6 +117,22 @@
   }
 
   /**
+   * The lengths of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  public int[] getCoveringExpressionLengths() {
+    return coveringExpressionLengths;
+  }
+
+  /**
+   * The offsets of the expressions that cover the specified selection, from the down most to the up
+   * most.
+   */
+  public int[] getCoveringExpressionOffsets() {
+    return coveringExpressionOffsets;
+  }
+
+  /**
    * The lengths of the expressions that would be replaced by a reference to the variable. The
    * lengths correspond to the offsets. In other words, for a given expression, if the offset of that
    * expression is offsets[i], then the length of that expression is lengths[i].
@@ -124,6 +158,8 @@
   @Override
   public int hashCode() {
     HashCodeBuilder builder = new HashCodeBuilder();
+    builder.append(coveringExpressionOffsets);
+    builder.append(coveringExpressionLengths);
     builder.append(names);
     builder.append(offsets);
     builder.append(lengths);
@@ -132,6 +168,16 @@
 
   public JsonObject toJson() {
     JsonObject jsonObject = new JsonObject();
+    JsonArray jsonArrayCoveringExpressionOffsets = new JsonArray();
+    for (int elt : coveringExpressionOffsets) {
+      jsonArrayCoveringExpressionOffsets.add(new JsonPrimitive(elt));
+    }
+    jsonObject.add("coveringExpressionOffsets", jsonArrayCoveringExpressionOffsets);
+    JsonArray jsonArrayCoveringExpressionLengths = new JsonArray();
+    for (int elt : coveringExpressionLengths) {
+      jsonArrayCoveringExpressionLengths.add(new JsonPrimitive(elt));
+    }
+    jsonObject.add("coveringExpressionLengths", jsonArrayCoveringExpressionLengths);
     JsonArray jsonArrayNames = new JsonArray();
     for (String elt : names) {
       jsonArrayNames.add(new JsonPrimitive(elt));
@@ -154,6 +200,10 @@
   public String toString() {
     StringBuilder builder = new StringBuilder();
     builder.append("[");
+    builder.append("coveringExpressionOffsets=");
+    builder.append(StringUtils.join(coveringExpressionOffsets, ", ") + ", ");
+    builder.append("coveringExpressionLengths=");
+    builder.append(StringUtils.join(coveringExpressionLengths, ", ") + ", ");
     builder.append("names=");
     builder.append(StringUtils.join(names, ", ") + ", ");
     builder.append("offsets=");
diff --git a/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
new file mode 100644
index 0000000..d9ba7bb
--- /dev/null
+++ b/pkg/analysis_server/tool/spec/generated/java/types/FileKind.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2014, the Dart project authors.
+ *
+ * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ *
+ * This file has been automatically generated.  Please do not edit it manually.
+ * To regenerate the file, use the script "pkg/analysis_server/tool/spec/generate_files".
+ */
+package org.dartlang.analysis.server.protocol;
+
+/**
+ * An enumeration of the kinds of files.
+ *
+ * @coverage dart.server.generated.types
+ */
+public class FileKind {
+
+  public static final String LIBRARY = "LIBRARY";
+
+  public static final String PART = "PART";
+
+}
diff --git a/pkg/analysis_server/tool/spec/spec_input.html b/pkg/analysis_server/tool/spec/spec_input.html
index c913011..a48d987 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.9.0</version></h1>
+    <h1 style="color:#999999">Version <version>1.12.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
@@ -1044,6 +1044,23 @@
               The file with which the outline is associated.
             </p>
           </field>
+          <field name="kind">
+            <ref>FileKind</ref>
+            <p>
+              The kind of the file.
+            </p>
+          </field>
+          <field name="libraryName" optional="true">
+            <ref>String</ref>
+            <p>
+              The name of the library defined by the file using a "library"
+              directive, or referenced by a "part of" directive. If both
+              "library" and "part of" directives are present, then the
+              "library" directive takes precedence.
+              This field will be omitted if the file has neither "library"
+              nor "part of" directives.
+            </p>
+          </field>
           <field name="outline">
             <ref>Outline</ref>
             <p>
@@ -2010,6 +2027,21 @@
               message associated with the error code.
             </p>
           </field>
+          <field name="hasFix" optional="true">
+            <ref>bool</ref>
+            <p>
+              A hint to indicate to interested clients that this error has
+              an associated fix (or fixes).  The absence of this field implies
+              there are not known to be fixes.  Note that since the operation
+              to calculate whether fixes apply needs to be performant it is
+              possible that complicated tests will be skipped and a false
+              negative returned.  For this reason, this attribute should be
+              treated as a "hint".  Despite the possibility of false negatives,
+              no false positives should be returned.  If a client sees this
+              flag set they can proceed with the confidence that there are in
+              fact associated fixes.
+            </p>
+          </field>
         </object>
       </type>
       <type name="AnalysisErrorFixes">
@@ -2551,6 +2583,15 @@
           <value><code>LAUNCH_DATA</code></value>
         </enum>
       </type>
+      <type name="FileKind">
+        <p>
+          An enumeration of the kinds of files.
+        </p>
+        <enum>
+          <value><code>LIBRARY</code></value>
+          <value><code>PART</code></value>
+        </enum>
+      </type>
       <type name="FilePath">
         <ref>String</ref>
         <p>
@@ -3985,14 +4026,28 @@
       </refactoring>
       <refactoring kind="EXTRACT_LOCAL_VARIABLE">
         <p>
-          Create a local variable initialized by a specified
-          expression.
+          Create a local variable initialized by the expression that covers
+          the specified selection.
         </p>
         <p>
-          It is an error if the range contains anything other than a
-          complete expression (no partial expressions are allowed).
+          It is an error if the selection range is not covered by a
+          complete expression.
         </p>
         <feedback>
+          <field name="coveringExpressionOffsets">
+            <list><ref>int</ref></list>
+            <p>
+              The offsets of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </field>
+          <field name="coveringExpressionLengths">
+            <list><ref>int</ref></list>
+            <p>
+              The lengths of the expressions that cover the specified
+              selection, from the down most to the up most.
+            </p>
+          </field>
           <field name="names">
             <list><ref>String</ref></list>
             <p>
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index b39f429..c555f1b 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -27,7 +27,6 @@
 import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/generated/java_engine.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
 import 'package:analyzer/src/generated/source.dart';
 import 'package:analyzer/src/generated/utilities_collection.dart';
@@ -572,31 +571,13 @@
     if (source == null) {
       return null;
     }
-    CompilationUnit unit = parseCompilationUnit(source);
-    if (unit == null) {
+    SourceRange docRange = element.docRange;
+    if (docRange == null) {
       return null;
     }
-    NodeLocator locator = new NodeLocator(element.nameOffset);
-    AstNode nameNode = locator.searchWithin(unit);
-    while (nameNode != null) {
-      if (nameNode is AnnotatedNode) {
-        Comment comment = nameNode.documentationComment;
-        if (comment == null) {
-          return null;
-        }
-        StringBuffer buffer = new StringBuffer();
-        List<Token> tokens = comment.tokens;
-        for (int i = 0; i < tokens.length; i++) {
-          if (i > 0) {
-            buffer.write("\n");
-          }
-          buffer.write(tokens[i].lexeme);
-        }
-        return buffer.toString();
-      }
-      nameNode = nameNode.parent;
-    }
-    return null;
+    String code = getContents(source).data;
+    String comment = code.substring(docRange.offset, docRange.end);
+    return comment.replaceAll('\r\n', '\n');
   }
 
   @override
@@ -1157,7 +1138,7 @@
           new LibrarySpecificUnit(librarySource, librarySource);
       entry = getCacheEntry(unit);
       setValue(HINTS, AnalysisError.NO_ERRORS);
-      // dartEntry.setValue(LINTS, AnalysisError.NO_ERRORS);
+      setValue(LINTS, AnalysisError.NO_ERRORS);
       setValue(INFER_STATIC_VARIABLE_TYPES_ERRORS, AnalysisError.NO_ERRORS);
       setValue(LIBRARY_UNIT_ERRORS, AnalysisError.NO_ERRORS);
       setValue(PARTIALLY_RESOLVE_REFERENCES_ERRORS, AnalysisError.NO_ERRORS);
@@ -1654,16 +1635,16 @@
               return;
             }
           }
-//          if (lintsEnabled) {
-//            state = unitEntry.getState(LINTS);
-//            if (state == CacheState.INVALID ||
-//                (isPriority && state == CacheState.FLUSHED)) {
-//              sources.add(source);
-//              return;
-//            } else if (state == CacheState.ERROR) {
-//              return;
-//            }
-//          }
+          if (lintsEnabled) {
+            state = unitEntry.getState(LINTS);
+            if (state == CacheState.INVALID ||
+                (isPriority && state == CacheState.FLUSHED)) {
+              sources.add(source);
+              return;
+            } else if (state == CacheState.ERROR) {
+              return;
+            }
+          }
         }
       }
 //    } else if (kind == SourceKind.HTML) {
@@ -1896,8 +1877,7 @@
           sourceEntry,
           unitEntry,
           oldUnit,
-          analysisOptions.incrementalApi,
-          analysisOptions);
+          analysisOptions.incrementalApi);
       bool success = resolver.resolve(newCode);
       AnalysisEngine.instance.instrumentationService.logPerformance(
           AnalysisPerformanceKind.INCREMENTAL,
diff --git a/pkg/analyzer/lib/src/generated/element.dart b/pkg/analyzer/lib/src/generated/element.dart
index bff8b4e..30aa17e 100644
--- a/pkg/analyzer/lib/src/generated/element.dart
+++ b/pkg/analyzer/lib/src/generated/element.dart
@@ -2462,6 +2462,12 @@
   String get displayName;
 
   /**
+   * Return the source range of the documentation comment for this element,
+   * or `null` if this element does not or cannot have a documentation.
+   */
+  SourceRange get docRange;
+
+  /**
    * Return the element that either physically or logically encloses this
    * element. This will be `null` if this element is a library because libraries
    * are the top-level elements in the model.
@@ -2828,6 +2834,17 @@
   ElementLocation _cachedLocation;
 
   /**
+   * The offset to the beginning of the documentation comment,
+   * or `null` if this element does not have a documentation comment.
+   */
+  int _docRangeOffset;
+
+  /**
+   * The length of the documentation comment range for this element.
+   */
+  int _docRangeLength;
+
+  /**
    * Initialize a newly created element to have the given [name] at the given
    * [_nameOffset].
    */
@@ -2853,6 +2870,14 @@
   String get displayName => _name;
 
   @override
+  SourceRange get docRange {
+    if (_docRangeOffset != null && _docRangeLength != null) {
+      return new SourceRange(_docRangeOffset, _docRangeLength);
+    }
+    return null;
+  }
+
+  @override
   Element get enclosingElement => _enclosingElement;
 
   /**
@@ -3102,6 +3127,14 @@
   }
 
   /**
+   * Set the documentation comment source range for this element.
+   */
+  void setDocRange(int offset, int length) {
+    _docRangeOffset = offset;
+    _docRangeLength = length;
+  }
+
+  /**
    * Set whether the given [modifier] is associated with this element to
    * correspond to the given [value].
    */
@@ -7917,6 +7950,9 @@
   @override
   String get displayName => _baseElement.displayName;
 
+  @override
+  SourceRange get docRange => _baseElement.docRange;
+
   int get id => _baseElement.id;
 
   @override
@@ -8427,6 +8463,9 @@
   String get displayName => _name;
 
   @override
+  SourceRange get docRange => null;
+
+  @override
   Element get enclosingElement => null;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/element_handle.dart b/pkg/analyzer/lib/src/generated/element_handle.dart
index 35af627..338a279 100644
--- a/pkg/analyzer/lib/src/generated/element_handle.dart
+++ b/pkg/analyzer/lib/src/generated/element_handle.dart
@@ -337,6 +337,9 @@
   String get displayName => actualElement.displayName;
 
   @override
+  SourceRange get docRange => actualElement.docRange;
+
+  @override
   Element get enclosingElement => actualElement.enclosingElement;
 
   @override
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index a57cc05..9560bff 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -1641,31 +1641,13 @@
     if (source == null) {
       return null;
     }
-    CompilationUnit unit = parseCompilationUnit(source);
-    if (unit == null) {
+    SourceRange docRange = element.docRange;
+    if (docRange == null) {
       return null;
     }
-    NodeLocator locator = new NodeLocator(element.nameOffset);
-    AstNode nameNode = locator.searchWithin(unit);
-    while (nameNode != null) {
-      if (nameNode is AnnotatedNode) {
-        Comment comment = nameNode.documentationComment;
-        if (comment == null) {
-          return null;
-        }
-        StringBuffer buffer = new StringBuffer();
-        List<Token> tokens = comment.tokens;
-        for (int i = 0; i < tokens.length; i++) {
-          if (i > 0) {
-            buffer.write("\n");
-          }
-          buffer.write(tokens[i].lexeme);
-        }
-        return buffer.toString();
-      }
-      nameNode = nameNode.parent;
-    }
-    return null;
+    String code = getContents(source).data;
+    String comment = code.substring(docRange.offset, docRange.end);
+    return comment.replaceAll('\r\n', '\n');
   }
 
   @override
@@ -4886,8 +4868,7 @@
           null,
           null,
           oldUnit,
-          analysisOptions.incrementalApi,
-          analysisOptions);
+          analysisOptions.incrementalApi);
       bool success = resolver.resolve(newCode);
       AnalysisEngine.instance.instrumentationService.logPerformance(
           AnalysisPerformanceKind.INCREMENTAL,
@@ -8792,8 +8773,10 @@
       AnalysisEngine.instance.instrumentationService
           .logFileRead(source.fullName, _modificationTime, _content);
     } catch (exception, stackTrace) {
-      errors.add(new AnalysisError(
-          source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+      if (source.exists()) {
+        errors.add(new AnalysisError(
+            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [exception]));
+      }
       throw new AnalysisException("Could not get contents of $source",
           new CaughtException(exception, stackTrace));
     }
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 832bb00..7c8516e 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -943,7 +943,6 @@
 
   @override
   Object visitPropertyAccess(PropertyAccess node) {
-    bool isConditional = node.operator.type == sc.TokenType.QUESTION_PERIOD;
     ClassElement typeReference =
         ElementResolver.getTypeReference(node.realTarget);
     SimpleIdentifier propertyName = node.propertyName;
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 46cd677..15bbec9 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -493,6 +493,24 @@
       _assertCompatibleParameter(node.parameter, element);
     } else if (node is FieldFormalParameter) {
       _assertTrue(element.isInitializingFormal);
+      DartType parameterType = element.type;
+      if (node.type == null && node.parameters == null) {
+        FieldFormalParameterElement parameterElement = element;
+        if (!parameterElement.hasImplicitType) {
+          _assertTrue(parameterType == null || parameterType.isDynamic);
+        }
+        if (parameterElement.field != null) {
+          _assertEquals(node.identifier.name, element.name);
+        }
+      } else {
+        if (node.parameters != null) {
+          _assertTrue(parameterType is FunctionType);
+          FunctionType parameterFunctionType = parameterType;
+          _assertSameType(node.type, parameterFunctionType.returnType);
+        } else {
+          _assertSameType(node.type, parameterType);
+        }
+      }
       _assertCompatibleParameters(node.parameters, element.parameters);
     } else if (node is FunctionTypedFormalParameter) {
       _assertFalse(element.isInitializingFormal);
@@ -1044,8 +1062,6 @@
       _context.invalidateLibraryHints(_librarySource);
       // update entry errors
       _updateEntry();
-      // notify unit
-      _definingUnit.afterIncrementalResolution();
       // OK
       return true;
     } finally {
@@ -1223,6 +1239,7 @@
 
   void _shiftEntryErrors_NEW() {
     _shiftErrors_NEW(HINTS);
+    _shiftErrors_NEW(LINTS);
     _shiftErrors_NEW(INFER_STATIC_VARIABLE_TYPES_ERRORS);
     _shiftErrors_NEW(LIBRARY_UNIT_ERRORS);
     _shiftErrors_NEW(PARTIALLY_RESOLVE_REFERENCES_ERRORS);
@@ -1279,6 +1296,7 @@
     try {
       _definingUnit
           .accept(new _ElementNameOffsetUpdater(_updateOffset, _updateDelta));
+      _definingUnit.afterIncrementalResolution();
     } finally {
       timer.stop('update element offsets');
     }
@@ -1303,6 +1321,7 @@
     newUnitEntry.setState(USED_IMPORTED_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(USED_LOCAL_ELEMENTS, CacheState.INVALID);
     newUnitEntry.setState(HINTS, CacheState.INVALID);
+    newUnitEntry.setState(LINTS, CacheState.INVALID);
   }
 
   void _updateEntry_OLD() {
@@ -1392,7 +1411,6 @@
   CacheEntry _newUnitEntry;
 
   final CompilationUnit _oldUnit;
-  final AnalysisOptions _options;
   CompilationUnitElement _unitElement;
 
   int _updateOffset;
@@ -1411,8 +1429,7 @@
       this._newSourceEntry,
       this._newUnitEntry,
       this._oldUnit,
-      bool resolveApiChanges,
-      this._options) {
+      bool resolveApiChanges) {
     _resolveApiChanges = resolveApiChanges;
   }
 
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 0a197f5..908c297 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -44,6 +44,10 @@
 
 typedef void VoidFunction();
 
+typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
+
+typedef bool _SubtypeChecker<T>(T t1, T t2);
+
 /**
  * Instances of the class `BestPracticesVerifier` traverse an AST structure looking for
  * violations of Dart best practices.
@@ -2511,6 +2515,7 @@
       //
       constructors = _createDefaultConstructors(interfaceType);
     }
+    _setDocRange(element, node);
     element.abstract = node.isAbstract;
     element.accessors = holder.accessors;
     element.constructors = constructors;
@@ -2584,6 +2589,7 @@
     SimpleIdentifier constructorName = node.name;
     ConstructorElementImpl element =
         new ConstructorElementImpl.forNode(constructorName);
+    _setDocRange(element, node);
     if (node.externalKeyword != null) {
       element.external = true;
     }
@@ -2688,6 +2694,7 @@
     SimpleIdentifier enumName = node.name;
     ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
     enumElement.enum2 = true;
+    _setDocRange(enumElement, node);
     InterfaceTypeImpl enumType = new InterfaceTypeImpl(enumElement);
     enumElement.type = enumType;
     // The equivalent code for enums in the spec shows a single constructor,
@@ -2760,6 +2767,7 @@
         SimpleIdentifier functionName = node.name;
         FunctionElementImpl element =
             new FunctionElementImpl.forNode(functionName);
+        _setDocRange(element, node);
         if (node.externalKeyword != null) {
           element.external = true;
         }
@@ -2806,6 +2814,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
           }
@@ -2831,6 +2840,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
           }
@@ -2917,6 +2927,7 @@
     List<TypeParameterElement> typeParameters = holder.typeParameters;
     FunctionTypeAliasElementImpl element =
         new FunctionTypeAliasElementImpl.forNode(aliasName);
+    _setDocRange(element, node);
     element.parameters = parameters;
     element.typeParameters = typeParameters;
     FunctionTypeImpl type = new FunctionTypeImpl.forTypedef(element);
@@ -2988,6 +2999,7 @@
         }
         MethodElementImpl element =
             new MethodElementImpl(nameOfMethod, methodName.offset);
+        _setDocRange(element, node);
         element.abstract = node.isAbstract;
         if (node.externalKeyword != null) {
           element.external = true;
@@ -3024,6 +3036,7 @@
         if (node.isGetter) {
           PropertyAccessorElementImpl getter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(getter, node);
           if (node.externalKeyword != null) {
             getter.external = true;
           }
@@ -3049,6 +3062,7 @@
         } else {
           PropertyAccessorElementImpl setter =
               new PropertyAccessorElementImpl.forNode(propertyNameNode);
+          _setDocRange(setter, node);
           if (node.externalKeyword != null) {
             setter.external = true;
           }
@@ -3185,6 +3199,9 @@
         field = new FieldElementImpl.forNode(fieldName);
       }
       element = field;
+      if (node.parent.parent is FieldDeclaration) {
+        _setDocRange(element, node.parent.parent);
+      }
       if ((node.parent as VariableDeclarationList).type == null) {
         field.hasImplicitType = true;
       }
@@ -3350,6 +3367,17 @@
   }
 
   /**
+   * If the given [node] has a documentation comment, remember its range
+   * into the given [element].
+   */
+  void _setDocRange(ElementImpl element, AnnotatedNode node) {
+    Comment comment = node.documentationComment;
+    if (comment != null && comment.isDocumentation) {
+      element.setDocRange(comment.offset, comment.length);
+    }
+  }
+
+  /**
    * Sets the visible source range for formal parameter.
    */
   void _setParameterVisibleRange(
@@ -7060,6 +7088,7 @@
         .buildCompilationUnit(
             librarySource, definingCompilationUnit, librarySource);
     NodeList<Directive> directives = definingCompilationUnit.directives;
+    LibraryDirective libraryDirective = null;
     LibraryIdentifier libraryNameNode = null;
     bool hasPartDirective = false;
     FunctionElement entryPoint =
@@ -7077,6 +7106,7 @@
       //
       if (directive is LibraryDirective) {
         if (libraryNameNode == null) {
+          libraryDirective = directive;
           libraryNameNode = directive.name;
           directivesToResolve.add(directive);
         }
@@ -7135,6 +7165,7 @@
     //
     LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
         _analysisContext.getContextFor(librarySource), libraryNameNode);
+    _setDocRange(libraryElement, libraryDirective);
     libraryElement.definingCompilationUnit = definingCompilationUnitElement;
     if (entryPoint != null) {
       libraryElement.entryPoint = entryPoint;
@@ -7166,6 +7197,7 @@
         .buildCompilationUnit(
             librarySource, definingCompilationUnit, librarySource);
     NodeList<Directive> directives = definingCompilationUnit.directives;
+    LibraryDirective libraryDirective = null;
     LibraryIdentifier libraryNameNode = null;
     bool hasPartDirective = false;
     FunctionElement entryPoint =
@@ -7183,6 +7215,7 @@
       //
       if (directive is LibraryDirective) {
         if (libraryNameNode == null) {
+          libraryDirective = directive;
           libraryNameNode = directive.name;
           directivesToResolve.add(directive);
         }
@@ -7243,6 +7276,7 @@
     //
     LibraryElementImpl libraryElement = new LibraryElementImpl.forNode(
         _analysisContext.getContextFor(librarySource), libraryNameNode);
+    _setDocRange(libraryElement, libraryDirective);
     libraryElement.definingCompilationUnit = definingCompilationUnitElement;
     if (entryPoint != null) {
       libraryElement.entryPoint = entryPoint;
@@ -7346,6 +7380,19 @@
       }
     }
   }
+
+  /**
+   * If the given [node] has a documentation comment, remember its range
+   * into the given [element].
+   */
+  void _setDocRange(ElementImpl element, LibraryDirective node) {
+    if (node != null) {
+      Comment comment = node.documentationComment;
+      if (comment != null && comment.isDocumentation) {
+        element.setDocRange(comment.offset, comment.length);
+      }
+    }
+  }
 }
 
 /**
@@ -8928,46 +8975,6 @@
 }
 
 /**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver2_TypeAliasInfo {
-  final ResolvableLibrary _library;
-
-  final Source _source;
-
-  final FunctionTypeAlias _typeAlias;
-
-  /**
-   * Initialize a newly created information holder with the given information.
-   *
-   * @param library the library containing the type alias
-   * @param source the source of the file containing the type alias
-   * @param typeAlias the type alias being remembered
-   */
-  LibraryResolver2_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
- * Instances of the class `TypeAliasInfo` hold information about a [TypeAlias].
- */
-class LibraryResolver_TypeAliasInfo {
-  final Library _library;
-
-  final Source _source;
-
-  final FunctionTypeAlias _typeAlias;
-
-  /**
-   * Initialize a newly created information holder with the given information.
-   *
-   * @param library the library containing the type alias
-   * @param source the source of the file containing the type alias
-   * @param typeAlias the type alias being remembered
-   */
-  LibraryResolver_TypeAliasInfo(this._library, this._source, this._typeAlias);
-}
-
-/**
  * Instances of the class `LibraryScope` implement a scope containing all of the names defined
  * in a given library.
  */
@@ -9261,8 +9268,7 @@
    *
    * @return a table containing the same mappings as those defined by this namespace
    */
-  Map<String, Element> get definedNames =>
-      new HashMap<String, Element>.from(_definedNames);
+  Map<String, Element> get definedNames => _definedNames;
 
   /**
    * Return the element in this namespace that is available to the containing scope using the given
@@ -9412,7 +9418,7 @@
       List<NamespaceCombinator> combinators) {
     for (NamespaceCombinator combinator in combinators) {
       if (combinator is HideElementCombinator) {
-        _hide(definedNames, combinator.hiddenNames);
+        definedNames = _hide(definedNames, combinator.hiddenNames);
       } else if (combinator is ShowElementCombinator) {
         definedNames = _show(definedNames, combinator.shownNames);
       } else {
@@ -9491,24 +9497,22 @@
   }
 
   /**
-   * Hide all of the given names by removing them from the given collection of defined names.
-   *
-   * @param definedNames the names that were defined before this operation
-   * @param hiddenNames the names to be hidden
+   * Return a new map of names which has all the names from [definedNames]
+   * with exception of [hiddenNames].
    */
-  void _hide(HashMap<String, Element> definedNames, List<String> hiddenNames) {
+  Map<String, Element> _hide(
+      HashMap<String, Element> definedNames, List<String> hiddenNames) {
+    HashMap<String, Element> newNames =
+        new HashMap<String, Element>.from(definedNames);
     for (String name in hiddenNames) {
-      definedNames.remove(name);
-      definedNames.remove("$name=");
+      newNames.remove(name);
+      newNames.remove("$name=");
     }
+    return newNames;
   }
 
   /**
-   * Show only the given names by removing all other names from the given collection of defined
-   * names.
-   *
-   * @param definedNames the names that were defined before this operation
-   * @param shownNames the names to be shown
+   * Return a new map of names which has only [shownNames] from [definedNames].
    */
   HashMap<String, Element> _show(
       HashMap<String, Element> definedNames, List<String> shownNames) {
@@ -10544,6 +10548,14 @@
    */
   DartType overrideVariable(VariableElement element, DartType potentialType,
       bool allowPrecisionLoss) {
+    // TODO(scheglov) type propagation for instance/top-level fields
+    // was disabled because it depends on the order or visiting.
+    // If both field and its client are in the same unit, and we visit
+    // the client before the field, then propagated type is not set yet.
+    if (element is PropertyInducingElement) {
+      return null;
+    }
+
     if (potentialType == null || potentialType.isBottom) {
       return null;
     }
@@ -10576,18 +10588,6 @@
         allowPrecisionLoss ||
         !currentType.isMoreSpecificThan(potentialType) ||
         potentialType.isMoreSpecificThan(currentType)) {
-      // TODO(scheglov) type propagation for instance/top-level fields
-      // was disabled because it depends on the order or visiting.
-      // If both field and its client are in the same unit, and we visit
-      // the client before the field, then propagated type is not set yet.
-//      if (element is PropertyInducingElement) {
-//        PropertyInducingElement variable = element;
-//        if (!variable.isConst && !variable.isFinal) {
-//          return;
-//        }
-//        (variable as PropertyInducingElementImpl).propagatedType =
-//            potentialType;
-//      }
       _overrideManager.setType(element, potentialType);
       return potentialType;
     }
@@ -12723,6 +12723,310 @@
 }
 
 /**
+ * Implementation of [TypeSystem] using the strong mode rules.
+ * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
+ */
+class StrongTypeSystemImpl implements TypeSystem {
+  final _specTypeSystem = new TypeSystemImpl();
+
+  StrongTypeSystemImpl();
+
+  @override
+  DartType getLeastUpperBound(
+      TypeProvider typeProvider, DartType type1, DartType type2) {
+    // TODO(leafp): Implement a strong mode version of this.
+    return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
+  }
+
+  // TODO(leafp): Document the rules in play here
+  @override
+  bool isAssignableTo(DartType fromType, DartType toType) {
+    // An actual subtype
+    if (isSubtypeOf(fromType, toType)) {
+      return true;
+    }
+
+    // Don't allow implicit downcasts between function types
+    // and call method objects, as these will almost always fail.
+    if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
+        (toType is FunctionType && _getCallMethodType(fromType) != null)) {
+      return false;
+    }
+
+    // If the subtype relation goes the other way, allow the implicit downcast.
+    // TODO(leafp): Emit warnings and hints for these in some way.
+    // TODO(leafp): Consider adding a flag to disable these?  Or just rely on
+    //   --warnings-as-errors?
+    if (isSubtypeOf(toType, fromType) ||
+        _specTypeSystem.isAssignableTo(toType, fromType)) {
+      // TODO(leafp): error if type is known to be exact (literal,
+      //  instance creation).
+      // TODO(leafp): Warn on composite downcast.
+      // TODO(leafp): hint on object/dynamic downcast.
+      // TODO(leafp): Consider allowing assignment casts.
+      return true;
+    }
+
+    return false;
+  }
+
+  @override
+  bool isSubtypeOf(DartType leftType, DartType rightType) {
+    return _isSubtypeOf(leftType, rightType, null);
+  }
+
+  FunctionType _getCallMethodType(DartType t) {
+    if (t is InterfaceType) {
+      ClassElement element = t.element;
+      InheritanceManager manager = new InheritanceManager(element.library);
+      FunctionType callType = manager.lookupMemberType(t, "call");
+      return callType;
+    }
+    return null;
+  }
+
+  // Given a type t, if t is an interface type with a call method
+  // defined, return the function type for the call method, otherwise
+  // return null.
+  _GuardedSubtypeChecker<DartType> _guard(
+      _GuardedSubtypeChecker<DartType> check) {
+    return (DartType t1, DartType t2, Set<Element> visited) {
+      Element element = t1.element;
+      if (visited == null) {
+        visited = new HashSet<Element>();
+      }
+      if (element == null || !visited.add(element)) {
+        return false;
+      }
+      try {
+        return check(t1, t2, visited);
+      } finally {
+        visited.remove(element);
+      }
+    };
+  }
+
+  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
+    return (t.isDynamic && dynamicIsBottom) || t.isBottom;
+  }
+
+  // Guard against loops in the class hierarchy
+  /**
+   * Check that [f1] is a subtype of [f2].
+   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
+   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
+   * as bottom).
+   */
+  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
+      {bool fuzzyArrows: true}) {
+    final r1s = f1.normalParameterTypes;
+    final o1s = f1.optionalParameterTypes;
+    final n1s = f1.namedParameterTypes;
+    final r2s = f2.normalParameterTypes;
+    final o2s = f2.optionalParameterTypes;
+    final n2s = f2.namedParameterTypes;
+    final ret1 = f1.returnType;
+    final ret2 = f2.returnType;
+
+    // A -> B <: C -> D if C <: A and
+    // either D is void or B <: D
+    if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
+      return false;
+    }
+
+    // Reject if one has named and the other has optional
+    if (n1s.length > 0 && o2s.length > 0) {
+      return false;
+    }
+    if (n2s.length > 0 && o1s.length > 0) {
+      return false;
+    }
+
+    // Rebind _isSubtypeOf for convenience
+    _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
+        _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
+
+    // f2 has named parameters
+    if (n2s.length > 0) {
+      // Check that every named parameter in f2 has a match in f1
+      for (String k2 in n2s.keys) {
+        if (!n1s.containsKey(k2)) {
+          return false;
+        }
+        if (!parameterSubtype(n2s[k2], n1s[k2])) {
+          return false;
+        }
+      }
+    }
+    // If we get here, we either have no named parameters,
+    // or else the named parameters match and we have no optional
+    // parameters
+
+    // If f1 has more required parameters, reject
+    if (r1s.length > r2s.length) {
+      return false;
+    }
+
+    // If f2 has more required + optional parameters, reject
+    if (r2s.length + o2s.length > r1s.length + o1s.length) {
+      return false;
+    }
+
+    // The parameter lists must look like the following at this point
+    // where rrr is a region of required, and ooo is a region of optionals.
+    // f1: rrr ooo ooo ooo
+    // f2: rrr rrr ooo
+    int rr = r1s.length; // required in both
+    int or = r2s.length - r1s.length; // optional in f1, required in f2
+    int oo = o2s.length; // optional in both
+
+    for (int i = 0; i < rr; ++i) {
+      if (!parameterSubtype(r2s[i], r1s[i])) {
+        return false;
+      }
+    }
+    for (int i = 0, j = rr; i < or; ++i, ++j) {
+      if (!parameterSubtype(r2s[j], o1s[i])) {
+        return false;
+      }
+    }
+    for (int i = or, j = 0; i < oo; ++i, ++j) {
+      if (!parameterSubtype(o2s[j], o1s[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool _isInterfaceSubtypeOf(
+      InterfaceType i1, InterfaceType i2, Set<Element> visited) {
+    // Guard recursive calls
+    _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
+        _guard(_isInterfaceSubtypeOf);
+
+    if (i1 == i2) {
+      return true;
+    }
+
+    if (i1.element == i2.element) {
+      List<DartType> tArgs1 = i1.typeArguments;
+      List<DartType> tArgs2 = i2.typeArguments;
+
+      assert(tArgs1.length == tArgs2.length);
+
+      for (int i = 0; i < tArgs1.length; i++) {
+        DartType t1 = tArgs1[i];
+        DartType t2 = tArgs2[i];
+        if (!isSubtypeOf(t1, t2)) {
+          return false;
+        }
+      }
+      return true;
+    }
+
+    if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
+      return true;
+    }
+
+    if (i1.isObject) {
+      return false;
+    }
+
+    if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
+      return true;
+    }
+
+    for (final parent in i1.interfaces) {
+      if (guardedInterfaceSubtype(parent, i2, visited)) {
+        return true;
+      }
+    }
+
+    for (final parent in i1.mixins) {
+      if (guardedInterfaceSubtype(parent, i2, visited)) {
+        return true;
+      }
+    }
+
+    return false;
+  }
+
+  bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
+      {bool dynamicIsBottom: false}) {
+    // Guard recursive calls
+    _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
+
+    if (t1 == t2) {
+      return true;
+    }
+
+    // The types are void, dynamic, bottom, interface types, function types
+    // and type parameters.  We proceed by eliminating these different classes
+    // from consideration.
+
+    // Trivially true.
+    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
+      return true;
+    }
+
+    // Trivially false.
+    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
+        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
+      return false;
+    }
+
+    // S <: T where S is a type variable
+    //  T is not dynamic or object (handled above)
+    //  S != T (handled above)
+    //  So only true if bound of S is S' and
+    //  S' <: T
+    if (t1 is TypeParameterType) {
+      DartType bound = t1.element.bound;
+      if (bound == null) return false;
+      return guardedSubtype(bound, t2, visited);
+    }
+
+    if (t2 is TypeParameterType) {
+      return false;
+    }
+
+    if (t1.isVoid || t2.isVoid) {
+      return false;
+    }
+
+    // We've eliminated void, dynamic, bottom, and type parameters.  The only
+    // cases are the combinations of interface type and function type.
+
+    // A function type can only subtype an interface type if
+    // the interface type is Function
+    if (t1 is FunctionType && t2 is InterfaceType) {
+      return t2.isDartCoreFunction;
+    }
+
+    // An interface type can only subtype a function type if
+    // the interface type declares a call method with a type
+    // which is a super type of the function type.
+    if (t1 is InterfaceType && t2 is FunctionType) {
+      var callType = _getCallMethodType(t1);
+      return (callType != null) && _isFunctionSubtypeOf(callType, t2);
+    }
+
+    // Two interface types
+    if (t1 is InterfaceType && t2 is InterfaceType) {
+      return _isInterfaceSubtypeOf(t1, t2, visited);
+    }
+
+    return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
+  }
+
+  // TODO(leafp): Document the rules in play here
+  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
+    return (t.isDynamic && !dynamicIsBottom) || t.isObject;
+  }
+}
+
+/**
  * Instances of this class manage the knowledge of what the set of subtypes are for a given type.
  */
 class SubtypeManager {
@@ -14956,15 +15260,6 @@
  */
 abstract class TypeSystem {
   /**
-   * Create either a strong mode or regular type system based on context.
-   */
-  static TypeSystem create(AnalysisContext context) {
-    return (context.analysisOptions.strongMode)
-        ? new StrongTypeSystemImpl()
-        : new TypeSystemImpl();
-  }
-
-  /**
    * Compute the least upper bound of two types.
    */
   DartType getLeastUpperBound(
@@ -14981,6 +15276,15 @@
    * if leftType <: rightType).
    */
   bool isSubtypeOf(DartType leftType, DartType rightType);
+
+  /**
+   * Create either a strong mode or regular type system based on context.
+   */
+  static TypeSystem create(AnalysisContext context) {
+    return (context.analysisOptions.strongMode)
+        ? new StrongTypeSystemImpl()
+        : new TypeSystemImpl();
+  }
 }
 
 /**
@@ -15080,313 +15384,6 @@
   }
 }
 
-typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
-typedef bool _SubtypeChecker<T>(T t1, T t2);
-
-/**
- * Implementation of [TypeSystem] using the strong mode rules.
- * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
- */
-class StrongTypeSystemImpl implements TypeSystem {
-  StrongTypeSystemImpl();
-
-  final _specTypeSystem = new TypeSystemImpl();
-
-  @override
-  DartType getLeastUpperBound(
-      TypeProvider typeProvider, DartType type1, DartType type2) {
-    // TODO(leafp): Implement a strong mode version of this.
-    return _specTypeSystem.getLeastUpperBound(typeProvider, type1, type2);
-  }
-
-  // TODO(leafp): Document the rules in play here
-  @override
-  bool isAssignableTo(DartType toType, DartType fromType) {
-    // An actual subtype
-    if (isSubtypeOf(fromType, toType)) {
-      return true;
-    }
-
-    // Don't allow implicit downcasts between function types
-    // and call method objects, as these will almost always fail.
-    if ((fromType is FunctionType && _getCallMethodType(toType) != null) ||
-        (toType is FunctionType && _getCallMethodType(fromType) != null)) {
-      return false;
-    }
-
-    // If the subtype relation goes the other way, allow the implicit downcast.
-    // TODO(leafp): Emit warnings and hints for these in some way.
-    // TODO(leafp): Consider adding a flag to disable these?  Or just rely on
-    //   --warnings-as-errors?
-    if (isSubtypeOf(toType, fromType) ||
-        _specTypeSystem.isAssignableTo(toType, fromType)) {
-      // TODO(leafp): error if type is known to be exact (literal,
-      //  instance creation).
-      // TODO(leafp): Warn on composite downcast.
-      // TODO(leafp): hint on object/dynamic downcast.
-      // TODO(leafp): Consider allowing assignment casts.
-      return true;
-    }
-
-    return false;
-  }
-
-  bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
-    return (t.isDynamic && dynamicIsBottom) || t.isBottom;
-  }
-
-  bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
-    return (t.isDynamic && !dynamicIsBottom) || t.isObject;
-  }
-
-  // Given a type t, if t is an interface type with a call method
-  // defined, return the function type for the call method, otherwise
-  // return null.
-  FunctionType _getCallMethodType(DartType t) {
-    if (t is InterfaceType) {
-      ClassElement element = t.element;
-      InheritanceManager manager = new InheritanceManager(element.library);
-      FunctionType callType = manager.lookupMemberType(t, "call");
-      return callType;
-    }
-    return null;
-  }
-
-  /**
-   * Check that [f1] is a subtype of [f2].
-   * [fuzzyArrows] indicates whether or not the f1 and f2 should be
-   * treated as fuzzy arrow types (and hence dynamic parameters to f2 treated
-   * as bottom).
-   */
-  bool _isFunctionSubtypeOf(FunctionType f1, FunctionType f2,
-      {bool fuzzyArrows: true}) {
-    final r1s = f1.normalParameterTypes;
-    final o1s = f1.optionalParameterTypes;
-    final n1s = f1.namedParameterTypes;
-    final r2s = f2.normalParameterTypes;
-    final o2s = f2.optionalParameterTypes;
-    final n2s = f2.namedParameterTypes;
-    final ret1 = f1.returnType;
-    final ret2 = f2.returnType;
-
-    // A -> B <: C -> D if C <: A and
-    // either D is void or B <: D
-    if (!ret2.isVoid && !isSubtypeOf(ret1, ret2)) {
-      return false;
-    }
-
-    // Reject if one has named and the other has optional
-    if (n1s.length > 0 && o2s.length > 0) {
-      return false;
-    }
-    if (n2s.length > 0 && o1s.length > 0) {
-      return false;
-    }
-
-    // Rebind _isSubtypeOf for convenience
-    _SubtypeChecker<DartType> parameterSubtype = (DartType t1, DartType t2) =>
-        _isSubtypeOf(t1, t2, null, dynamicIsBottom: fuzzyArrows);
-
-    // f2 has named parameters
-    if (n2s.length > 0) {
-      // Check that every named parameter in f2 has a match in f1
-      for (String k2 in n2s.keys) {
-        if (!n1s.containsKey(k2)) {
-          return false;
-        }
-        if (!parameterSubtype(n2s[k2], n1s[k2])) {
-          return false;
-        }
-      }
-    }
-    // If we get here, we either have no named parameters,
-    // or else the named parameters match and we have no optional
-    // parameters
-
-    // If f1 has more required parameters, reject
-    if (r1s.length > r2s.length) {
-      return false;
-    }
-
-    // If f2 has more required + optional parameters, reject
-    if (r2s.length + o2s.length > r1s.length + o1s.length) {
-      return false;
-    }
-
-    // The parameter lists must look like the following at this point
-    // where rrr is a region of required, and ooo is a region of optionals.
-    // f1: rrr ooo ooo ooo
-    // f2: rrr rrr ooo
-    int rr = r1s.length; // required in both
-    int or = r2s.length - r1s.length; // optional in f1, required in f2
-    int oo = o2s.length; // optional in both
-
-    for (int i = 0; i < rr; ++i) {
-      if (!parameterSubtype(r2s[i], r1s[i])) {
-        return false;
-      }
-    }
-    for (int i = 0, j = rr; i < or; ++i, ++j) {
-      if (!parameterSubtype(r2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    for (int i = or, j = 0; i < oo; ++i, ++j) {
-      if (!parameterSubtype(o2s[j], o1s[i])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  // Guard against loops in the class hierarchy
-  _GuardedSubtypeChecker<DartType> _guard(
-      _GuardedSubtypeChecker<DartType> check) {
-    return (DartType t1, DartType t2, Set<Element> visited) {
-      Element element = t1.element;
-      if (visited == null) {
-        visited = new HashSet<Element>();
-      }
-      if (element == null || !visited.add(element)) {
-        return false;
-      }
-      try {
-        return check(t1, t2, visited);
-      } finally {
-        visited.remove(element);
-      }
-    };
-  }
-
-  bool _isInterfaceSubtypeOf(
-      InterfaceType i1, InterfaceType i2, Set<Element> visited) {
-    // Guard recursive calls
-    _GuardedSubtypeChecker<InterfaceType> guardedInterfaceSubtype =
-        _guard(_isInterfaceSubtypeOf);
-
-    if (i1 == i2) {
-      return true;
-    }
-
-    if (i1.element == i2.element) {
-      List<DartType> tArgs1 = i1.typeArguments;
-      List<DartType> tArgs2 = i2.typeArguments;
-
-      assert(tArgs1.length == tArgs2.length);
-
-      for (int i = 0; i < tArgs1.length; i++) {
-        DartType t1 = tArgs1[i];
-        DartType t2 = tArgs2[i];
-        if (!isSubtypeOf(t1, t2)) {
-          return false;
-        }
-      }
-      return true;
-    }
-
-    if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
-      return true;
-    }
-
-    if (i1.isObject) {
-      return false;
-    }
-
-    if (guardedInterfaceSubtype(i1.superclass, i2, visited)) {
-      return true;
-    }
-
-    for (final parent in i1.interfaces) {
-      if (guardedInterfaceSubtype(parent, i2, visited)) {
-        return true;
-      }
-    }
-
-    for (final parent in i1.mixins) {
-      if (guardedInterfaceSubtype(parent, i2, visited)) {
-        return true;
-      }
-    }
-
-    return false;
-  }
-
-  bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
-      {bool dynamicIsBottom: false}) {
-    // Guard recursive calls
-    _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
-
-    if (t1 == t2) {
-      return true;
-    }
-
-    // The types are void, dynamic, bottom, interface types, function types
-    // and type parameters.  We proceed by eliminating these different classes
-    // from consideration.
-
-    // Trivially true.
-    if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
-      return true;
-    }
-
-    // Trivially false.
-    if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
-        _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
-      return false;
-    }
-
-    // S <: T where S is a type variable
-    //  T is not dynamic or object (handled above)
-    //  S != T (handled above)
-    //  So only true if bound of S is S' and
-    //  S' <: T
-    if (t1 is TypeParameterType) {
-      DartType bound = t1.element.bound;
-      if (bound == null) return false;
-      return guardedSubtype(bound, t2, visited);
-    }
-
-    if (t2 is TypeParameterType) {
-      return false;
-    }
-
-    if (t1.isVoid || t2.isVoid) {
-      return false;
-    }
-
-    // We've eliminated void, dynamic, bottom, and type parameters.  The only
-    // cases are the combinations of interface type and function type.
-
-    // A function type can only subtype an interface type if
-    // the interface type is Function
-    if (t1 is FunctionType && t2 is InterfaceType) {
-      return t2.isDartCoreFunction;
-    }
-
-    // An interface type can only subtype a function type if
-    // the interface type declares a call method with a type
-    // which is a super type of the function type.
-    if (t1 is InterfaceType && t2 is FunctionType) {
-      var callType = _getCallMethodType(t1);
-      return (callType != null) && _isFunctionSubtypeOf(callType, t2);
-    }
-
-    // Two interface types
-    if (t1 is InterfaceType && t2 is InterfaceType) {
-      return _isInterfaceSubtypeOf(t1, t2, visited);
-    }
-
-    return _isFunctionSubtypeOf(t1 as FunctionType, t2 as FunctionType);
-  }
-
-  // TODO(leafp): Document the rules in play here
-  @override
-  bool isSubtypeOf(DartType leftType, DartType rightType) {
-    return _isSubtypeOf(leftType, rightType, null);
-  }
-}
-
 /**
  * Instances of the class [UnusedLocalElementsVerifier] traverse an element
  * structure looking for cases of [HintCode.UNUSED_ELEMENT],
diff --git a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
index 86f1e04..bb758b3 100644
--- a/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
+++ b/pkg/analyzer/lib/src/generated/testing/ast_factory.dart
@@ -377,6 +377,11 @@
           TypeName type, String identifier) =>
       declaredIdentifier2(null, type, identifier);
 
+  static Comment documentationComment(
+      List<Token> tokens, List<CommentReference> references) {
+    return new Comment(tokens, CommentType.DOCUMENTATION, references);
+  }
+
   static DoStatement doStatement(Statement body, Expression condition) =>
       new DoStatement(
           TokenFactory.tokenFromKeyword(Keyword.DO),
diff --git a/pkg/analyzer/lib/src/plugin/engine_plugin.dart b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
index 75debaa..f720367 100644
--- a/pkg/analyzer/lib/src/plugin/engine_plugin.dart
+++ b/pkg/analyzer/lib/src/plugin/engine_plugin.dart
@@ -159,8 +159,6 @@
 
   void _registerDartErrorsForSource(RegisterExtension registerExtension) {
     String id = DART_ERRORS_FOR_SOURCE_EXTENSION_POINT_ID;
-    registerExtension(id, BUILD_DIRECTIVES_ERRORS);
-    registerExtension(id, BUILD_LIBRARY_ERRORS);
     registerExtension(id, PARSE_ERRORS);
     registerExtension(id, SCAN_ERRORS);
   }
@@ -203,6 +201,7 @@
     registerExtension(taskId, GatherUsedImportedElementsTask.DESCRIPTOR);
     registerExtension(taskId, GatherUsedLocalElementsTask.DESCRIPTOR);
     registerExtension(taskId, GenerateHintsTask.DESCRIPTOR);
+    registerExtension(taskId, GenerateLintsTask.DESCRIPTOR);
     registerExtension(taskId, InferInstanceMembersInUnitTask.DESCRIPTOR);
     registerExtension(taskId, InferStaticVariableTypesInUnitTask.DESCRIPTOR);
     registerExtension(taskId, InferStaticVariableTypeTask.DESCRIPTOR);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 8ce9084..2091fdc 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -21,7 +21,9 @@
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/generated/visitors.dart';
 import 'package:analyzer/src/plugin/engine_plugin.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/driver.dart';
 import 'package:analyzer/src/task/general.dart';
 import 'package:analyzer/src/task/html.dart';
@@ -291,6 +293,17 @@
         'LIBRARY_UNIT_ERRORS', AnalysisError.NO_ERRORS);
 
 /**
+ * The errors produced while generating lints for a compilation unit.
+ *
+ * The list will be empty if there were no errors, but will not be `null`.
+ *
+ * The result is only available for [LibrarySpecificUnit]s.
+ */
+final ListResultDescriptor<AnalysisError> LINTS =
+    new ListResultDescriptor<AnalysisError>(
+        'LINT_ERRORS', AnalysisError.NO_ERRORS);
+
+/**
  * The errors produced while parsing a compilation unit.
  *
  * The list will be empty if there were no errors, but will not be `null`.
@@ -537,7 +550,7 @@
     //
     // Build or reuse CompilationUnitElement.
     //
-    unit = AstCloner.clone(unit);
+//    unit = AstCloner.clone(unit);
     AnalysisCache analysisCache =
         (context as InternalAnalysisContext).analysisCache;
     CompilationUnitElement element =
@@ -573,7 +586,7 @@
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
-      PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit)
+      PARSED_UNIT_INPUT_NAME: PARSED_UNIT.of(unit.unit, flushOnAccess: true)
     };
   }
 
@@ -2419,6 +2432,92 @@
 }
 
 /**
+ * A task that generates [LINTS] for a unit.
+ */
+class GenerateLintsTask extends SourceBasedAnalysisTask {
+  /**
+   * The name of the [RESOLVED_UNIT8] input.
+   */
+  static const String RESOLVED_UNIT_INPUT = 'RESOLVED_UNIT';
+
+  /**
+   * The name of a list of [USED_LOCAL_ELEMENTS] for each library unit input.
+   */
+  static const String USED_LOCAL_ELEMENTS_INPUT = 'USED_LOCAL_ELEMENTS';
+
+  /**
+   * The name of a list of [USED_IMPORTED_ELEMENTS] for each library unit input.
+   */
+  static const String USED_IMPORTED_ELEMENTS_INPUT = 'USED_IMPORTED_ELEMENTS';
+
+  /**
+   * The name of the [TYPE_PROVIDER] input.
+   */
+  static const String TYPE_PROVIDER_INPUT = 'TYPE_PROVIDER_INPUT';
+
+  /**
+   * The task descriptor describing this kind of task.
+   */
+  static final TaskDescriptor DESCRIPTOR = new TaskDescriptor(
+      'GenerateLintsTask', createTask, buildInputs, <ResultDescriptor>[LINTS]);
+
+  GenerateLintsTask(InternalAnalysisContext context, AnalysisTarget target)
+      : super(context, target);
+
+  @override
+  TaskDescriptor get descriptor => DESCRIPTOR;
+
+  @override
+  void internalPerform() {
+    AnalysisOptions analysisOptions = context.analysisOptions;
+    if (!analysisOptions.lint) {
+      outputs[LINTS] = AnalysisError.NO_ERRORS;
+      return;
+    }
+    //
+    // Prepare collectors.
+    //
+    RecordingErrorListener errorListener = new RecordingErrorListener();
+    Source source = getRequiredSource();
+    ErrorReporter errorReporter = new ErrorReporter(errorListener, source);
+    //
+    // Prepare inputs.
+    //
+    CompilationUnit unit = getRequiredInput(RESOLVED_UNIT_INPUT);
+
+    //
+    // Generate lints.
+    //
+    LintGenerator.LINTERS.forEach((l) => l.reporter = errorReporter);
+    Iterable<AstVisitor> visitors =
+        LintGenerator.LINTERS.map((l) => l.getVisitor()).toList();
+    unit.accept(new DelegatingAstVisitor(visitors.where((v) => v != null)));
+
+    //
+    // Record outputs.
+    //
+    outputs[LINTS] = errorListener.errors;
+  }
+
+  /**
+   * Return a map from the names of the inputs of this kind of task to the task
+   * input descriptors describing those inputs for a task with the
+   * given [target].
+   */
+  static Map<String, TaskInput> buildInputs(AnalysisTarget target) =>
+      <String, TaskInput>{RESOLVED_UNIT_INPUT: RESOLVED_UNIT.of(target)};
+
+  /**
+   * Create a [GenerateLintsTask] based on the given [target] in
+   * the given [context].
+   */
+  static GenerateLintsTask createTask(
+      AnalysisContext context, AnalysisTarget target) {
+    return new GenerateLintsTask(context, target);
+  }
+}
+
+/**
  * A task that ensures that all of the inferrable instance members in a
  * compilation unit have had their type inferred.
  */
@@ -2804,11 +2903,26 @@
  */
 class LibraryUnitErrorsTask extends SourceBasedAnalysisTask {
   /**
+   * The name of the [BUILD_DIRECTIVES_ERRORS] input.
+   */
+  static const String BUILD_DIRECTIVES_ERRORS_INPUT = 'BUILD_DIRECTIVES_ERRORS';
+
+  /**
+   * The name of the [BUILD_LIBRARY_ERRORS] input.
+   */
+  static const String BUILD_LIBRARY_ERRORS_INPUT = 'BUILD_LIBRARY_ERRORS';
+
+  /**
    * The name of the [HINTS] input.
    */
   static const String HINTS_INPUT = 'HINTS';
 
   /**
+   * The name of the [LINTS] input.
+   */
+  static const String LINTS_INPUT = 'LINTS';
+
+  /**
    * The name of the [INFER_STATIC_VARIABLE_TYPES_ERRORS] input.
    */
   static const String INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT =
@@ -2864,7 +2978,10 @@
     // Prepare inputs.
     //
     List<List<AnalysisError>> errorLists = <List<AnalysisError>>[];
+    errorLists.add(getRequiredInput(BUILD_DIRECTIVES_ERRORS_INPUT));
+    errorLists.add(getRequiredInput(BUILD_LIBRARY_ERRORS_INPUT));
     errorLists.add(getRequiredInput(HINTS_INPUT));
+    errorLists.add(getRequiredInput(LINTS_INPUT));
     errorLists.add(getRequiredInput(INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT));
     errorLists.add(getRequiredInput(RESOLVE_FUNCTION_BODIES_ERRORS_INPUT));
@@ -2884,8 +3001,9 @@
    */
   static Map<String, TaskInput> buildInputs(AnalysisTarget target) {
     LibrarySpecificUnit unit = target;
-    return <String, TaskInput>{
+    Map<String, TaskInput> inputs = <String, TaskInput>{
       HINTS_INPUT: HINTS.of(unit),
+      LINTS_INPUT: LINTS.of(unit),
       INFER_STATIC_VARIABLE_TYPES_ERRORS_INPUT:
           INFER_STATIC_VARIABLE_TYPES_ERRORS.of(unit),
       PARTIALLY_RESOLVE_REFERENCES_ERRORS_INPUT:
@@ -2896,6 +3014,18 @@
       VARIABLE_REFERENCE_ERRORS_INPUT: VARIABLE_REFERENCE_ERRORS.of(unit),
       VERIFY_ERRORS_INPUT: VERIFY_ERRORS.of(unit)
     };
+    Source source = unit.source;
+    if (unit.library == source) {
+      inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+          BUILD_DIRECTIVES_ERRORS.of(source);
+      inputs[BUILD_LIBRARY_ERRORS_INPUT] = BUILD_LIBRARY_ERRORS.of(source);
+    } else {
+      inputs[BUILD_DIRECTIVES_ERRORS_INPUT] =
+          new ConstantTaskInput(AnalysisError.NO_ERRORS);
+      inputs[BUILD_LIBRARY_ERRORS_INPUT] =
+          new ConstantTaskInput(AnalysisError.NO_ERRORS);
+    }
+    return inputs;
   }
 
   /**
@@ -3730,7 +3860,7 @@
     LibrarySpecificUnit unit = target;
     return <String, TaskInput>{
       LIBRARY_INPUT: LIBRARY_ELEMENT1.of(unit.library),
-      UNIT_INPUT: RESOLVED_UNIT1.of(unit),
+      UNIT_INPUT: RESOLVED_UNIT3.of(unit),
       TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
     };
   }
@@ -3788,8 +3918,10 @@
           message = exception.toString();
         }
       }
-      errorListener.onError(new AnalysisError(
-          source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+      if (source.exists()) {
+        errorListener.onError(new AnalysisError(
+            source, 0, 0, ScannerErrorCode.UNABLE_GET_CONTENT, [message]));
+      }
     }
     if (target is DartScript) {
       DartScript script = target;
@@ -4087,6 +4219,9 @@
   }
 
   @override
+  bool get flushOnAccess => false;
+
+  @override
   List<Source> get inputValue {
     return _libraries.map((LibraryElement library) => library.source).toList();
   }
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 77c4a0a..cc4d4e6 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -42,6 +42,7 @@
    */
   static final List<ResultDescriptor> _UNIT_ERRORS = <ResultDescriptor>[
     HINTS,
+    LINTS,
     INFER_STATIC_VARIABLE_TYPES_ERRORS,
     LIBRARY_UNIT_ERRORS,
     PARTIALLY_RESOLVE_REFERENCES_ERRORS,
diff --git a/pkg/analyzer/lib/src/task/driver.dart b/pkg/analyzer/lib/src/task/driver.dart
index 8daa5cf..3231454 100644
--- a/pkg/analyzer/lib/src/task/driver.dart
+++ b/pkg/analyzer/lib/src/task/driver.dart
@@ -667,6 +667,9 @@
         }
       } else {
         builder.currentValue = inputEntry.getValue(inputResult);
+        if (builder.flushOnAccess) {
+          inputEntry.setState(inputResult, CacheState.FLUSHED);
+        }
       }
       if (!builder.moveNext()) {
         inputs = builder.inputValue;
diff --git a/pkg/analyzer/lib/src/task/inputs.dart b/pkg/analyzer/lib/src/task/inputs.dart
index c93a127..468f313 100644
--- a/pkg/analyzer/lib/src/task/inputs.dart
+++ b/pkg/analyzer/lib/src/task/inputs.dart
@@ -24,6 +24,55 @@
  * An input to an [AnalysisTask] that is computed by accessing a single result
  * defined on a single target.
  */
+class ConstantTaskInput<V> extends TaskInputImpl<V> {
+  final V value;
+
+  ConstantTaskInput(this.value);
+
+  @override
+  TaskInputBuilder<V> createBuilder() {
+    return new ConstantTaskInputBuilder<V>(this);
+  }
+}
+
+/**
+ * A [TaskInputBuilder] used to build an input based on a [ConstantTaskInput].
+ */
+class ConstantTaskInputBuilder<V> implements TaskInputBuilder<V> {
+  final ConstantTaskInput input;
+
+  ConstantTaskInputBuilder(this.input);
+
+  @override
+  ResultDescriptor get currentResult => null;
+
+  @override
+  AnalysisTarget get currentTarget => null;
+
+  @override
+  void set currentValue(Object value) {
+    throw new StateError('Only supported after moveNext() returns true');
+  }
+
+  @override
+  bool get flushOnAccess => false;
+
+  @override
+  V get inputValue => input.value;
+
+  @override
+  void currentValueNotAvailable() {
+    throw new StateError('Only supported after moveNext() returns true');
+  }
+
+  @override
+  bool moveNext() => false;
+}
+
+/**
+ * An input to an [AnalysisTask] that is computed by accessing a single result
+ * defined on a single target.
+ */
 class ListTaskInputImpl<E> extends SimpleTaskInput<List<E>>
     with ListTaskInputMixin<E>
     implements ListTaskInput<E> {
@@ -32,7 +81,7 @@
    * the given [result] associated with the given [target].
    */
   ListTaskInputImpl(AnalysisTarget target, ResultDescriptor<List<E>> result)
-      : super(target, result);
+      : super._unflushable(target, result);
 }
 
 /**
@@ -243,6 +292,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   void currentValueNotAvailable() {
     if (currentBuilder == null) {
       throw new StateError(
@@ -394,6 +446,9 @@
   }
 
   @override
+  bool get flushOnAccess => builder.flushOnAccess;
+
+  @override
   List<E> get inputValue {
     if (builder != null) {
       throw new StateError('Result value has not been created');
@@ -445,10 +500,23 @@
   final ResultDescriptor<V> result;
 
   /**
+   * Return `true` if the value accessed by this input builder should be flushed
+   * from the cache at the time it is retrieved.
+   */
+  final bool flushOnAccess;
+
+  /**
    * Initialize a newly created task input that computes the input by accessing
    * the given [result] associated with the given [target].
    */
-  SimpleTaskInput(this.target, this.result);
+  SimpleTaskInput(this.target, this.result, {this.flushOnAccess: false});
+
+  /**
+   * Initialize a newly created task input that computes the input by accessing
+   * the given [result] associated with the given [target].
+   */
+  SimpleTaskInput._unflushable(this.target, this.result)
+      : flushOnAccess = false;
 
   @override
   TaskInputBuilder<V> createBuilder() => new SimpleTaskInputBuilder<V>(this);
@@ -520,6 +588,9 @@
   }
 
   @override
+  bool get flushOnAccess => input.flushOnAccess;
+
+  @override
   V get inputValue {
     if (_state != _AFTER) {
       throw new StateError('Result value has not been created');
@@ -628,6 +699,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   Map<String, Object> get inputValue {
     if (nameIndex < inputNames.length) {
       throw new StateError('Result value has not been created');
@@ -675,11 +749,18 @@
       return false;
     }
     currentBuilder = inputDescriptors[_currentName].createBuilder();
-    // NOTE: This assumes that every builder will require at least one result
-    // value to be created. If that assumption is every broken, this method will
-    // need to be changed to advance until we find a builder that does require
-    // a result to be computed (or run out of builders).
-    return currentBuilder.moveNext();
+    while (!currentBuilder.moveNext()) {
+      if (currentBuilder.inputValue != null) {
+        inputs[_currentName] = currentBuilder.inputValue;
+      }
+      nameIndex++;
+      if (nameIndex >= inputNames.length) {
+        // There is no next value, so we're done.
+        return false;
+      }
+      currentBuilder = inputDescriptors[_currentName].createBuilder();
+    }
+    return true;
   }
 }
 
@@ -774,6 +855,9 @@
   }
 
   @override
+  bool get flushOnAccess => currentBuilder.flushOnAccess;
+
+  @override
   C get inputValue {
     if (currentBuilder != null || _resultValue == null) {
       throw new StateError('Result value has not been created');
diff --git a/pkg/analyzer/lib/src/task/model.dart b/pkg/analyzer/lib/src/task/model.dart
index 9ef568e..50c05ee 100644
--- a/pkg/analyzer/lib/src/task/model.dart
+++ b/pkg/analyzer/lib/src/task/model.dart
@@ -29,8 +29,12 @@
       : super(name, defaultValue, cachingPolicy: cachingPolicy);
 
   @override
-  ListTaskInput<E> of(AnalysisTarget target) =>
-      new ListTaskInputImpl<E>(target, this);
+  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false}) {
+    if (flushOnAccess) {
+      throw new StateError('Cannot flush a list of values');
+    }
+    return new ListTaskInputImpl<E>(target, this);
+  }
 }
 
 /**
@@ -71,8 +75,8 @@
   }
 
   @override
-  TaskInput<V> of(AnalysisTarget target) =>
-      new SimpleTaskInput<V>(target, this);
+  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false}) =>
+      new SimpleTaskInput<V>(target, this, flushOnAccess: flushOnAccess);
 
   @override
   String toString() => name;
diff --git a/pkg/analyzer/lib/task/model.dart b/pkg/analyzer/lib/task/model.dart
index 018b349..9d949c3 100644
--- a/pkg/analyzer/lib/task/model.dart
+++ b/pkg/analyzer/lib/task/model.dart
@@ -5,6 +5,7 @@
 library analyzer.task.model;
 
 import 'dart:collection';
+import 'dart:developer';
 
 import 'package:analyzer/src/generated/engine.dart' hide AnalysisTask;
 import 'package:analyzer/src/generated/error.dart' show AnalysisError;
@@ -84,6 +85,12 @@
   static final Map<Type, int> countMap = new HashMap<Type, int>();
 
   /**
+   * A table mapping the types of analysis tasks to user tags used to collect
+   * timing data for the Observatory.
+   */
+  static Map<Type, UserTag> tagMap = new HashMap<Type, UserTag>();
+
+  /**
    * A table mapping the types of analysis tasks to stopwatches used to compute
    * how much time was spent executing each kind of task.
    */
@@ -228,11 +235,15 @@
       //
       int count = countMap[runtimeType];
       countMap[runtimeType] = count == null ? 1 : count + 1;
+//      UserTag tag = tagMap.putIfAbsent(
+//          runtimeType, () => new UserTag(runtimeType.toString()));
       Stopwatch stopwatch = stopwatchMap[runtimeType];
       if (stopwatch == null) {
         stopwatch = new Stopwatch();
         stopwatchMap[runtimeType] = stopwatch;
       }
+//      UserTag previousTag = tag.makeCurrent();
+//      try {
       stopwatch.start();
       //
       // Actually perform the task.
@@ -245,6 +256,9 @@
       } finally {
         stopwatch.stop();
       }
+//      } finally {
+//        previousTag.makeCurrent();
+//      }
     } on AnalysisException {
       rethrow;
     } catch (exception, stackTrace) {
@@ -272,7 +286,7 @@
       E>;
 
   @override
-  ListTaskInput<E> of(AnalysisTarget target);
+  ListTaskInput<E> of(AnalysisTarget target, {bool flushOnAccess: false});
 }
 
 /**
@@ -387,9 +401,10 @@
 
   /**
    * Return a task input that can be used to compute this result for the given
-   * [target].
+   * [target]. If [flushOnAccess] is `true` then the value of this result that
+   * is associated with the [target] will be flushed when it is accessed.
    */
-  TaskInput<V> of(AnalysisTarget target);
+  TaskInput<V> of(AnalysisTarget target, {bool flushOnAccess: false});
 }
 
 /**
@@ -530,6 +545,12 @@
   void set currentValue(Object value);
 
   /**
+   * Return `true` if the value accessed by this input builder should be flushed
+   * from the cache at the time it is retrieved.
+   */
+  bool get flushOnAccess;
+
+  /**
    * Return the [value] that was computed by this builder.
    *
    * Throws a [StateError] if [moveNext] has not been invoked or if the last
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 056ec55..022f3f8 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.26.1+6
+version: 0.26.1+7
 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 0b878f5..cabe5d7 100644
--- a/pkg/analyzer/test/generated/all_the_rest_test.dart
+++ b/pkg/analyzer/test/generated/all_the_rest_test.dart
@@ -5052,6 +5052,8 @@
     String className = "C";
     ClassDeclaration classDeclaration =
         AstFactory.classDeclaration(null, className, null, null, null, null);
+    classDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     classDeclaration.accept(builder);
     List<ClassElement> types = holder.types;
     expect(types, hasLength(1));
@@ -5063,6 +5065,7 @@
     expect(type.isAbstract, isFalse);
     expect(type.isMixinApplication, isFalse);
     expect(type.isSynthetic, isFalse);
+    _assertHasDocRange(type, 50, 7);
   }
 
   void test_visitClassDeclaration_parameterized() {
@@ -5296,11 +5299,16 @@
             AstFactory.formalParameterList(),
             null,
             AstFactory.blockFunctionBody2());
+    constructorDeclaration.documentationComment = AstFactory
+        .documentationComment(
+            [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     constructorDeclaration.accept(builder);
+
     List<ConstructorElement> constructors = holder.constructors;
     expect(constructors, hasLength(1));
     ConstructorElement constructor = constructors[0];
     expect(constructor, isNotNull);
+    _assertHasDocRange(constructor, 50, 7);
     expect(constructor.isExternal, isFalse);
     expect(constructor.isFactory, isFalse);
     expect(constructor.name, "");
@@ -5478,11 +5486,14 @@
     String enumName = "E";
     EnumDeclaration enumDeclaration =
         AstFactory.enumDeclaration2(enumName, ["ONE"]);
+    enumDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     enumDeclaration.accept(builder);
     List<ClassElement> enums = holder.enums;
     expect(enums, hasLength(1));
     ClassElement enumElement = enums[0];
     expect(enumElement, isNotNull);
+    _assertHasDocRange(enumElement, 50, 7);
     expect(enumElement.name, enumName);
   }
 
@@ -5496,18 +5507,25 @@
       AstFactory.variableDeclaration(firstFieldName),
       AstFactory.variableDeclaration(secondFieldName)
     ]);
+    fieldDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     fieldDeclaration.accept(builder);
+
     List<FieldElement> fields = holder.fields;
     expect(fields, hasLength(2));
+
     FieldElement firstField = fields[0];
     expect(firstField, isNotNull);
+    _assertHasDocRange(firstField, 50, 7);
     expect(firstField.name, firstFieldName);
     expect(firstField.initializer, isNull);
     expect(firstField.isConst, isFalse);
     expect(firstField.isFinal, isFalse);
     expect(firstField.isSynthetic, isFalse);
+
     FieldElement secondField = fields[1];
     expect(secondField, isNotNull);
+    _assertHasDocRange(secondField, 50, 7);
     expect(secondField.name, secondFieldName);
     expect(secondField.initializer, isNull);
     expect(secondField.isConst, isFalse);
@@ -5614,12 +5632,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.name, functionName);
     expect(declaration.element, same(accessor));
     expect(declaration.functionExpression.element, same(accessor));
@@ -5646,12 +5667,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<FunctionElement> functions = holder.functions;
     expect(functions, hasLength(1));
     FunctionElement function = functions[0];
     expect(function, isNotNull);
+    _assertHasDocRange(function, 50, 7);
     expect(function.hasImplicitReturnType, isFalse);
     expect(function.name, functionName);
     expect(declaration.element, same(function));
@@ -5672,12 +5696,15 @@
         functionName,
         AstFactory.functionExpression2(
             AstFactory.formalParameterList(), AstFactory.blockFunctionBody2()));
+    declaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     declaration.accept(builder);
 
     List<PropertyAccessorElement> accessors = holder.accessors;
     expect(accessors, hasLength(1));
     PropertyAccessorElement accessor = accessors[0];
     expect(accessor, isNotNull);
+    _assertHasDocRange(accessor, 50, 7);
     expect(accessor.hasImplicitReturnType, isFalse);
     expect(accessor.name, "$functionName=");
     expect(declaration.element, same(accessor));
@@ -5747,11 +5774,15 @@
     String parameterName = "E";
     FunctionTypeAlias aliasNode = AstFactory.typeAlias(
         null, aliasName, AstFactory.typeParameterList([parameterName]), null);
+    aliasNode.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     aliasNode.accept(builder);
+
     List<FunctionTypeAliasElement> aliases = holder.typeAliases;
     expect(aliases, hasLength(1));
     FunctionTypeAliasElement alias = aliases[0];
     expect(alias, isNotNull);
+    _assertHasDocRange(alias, 50, 7);
     expect(alias.name, aliasName);
     expect(alias.parameters, hasLength(0));
     List<TypeParameterElement> typeParameters = alias.typeParameters;
@@ -5903,6 +5934,8 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -5914,6 +5947,7 @@
     expect(field.setter, isNull);
     PropertyAccessorElement getter = field.getter;
     expect(getter, isNotNull);
+    _assertHasDocRange(getter, 50, 7);
     expect(getter.hasImplicitReturnType, isTrue);
     expect(getter.isAbstract, isFalse);
     expect(getter.isExternal, isFalse);
@@ -6015,11 +6049,15 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
+
     List<MethodElement> methods = holder.methods;
     expect(methods, hasLength(1));
     MethodElement method = methods[0];
     expect(method, isNotNull);
+    _assertHasDocRange(method, 50, 7);
     expect(method.hasImplicitReturnType, isFalse);
     expect(method.name, methodName);
     expect(method.functions, hasLength(0));
@@ -6079,6 +6117,8 @@
         AstFactory.identifier3(methodName),
         AstFactory.formalParameterList(),
         AstFactory.blockFunctionBody2());
+    methodDeclaration.documentationComment = AstFactory.documentationComment(
+        [TokenFactory.tokenFromString('/// aaa')..offset = 50], []);
     methodDeclaration.accept(builder);
 
     List<FieldElement> fields = holder.fields;
@@ -6088,8 +6128,10 @@
     expect(field.name, methodName);
     expect(field.isSynthetic, isTrue);
     expect(field.getter, isNull);
+
     PropertyAccessorElement setter = field.setter;
     expect(setter, isNotNull);
+    _assertHasDocRange(setter, 50, 7);
     expect(setter.hasImplicitReturnType, isFalse);
     expect(setter.isAbstract, isFalse);
     expect(setter.isExternal, isFalse);
@@ -6654,6 +6696,14 @@
     expect(variable.setter, isNull);
   }
 
+  void _assertHasDocRange(
+      Element element, int expectedOffset, int expectedLength) {
+    SourceRange docRange = element.docRange;
+    expect(docRange, isNotNull);
+    expect(docRange.offset, expectedOffset);
+    expect(docRange.length, expectedLength);
+  }
+
   void _useParameterInMethod(
       FormalParameter formalParameter, int blockOffset, int blockEnd) {
     Block block = AstFactory.block();
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index 18a45f6..eaef165 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -834,6 +834,24 @@
 ''');
   }
 
+  void test_false_fieldFormalParameter_differentField() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final aaa;
+  final bbb;
+  A(this.aaa, this.bbb);
+}
+''',
+        r'''
+class A {
+  final aaa;
+  final bbb;
+  A(this.bbb, this.aaa);
+}
+''');
+  }
+
   void test_false_fieldFormalParameter_parameters_add() {
     _assertDoesNotMatch(
         r'''
@@ -930,6 +948,54 @@
 ''');
   }
 
+  void test_false_fieldFormalParameter_typeAdd() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''');
+  }
+
+  void test_false_fieldFormalParameter_typeEdit() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(String this.fff);
+}
+''');
+  }
+
+  void test_false_fieldFormalParameter_typeRemove() {
+    _assertDoesNotMatch(
+        r'''
+class A {
+  final fff;
+  A(int this.fff);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''');
+  }
+
   void test_false_fieldFormalParameterElement_wasSimple() {
     _assertDoesNotMatch(
         r'''
@@ -2383,6 +2449,22 @@
 ''');
   }
 
+  void test_true_fieldFormalParameter_changeName_wasUnresolvedField() {
+    _assertMatches(
+        r'''
+class A {
+  final fff;
+  A(this.unresolved);
+}
+''',
+        r'''
+class A {
+  final fff;
+  A(this.fff);
+}
+''');
+  }
+
   void test_true_fieldFormalParameter_function() {
     _assertMatches(
         r'''
@@ -2987,15 +3069,6 @@
     _resolve(_editString('+', '*'), _isFunctionBody);
   }
 
-  void test_constructor_fieldFormalParameter() {
-    _resolveUnit(r'''
-class A {
-  int xy;
-  A(this.x);
-}''');
-    _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
-  }
-
   void test_constructor_fieldInitializer_add() {
     _resolveUnit(r'''
 class A {
@@ -3050,6 +3123,15 @@
     _resolve(_editString('+', '*'), _isExpression);
   }
 
+  void test_fieldFormalParameter() {
+    _resolveUnit(r'''
+class A {
+  int xy;
+  A(this.x);
+}''');
+    _resolve(_editString('this.x', 'this.xy'), _isDeclaration);
+  }
+
   void test_function_localFunction_add() {
     _resolveUnit(r'''
 int main() {
@@ -4091,6 +4173,28 @@
 ''');
   }
 
+  void test_true_todoHint() {
+    _resolveUnit(r'''
+main() {
+  print(1);
+}
+foo() {
+ // TODO
+}
+''');
+    List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
+    _updateAndValidate(r'''
+main() {
+  print(2);
+}
+foo() {
+ // TODO
+}
+''');
+    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
+    _assertEqualErrors(newErrors, oldErrors);
+  }
+
   void test_true_wholeConstructor() {
     _resolveUnit(r'''
 class A {
@@ -4168,28 +4272,6 @@
 ''');
   }
 
-  void test_true_todoHint() {
-    _resolveUnit(r'''
-main() {
-  print(1);
-}
-foo() {
- // TODO
-}
-''');
-    List<AnalysisError> oldErrors = analysisContext.computeErrors(source);
-    _updateAndValidate(r'''
-main() {
-  print(2);
-}
-foo() {
- // TODO
-}
-''');
-    List<AnalysisError> newErrors = analysisContext.computeErrors(source);
-    _assertEqualErrors(newErrors, oldErrors);
-  }
-
   void test_unusedHint_add_wasUsedOnlyInPart() {
     Source partSource = addNamedSource(
         '/my_unit.dart',
@@ -4440,6 +4522,36 @@
 ''');
   }
 
+  void test_whitespace_getElementAt() {
+    _resolveUnit(r'''
+class A {}
+class B extends A {}
+''');
+    {
+      ClassElement typeA = oldUnitElement.getType('A');
+      expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+    }
+    {
+      ClassElement typeB = oldUnitElement.getType('B');
+      expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+    }
+    _updateAndValidate(r'''
+class A {}
+
+class B extends A {}
+''');
+    // getElementAt() caches results, it should be notified when offset
+    // are changed.
+    {
+      ClassElement typeA = oldUnitElement.getType('A');
+      expect(oldUnitElement.getElementAt(typeA.nameOffset), typeA);
+    }
+    {
+      ClassElement typeB = oldUnitElement.getType('B');
+      expect(oldUnitElement.getElementAt(typeB.nameOffset), typeB);
+    }
+  }
+
   void _assertEqualLineInfo(LineInfo incrLineInfo, LineInfo fullLineInfo) {
     for (int offset = 0; offset < 1000; offset++) {
       LineInfo_Location incrLocation = incrLineInfo.getLocation(offset);
diff --git a/pkg/analyzer/test/generated/resolver_test.dart b/pkg/analyzer/test/generated/resolver_test.dart
index 307c41c..1339162 100644
--- a/pkg/analyzer/test/generated/resolver_test.dart
+++ b/pkg/analyzer/test/generated/resolver_test.dart
@@ -995,13 +995,13 @@
   final T x = y;
   const C();
 }
-const y = 1;
+const int y = 1;
 var v = const C<String>();
 ''');
     computeLibrarySourceErrors(source);
     assertErrors(source, [
       CheckedModeCompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,
-      HintCode.INVALID_ASSIGNMENT
+      StaticTypeWarningCode.INVALID_ASSIGNMENT
     ]);
     verify([source]);
   }
@@ -1027,11 +1027,11 @@
   final T x = y;
   const C();
 }
-const y = 1;
+const int y = 1;
 var v = const C<int>();
 ''');
     computeLibrarySourceErrors(source);
-    assertErrors(source, [HintCode.INVALID_ASSIGNMENT]);
+    assertErrors(source, [StaticTypeWarningCode.INVALID_ASSIGNMENT]);
     verify([source]);
   }
 
@@ -5931,6 +5931,21 @@
     expect(unit.topLevelVariables, hasLength(0));
   }
 
+  void test_libraryElement_docRange() {
+    String code = r'''
+/// My dart doc.
+library lib;
+
+class A {}''';
+    Source librarySource = addSource("/lib.dart", code);
+    LibraryElement element = _buildLibrary(librarySource);
+    expect(element, isNotNull);
+    SourceRange docRange = element.docRange;
+    expect(docRange, isNotNull);
+    expect(docRange.offset, code.indexOf('/// My dart doc.'));
+    expect(docRange.length, '/// My dart doc.'.length);
+  }
+
   void test_missingLibraryDirectiveWithPart() {
     addSource("/a.dart", "part of lib;");
     Source librarySource = addSource("/lib.dart", "part 'a.dart';");
@@ -5989,6 +6004,7 @@
     Source librarySource = addSource(
         "/lib.dart",
         r'''
+/// My dart doc.
 library lib;
 
 class A {}''');
@@ -9974,31 +9990,6 @@
 }
 
 /**
- * Shared infrastructure for [StaticTypeAnalyzer2Test] and
- * [StrongModeStaticTypeAnalyzer2Test].
- */
-class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
-  String testCode;
-  Source testSource;
-  CompilationUnit testUnit;
-
-  SimpleIdentifier _findIdentifier(String search) {
-    SimpleIdentifier identifier = EngineTestCase.findNode(
-        testUnit, testCode, search, (node) => node is SimpleIdentifier);
-    return identifier;
-  }
-
-  void _resolveTestUnit(String code) {
-    testCode = code;
-    testSource = addSource(testCode);
-    LibraryElement library = resolve2(testSource);
-    assertNoErrors(testSource);
-    verify([testSource]);
-    testUnit = resolveCompilationUnit(testSource, library);
-  }
-}
-
-/**
  * Like [StaticTypeAnalyzerTest], but as end-to-end tests.
  */
 @reflectiveTest
@@ -11915,25 +11906,11 @@
     resetWithOptions(options);
   }
 
-  void test_ternaryOperator_null_right() {
+  void test_dynamicObjectGetter_hashCode() {
     String code = r'''
 main() {
-  var foo = (true) ? 3 : null;
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_ternaryOperator_null_left() {
-    String code = r'''
-main() {
-  var foo = (true) ? null : 3;
+  dynamic a = null;
+  var foo = a.hashCode;
 }
 ''';
     _resolveTestUnit(code);
@@ -11961,38 +11938,6 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
-  void test_dynamicObjectGetter_hashCode() {
-    String code = r'''
-main() {
-  dynamic a = null;
-  var foo = a.hashCode;
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
-  void test_pseudoGeneric_max_intInt() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'int');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
   void test_pseudoGeneric_max_doubleDouble() {
     String code = r'''
 import 'dart:math';
@@ -12009,22 +11954,6 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
-  void test_pseudoGeneric_max_intDouble() {
-    String code = r'''
-import 'dart:math';
-main() {
-  var foo = max(1, 2.0);
-}
-''';
-    _resolveTestUnit(code);
-
-    SimpleIdentifier identifier = _findIdentifier('foo');
-    VariableDeclaration declaration =
-        identifier.getAncestor((node) => node is VariableDeclaration);
-    expect(declaration.initializer.staticType.name, 'num');
-    expect(declaration.initializer.propagatedType, isNull);
-  }
-
   void test_pseudoGeneric_max_doubleInt() {
     String code = r'''
 import 'dart:math';
@@ -12041,6 +11970,38 @@
     expect(declaration.initializer.propagatedType, isNull);
   }
 
+  void test_pseudoGeneric_max_intDouble() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2.0);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'num');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
+  void test_pseudoGeneric_max_intInt() {
+    String code = r'''
+import 'dart:math';
+main() {
+  var foo = max(1, 2);
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
   void test_pseudoGeneric_then() {
     String code = r'''
 import 'dart:async';
@@ -12055,14 +12016,40 @@
     SimpleIdentifier identifier = _findIdentifier('foo');
     VariableDeclaration declaration =
         identifier.getAncestor((node) => node is VariableDeclaration);
-    InterfaceType stringType = typeProvider.stringType;
-    InterfaceType futureType = typeProvider.futureType;
-    InterfaceType futureOfStringType =
-        futureType.substitute4(<DartType>[stringType]);
 
     expect(declaration.initializer.staticType.toString(), "Future<String>");
     expect(declaration.initializer.propagatedType, isNull);
   }
+
+  void test_ternaryOperator_null_left() {
+    String code = r'''
+main() {
+  var foo = (true) ? null : 3;
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
+
+  void test_ternaryOperator_null_right() {
+    String code = r'''
+main() {
+  var foo = (true) ? 3 : null;
+}
+''';
+    _resolveTestUnit(code);
+
+    SimpleIdentifier identifier = _findIdentifier('foo');
+    VariableDeclaration declaration =
+        identifier.getAncestor((node) => node is VariableDeclaration);
+    expect(declaration.initializer.staticType.name, 'int');
+    expect(declaration.initializer.propagatedType, isNull);
+  }
 }
 
 @reflectiveTest
@@ -12559,6 +12546,18 @@
         code, typeProvider.dynamicType, typeProvider.intType);
   }
 
+  void fail_finalPropertyInducingVariable_classMember_instance_unprefixed() {
+    String code = r'''
+class A {
+  final v = 0;
+  m() {
+    v; // marker
+  }
+}''';
+    _assertTypeOfMarkedExpression(
+        code, typeProvider.dynamicType, typeProvider.intType);
+  }
+
   void fail_finalPropertyInducingVariable_classMember_static() {
     addNamedSource(
         "/lib.dart",
@@ -13853,6 +13852,99 @@
     assertNoErrors(source);
   }
 
+  void test_objectAccessInference_disabled_for_library_prefix() {
+    String name = 'hashCode';
+    addNamedSource(
+        '/helper.dart',
+        '''
+library helper;
+dynamic get $name => 42;
+''');
+    String code = '''
+import 'helper.dart' as helper;
+main() {
+  helper.$name; // marker
+}''';
+
+    SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
+    PrefixedIdentifier prefixedId = id.parent;
+    expect(id.staticType, typeProvider.dynamicType);
+    expect(prefixedId.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectAccessInference_disabled_for_local_getter() {
+    String name = 'hashCode';
+    String code = '''
+dynamic get $name => null;
+main() {
+  $name; // marker
+}''';
+
+    SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
+    expect(getter.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectAccessInference_enabled_for_cascades() {
+    String name = 'hashCode';
+    String code = '''
+main() {
+  dynamic obj;
+  obj..$name..$name; // marker
+}''';
+    PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
+    expect(access.staticType, typeProvider.dynamicType);
+    expect(access.realTarget.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_disabled_for_library_prefix() {
+    String name = 'toString';
+    addNamedSource(
+        '/helper.dart',
+        '''
+library helper;
+dynamic $name = (int x) => x + 42');
+''');
+    String code = '''
+import 'helper.dart' as helper;
+main() {
+  helper.$name(); // marker
+}''';
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+    expect(methodName.staticType, null, reason: 'library prefix has no type');
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_disabled_for_local_function() {
+    String name = 'toString';
+    String code = '''
+main() {
+  dynamic $name = () => null;
+  $name(); // marker
+}''';
+    SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
+    expect(identifier.staticType, typeProvider.dynamicType);
+
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+    expect(methodName.staticType, typeProvider.dynamicType);
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+  }
+
+  void test_objectMethodInference_enabled_for_cascades() {
+    String name = 'toString';
+    String code = '''
+main() {
+  dynamic obj;
+  obj..$name()..$name(); // marker
+}''';
+    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
+    MethodInvocation methodInvoke = methodName.parent;
+
+    expect(methodInvoke.staticType, typeProvider.dynamicType);
+    expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
+  }
+
   void test_objectMethodOnDynamicExpression_doubleEquals() {
     // https://code.google.com/p/dart/issues/detail?id=20342
     //
@@ -13906,96 +13998,6 @@
         typeProvider.stringType);
   }
 
-  void test_objectMethodInference_disabled_for_local_function() {
-    String name = 'toString';
-    String code = '''
-main() {
-  dynamic $name = () => null;
-  $name(); // marker
-}''';
-    SimpleIdentifier identifier = _findMarkedIdentifier(code, "$name = ");
-    expect(identifier.staticType, typeProvider.dynamicType);
-
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-    expect(methodName.staticType, typeProvider.dynamicType);
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectMethodInference_disabled_for_library_prefix() {
-    String name = 'toString';
-    addNamedSource('/helper.dart', '''
-library helper;
-dynamic $name = (int x) => x + 42');
-''');
-    String code = '''
-import 'helper.dart' as helper;
-main() {
-  helper.$name(); // marker
-}''';
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-    expect(methodName.staticType, null, reason: 'library prefix has no type');
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectMethodInference_enabled_for_cascades() {
-    String name = 'toString';
-    String code = '''
-main() {
-  dynamic obj;
-  obj..$name()..$name(); // marker
-}''';
-    SimpleIdentifier methodName = _findMarkedIdentifier(code, "(); // marker");
-    MethodInvocation methodInvoke = methodName.parent;
-
-    expect(methodInvoke.staticType, typeProvider.dynamicType);
-    expect(methodInvoke.realTarget.staticType, typeProvider.dynamicType);
-  }
-
-
-  void test_objectAccessInference_disabled_for_local_getter() {
-    String name = 'hashCode';
-    String code = '''
-dynamic get $name => null;
-main() {
-  $name; // marker
-}''';
-
-    SimpleIdentifier getter = _findMarkedIdentifier(code, "; // marker");
-    expect(getter.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectAccessInference_disabled_for_library_prefix() {
-    String name = 'hashCode';
-    addNamedSource('/helper.dart', '''
-library helper;
-dynamic get $name => 42;
-''');
-    String code = '''
-import 'helper.dart' as helper;
-main() {
-  helper.$name; // marker
-}''';
-
-    SimpleIdentifier id = _findMarkedIdentifier(code, "; // marker");
-    PrefixedIdentifier prefixedId = id.parent;
-    expect(id.staticType, typeProvider.dynamicType);
-    expect(prefixedId.staticType, typeProvider.dynamicType);
-  }
-
-  void test_objectAccessInference_enabled_for_cascades() {
-    String name = 'hashCode';
-    String code = '''
-main() {
-  dynamic obj;
-  obj..$name..$name; // marker
-}''';
-    PropertyAccess access = _findMarkedIdentifier(code, "; // marker").parent;
-    expect(access.staticType, typeProvider.dynamicType);
-    expect(access.realTarget.staticType, typeProvider.dynamicType);
-  }
-
   void test_propagatedReturnType_localFunction() {
     String code = r'''
 main() {
@@ -14833,3 +14835,28 @@
     return null;
   }
 }
+
+/**
+ * Shared infrastructure for [StaticTypeAnalyzer2Test] and
+ * [StrongModeStaticTypeAnalyzer2Test].
+ */
+class _StaticTypeAnalyzer2TestShared extends ResolverTestCase {
+  String testCode;
+  Source testSource;
+  CompilationUnit testUnit;
+
+  SimpleIdentifier _findIdentifier(String search) {
+    SimpleIdentifier identifier = EngineTestCase.findNode(
+        testUnit, testCode, search, (node) => node is SimpleIdentifier);
+    return identifier;
+  }
+
+  void _resolveTestUnit(String code) {
+    testCode = code;
+    testSource = addSource(testCode);
+    LibraryElement library = resolve2(testSource);
+    assertNoErrors(testSource);
+    verify([testSource]);
+    testUnit = resolveCompilationUnit(testSource, library);
+  }
+}
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index a6c552a..d49c75c 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -791,7 +791,7 @@
     DartType top = TypeBuilder.functionType(<DartType>[intType], objectType);
     InterfaceType bottom = classBottom.type;
 
-    _checkIsAssignableTo(top, bottom);
+    _checkIsStrictAssignableTo(bottom, top);
   }
 
   void test_isAssignableTo_fuzzy_arrows() {
diff --git a/pkg/analyzer/test/source/analysis_options_provider_test.dart b/pkg/analyzer/test/source/analysis_options_provider_test.dart
index 80bf2ad..a251770 100644
--- a/pkg/analyzer/test/source/analysis_options_provider_test.dart
+++ b/pkg/analyzer/test/source/analysis_options_provider_test.dart
@@ -52,6 +52,7 @@
       var optionsProvider = new AnalysisOptionsProvider();
       Map<String, YamlNode> options =
           optionsProvider.getOptions(resourceProvider.getFolder('/'));
+      expect(options, isNotNull);
     });
   });
   group('AnalysisOptionsProvider', () {
@@ -67,7 +68,8 @@
       try {
         Map<String, YamlNode> options =
             optionsProvider.getOptions(resourceProvider.getFolder('/'));
-      } catch (e, st) {
+        expect(options, isNotNull);
+      } catch (e) {
         exceptionCaught = true;
       }
       expect(exceptionCaught, isTrue);
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index 734c1b2..0544bf5 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -1500,7 +1500,7 @@
         reason: "part changed 3");
     _analyzeAll_assertFinished();
     expect(context.getResolvedCompilationUnit2(libSource, libSource), isNotNull,
-        reason: "library resolved 2");
+        reason: "library resolved 3");
     expect(
         context.getResolvedCompilationUnit2(partSource, libSource), isNotNull,
         reason: "part resolved 3");
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 51a86fb..1c94faf 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -15,6 +15,7 @@
 import 'package:analyzer/src/generated/scanner.dart';
 import 'package:analyzer/src/generated/sdk.dart';
 import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/services/lint.dart';
 import 'package:analyzer/src/task/dart.dart';
 import 'package:analyzer/src/task/html.dart';
 import 'package:analyzer/task/dart.dart';
@@ -48,6 +49,7 @@
   runReflectiveTests(GatherUsedImportedElementsTaskTest);
   runReflectiveTests(GatherUsedLocalElementsTaskTest);
   runReflectiveTests(GenerateHintsTaskTest);
+  runReflectiveTests(GenerateLintsTaskTest);
   runReflectiveTests(InferInstanceMembersInUnitTaskTest);
   runReflectiveTests(InferStaticVariableTypesInUnitTaskTest);
   runReflectiveTests(InferStaticVariableTypeTaskTest);
@@ -98,6 +100,7 @@
 isInstanceOf isGatherUsedLocalElementsTask =
     new isInstanceOf<GatherUsedLocalElementsTask>();
 isInstanceOf isGenerateHintsTask = new isInstanceOf<GenerateHintsTask>();
+isInstanceOf isGenerateLintsTask = new isInstanceOf<GenerateLintsTask>();
 isInstanceOf isInferInstanceMembersInUnitTask =
     new isInstanceOf<InferInstanceMembersInUnitTask>();
 isInstanceOf isInferStaticVariableTypesInUnitTask =
@@ -122,6 +125,8 @@
 isInstanceOf isScanDartTask = new isInstanceOf<ScanDartTask>();
 isInstanceOf isVerifyUnitTask = new isInstanceOf<VerifyUnitTask>();
 
+final LintCode _testLintCode = new LintCode('test lint', 'test lint code');
+
 @reflectiveTest
 class BuildCompilationUnitElementTaskTest extends _AbstractDartTaskTest {
   Source source;
@@ -1876,6 +1881,62 @@
 }
 
 @reflectiveTest
+class GenerateLintsTaskTest extends _AbstractDartTaskTest {
+  void enableLints() {
+    AnalysisOptionsImpl options = context.analysisOptions;
+    options.lint = true;
+    context.analysisOptions = options;
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    enableLints();
+  }
+
+  @override
+  void tearDown() {
+    LintGenerator.LINTERS.clear();
+    super.tearDown();
+  }
+
+  test_camel_case_types() {
+    Source source = newSource(
+        '/test.dart',
+        '''
+class a { }
+''');
+
+    LintGenerator.LINTERS.clear();
+    LintGenerator.LINTERS.add(new GenerateLintsTaskTest_TestLinter());
+
+    LibrarySpecificUnit target = new LibrarySpecificUnit(source, source);
+    computeResult(target, LINTS, matcher: isGenerateLintsTask);
+    // validate
+    _fillErrorListener(LINTS);
+    errorListener.assertErrorsWithCodes(<ErrorCode>[_testLintCode]);
+  }
+}
+
+class GenerateLintsTaskTest_AstVisitor extends SimpleAstVisitor {
+  Linter linter;
+  GenerateLintsTaskTest_AstVisitor(this.linter);
+
+  @override
+  visitClassDeclaration(ClassDeclaration node) {
+    if (!new RegExp(r'^([_]*)([A-Z]+[a-z0-9]*)+$')
+        .hasMatch(node.name.toString())) {
+      linter.reporter.reportErrorForNode(_testLintCode, node, []);
+    }
+  }
+}
+
+class GenerateLintsTaskTest_TestLinter extends Linter {
+  @override
+  AstVisitor getVisitor() => new GenerateLintsTaskTest_AstVisitor(this);
+}
+
+@reflectiveTest
 class InferInstanceMembersInUnitTaskTest extends _AbstractDartTaskTest {
   void test_perform() {
     enableStrongMode();
@@ -1973,6 +2034,23 @@
 
 @reflectiveTest
 class InferStaticVariableTypesInUnitTaskTest extends _AbstractDartTaskTest {
+  void test_perform_const_field() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+class M {
+  static const X = "";
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
+        matcher: isInferStaticVariableTypesInUnitTask);
+    CompilationUnit unit = outputs[RESOLVED_UNIT6];
+    VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(declaration.element.type, stringType);
+  }
+
   void test_perform_nestedDeclarations() {
     enableStrongMode();
     AnalysisTarget source = newSource(
@@ -2050,23 +2128,6 @@
     InterfaceType intType = context.typeProvider.intType;
     expect(expression.staticType, intType);
   }
-
-  void test_perform_const_field() {
-    enableStrongMode();
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-class M {
-  static const X = "";
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT6,
-        matcher: isInferStaticVariableTypesInUnitTask);
-    CompilationUnit unit = outputs[RESOLVED_UNIT6];
-    VariableDeclaration declaration = getFieldInClass(unit, 'M', 'X');
-    InterfaceType stringType = context.typeProvider.stringType;
-    expect(declaration.element.type, stringType);
-  }
 }
 
 @reflectiveTest
@@ -2128,31 +2189,6 @@
     expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
   }
 
-  void test_perform_reresolution() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-const topLevel = '';
-class C {
-  String field = topLevel;
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
-    CompilationUnit unit = outputs[RESOLVED_UNIT5];
-    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
-    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
-    VariableElement topLevel = topLevelDecl.name.staticElement;
-    VariableElement field = fieldDecl.name.staticElement;
-
-    computeResult(field, INFERRED_STATIC_VARIABLE,
-        matcher: isInferStaticVariableTypeTask);
-    InterfaceType stringType = context.typeProvider.stringType;
-    expect(topLevel.type, stringType);
-    expect(field.type, stringType);
-    expect(fieldDecl.initializer.staticType, stringType);
-    expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
-  }
-
   void test_perform_const() {
     AnalysisTarget source = newSource(
         '/test.dart',
@@ -2231,6 +2267,31 @@
     expect(a.type.isDynamic, isTrue);
     expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
   }
+
+  void test_perform_reresolution() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const topLevel = '';
+class C {
+  String field = topLevel;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT5);
+    CompilationUnit unit = outputs[RESOLVED_UNIT5];
+    VariableDeclaration topLevelDecl = getTopLevelVariable(unit, 'topLevel');
+    VariableDeclaration fieldDecl = getFieldInClass(unit, 'C', 'field');
+    VariableElement topLevel = topLevelDecl.name.staticElement;
+    VariableElement field = fieldDecl.name.staticElement;
+
+    computeResult(field, INFERRED_STATIC_VARIABLE,
+        matcher: isInferStaticVariableTypeTask);
+    InterfaceType stringType = context.typeProvider.stringType;
+    expect(topLevel.type, stringType);
+    expect(field.type, stringType);
+    expect(fieldDecl.initializer.staticType, stringType);
+    expect(outputs[INFER_STATIC_VARIABLE_ERRORS], hasLength(0));
+  }
 }
 
 @reflectiveTest
@@ -2594,472 +2655,6 @@
 }
 
 @reflectiveTest
-class StrongModeInferenceTest extends _AbstractDartTaskTest {
-
-  @override
-  void setUp() {
-    super.setUp();
-    enableStrongMode();
-  }
-
-  // Check that even within a static variable cycle, inferred
-  // types get propagated to the members of the cycle.
-  void test_perform_cycle() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-var piFirst = true;
-var pi = piFirst ? 3.14 : tau / 2;
-var tau = piFirst ? pi * 2 : 6.28;
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-    VariableElement piFirst =
-        getTopLevelVariable(unit, 'piFirst').name.staticElement;
-    VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
-    VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
-    Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
-        as ConditionalExpression).condition;
-
-    expect(piFirstUse.staticType, context.typeProvider.boolType);
-    expect(piFirst.type, context.typeProvider.boolType);
-    expect(pi.type.isDynamic, isTrue);
-    expect(tau.type.isDynamic, isTrue);
-  }
-
-  void test_perform_local_explicit_disabled() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      test() {
-        int x = 3;
-        x = "hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-    VariableDeclaration decl =
-        (statements[0] as VariableDeclarationStatement).variables.variables[0];
-    expect(decl.element.type, intType);
-    expect(decl.initializer.staticType, intType);
-
-    ExpressionStatement statement = statements[1];
-    AssignmentExpression assgn = statement.expression;
-    expect(assgn.leftHandSide.staticType, intType);
-    expect(assgn.rightHandSide.staticType, stringType);
-  }
-
-  void assertVariableDeclarationTypes(
-      VariableDeclaration decl, DartType varType, DartType initializerType) {
-    expect(decl.element.type, varType);
-    expect(decl.initializer.staticType, initializerType);
-  }
-
-  void assertVariableDeclarationStatementTypes(
-      Statement stmt, DartType varType, DartType initializerType) {
-    VariableDeclaration decl =
-        (stmt as VariableDeclarationStatement).variables.variables[0];
-    assertVariableDeclarationTypes(decl, varType, initializerType);
-  }
-
-  void assertAssignmentStatementTypes(
-      Statement stmt, DartType leftType, DartType rightType) {
-    AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
-    expect(assgn.leftHandSide.staticType, leftType);
-    expect(assgn.rightHandSide.staticType, rightType);
-  }
-
-  // Test that local variables in method bodies are inferred appropriately
-  void test_perform_inference_local_variables() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      test() {
-        int x = 3;
-        x = "hi";
-        var y = 3;
-        y = "hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertVariableDeclarationStatementTypes(statements[2], intType, intType);
-    assertAssignmentStatementTypes(statements[3], intType, stringType);
-  }
-
-  // Test inference interactions between local variables and fields
-  void test_perform_inference_local_variables_fields() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      class A {
-        int x = 0;
-
-        test1() {
-          var a = x;
-          a = "hi";
-          a = 3;
-          var b = y;
-          b = "hi";
-          b = 4;
-          var c = z;
-          c = "hi";
-          c = 4;
-        }
-
-        int y; // field def after use
-        final z = 42; // should infer `int`
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
-    assertAssignmentStatementTypes(statements[7], intType, stringType);
-    assertAssignmentStatementTypes(statements[8], intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "z"), intType, intType);
-  }
-
-  // Test inference interactions between local variables and top level
-  // variables
-  void test_perform_inference_local_variables_topLevel() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      int x = 0;
-
-      test1() {
-        var a = x;
-        a = /*severe:StaticTypeError*/"hi";
-        a = 3;
-        var b = y;
-        b = /*severe:StaticTypeError*/"hi";
-        b = 4;
-        var c = z;
-        c = /*severe:StaticTypeError*/"hi";
-        c = 4;
-      }
-
-      int y = 0; // field def after use
-      final z = 42; // should infer `int`
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
-
-    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, intType);
-
-    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
-    assertAssignmentStatementTypes(statements[7], intType, stringType);
-    assertAssignmentStatementTypes(statements[8], intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "z"), intType, intType);
-  }
-
-  // Test that inference does not propagate from null
-  void test_perform_inference_null() {
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-      var x = null;
-      var y = 3;
-      class A {
-        static var x = null;
-        static var y = 3;
-
-        var x2 = null;
-        var y2 = 3;
-      }
-
-      test() {
-        x = "hi";
-        y = /*severe:StaticTypeError*/"hi";
-        A.x = "hi";
-        A.y = /*severe:StaticTypeError*/"hi";
-        new A().x2 = "hi";
-        new A().y2 = /*severe:StaticTypeError*/"hi";
-      }
-''');
-    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
-    CompilationUnit unit = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-    DartType bottomType = context.typeProvider.bottomType;
-    DartType dynamicType = context.typeProvider.dynamicType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "x"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit, "A", "y2"), intType, intType);
-
-    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
-
-    assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-    assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[3], intType, stringType);
-    assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
-    assertAssignmentStatementTypes(statements[5], intType, stringType);
-  }
-
-  // Test inference across units (non-cyclic)
-  void test_perform_inference_cross_unit_non_cyclic() {
-    AnalysisTarget firstSource = newSource(
-        '/a.dart',
-        '''
-          var x = 2;
-          class A { static var x = 2; }
-''');
-    AnalysisTarget secondSource = newSource(
-        '/test.dart',
-        '''
-          import 'a.dart';
-          var y = x;
-          class B { static var y = A.x; }
-
-          test1() {
-            x = /*severe:StaticTypeError*/"hi";
-            y = /*severe:StaticTypeError*/"hi";
-            A.x = /*severe:StaticTypeError*/"hi";
-            B.y = /*severe:StaticTypeError*/"hi";
-          }
-''');
-    computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
-    computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-    DartType dynamicType = context.typeProvider.dynamicType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[0], intType, stringType);
-    assertAssignmentStatementTypes(statements[1], intType, stringType);
-  }
-
-  // Test inference across units (cyclic)
-  void test_perform_inference_cross_unit_cyclic() {
-    AnalysisTarget firstSource = newSource(
-        '/a.dart',
-        '''
-          import 'test.dart';
-          var x = 2;
-          class A { static var x = 2; }
-''');
-    AnalysisTarget secondSource = newSource(
-        '/test.dart',
-        '''
-          import 'a.dart';
-          var y = x;
-          class B { static var y = A.x; }
-
-          test1() {
-            int t = 3;
-            t = x;
-            t = y;
-            t = A.x;
-            t = B.y;
-          }
-''');
-    computeResult(
-        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
-    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
-    computeResult(
-        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
-    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
-
-    InterfaceType intType = context.typeProvider.intType;
-    InterfaceType stringType = context.typeProvider.stringType;
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit1, "x"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "A", "x"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getTopLevelVariable(unit2, "y"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit2, "B", "y"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-    assertAssignmentStatementTypes(statements[3], intType, intType);
-    assertAssignmentStatementTypes(statements[4], intType, intType);
-  }
-
-  // Test inference of instance fields across units
-  // TODO(leafp): Fix this
-  // https://github.com/dart-lang/dev_compiler/issues/354
-  void fail_perform_inference_cross_unit_instance() {
-    List<Source> sources = newSources({
-      '/a7.dart': '''
-          import 'b7.dart';
-          class A {
-            final a2 = new B().b2;
-          }
-      ''',
-      '/b7.dart': '''
-          class B {
-            final b2 = 1;
-          }
-      ''',
-      '/main7.dart': '''
-          import "a7.dart";
-
-          test1() {
-            int x = 0;
-            x = new A().a2;
-          }
-    '''
-    });
-    List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
-    CompilationUnit unit0 = units[0];
-    CompilationUnit unit1 = units[1];
-    CompilationUnit unit2 = units[2];
-
-    InterfaceType intType = context.typeProvider.intType;
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-  }
-
-  // Test inference between static and instance fields
-  // TODO(leafp): Fix this
-  // https://github.com/dart-lang/dev_compiler/issues/354
-  void fail_perform_inference_cross_unit_static_instance() {
-    List<Source> sources = newSources({
-      '/a.dart': '''
-          import 'b.dart';
-          class A {
-            static final a1 = B.b1;
-            final a2 = new B().b2;
-          }
-      ''',
-      '/b.dart': '''
-          class B {
-            static final b1 = 1;
-            final b2 = 1;
-          }
-      ''',
-      '/main.dart': '''
-          import "a.dart";
-
-          test1() {
-            int x = 0;
-            // inference in A now works.
-            x = A.a1;
-            x = new A().a2;
-          }
-    '''
-    });
-    List<dynamic> units =
-        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
-    CompilationUnit unit0 = units[0];
-    CompilationUnit unit1 = units[1];
-    CompilationUnit unit2 = units[2];
-
-    InterfaceType intType = context.typeProvider.intType;
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a1"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit0, "A", "a2"), intType, intType);
-
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b1"), intType, intType);
-    assertVariableDeclarationTypes(
-        getFieldInClass(unit1, "B", "b2"), intType, intType);
-
-    List<Statement> statements =
-        getStatementsInTopLevelFunction(unit2, "test1");
-
-    assertAssignmentStatementTypes(statements[1], intType, intType);
-    assertAssignmentStatementTypes(statements[2], intType, intType);
-  }
-}
-
-@reflectiveTest
 class ResolveLibraryTypeNamesTaskTest extends _AbstractDartTaskTest {
   test_perform() {
     Source sourceLib = newSource(
@@ -3338,6 +2933,469 @@
 }
 
 @reflectiveTest
+class StrongModeInferenceTest extends _AbstractDartTaskTest {
+  void assertAssignmentStatementTypes(
+      Statement stmt, DartType leftType, DartType rightType) {
+    AssignmentExpression assgn = (stmt as ExpressionStatement).expression;
+    expect(assgn.leftHandSide.staticType, leftType);
+    expect(assgn.rightHandSide.staticType, rightType);
+  }
+
+  // Check that even within a static variable cycle, inferred
+  // types get propagated to the members of the cycle.
+  void assertVariableDeclarationStatementTypes(
+      Statement stmt, DartType varType, DartType initializerType) {
+    VariableDeclaration decl =
+        (stmt as VariableDeclarationStatement).variables.variables[0];
+    assertVariableDeclarationTypes(decl, varType, initializerType);
+  }
+
+  void assertVariableDeclarationTypes(
+      VariableDeclaration decl, DartType varType, DartType initializerType) {
+    expect(decl.element.type, varType);
+    expect(decl.initializer.staticType, initializerType);
+  }
+
+  void fail_perform_inference_cross_unit_instance() {
+    List<Source> sources = newSources({
+      '/a7.dart': '''
+          import 'b7.dart';
+          class A {
+            final a2 = new B().b2;
+          }
+      ''',
+      '/b7.dart': '''
+          class B {
+            final b2 = 1;
+          }
+      ''',
+      '/main7.dart': '''
+          import "a7.dart";
+
+          test1() {
+            int x = 0;
+            x = new A().a2;
+          }
+    '''
+    });
+    List<dynamic> units =
+        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+    CompilationUnit unit0 = units[0];
+    CompilationUnit unit1 = units[1];
+    CompilationUnit unit2 = units[2];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+  }
+
+  void fail_perform_inference_cross_unit_static_instance() {
+    List<Source> sources = newSources({
+      '/a.dart': '''
+          import 'b.dart';
+          class A {
+            static final a1 = B.b1;
+            final a2 = new B().b2;
+          }
+      ''',
+      '/b.dart': '''
+          class B {
+            static final b1 = 1;
+            final b2 = 1;
+          }
+      ''',
+      '/main.dart': '''
+          import "a.dart";
+
+          test1() {
+            int x = 0;
+            // inference in A now works.
+            x = A.a1;
+            x = new A().a2;
+          }
+    '''
+    });
+    List<dynamic> units =
+        computeLibraryResults(sources, RESOLVED_UNIT8).toList();
+    CompilationUnit unit0 = units[0];
+    CompilationUnit unit1 = units[1];
+    CompilationUnit unit2 = units[2];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a1"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit0, "A", "a2"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b1"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "B", "b2"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+  }
+
+  @override
+  void setUp() {
+    super.setUp();
+    enableStrongMode();
+  }
+
+  // Test that local variables in method bodies are inferred appropriately
+  void test_perform_cycle() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+var piFirst = true;
+var pi = piFirst ? 3.14 : tau / 2;
+var tau = piFirst ? pi * 2 : 6.28;
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+    VariableElement piFirst =
+        getTopLevelVariable(unit, 'piFirst').name.staticElement;
+    VariableElement pi = getTopLevelVariable(unit, 'pi').name.staticElement;
+    VariableElement tau = getTopLevelVariable(unit, 'tau').name.staticElement;
+    Expression piFirstUse = (getTopLevelVariable(unit, 'tau').initializer
+        as ConditionalExpression).condition;
+
+    expect(piFirstUse.staticType, context.typeProvider.boolType);
+    expect(piFirst.type, context.typeProvider.boolType);
+    expect(pi.type.isDynamic, isTrue);
+    expect(tau.type.isDynamic, isTrue);
+  }
+
+  // Test inference interactions between local variables and fields
+  void test_perform_inference_cross_unit_cyclic() {
+    AnalysisTarget firstSource = newSource(
+        '/a.dart',
+        '''
+          import 'test.dart';
+          var x = 2;
+          class A { static var x = 2; }
+''');
+    AnalysisTarget secondSource = newSource(
+        '/test.dart',
+        '''
+          import 'a.dart';
+          var y = x;
+          class B { static var y = A.x; }
+
+          test1() {
+            int t = 3;
+            t = x;
+            t = y;
+            t = A.x;
+            t = B.y;
+          }
+''');
+    computeResult(
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+    computeResult(
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit1, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "A", "x"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit2, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit2, "B", "y"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[1], intType, intType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+    assertAssignmentStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, intType);
+  }
+
+  // Test inference interactions between local variables and top level
+  // variables
+  void test_perform_inference_cross_unit_non_cyclic() {
+    AnalysisTarget firstSource = newSource(
+        '/a.dart',
+        '''
+          var x = 2;
+          class A { static var x = 2; }
+''');
+    AnalysisTarget secondSource = newSource(
+        '/test.dart',
+        '''
+          import 'a.dart';
+          var y = x;
+          class B { static var y = A.x; }
+
+          test1() {
+            x = /*severe:StaticTypeError*/"hi";
+            y = /*severe:StaticTypeError*/"hi";
+            A.x = /*severe:StaticTypeError*/"hi";
+            B.y = /*severe:StaticTypeError*/"hi";
+          }
+''');
+    computeResult(
+        new LibrarySpecificUnit(firstSource, firstSource), RESOLVED_UNIT8);
+    CompilationUnit unit1 = outputs[RESOLVED_UNIT8];
+    computeResult(
+        new LibrarySpecificUnit(secondSource, secondSource), RESOLVED_UNIT8);
+    CompilationUnit unit2 = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit1, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit1, "A", "x"), intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit2, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit2, "B", "y"), intType, intType);
+
+    List<Statement> statements =
+        getStatementsInTopLevelFunction(unit2, "test1");
+
+    assertAssignmentStatementTypes(statements[0], intType, stringType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+  }
+
+  // Test that inference does not propagate from null
+  void test_perform_inference_local_variables() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      test() {
+        int x = 3;
+        x = "hi";
+        var y = 3;
+        y = "hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertVariableDeclarationStatementTypes(statements[2], intType, intType);
+    assertAssignmentStatementTypes(statements[3], intType, stringType);
+  }
+
+  // Test inference across units (non-cyclic)
+  void test_perform_inference_local_variables_fields() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      class A {
+        int x = 0;
+
+        test1() {
+          var a = x;
+          a = "hi";
+          a = 3;
+          var b = y;
+          b = "hi";
+          b = 4;
+          var c = z;
+          c = "hi";
+          c = 4;
+        }
+
+        int y; // field def after use
+        final z = 42; // should infer `int`
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInMethod(unit, "A", "test1");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+    assertAssignmentStatementTypes(statements[7], intType, stringType);
+    assertAssignmentStatementTypes(statements[8], intType, intType);
+
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "z"), intType, intType);
+  }
+
+  // Test inference across units (cyclic)
+  void test_perform_inference_local_variables_topLevel() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      int x = 0;
+
+      test1() {
+        var a = x;
+        a = /*severe:StaticTypeError*/"hi";
+        a = 3;
+        var b = y;
+        b = /*severe:StaticTypeError*/"hi";
+        b = 4;
+        var c = z;
+        c = /*severe:StaticTypeError*/"hi";
+        c = 4;
+      }
+
+      int y = 0; // field def after use
+      final z = 42; // should infer `int`
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test1");
+
+    assertVariableDeclarationStatementTypes(statements[0], intType, intType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[3], intType, intType);
+    assertAssignmentStatementTypes(statements[4], intType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, intType);
+
+    assertVariableDeclarationStatementTypes(statements[6], intType, intType);
+    assertAssignmentStatementTypes(statements[7], intType, stringType);
+    assertAssignmentStatementTypes(statements[8], intType, intType);
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "x"), intType, intType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "z"), intType, intType);
+  }
+
+  // Test inference of instance fields across units
+  // TODO(leafp): Fix this
+  // https://github.com/dart-lang/dev_compiler/issues/354
+  void test_perform_inference_null() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      var x = null;
+      var y = 3;
+      class A {
+        static var x = null;
+        static var y = 3;
+
+        var x2 = null;
+        var y2 = 3;
+      }
+
+      test() {
+        x = "hi";
+        y = /*severe:StaticTypeError*/"hi";
+        A.x = "hi";
+        A.y = /*severe:StaticTypeError*/"hi";
+        new A().x2 = "hi";
+        new A().y2 = /*severe:StaticTypeError*/"hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+    DartType bottomType = context.typeProvider.bottomType;
+    DartType dynamicType = context.typeProvider.dynamicType;
+
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "x"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getTopLevelVariable(unit, "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "y"), intType, intType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "x2"), dynamicType, bottomType);
+    assertVariableDeclarationTypes(
+        getFieldInClass(unit, "A", "y2"), intType, intType);
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+
+    assertAssignmentStatementTypes(statements[0], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[1], intType, stringType);
+    assertAssignmentStatementTypes(statements[2], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[3], intType, stringType);
+    assertAssignmentStatementTypes(statements[4], dynamicType, stringType);
+    assertAssignmentStatementTypes(statements[5], intType, stringType);
+  }
+
+  // Test inference between static and instance fields
+  // TODO(leafp): Fix this
+  // https://github.com/dart-lang/dev_compiler/issues/354
+  void test_perform_local_explicit_disabled() {
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+      test() {
+        int x = 3;
+        x = "hi";
+      }
+''');
+    computeResult(new LibrarySpecificUnit(source, source), RESOLVED_UNIT8);
+    CompilationUnit unit = outputs[RESOLVED_UNIT8];
+
+    InterfaceType intType = context.typeProvider.intType;
+    InterfaceType stringType = context.typeProvider.stringType;
+
+    List<Statement> statements = getStatementsInTopLevelFunction(unit, "test");
+    VariableDeclaration decl =
+        (statements[0] as VariableDeclarationStatement).variables.variables[0];
+    expect(decl.element.type, intType);
+    expect(decl.initializer.staticType, intType);
+
+    ExpressionStatement statement = statements[1];
+    AssignmentExpression assgn = statement.expression;
+    expect(assgn.leftHandSide.staticType, intType);
+    expect(assgn.rightHandSide.staticType, stringType);
+  }
+}
+
+@reflectiveTest
 class VerifyUnitTaskTest extends _AbstractDartTaskTest {
   test_perform_constantError() {
     Source source = newSource(
@@ -3370,6 +3428,23 @@
         <ErrorCode>[CompileTimeErrorCode.URI_DOES_NOT_EXIST]);
   }
 
+  void test_perform_reresolution() {
+    enableStrongMode();
+    AnalysisTarget source = newSource(
+        '/test.dart',
+        '''
+const topLevel = 3;
+class C {
+  String field = topLevel;
+}
+''');
+    computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
+    // validate
+    _fillErrorListener(VERIFY_ERRORS);
+    errorListener.assertErrorsWithCodes(
+        <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
+  }
+
   test_perform_verifyError() {
     Source source = newSource(
         '/test.dart',
@@ -3387,23 +3462,6 @@
     errorListener.assertErrorsWithCodes(
         <ErrorCode>[StaticTypeWarningCode.NON_BOOL_CONDITION]);
   }
-
-  void test_perform_reresolution() {
-    enableStrongMode();
-    AnalysisTarget source = newSource(
-        '/test.dart',
-        '''
-const topLevel = 3;
-class C {
-  String field = topLevel;
-}
-''');
-    computeResult(new LibrarySpecificUnit(source, source), VERIFY_ERRORS);
-    // validate
-    _fillErrorListener(VERIFY_ERRORS);
-    errorListener.assertErrorsWithCodes(
-        <ErrorCode>[StaticTypeWarningCode.INVALID_ASSIGNMENT]);
-  }
 }
 
 class _AbstractDartTaskTest extends AbstractContextTest {
@@ -3540,6 +3598,23 @@
   }
 
   /**
+   * Return the declaration of the top-level function with the given
+   * [functionName] in the given compilation [unit].
+   */
+  FunctionDeclaration getTopLevelFunction(
+      CompilationUnit unit, String functionName) {
+    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
+    for (CompilationUnitMember unitMember in unitMembers) {
+      if (unitMember is FunctionDeclaration) {
+        if (unitMember.name.name == functionName) {
+          return unitMember;
+        }
+      }
+    }
+    return null;
+  }
+
+  /**
    * Return the declaration of the top-level variable with the given
    * [variableName] in the given compilation [unit].
    */
@@ -3560,23 +3635,6 @@
     return null;
   }
 
-  /**
-   * Return the declaration of the top-level function with the given
-   * [functionName] in the given compilation [unit].
-   */
-  FunctionDeclaration getTopLevelFunction(
-      CompilationUnit unit, String functionName) {
-    NodeList<CompilationUnitMember> unitMembers = unit.declarations;
-    for (CompilationUnitMember unitMember in unitMembers) {
-      if (unitMember is FunctionDeclaration) {
-        if (unitMember.name.name == functionName) {
-          return unitMember;
-        }
-      }
-    }
-    return null;
-  }
-
   void setUp() {
     super.setUp();
     emptySource = newSource('/test.dart');
diff --git a/pkg/analyzer/test/src/task/inputs_test.dart b/pkg/analyzer/test/src/task/inputs_test.dart
index 35e4660..3943a99 100644
--- a/pkg/analyzer/test/src/task/inputs_test.dart
+++ b/pkg/analyzer/test/src/task/inputs_test.dart
@@ -15,6 +15,8 @@
 
 main() {
   initializeTestEnvironment();
+  runReflectiveTests(ConstantTaskInputBuilderTest);
+  runReflectiveTests(ConstantTaskInputTest);
   runReflectiveTests(ListTaskInputImplTest);
   runReflectiveTests(ListToListTaskInputTest);
   runReflectiveTests(ListToListTaskInputBuilderTest);
@@ -28,6 +30,96 @@
 }
 
 @reflectiveTest
+class ConstantTaskInputBuilderTest extends EngineTestCase {
+  static final int value = 7;
+  static final ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+
+  ConstantTaskInputBuilder builder;
+
+  void setUp() {
+    builder = new ConstantTaskInputBuilder(input);
+  }
+
+  test_create() {
+    expect(builder, isNotNull);
+    expect(builder.input, input);
+  }
+
+  test_currentResult_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.currentResult, null);
+  }
+
+  test_currentResult_beforeMoveNext() {
+    expect(builder.currentResult, null);
+  }
+
+  test_currentTarget_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.currentTarget, null);
+  }
+
+  test_currentTarget_beforeMoveNext() {
+    expect(builder.currentTarget, null);
+  }
+
+  test_currentValue_afterOneMoveNext() {
+    builder.moveNext();
+    expect(() {
+      builder.currentValue = 'value';
+    }, throwsStateError);
+  }
+
+  test_currentValue_beforeMoveNext() {
+    expect(() {
+      builder.currentValue = 'value';
+    }, throwsStateError);
+  }
+
+  test_currentValueNotAvailable_afterOneMoveNext() {
+    builder.moveNext();
+    expect(() {
+      builder.currentValueNotAvailable();
+    }, throwsStateError);
+  }
+
+  test_currentValueNotAvailable_beforeMoveNext() {
+    expect(() {
+      builder.currentValueNotAvailable();
+    }, throwsStateError);
+  }
+
+  test_inputValue_afterOneMoveNext() {
+    builder.moveNext();
+    expect(builder.inputValue, value);
+  }
+
+  test_inputValue_beforeMoveNext() {
+    expect(builder.inputValue, value);
+  }
+
+  test_moveNext() {
+    expect(builder.moveNext(), false);
+    expect(builder.moveNext(), false);
+  }
+}
+
+@reflectiveTest
+class ConstantTaskInputTest extends EngineTestCase {
+  test_create() {
+    int value = 3;
+    ConstantTaskInput<int> input = new ConstantTaskInput<int>(value);
+    expect(input, isNotNull);
+    expect(input.value, value);
+  }
+
+  test_createBuilder() {
+    ConstantTaskInput<int> input = new ConstantTaskInput<int>(5);
+    expect(input.createBuilder(), new isInstanceOf<ConstantTaskInputBuilder>());
+  }
+}
+
+@reflectiveTest
 class ListTaskInputImplTest extends EngineTestCase {
   static final AnalysisTarget target = new TestSource();
   static final result1 =
@@ -800,6 +892,21 @@
     expect(builder.currentResult, result1);
   }
 
+  test_currentResult_afterTwoMoveNext_withConstantInput() {
+    ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+    Map<String, TaskInput> inputDescriptors = {
+      'one': input1,
+      'constant': constantInput,
+      'two': input2
+    };
+    TopLevelTaskInputBuilder builder =
+        new TopLevelTaskInputBuilder(inputDescriptors);
+    builder.moveNext();
+    builder.currentValue = 'value1';
+    builder.moveNext();
+    expect(builder.currentResult, result2);
+  }
+
   test_currentResult_beforeMoveNext() {
     Map<String, TaskInput> inputDescriptors = {};
     TopLevelTaskInputBuilder builder =
@@ -835,6 +942,21 @@
     expect(builder.currentTarget, target);
   }
 
+  test_currentTarget_afterTwoMoveNext_withConstantInput() {
+    ConstantTaskInput<int> constantInput = new ConstantTaskInput<int>(11);
+    Map<String, TaskInput> inputDescriptors = {
+      'one': input1,
+      'constant': constantInput,
+      'two': input2
+    };
+    TopLevelTaskInputBuilder builder =
+        new TopLevelTaskInputBuilder(inputDescriptors);
+    builder.moveNext();
+    builder.currentValue = 'value1';
+    builder.moveNext();
+    expect(builder.currentTarget, target);
+  }
+
   test_currentTarget_beforeMoveNext() {
     Map<String, TaskInput> inputDescriptors = {};
     TopLevelTaskInputBuilder builder =
diff --git a/pkg/analyzer/test/src/task/strong_mode_test.dart b/pkg/analyzer/test/src/task/strong_mode_test.dart
index fbbbae6..ff87d92 100644
--- a/pkg/analyzer/test/src/task/strong_mode_test.dart
+++ b/pkg/analyzer/test/src/task/strong_mode_test.dart
@@ -252,9 +252,6 @@
   final $fieldName = 0;
 }
 ''');
-    ClassElement classA = unit.getType('A');
-    FieldElement fieldA = classA.getField(fieldName);
-    PropertyAccessorElement getterA = classA.getGetter(fieldName);
     ClassElement classB = unit.getType('B');
     FieldElement fieldB = classB.getField(fieldName);
     PropertyAccessorElement getterB = classB.getGetter(fieldName);
@@ -564,7 +561,6 @@
 }
 ''');
     ClassElement classA = unit.getType('A');
-    FieldElement fieldA = classA.getField(getterName);
     PropertyAccessorElement setterA = classA.getSetter(getterName);
     ClassElement classB = unit.getType('B');
     FieldElement fieldB = classB.getField(getterName);
diff --git a/pkg/compiler/lib/src/apiimpl.dart b/pkg/compiler/lib/src/apiimpl.dart
index 7f5ce65..e515631 100644
--- a/pkg/compiler/lib/src/apiimpl.dart
+++ b/pkg/compiler/lib/src/apiimpl.dart
@@ -24,7 +24,8 @@
     GenericTask;
 import 'compiler.dart' as leg;
 import 'diagnostics/diagnostic_listener.dart' show
-    DiagnosticMessage;
+    DiagnosticMessage,
+    DiagnosticOptions;
 import 'diagnostics/messages.dart';
 import 'diagnostics/source_span.dart' show
     SourceSpan;
@@ -90,8 +91,6 @@
             analyzeSignaturesOnly:
                 hasOption(options, Flags.analyzeSignaturesOnly),
             strips: extractCsvOption(options, '--force-strip='),
-            enableConcreteTypeInference:
-                hasOption(options, Flags.enableConcreteTypeInference),
             disableTypeInferenceFlag:
                 hasOption(options, Flags.disableTypeInference),
             preserveComments: hasOption(options, Flags.preserveComments),
@@ -99,22 +98,24 @@
             verbose: hasOption(options, Flags.verbose),
             sourceMapUri: extractUriOption(options, '--source-map='),
             outputUri: extractUriOption(options, '--out='),
-            terseDiagnostics: hasOption(options, Flags.terse),
             deferredMapUri: extractUriOption(options, '--deferred-map='),
             dumpInfo: hasOption(options, Flags.dumpInfo),
             buildId: extractStringOption(
                 options, '--build-id=',
                 "build number could not be determined"),
-            showPackageWarnings:
-                hasOption(options, Flags.showPackageWarnings),
             useContentSecurityPolicy:
               hasOption(options, Flags.useContentSecurityPolicy),
             useStartupEmitter: hasOption(options, Flags.fastStartup),
             hasIncrementalSupport:
                 forceIncrementalSupport ||
                 hasOption(options, Flags.incrementalSupport),
-            suppressWarnings: hasOption(options, Flags.suppressWarnings),
-            fatalWarnings: hasOption(options, Flags.fatalWarnings),
+            diagnosticOptions: new DiagnosticOptions(
+                suppressWarnings: hasOption(options, Flags.suppressWarnings),
+                fatalWarnings: hasOption(options, Flags.fatalWarnings),
+                suppressHints: hasOption(options, Flags.suppressHints),
+                terseDiagnostics: hasOption(options, Flags.terse),
+                showPackageWarnings:
+                    hasOption(options, Flags.showPackageWarnings)),
             enableExperimentalMirrors:
                 hasOption(options, Flags.enableExperimentalMirrors),
             enableAssertMessage:
@@ -237,7 +238,7 @@
   Future<Script> readScript(Spannable node, Uri readableUri) {
     if (!readableUri.isAbsolute) {
       if (node == null) node = NO_LOCATION_SPANNABLE;
-      internalError(node,
+      reporter.internalError(node,
           'Relative uri $readableUri provided to readScript(Uri).');
     }
 
@@ -247,13 +248,13 @@
     elements.Element element = currentElement;
     void reportReadError(exception) {
       if (element == null || node == null) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             new SourceSpan(readableUri, 0, 0),
             MessageKind.READ_SELF_ERROR,
             {'uri': readableUri, 'exception': exception});
       } else {
-        withCurrentElement(element, () {
-          reportErrorMessage(
+        reporter.withCurrentElement(element, () {
+          reporter.reportErrorMessage(
               node,
               MessageKind.READ_SCRIPT_ERROR,
               {'uri': readableUri, 'exception': exception});
@@ -265,8 +266,8 @@
     if (resourceUri == null) return synthesizeScript(node, readableUri);
     if (resourceUri.scheme == 'dart-ext') {
       if (!allowNativeExtensions) {
-        withCurrentElement(element, () {
-          reportErrorMessage(
+        reporter.withCurrentElement(element, () {
+          reporter.reportErrorMessage(
               node, MessageKind.DART_EXT_NOT_SUPPORTED);
         });
       }
@@ -337,13 +338,13 @@
       }
       if (!allowInternalLibraryAccess) {
         if (importingLibrary != null) {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               spannable,
               MessageKind.INTERNAL_LIBRARY_FROM,
               {'resolvedUri': resolvedUri,
                'importingUri': importingLibrary.canonicalUri});
         } else {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               spannable,
               MessageKind.INTERNAL_LIBRARY,
               {'resolvedUri': resolvedUri});
@@ -352,12 +353,12 @@
     }
     if (path == null) {
       if (libraryInfo == null) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.LIBRARY_NOT_FOUND,
             {'resolvedUri': resolvedUri});
       } else {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             spannable,
             MessageKind.LIBRARY_NOT_SUPPORTED,
             {'resolvedUri': resolvedUri});
@@ -385,7 +386,7 @@
     try {
       checkValidPackageUri(uri);
     } on ArgumentError catch (e) {
-      reportErrorMessage(
+      reporter.reportErrorMessage(
           node,
           MessageKind.INVALID_PACKAGE_URI,
           {'uri': uri, 'exception': e.message});
@@ -393,7 +394,7 @@
     }
     return packages.resolve(uri,
         notFound: (Uri notFound) {
-          reportErrorMessage(
+          reporter.reportErrorMessage(
               node,
               MessageKind.LIBRARY_NOT_FOUND,
               {'resolvedUri': uri});
@@ -431,7 +432,7 @@
         packages =
             new MapPackages(pkgs.parse(packageConfigContents, packageConfig));
       }).catchError((error) {
-        reportErrorMessage(
+        reporter.reportErrorMessage(
             NO_LOCATION_SPANNABLE,
             MessageKind.INVALID_PACKAGE_CONFIG,
             {'uri': packageConfig, 'exception': error});
@@ -479,9 +480,11 @@
   void reportDiagnostic(DiagnosticMessage message,
                         List<DiagnosticMessage> infos,
                         api.Diagnostic kind) {
+    // TODO(johnniwinther): Move this to the [DiagnosticReporter]?
     if (kind == api.Diagnostic.ERROR ||
         kind == api.Diagnostic.CRASH ||
-        (fatalWarnings && kind == api.Diagnostic.WARNING)) {
+        (reporter.options.fatalWarnings &&
+         kind == api.Diagnostic.WARNING)) {
       compilationFailed = true;
     }
     _reportDiagnosticMessage(message, kind);
@@ -541,11 +544,6 @@
     }
   }
 
-  void diagnoseCrashInUserCode(String message, exception, stackTrace) {
-    hasCrashed = true;
-    print('$message: ${tryToString(exception)}');
-    print(tryToString(stackTrace));
-  }
 
   fromEnvironment(String name) => environment[name];
 
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index 0f8f218..b0fff43 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -6,6 +6,9 @@
 
 import 'common/names.dart' show
     Identifiers;
+import 'common/resolution.dart' show
+    Parsing,
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -75,7 +78,7 @@
     return measure(() {
       ClosureClassMap nestedClosureData = closureMappingCache[node];
       if (nestedClosureData == null) {
-        compiler.internalError(node, "No closure cache.");
+        reporter.internalError(node, "No closure cache.");
       }
       return nestedClosureData;
     });
@@ -140,7 +143,7 @@
   bool get isInstanceMember => true;
   bool get isAssignable => false;
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   DartType get type {
     if (local is LocalElement) {
@@ -197,7 +200,7 @@
     ClassElement superclass = methodElement.isInstanceMember
         ? backend.boundClosureClass
         : backend.closureClass;
-    superclass.ensureResolved(compiler);
+    superclass.ensureResolved(compiler.resolution);
     supertype = superclass.thisType;
     interfaces = const Link<DartType>();
     thisType = rawType = new InterfaceType(this);
@@ -208,7 +211,7 @@
 
   Iterable<ClosureFieldElement> get closureFields => _closureFields;
 
-  void addField(ClosureFieldElement field, DiagnosticListener listener) {
+  void addField(ClosureFieldElement field, DiagnosticReporter listener) {
     _closureFields.add(field);
     addMember(field, listener);
   }
@@ -219,7 +222,7 @@
 
   Token get position => node.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => node;
+  Node parseNode(Parsing parsing) => node;
 
   // A [ClosureClassElement] is nested inside a function or initializer in terms
   // of [enclosingElement], but still has to be treated as a top-level
@@ -252,7 +255,7 @@
       : this.box = box,
         super(name, ElementKind.FIELD, box.executableContext);
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 
   DartType get type => variableElement.type;
 
@@ -315,7 +318,7 @@
       : expression = other,
         super(name, other.kind, other.modifiers, enclosing) {
     asyncMarker = other.asyncMarker;
-    functionSignatureCache = other.functionSignature;
+    functionSignature = other.functionSignature;
   }
 
   /// Use [closureClass] instead.
@@ -332,7 +335,7 @@
 
   FunctionExpression get node => expression.node;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 
   ResolvedAst get resolvedAst {
     return new ResolvedAst(this, node, treeElements);
@@ -507,6 +510,8 @@
                     this.elements,
                     this.closureMappingCache);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Generate a unique name for the [id]th closure field, with proposed name
   /// [name].
   ///
@@ -539,7 +544,7 @@
 
   void addCapturedVariable(Node node, Local variable) {
     if (_capturedVariableMapping[variable] != null) {
-      compiler.internalError(node, 'In closure analyzer.');
+      reporter.internalError(node, 'In closure analyzer.');
     }
     _capturedVariableMapping[variable] = null;
   }
@@ -609,7 +614,7 @@
       void addClosureField(Local local, String name) {
         ClosureFieldElement closureField =
             new ClosureFieldElement(name, local, closureClass);
-        closureClass.addField(closureField, compiler);
+        closureClass.addField(closureField, reporter);
         data.freeVariableMap[local] = closureField;
       }
 
@@ -999,7 +1004,7 @@
         globalizedElement, callElement, element);
     MemberElement enclosing = element.memberContext;
     enclosing.nestedClosures.add(callElement);
-    globalizedElement.addMember(callElement, compiler);
+    globalizedElement.addMember(callElement, reporter);
     globalizedElement.computeAllClassMembers(compiler);
     // The nested function's 'this' is the same as the one for the outer
     // function. It could be [null] if we are inside a static method.
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 204bb2a..668cb28 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -19,8 +19,6 @@
   static const String dumpInfo = '--dump-info';
   static const String enableAssertMessage = '--assert-message';
   static const String enableCheckedMode = '--enable-checked-mode';
-  static const String enableConcreteTypeInference =
-      '--enable-concrete-type-inference';
   static const String enableDiagnosticColors = '--enable-diagnostic-colors';
   static const String enableExperimentalMirrors =
       '--enable-experimental-mirrors';
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index 487f01d..948fdba 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -11,6 +11,8 @@
 import '../compile_time_constants.dart' show
     BackendConstantEnvironment,
     ConstantCompilerTask;
+import '../constants/expressions.dart' show
+    ConstantExpression;
 import '../constants/constant_system.dart' show
     ConstantSystem;
 import '../constants/values.dart' show
@@ -48,6 +50,11 @@
     checkNativeAnnotation;
 import '../resolution/tree_elements.dart' show
     TreeElements;
+import '../tree/tree.dart' show
+    Node,
+    Send;
+import '../universe/call_structure.dart' show
+    CallStructure;
 
 import 'codegen.dart' show
     CodegenWorkItem;
@@ -220,7 +227,7 @@
   /// Call this method to enable support for isolates.
   void enableIsolateSupport(Enqueuer enqueuer) {}
 
-  void registerRequiredType(DartType type, Element enclosingElement) {}
+  void registerRequiredType(DartType type) {}
 
   void registerConstSymbol(String name, Registry registry) {}
   void registerNewSymbol(Registry registry) {}
@@ -375,5 +382,23 @@
   void registerAsyncMarker(FunctionElement element,
                            Enqueuer enqueuer,
                            Registry registry) {}
+
+  /// Called when resolving a call to a foreign function.
+  void registerForeignCall(Send node,
+                           Element element,
+                           CallStructure callStructure,
+                           ForeignResolver resolver) {}
 }
 
+/// Interface for resolving calls to foreign functions.
+abstract class ForeignResolver {
+  /// Returns the constant expression of [node], or `null` if [node] is not
+  /// a constant expression.
+  ConstantExpression getConstant(Node node);
+
+  /// Registers [type] as instantiated.
+  void registerInstantiatedType(InterfaceType type);
+
+  /// Resolves [typeName] to a type in the context of [node].
+  DartType resolveTypeFromString(Node node, String typeName);
+}
diff --git a/pkg/compiler/lib/src/common/codegen.dart b/pkg/compiler/lib/src/common/codegen.dart
index e220aab..e5554c9 100644
--- a/pkg/compiler/lib/src/common/codegen.dart
+++ b/pkg/compiler/lib/src/common/codegen.dart
@@ -191,7 +191,7 @@
     // generation could spuriously be adding dependencies on things we know we
     // don't need.
     assert(invariant(element,
-        compiler.enqueuer.resolution.hasBeenResolved(element),
+        compiler.enqueuer.resolution.hasBeenProcessed(element),
         message: "$element has not been resolved."));
     assert(invariant(element, element.resolvedAst.elements != null,
         message: 'Resolution tree is null for $element in codegen work item'));
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 86a21bd..474b10e 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -1,3 +1,4 @@
+
 // Copyright (c) 2012, 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.
@@ -6,18 +7,36 @@
 
 import '../compiler.dart' show
     Compiler;
+import '../core_types.dart' show
+    CoreTypes;
 import '../dart_types.dart' show
-    DartType;
+    DartType,
+    InterfaceType;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../elements/elements.dart' show
     AstElement,
+    ClassElement,
+    Element,
     ErroneousElement,
+    FunctionElement,
+    FunctionSignature,
+    LocalFunctionElement,
+    MetadataAnnotation,
+    MethodElement,
+    TypedefElement,
     TypeVariableElement;
 import '../enqueue.dart' show
     ResolutionEnqueuer,
     WorldImpact;
 import '../tree/tree.dart' show
     AsyncForIn,
-    Send;
+    Send,
+    TypeAnnotation;
+import '../universe/universe.dart' show
+    UniverseSelector;
+import '../util/util.dart' show
+    Setlet;
 import 'registry.dart' show
     Registry;
 import 'work.dart' show
@@ -34,6 +53,7 @@
 
   WorldImpact run(Compiler compiler, ResolutionEnqueuer world) {
     WorldImpact impact = compiler.analyze(this, world);
+    impact = compiler.backend.resolutionCallbacks.transformImpact(impact);
     _isAnalyzed = true;
     return impact;
   }
@@ -41,8 +61,13 @@
   bool get isAnalyzed => _isAnalyzed;
 }
 
+// TODO(johnniwinther): Rename this to something like  `BackendResolutionApi`
+// and clean up the interface.
 /// Backend callbacks function specific to the resolution phase.
 class ResolutionCallbacks {
+  ///
+  WorldImpact transformImpact(ResolutionWorldImpact worldImpact) => worldImpact;
+
   /// Register that an assert has been seen.
   void onAssert(bool hasMessage, Registry registry) {}
 
@@ -120,3 +145,279 @@
   /// Called when resolving a prefix or postfix expression.
   void onIncDecOperation(Registry registry) {}
 }
+
+class ResolutionWorldImpact extends WorldImpact {
+  const ResolutionWorldImpact();
+
+  // TODO(johnniwinther): Remove this.
+  void registerDependency(Element element) {}
+
+  Iterable<Feature> get features => const <Feature>[];
+  Iterable<DartType> get requiredTypes => const <DartType>[];
+  Iterable<MapLiteralUse> get mapLiterals => const <MapLiteralUse>[];
+  Iterable<ListLiteralUse> get listLiterals => const <ListLiteralUse>[];
+  Iterable<DartType> get typeLiterals => const <DartType>[];
+  Iterable<String> get constSymbolNames => const <String>[];
+}
+
+/// A language feature seen during resolution.
+// TODO(johnniwinther): Should mirror usage be part of this?
+enum Feature {
+  /// Invocation of a generative construction on an abstract class.
+  ABSTRACT_CLASS_INSTANTIATION,
+  /// An assert statement with no message.
+  ASSERT,
+  /// An assert statement with a message.
+  ASSERT_WITH_MESSAGE,
+  /// A method with an `async` body modifier.
+  ASYNC,
+  /// An asynchronous for in statement like `await for (var e in i) {}`.
+  ASYNC_FOR_IN,
+  /// A method with an `async*` body modifier.
+  ASYNC_STAR,
+  /// A catch statement.
+  CATCH_STATEMENT,
+  /// A compile time error.
+  COMPILE_TIME_ERROR,
+  /// A fall through in a switch case.
+  FALL_THROUGH_ERROR,
+  /// A ++/-- operation.
+  INC_DEC_OPERATION,
+  /// A field whose initialization is not a constant.
+  LAZY_FIELD,
+  /// A call to `new Symbol`.
+  NEW_SYMBOL,
+  /// A catch clause with a variable for the stack trace.
+  STACK_TRACE_IN_CATCH,
+  /// String interpolation.
+  STRING_INTERPOLATION,
+  /// An implicit call to `super.noSuchMethod`, like calling an unresolved
+  /// super method.
+  SUPER_NO_SUCH_METHOD,
+  /// A redirection to the `Symbol` constructor.
+  SYMBOL_CONSTRUCTOR,
+  /// An synchronous for in statement, like `for (var e in i) {}`.
+  SYNC_FOR_IN,
+  /// A method with a `sync*` body modifier.
+  SYNC_STAR,
+  /// A throw expression.
+  THROW_EXPRESSION,
+  /// An implicit throw of a `NoSuchMethodError`, like calling an unresolved
+  /// static method.
+  THROW_NO_SUCH_METHOD,
+  /// An implicit throw of a runtime error, like
+  THROW_RUNTIME_ERROR,
+  /// The need for a type variable bound check, like instantiation of a generic
+  /// type whose type variable have non-trivial bounds.
+  TYPE_VARIABLE_BOUNDS_CHECK,
+}
+
+/// A use of a map literal seen during resolution.
+class MapLiteralUse {
+  final InterfaceType type;
+  final bool isConstant;
+  final bool isEmpty;
+
+  MapLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+  int get hashCode {
+    return
+        type.hashCode * 13 +
+        isConstant.hashCode * 17 +
+        isEmpty.hashCode * 19;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! MapLiteralUse) return false;
+    return
+        type == other.type &&
+        isConstant == other.isConstant &&
+        isEmpty == other.isEmpty;
+  }
+}
+
+/// A use of a list literal seen during resolution.
+class ListLiteralUse {
+  final InterfaceType type;
+  final bool isConstant;
+  final bool isEmpty;
+
+  ListLiteralUse(this.type, {this.isConstant: false, this.isEmpty: false});
+
+  int get hashCode {
+    return
+        type.hashCode * 13 +
+        isConstant.hashCode * 17 +
+        isEmpty.hashCode * 19;
+  }
+
+  bool operator ==(other) {
+    if (identical(this, other)) return true;
+    if (other is! ListLiteralUse) return false;
+    return
+        type == other.type &&
+        isConstant == other.isConstant &&
+        isEmpty == other.isEmpty;
+  }
+}
+
+/// Mutable implementation of [WorldImpact] used to transform
+/// [ResolutionWorldImpact] to [WorldImpact].
+// TODO(johnniwinther): Remove [Registry] when dependency is tracked directly
+// on [WorldImpact].
+class TransformedWorldImpact implements WorldImpact, Registry {
+  final ResolutionWorldImpact worldImpact;
+
+  Setlet<Element> _staticUses;
+  Setlet<InterfaceType> _instantiatedTypes;
+  Setlet<UniverseSelector> _dynamicGetters;
+  Setlet<UniverseSelector> _dynamicInvocations;
+  Setlet<UniverseSelector> _dynamicSetters;
+
+  TransformedWorldImpact(this.worldImpact);
+
+  @override
+  Iterable<DartType> get asCasts => worldImpact.asCasts;
+
+  @override
+  Iterable<DartType> get checkedModeChecks => worldImpact.checkedModeChecks;
+
+  @override
+  Iterable<MethodElement> get closurizedFunctions {
+    return worldImpact.closurizedFunctions;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicGetters {
+    return _dynamicGetters != null
+        ? _dynamicGetters : worldImpact.dynamicGetters;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicInvocations {
+    return _dynamicInvocations != null
+        ? _dynamicInvocations : worldImpact.dynamicInvocations;
+  }
+
+  @override
+  Iterable<UniverseSelector> get dynamicSetters {
+    return _dynamicSetters != null
+        ? _dynamicSetters : worldImpact.dynamicSetters;
+  }
+
+  @override
+  Iterable<DartType> get isChecks => worldImpact.isChecks;
+
+  @override
+  Iterable<Element> get staticUses {
+    if (_staticUses == null) {
+      return worldImpact.staticUses;
+    }
+    return _staticUses;
+  }
+
+  @override
+  bool get isForResolution => true;
+
+  _unsupported(String message) => throw new UnsupportedError(message);
+
+  @override
+  Iterable<Element> get otherDependencies => _unsupported('otherDependencies');
+
+  // TODO(johnniwinther): Remove this.
+  @override
+  void registerAssert(bool hasMessage) => _unsupported('registerAssert');
+
+  @override
+  void registerDependency(Element element) {
+    worldImpact.registerDependency(element);
+  }
+
+  @override
+  void registerDynamicGetter(UniverseSelector selector) {
+    if (_dynamicGetters == null) {
+      _dynamicGetters = new Setlet<UniverseSelector>();
+      _dynamicGetters.addAll(worldImpact.dynamicGetters);
+    }
+    _dynamicGetters.add(selector);
+  }
+
+  @override
+  void registerDynamicInvocation(UniverseSelector selector) {
+    if (_dynamicInvocations == null) {
+      _dynamicInvocations = new Setlet<UniverseSelector>();
+      _dynamicInvocations.addAll(worldImpact.dynamicInvocations);
+    }
+    _dynamicInvocations.add(selector);
+  }
+
+  @override
+  void registerDynamicSetter(UniverseSelector selector) {
+    if (_dynamicSetters == null) {
+      _dynamicSetters = new Setlet<UniverseSelector>();
+      _dynamicSetters.addAll(worldImpact.dynamicSetters);
+    }
+    _dynamicSetters.add(selector);
+  }
+
+  @override
+  void registerGetOfStaticFunction(FunctionElement element) {
+    _unsupported('registerGetOfStaticFunction($element)');
+  }
+
+  @override
+  void registerInstantiation(InterfaceType type) {
+    // TODO(johnniwinther): Remove this when dependency tracking is done on
+    // the world impact itself.
+    registerDependency(type.element);
+    if (_instantiatedTypes == null) {
+      _instantiatedTypes = new Setlet<InterfaceType>();
+    }
+    _instantiatedTypes.add(type);
+  }
+
+  @override
+  Iterable<InterfaceType> get instantiatedTypes {
+    return _instantiatedTypes != null
+        ? _instantiatedTypes : const <InterfaceType>[];
+  }
+
+  @override
+  void registerStaticInvocation(Element element) {
+    // TODO(johnniwinther): Remove this when dependency tracking is done on
+    // the world impact itself.
+    registerDependency(element);
+    if (_staticUses == null) {
+      _staticUses = new Setlet<Element>();
+    }
+    _staticUses.add(element);
+  }
+
+  @override
+  Iterable<LocalFunctionElement> get closures => worldImpact.closures;
+}
+
+// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
+abstract class Resolution {
+  Parsing get parsing;
+  DiagnosticReporter get reporter;
+  CoreTypes get coreTypes;
+
+  void resolveTypedef(TypedefElement typdef);
+  void resolveClass(ClassElement cls);
+  void registerClass(ClassElement cls);
+  void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation);
+  FunctionSignature resolveSignature(FunctionElement function);
+  DartType resolveTypeAnnotation(Element element, TypeAnnotation node);
+
+  bool hasBeenResolved(Element element);
+  ResolutionWorldImpact analyzeElement(Element element);
+}
+
+// TODO(johnniwinther): Rename to `Parser` or `ParsingContext`.
+abstract class Parsing {
+  DiagnosticReporter get reporter;
+  void parsePatchClass(ClassElement cls);
+  measure(f());
+}
\ No newline at end of file
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index 32966df..56253db 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -8,6 +8,8 @@
     UserTag;
 import '../compiler.dart' show
     Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../elements/elements.dart' show
     Element;
 
@@ -30,6 +32,8 @@
       : this.compiler = compiler,
         watch = (compiler.verbose) ? new Stopwatch() : null;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String get name => "Unknown task '${this.runtimeType}'";
 
   int get timing {
@@ -66,7 +70,7 @@
   }
 
   measureElement(Element element, action()) {
-    compiler.withCurrentElement(element, () => measure(action));
+    reporter.withCurrentElement(element, () => measure(action));
   }
 
   /// Measure the time spent in [action] (if in verbose mode) and accumulate it
diff --git a/pkg/compiler/lib/src/compile_time_constants.dart b/pkg/compiler/lib/src/compile_time_constants.dart
index dba9976..59166a0 100644
--- a/pkg/compiler/lib/src/compile_time_constants.dart
+++ b/pkg/compiler/lib/src/compile_time_constants.dart
@@ -4,6 +4,8 @@
 
 library dart2js.compile_time_constant_evaluator;
 
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -14,6 +16,8 @@
 import 'constants/expressions.dart';
 import 'constants/values.dart';
 import 'dart_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/messages.dart' show
@@ -161,6 +165,8 @@
 
   ConstantCompilerBase(this.compiler, this.constantSystem);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   @override
   ConstantValue getConstantValueForVariable(VariableElement element) {
     return getConstantValue(initialVariableValues[element.declaration]);
@@ -198,7 +204,7 @@
       return result;
     }
     AstElement currentElement = element.analyzableElement;
-    return compiler.withCurrentElement(currentElement, () {
+    return reporter.withCurrentElement(currentElement, () {
       // TODO(johnniwinther): Avoid this eager analysis.
       _analyzeElementEagerly(compiler, currentElement);
 
@@ -221,7 +227,7 @@
     Node node = element.node;
     if (pendingVariables.contains(element)) {
       if (isConst) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node, MessageKind.CYCLIC_COMPILE_TIME_CONSTANTS);
         ConstantExpression expression = new ErroneousConstantExpression();
         constantValueMap[expression] = constantSystem.createNull();
@@ -249,7 +255,7 @@
         if (elementType.isMalformed && !value.isNull) {
           if (isConst) {
             ErroneousElement element = elementType.element;
-            compiler.reportErrorMessage(
+            reporter.reportErrorMessage(
                 node, element.messageKind, element.messageArguments);
           } else {
             // We need to throw an exception at runtime.
@@ -260,7 +266,7 @@
           if (!constantSystem.isSubtype(
               compiler.types, constantType, elementType)) {
             if (isConst) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   node,
                   MessageKind.NOT_ASSIGNABLE,
                   {'fromType': constantType,
@@ -366,6 +372,9 @@
       : this.isEvaluatingConstant = isConst;
 
   ConstantSystem get constantSystem => handler.constantSystem;
+  Resolution get resolution => compiler.resolution;
+
+  DiagnosticReporter get reporter => compiler.reporter;
 
   AstConstant evaluate(Node node) {
     // TODO(johnniwinther): should there be a visitErrorNode?
@@ -448,7 +457,7 @@
       if (!map.containsKey(key.value)) {
         keyValues.add(key.value);
       } else {
-        compiler.reportWarningMessage(
+        reporter.reportWarningMessage(
             entry.key, MessageKind.EQUAL_MAP_ENTRY_KEY);
       }
       keyExpressions.add(key.expression);
@@ -573,7 +582,7 @@
       AstConstant result;
       if (Elements.isStaticOrTopLevelFunction(element)) {
         FunctionElementX function = element;
-        function.computeType(compiler);
+        function.computeType(resolution);
         result = new AstConstant(context, send,
             new FunctionConstantExpression(function),
             new FunctionConstantValue(function));
@@ -623,7 +632,7 @@
       }
       if (isDeferredUse(send)) {
         if (isEvaluatingConstant) {
-          compiler.reportErrorMessage(
+          reporter.reportErrorMessage(
               send, MessageKind.DEFERRED_COMPILE_TIME_CONSTANT);
         }
         PrefixElement prefix =
@@ -660,7 +669,7 @@
       UnaryOperator operator = UnaryOperator.parse(node.source);
       UnaryOperation operation = constantSystem.lookupUnary(operator);
       if (operation == null) {
-        compiler.internalError(send.selector, "Unexpected operator.");
+        reporter.internalError(send.selector, "Unexpected operator.");
       }
       ConstantValue folded = operation.fold(receiverConstant.value);
       if (folded == null) {
@@ -723,7 +732,7 @@
     } else if (!condition.value.isBool) {
       DartType conditionType = condition.value.getType(compiler.coreTypes);
       if (isEvaluatingConstant) {
-        compiler.reportErrorMessage(
+        reporter.reportErrorMessage(
             node.condition,
             MessageKind.NOT_ASSIGNABLE,
             {'fromType': conditionType,
@@ -766,13 +775,13 @@
       return new AstConstant.fromDefaultValue(
           element, constant, handler.getConstantValue(constant));
     }
-    target.computeType(compiler);
+    target.computeType(resolution);
 
     FunctionSignature signature = target.functionSignature;
     if (!callStructure.signatureApplies(signature)) {
       String name = Elements.constructorNameForDiagnostics(
           target.enclosingClass.name, target.name);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           node, MessageKind.INVALID_CONSTRUCTOR_ARGUMENTS,
           {'constructorName': name});
 
@@ -876,14 +885,14 @@
     ConstantValue defaultValue = normalizedArguments[1].value;
 
     if (firstArgument.isNull) {
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[0].node, MessageKind.NULL_NOT_ALLOWED);
       return null;
     }
 
     if (!firstArgument.isString) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[0].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -894,7 +903,7 @@
     if (constructor == compiler.intEnvironment &&
         !(defaultValue.isNull || defaultValue.isInt)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -905,7 +914,7 @@
     if (constructor == compiler.boolEnvironment &&
         !(defaultValue.isNull || defaultValue.isBool)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -916,7 +925,7 @@
     if (constructor == compiler.stringEnvironment &&
         !(defaultValue.isNull || defaultValue.isString)) {
       DartType type = defaultValue.getType(compiler.coreTypes);
-      compiler.reportErrorMessage(
+      reporter.reportErrorMessage(
           normalizedArguments[1].node,
           MessageKind.NOT_ASSIGNABLE,
           {'fromType': type,
@@ -1010,7 +1019,7 @@
   AstConstant signalNotCompileTimeConstant(Node node,
       {MessageKind message: MessageKind.NOT_A_COMPILE_TIME_CONSTANT}) {
     if (isEvaluatingConstant) {
-      compiler.reportErrorMessage(node, message);
+      reporter.reportErrorMessage(node, message);
 
       return new AstConstant(context, node, new ErroneousConstantExpression(),
           new NullConstantValue());
@@ -1050,7 +1059,7 @@
     if (Elements.isLocal(element)) {
       AstConstant constant = definitions[element];
       if (constant == null) {
-        compiler.internalError(send, "Local variable without value.");
+        reporter.internalError(send, "Local variable without value.");
       }
       return constant;
     }
@@ -1063,8 +1072,8 @@
       DartType constantType = constant.value.getType(compiler.coreTypes);
       if (!constantSystem.isSubtype(
           compiler.types, constantType, elementType)) {
-        compiler.withCurrentElement(constant.element, () {
-          compiler.reportErrorMessage(
+        reporter.withCurrentElement(constant.element, () {
+          reporter.reportErrorMessage(
               constant.node,
               MessageKind.NOT_ASSIGNABLE,
               {'fromType': constantType,
@@ -1190,7 +1199,7 @@
    */
   void evaluateConstructorFieldValues(List<AstConstant> arguments) {
     if (constructor.isErroneous) return;
-    compiler.withCurrentElement(constructor, () {
+    reporter.withCurrentElement(constructor, () {
       assignArgumentsToParameters(arguments);
       evaluateConstructorInitializers();
     });
@@ -1256,10 +1265,9 @@
           new ErroneousConstantExpression(), new NullConstantValue());
 }
 
-// TODO(johnniwinther): Avoid the need for this hack.
+// TODO(johnniwinther): Clean this up.
 TreeElements _analyzeElementEagerly(Compiler compiler, AstElement element) {
-  WorldImpact worldImpact = compiler.analyzeElement(element.declaration);
-  compiler.enqueuer.resolution.applyImpact(element.declaration, worldImpact);
+  compiler.resolution.analyzeElement(element.declaration);
   return element.resolvedAst.elements;
 }
 
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index 86a87f3..e3105d7 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -24,7 +24,10 @@
 import 'common/registry.dart' show
     Registry;
 import 'common/resolution.dart' show
-    ResolutionWorkItem;
+    Parsing,
+    Resolution,
+    ResolutionWorkItem,
+    ResolutionWorldImpact;
 import 'common/tasks.dart' show
     CompilerTask,
     GenericTask;
@@ -42,7 +45,10 @@
     Types;
 import 'deferred_load.dart' show DeferredLoadTask, OutputUnit;
 import 'diagnostics/code_location.dart';
-import 'diagnostics/diagnostic_listener.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticMessage,
+    DiagnosticOptions,
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant,
     REPORT_EXCESS_RESOLUTION;
@@ -120,7 +126,8 @@
 import 'tokens/token_map.dart' show
     TokenMap;
 import 'tree/tree.dart' show
-    Node;
+    Node,
+    TypeAnnotation;
 import 'typechecker.dart' show
     TypeCheckerTask;
 import 'types/types.dart' as ti;
@@ -136,13 +143,16 @@
 import 'world.dart' show
     World;
 
-abstract class Compiler extends DiagnosticListener {
+abstract class Compiler {
 
   final Stopwatch totalCompileTime = new Stopwatch();
   int nextFreeClassId = 0;
   World world;
   Types types;
   _CompilerCoreTypes _coreTypes;
+  _CompilerDiagnosticReporter _reporter;
+  _CompilerResolution _resolution;
+  _CompilerParsing _parsing;
 
   final CacheStrategy cacheStrategy;
 
@@ -181,7 +191,6 @@
   final bool enableUserAssertions;
   final bool trustTypeAnnotations;
   final bool trustPrimitives;
-  final bool enableConcreteTypeInference;
   final bool disableTypeInferenceFlag;
   final Uri deferredMapUri;
   final bool dumpInfo;
@@ -238,23 +247,6 @@
    */
   final Uri outputUri;
 
-  /// Emit terse diagnostics without howToFix.
-  final bool terseDiagnostics;
-
-  /// If `true`, warnings and hints not from user code are reported.
-  final bool showPackageWarnings;
-
-  /// `true` if the last diagnostic was filtered, in which case the
-  /// accompanying info message should be filtered as well.
-  bool lastDiagnosticWasFiltered = false;
-
-  /// Map containing information about the warnings and hints that have been
-  /// suppressed for each library.
-  Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
-
-  final bool suppressWarnings;
-  final bool fatalWarnings;
-
   /// If `true`, some values are cached for reuse in incremental compilation.
   /// Incremental compilation is basically calling [run] more than once.
   final bool hasIncrementalSupport;
@@ -283,7 +275,6 @@
   Tracer tracer;
 
   CompilerTask measuredTask;
-  Element _currentElement;
   LibraryElement coreLibrary;
   LibraryElement asyncLibrary;
 
@@ -314,7 +305,10 @@
   ClassElement get iterableClass => _coreTypes.iterableClass;
   ClassElement get streamClass => _coreTypes.streamClass;
 
+  DiagnosticReporter get reporter => _reporter;
   CoreTypes get coreTypes => _coreTypes;
+  Resolution get resolution => _resolution;
+  Parsing get parsing => _parsing;
 
   ClassElement typedDataClass;
 
@@ -372,49 +366,7 @@
 
   fromEnvironment(String name) => null;
 
-  Element get currentElement => _currentElement;
-
-  String tryToString(object) {
-    try {
-      return object.toString();
-    } catch (_) {
-      return '<exception in toString()>';
-    }
-  }
-
-  /**
-   * Perform an operation, [f], returning the return value from [f].  If an
-   * error occurs then report it as having occurred during compilation of
-   * [element].  Can be nested.
-   */
-  withCurrentElement(Element element, f()) {
-    Element old = currentElement;
-    _currentElement = element;
-    try {
-      return f();
-    } on SpannableAssertionFailure catch (ex) {
-      if (!hasCrashed) {
-        reportAssertionFailure(ex);
-        pleaseReportCrash();
-      }
-      hasCrashed = true;
-      rethrow;
-    } on StackOverflowError {
-      // We cannot report anything useful in this case, because we
-      // do not have enough stack space.
-      rethrow;
-    } catch (ex) {
-      if (hasCrashed) rethrow;
-      try {
-        unhandledExceptionOnElement(element);
-      } catch (doubleFault) {
-        // Ignoring exceptions in exception handling.
-      }
-      rethrow;
-    } finally {
-      _currentElement = old;
-    }
-  }
+  Element get currentElement => _reporter.currentElement;
 
   List<CompilerTask> tasks;
   ScannerTask scanner;
@@ -458,6 +410,8 @@
   bool enabledInvokeOn = false;
   bool hasIsolateSupport = false;
 
+  bool get hasCrashed => _reporter.hasCrashed;
+
   Stopwatch progress;
 
   bool get shouldPrintProgress {
@@ -481,8 +435,6 @@
     compilationFailedInternal = value;
   }
 
-  bool hasCrashed = false;
-
   /// Set by the backend if real reflection is detected in use of dart:mirrors.
   bool disableTypeInferenceForMirrors = false;
 
@@ -490,7 +442,6 @@
             this.enableUserAssertions: false,
             this.trustTypeAnnotations: false,
             this.trustPrimitives: false,
-            this.enableConcreteTypeInference: false,
             bool disableTypeInferenceFlag: false,
             this.maxConcreteTypeSize: 5,
             this.enableMinification: false,
@@ -510,20 +461,17 @@
             this.sourceMapUri: null,
             this.outputUri: null,
             this.buildId: UNDETERMINED_BUILD_ID,
-            this.terseDiagnostics: false,
             this.deferredMapUri: null,
             this.dumpInfo: false,
-            this.showPackageWarnings: false,
             bool useStartupEmitter: false,
             this.useContentSecurityPolicy: false,
-            this.suppressWarnings: false,
-            this.fatalWarnings: false,
             bool hasIncrementalSupport: false,
             this.enableExperimentalMirrors: false,
             this.enableAssertMessage: false,
             this.allowNativeExtensions: false,
             this.generateCodeWithCompileTimeErrors: false,
             this.testMode: false,
+            DiagnosticOptions diagnosticOptions,
             api.CompilerOutput outputProvider,
             List<String> strips: const []})
       : this.disableTypeInferenceFlag =
@@ -544,7 +492,10 @@
     world = new World(this);
     // TODO(johnniwinther): Initialize core types in [initializeCoreClasses] and
     // make its field final.
-    _coreTypes = new _CompilerCoreTypes(this);
+    _reporter = new _CompilerDiagnosticReporter(this, diagnosticOptions);
+    _parsing = new _CompilerParsing(this);
+    _resolution = new _CompilerResolution(this);
+    _coreTypes = new _CompilerCoreTypes(_resolution);
     types = new Types(this);
     tracer = new Tracer(this, this.outputProvider);
 
@@ -609,118 +560,15 @@
   int getNextFreeClassId() => nextFreeClassId++;
 
   void unimplemented(Spannable spannable, String methodName) {
-    internalError(spannable, "$methodName not implemented.");
-  }
-
-  internalError(Spannable node, reason) {
-    String message = tryToString(reason);
-    reportDiagnosticInternal(
-        createMessage(node, MessageKind.GENERIC, {'text': message}),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-    throw 'Internal Error: $message';
-  }
-
-  void unhandledExceptionOnElement(Element element) {
-    if (hasCrashed) return;
-    hasCrashed = true;
-    reportDiagnostic(
-        createMessage(element, MessageKind.COMPILER_CRASHED),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-    pleaseReportCrash();
-  }
-
-  void pleaseReportCrash() {
-    print(
-        MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
-            .message({'buildId': buildId}));
-  }
-
-  SourceSpan spanFromSpannable(Spannable node) {
-    // TODO(johnniwinther): Disallow `node == null` ?
-    if (node == null) return null;
-    if (node == CURRENT_ELEMENT_SPANNABLE) {
-      node = currentElement;
-    } else if (node == NO_LOCATION_SPANNABLE) {
-      if (currentElement == null) return null;
-      node = currentElement;
-    }
-    if (node is SourceSpan) {
-      return node;
-    } else if (node is Node) {
-      return spanFromNode(node);
-    } else if (node is TokenPair) {
-      return spanFromTokens(node.begin, node.end);
-    } else if (node is Token) {
-      return spanFromTokens(node, node);
-    } else if (node is HInstruction) {
-      return spanFromHInstruction(node);
-    } else if (node is Element) {
-      return spanFromElement(node);
-    } else if (node is MetadataAnnotation) {
-      Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
-      return spanFromTokens(node.beginToken, node.endToken, uri);
-    } else if (node is Local) {
-      Local local = node;
-      return spanFromElement(local.executableContext);
-    } else {
-      throw 'No error location.';
-    }
-  }
-
-  Element _elementFromHInstruction(HInstruction instruction) {
-    return instruction.sourceElement is Element
-        ? instruction.sourceElement : null;
-  }
-
-  /// Finds the approximate [Element] for [node]. [currentElement] is used as
-  /// the default value.
-  Element elementFromSpannable(Spannable node) {
-    Element element;
-    if (node is Element) {
-      element = node;
-    } else if (node is HInstruction) {
-      element = _elementFromHInstruction(node);
-    } else if (node is MetadataAnnotation) {
-      element = node.annotatedElement;
-    }
-    return element != null ? element : currentElement;
-  }
-
-  void log(message) {
-    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
-        .message({'text': '$message'});
-    reportDiagnostic(
-        new DiagnosticMessage(null, null, msg),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.VERBOSE_INFO);
+    reporter.internalError(spannable, "$methodName not implemented.");
   }
 
   Future<bool> run(Uri uri) {
     totalCompileTime.start();
 
-    return new Future.sync(() => runCompiler(uri)).catchError((error) {
-      try {
-        if (!hasCrashed) {
-          hasCrashed = true;
-          if (error is SpannableAssertionFailure) {
-            reportAssertionFailure(error);
-          } else {
-            reportDiagnostic(
-                createMessage(
-                    new SourceSpan(uri, 0, 0),
-                    MessageKind.COMPILER_CRASHED),
-                const <DiagnosticMessage>[],
-                api.Diagnostic.CRASH);
-          }
-          pleaseReportCrash();
-        }
-      } catch (doubleFault) {
-        // Ignoring exceptions in exception handling.
-      }
-      throw error;
-    }).whenComplete(() {
+    return new Future.sync(() => runCompiler(uri))
+        .catchError((error) => _reporter.onError(uri, error))
+        .whenComplete(() {
       tracer.close();
       totalCompileTime.stop();
     }).then((_) {
@@ -859,7 +707,7 @@
         if (loadedLibraries.containsLibrary(uri)) {
           Set<String> importChains =
               computeImportChainsFor(loadedLibraries, Uri.parse('dart:io'));
-          reportInfo(NO_LOCATION_SPANNABLE,
+          reporter.reportInfo(NO_LOCATION_SPANNABLE,
              MessageKind.DISALLOWED_LIBRARY_IMPORT,
               {'uri': uri,
                'importChain': importChains.join(
@@ -871,24 +719,27 @@
         return null;
       }
 
-      if (!enableExperimentalMirrors &&
-          loadedLibraries.containsLibrary(Uris.dart_mirrors)) {
+      bool importsMirrorsLibrary =
+          loadedLibraries.containsLibrary(Uris.dart_mirrors);
+      if (importsMirrorsLibrary && !backend.supportsReflection) {
         Set<String> importChains =
             computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
-        if (!backend.supportsReflection) {
-          reportErrorMessage(
-              NO_LOCATION_SPANNABLE,
-              MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND);
-        } else {
-          reportWarningMessage(
-              NO_LOCATION_SPANNABLE,
-              MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
-              {'importChain': importChains.join(
-                   MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
-        }
+        reporter.reportErrorMessage(
+            NO_LOCATION_SPANNABLE,
+            MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
+            {'importChain': importChains.join(
+                MessageTemplate.MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING)});
+      } else if (importsMirrorsLibrary && !enableExperimentalMirrors) {
+        Set<String> importChains =
+            computeImportChainsFor(loadedLibraries, Uris.dart_mirrors);
+        reporter.reportWarningMessage(
+            NO_LOCATION_SPANNABLE,
+            MessageKind.IMPORT_EXPERIMENTAL_MIRRORS,
+            {'importChain': importChains.join(
+                 MessageTemplate.IMPORT_EXPERIMENTAL_MIRRORS_PADDING)});
       }
 
-      functionClass.ensureResolved(this);
+      functionClass.ensureResolved(resolution);
       functionApplyMethod = functionClass.lookupLocalMember('apply');
 
       if (preserveComments) {
@@ -903,7 +754,7 @@
   bool isProxyConstant(ConstantValue value) {
     FieldElement field = coreLibrary.find('proxy');
     if (field == null) return false;
-    if (!enqueuer.resolution.hasBeenResolved(field)) return false;
+    if (!resolution.hasBeenResolved(field)) return false;
     if (proxyConstant == null) {
       proxyConstant =
           constants.getConstantValue(
@@ -915,10 +766,10 @@
   Element findRequiredElement(LibraryElement library, String name) {
     var element = library.find(name);
     if (element == null) {
-      internalError(library,
+      reporter.internalError(library,
           "The library '${library.canonicalUri}' does not contain required "
           "element: '$name'.");
-      }
+    }
     return element;
   }
 
@@ -973,7 +824,7 @@
     _coreTypes.iterableClass = lookupCoreClass('Iterable');
     _coreTypes.symbolClass = lookupCoreClass('Symbol');
     if (!missingCoreClasses.isEmpty) {
-      internalError(
+      reporter.internalError(
           coreLibrary,
           'dart:core library does not contain required classes: '
           '$missingCoreClasses');
@@ -1010,16 +861,16 @@
     return new Future.sync(() {
       if (librariesToAnalyzeWhenRun != null) {
         return Future.forEach(librariesToAnalyzeWhenRun, (libraryUri) {
-          log('Analyzing $libraryUri ($buildId)');
+          reporter.log('Analyzing $libraryUri ($buildId)');
           return libraryLoader.loadLibrary(libraryUri);
         });
       }
     }).then((_) {
       if (uri != null) {
         if (analyzeOnly) {
-          log('Analyzing $uri ($buildId)');
+          reporter.log('Analyzing $uri ($buildId)');
         } else {
-          log('Compiling $uri ($buildId)');
+          reporter.log('Compiling $uri ($buildId)');
         }
         return libraryLoader.loadLibrary(uri).then((LibraryElement library) {
           mainApp = library;
@@ -1053,7 +904,7 @@
       if (main is ErroneousElement) {
         errorElement = main;
       } else {
-        internalError(main, 'Problem with ${Identifiers.main}.');
+        reporter.internalError(main, 'Problem with ${Identifiers.main}.');
       }
       mainFunction = backend.helperForBadMain();
     } else if (!main.isFunction) {
@@ -1063,7 +914,7 @@
       mainFunction = backend.helperForBadMain();
     } else {
       mainFunction = main;
-      mainFunction.computeType(this);
+      mainFunction.computeType(resolution);
       FunctionSignature parameters = mainFunction.functionSignature;
       if (parameters.requiredParameterCount > 2) {
         int index = 0;
@@ -1081,7 +932,7 @@
     }
     if (mainFunction == null) {
       if (errorElement == null && !analyzeOnly && !analyzeAll) {
-        internalError(mainApp, "Problem with '${Identifiers.main}'.");
+        reporter.internalError(mainApp, "Problem with '${Identifiers.main}'.");
       } else {
         mainFunction = errorElement;
       }
@@ -1089,7 +940,7 @@
     if (errorElement != null &&
         errorElement.isSynthesized &&
         !mainApp.isSynthesized) {
-      reportWarningMessage(
+      reporter.reportWarningMessage(
           errorElement, errorElement.messageKind,
           errorElement.messageArguments);
     }
@@ -1106,7 +957,7 @@
       Uri libraryUri,
       {bool skipLibraryWithPartOfTag: true}) {
     assert(analyzeMain);
-    log('Analyzing $libraryUri ($buildId)');
+    reporter.log('Analyzing $libraryUri ($buildId)');
     return libraryLoader.loadLibrary(libraryUri).then((LibraryElement library) {
       var compilationUnit = library.compilationUnit;
       if (skipLibraryWithPartOfTag && compilationUnit.partTag != null) {
@@ -1114,7 +965,7 @@
       }
       fullyEnqueueLibrary(library, enqueuer.resolution);
       emptyQueue(enqueuer.resolution);
-      enqueuer.resolution.logSummary(log);
+      enqueuer.resolution.logSummary(reporter.log);
       return library;
     });
   }
@@ -1134,7 +985,7 @@
     phase = PHASE_RESOLVING;
     if (analyzeAll) {
       libraryLoader.libraries.forEach((LibraryElement library) {
-        log('Enqueuing ${library.canonicalUri}');
+      reporter.log('Enqueuing ${library.canonicalUri}');
         fullyEnqueueLibrary(library, enqueuer.resolution);
       });
     } else if (analyzeMain && mainApp != null) {
@@ -1144,30 +995,11 @@
     // that are not pulled in by a particular element.
     backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
     resolveLibraryMetadata();
-    log('Resolving...');
+    reporter.log('Resolving...');
     processQueue(enqueuer.resolution, mainFunction);
-    enqueuer.resolution.logSummary(log);
+    enqueuer.resolution.logSummary(reporter.log);
 
-    if (!showPackageWarnings && !suppressWarnings) {
-      suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
-        MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
-        if (info.warnings == 0) {
-          kind = MessageKind.HIDDEN_HINTS;
-        } else if (info.hints == 0) {
-          kind = MessageKind.HIDDEN_WARNINGS;
-        }
-        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
-        Message message = template.message(
-            {'warnings': info.warnings,
-             'hints': info.hints,
-             'uri': uri},
-            terseDiagnostics);
-        reportDiagnostic(
-            new DiagnosticMessage(null, null, message),
-            const <DiagnosticMessage>[],
-            api.Diagnostic.HINT);
-      });
-    }
+    _reporter.reportSuppressedMessagesSummary();
 
     if (compilationFailed){
       if (!generateCodeWithCompileTimeErrors) return;
@@ -1198,14 +1030,14 @@
 
     deferredLoadTask.onResolutionComplete(mainFunction);
 
-    log('Inferring types...');
+    reporter.log('Inferring types...');
     typesTask.onResolutionComplete(mainFunction);
 
     if (stopAfterTypeInference) return;
 
     backend.onTypeInferenceComplete();
 
-    log('Compiling...');
+    reporter.log('Compiling...');
     phase = PHASE_COMPILING;
     backend.onCodegenStart();
     // TODO(johnniwinther): Move these to [CodegenEnqueuer].
@@ -1218,7 +1050,7 @@
       });
     }
     processQueue(enqueuer.codegen, mainFunction);
-    enqueuer.codegen.logSummary(log);
+    enqueuer.codegen.logSummary(reporter.log);
 
     int programSize = backend.assembleProgram();
 
@@ -1240,7 +1072,7 @@
   void fullyEnqueueTopLevelElement(Element element, Enqueuer world) {
     if (element.isClass) {
       ClassElement cls = element;
-      cls.ensureResolved(this);
+      cls.ensureResolved(resolution);
       cls.forEachLocalMember(enqueuer.resolution.addToWorkList);
       backend.registerInstantiatedType(
           cls.rawType, world, globalDependencies);
@@ -1256,7 +1088,7 @@
     for (LibraryElement library in libraryLoader.libraries) {
       if (library.metadata != null) {
         for (MetadataAnnotation metadata in library.metadata) {
-          metadata.ensureResolved(this);
+          metadata.ensureResolved(resolution);
         }
       }
     }
@@ -1267,7 +1099,7 @@
    */
   void emptyQueue(Enqueuer world) {
     world.forEach((WorkItem work) {
-      withCurrentElement(work.element, () {
+    reporter.withCurrentElement(work.element, () {
         world.applyImpact(work.element, work.run(this, world));
       });
     });
@@ -1277,13 +1109,13 @@
     world.nativeEnqueuer.processNativeClasses(libraryLoader.libraries);
     if (main != null && !main.isErroneous) {
       FunctionElement mainMethod = main;
-      mainMethod.computeType(this);
+      mainMethod.computeType(resolution);
       if (mainMethod.functionSignature.parameterCount != 0) {
         // The first argument could be a list of strings.
-        backend.listImplementation.ensureResolved(this);
+        backend.listImplementation.ensureResolved(resolution);
         backend.registerInstantiatedType(
             backend.listImplementation.rawType, world, globalDependencies);
-        backend.stringImplementation.ensureResolved(this);
+        backend.stringImplementation.ensureResolved(resolution);
         backend.registerInstantiatedType(
             backend.stringImplementation.rawType, world, globalDependencies);
 
@@ -1309,11 +1141,11 @@
   checkQueues() {
     for (Enqueuer world in [enqueuer.resolution, enqueuer.codegen]) {
       world.forEach((WorkItem work) {
-        internalError(work.element, "Work list is not empty.");
+        reporter.internalError(work.element, "Work list is not empty.");
       });
     }
     if (!REPORT_EXCESS_RESOLUTION) return;
-    var resolved = new Set.from(enqueuer.resolution.resolvedElements);
+    var resolved = new Set.from(enqueuer.resolution.processedElements);
     for (Element e in enqueuer.codegen.generatedCode.keys) {
       resolved.remove(e);
     }
@@ -1332,15 +1164,15 @@
         resolved.remove(e);
       }
     }
-    log('Excess resolution work: ${resolved.length}.');
+    reporter.log('Excess resolution work: ${resolved.length}.');
     for (Element e in resolved) {
-      reportWarningMessage(e,
+      reporter.reportWarningMessage(e,
           MessageKind.GENERIC,
           {'text': 'Warning: $e resolved but not compiled.'});
     }
   }
 
-  WorldImpact analyzeElement(Element element) {
+  ResolutionWorldImpact analyzeElement(Element element) {
     assert(invariant(element,
            element.impliesType ||
            element.isField ||
@@ -1352,23 +1184,11 @@
     assert(invariant(element, element is AnalyzableElement,
         message: 'Element $element is not analyzable.'));
     assert(invariant(element, element.isDeclaration));
-    ResolutionEnqueuer world = enqueuer.resolution;
-    if (world.hasBeenResolved(element)) {
-      return const WorldImpact();
-    }
-    assert(parser != null);
-    Node tree = parser.parse(element);
-    assert(invariant(element, !element.isSynthesized || tree == null));
-    WorldImpact worldImpact = resolver.resolve(element);
-    if (tree != null && !analyzeSignaturesOnly && !suppressWarnings) {
-      // Only analyze nodes with a corresponding [TreeElements].
-      checker.check(element);
-    }
-    world.registerResolvedElement(element);
-    return worldImpact;
+    return resolution.analyzeElement(element);
   }
 
-  WorldImpact analyze(ResolutionWorkItem work, ResolutionEnqueuer world) {
+  ResolutionWorldImpact analyze(ResolutionWorkItem work,
+                                ResolutionEnqueuer world) {
     assert(invariant(work.element, identical(world, enqueuer.resolution)));
     assert(invariant(work.element, !work.isAnalyzed,
         message: 'Element ${work.element} has already been analyzed'));
@@ -1376,17 +1196,19 @@
       // TODO(ahe): Add structured diagnostics to the compiler API and
       // use it to separate this from the --verbose option.
       if (phase == PHASE_RESOLVING) {
-        log('Resolved ${enqueuer.resolution.resolvedElements.length} '
+        reporter.log(
+            'Resolved ${enqueuer.resolution.processedElements.length} '
             'elements.');
         progress.reset();
       }
     }
     AstElement element = work.element;
-    if (world.hasBeenResolved(element)) {
-      return const WorldImpact();
+    if (world.hasBeenProcessed(element)) {
+      return const ResolutionWorldImpact();
     }
-    WorldImpact worldImpact = analyzeElement(element);
+    ResolutionWorldImpact worldImpact = analyzeElement(element);
     backend.onElementResolved(element, element.resolvedAst.elements);
+    world.registerProcessedElement(element);
     return worldImpact;
   }
 
@@ -1395,153 +1217,19 @@
     if (shouldPrintProgress) {
       // TODO(ahe): Add structured diagnostics to the compiler API and
       // use it to separate this from the --verbose option.
-      log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
+      reporter.log(
+          'Compiled ${enqueuer.codegen.generatedCode.length} methods.');
       progress.reset();
     }
     return backend.codegen(work);
   }
 
-  DiagnosticMessage createMessage(
-      Spannable spannable,
-      MessageKind messageKind,
-      [Map arguments = const {}]) {
-    SourceSpan span = spanFromSpannable(spannable);
-    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
-    Message message = template.message(arguments, terseDiagnostics);
-    return new DiagnosticMessage(span, spannable, message);
-  }
-
-  void reportError(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
-  }
-
-  void reportWarning(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
-  }
-
-  void reportHint(
-      DiagnosticMessage message,
-      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
-    reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
-  }
-
-  @deprecated
-  void reportInfo(Spannable node, MessageKind messageKind,
-                  [Map arguments = const {}]) {
-    reportDiagnosticInternal(
-        createMessage(node, messageKind, arguments),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.INFO);
-  }
-
-  void reportDiagnosticInternal(DiagnosticMessage message,
-                                List<DiagnosticMessage> infos,
-                                api.Diagnostic kind) {
-    if (!showPackageWarnings && message.spannable != NO_LOCATION_SPANNABLE) {
-      switch (kind) {
-      case api.Diagnostic.WARNING:
-      case api.Diagnostic.HINT:
-        Element element = elementFromSpannable(message.spannable);
-        if (!inUserCode(element, assumeInUserCode: true)) {
-          Uri uri = getCanonicalUri(element);
-          SuppressionInfo info =
-              suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
-          if (kind == api.Diagnostic.WARNING) {
-            info.warnings++;
-          } else {
-            info.hints++;
-          }
-          lastDiagnosticWasFiltered = true;
-          return;
-        }
-        break;
-      case api.Diagnostic.INFO:
-        if (lastDiagnosticWasFiltered) {
-          return;
-        }
-        break;
-      }
-    }
-    lastDiagnosticWasFiltered = false;
-    reportDiagnostic(message, infos, kind);
-  }
-
   void reportDiagnostic(DiagnosticMessage message,
                         List<DiagnosticMessage> infos,
                         api.Diagnostic kind);
 
-  void reportAssertionFailure(SpannableAssertionFailure ex) {
-    String message = (ex.message != null) ? tryToString(ex.message)
-                                          : tryToString(ex);
-    reportDiagnosticInternal(
-        createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
-        const <DiagnosticMessage>[],
-        api.Diagnostic.CRASH);
-  }
-
-  SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
-    if (begin == null || end == null) {
-      // TODO(ahe): We can almost always do better. Often it is only
-      // end that is null. Otherwise, we probably know the current
-      // URI.
-      throw 'Cannot find tokens to produce error message.';
-    }
-    if (uri == null && currentElement != null) {
-      uri = currentElement.compilationUnit.script.resourceUri;
-    }
-    return new SourceSpan.fromTokens(uri, begin, end);
-  }
-
-  SourceSpan spanFromNode(Node node) {
-    return spanFromTokens(node.getBeginToken(), node.getEndToken());
-  }
-
-  SourceSpan spanFromElement(Element element) {
-    if (element != null && element.sourcePosition != null) {
-      return element.sourcePosition;
-    }
-    while (element != null && element.isSynthesized) {
-      element = element.enclosingElement;
-    }
-    if (element != null &&
-        element.sourcePosition == null &&
-        !element.isLibrary &&
-        !element.isCompilationUnit) {
-      // Sometimes, the backend fakes up elements that have no
-      // position. So we use the enclosing element instead. It is
-      // not a good error location, but cancel really is "internal
-      // error" or "not implemented yet", so the vicinity is good
-      // enough for now.
-      element = element.enclosingElement;
-      // TODO(ahe): I plan to overhaul this infrastructure anyways.
-    }
-    if (element == null) {
-      element = currentElement;
-    }
-    if (element == null) {
-      return null;
-    }
-
-    if (element.sourcePosition != null) {
-      return element.sourcePosition;
-    }
-    Token position = element.position;
-    Uri uri = element.compilationUnit.script.resourceUri;
-    return (position == null)
-        ? new SourceSpan(uri, 0, 0)
-        : spanFromTokens(position, position, uri);
-  }
-
-  SourceSpan spanFromHInstruction(HInstruction instruction) {
-    Element element = _elementFromHInstruction(instruction);
-    if (element == null) element = currentElement;
-    SourceInformation position = instruction.sourceInformation;
-    if (position == null) return spanFromElement(element);
-    return position.sourceSpan;
+  void reportCrashInUserCode(String message, exception, stackTrace) {
+    _reporter.onCrashInUserCode(message, exception, stackTrace);
   }
 
   /**
@@ -1616,20 +1304,20 @@
     void checkLive(member) {
       if (member.isErroneous) return;
       if (member.isFunction) {
-        if (!enqueuer.resolution.hasBeenResolved(member)) {
-          reportHintMessage(
+        if (!enqueuer.resolution.hasBeenProcessed(member)) {
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_METHOD, {'name': member.name});
         }
       } else if (member.isClass) {
         if (!member.isResolved) {
-          reportHintMessage(
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_CLASS, {'name': member.name});
         } else {
           member.forEachLocalMember(checkLive);
         }
       } else if (member.isTypedef) {
         if (!member.isResolved) {
-          reportHintMessage(
+          reporter.reportHintMessage(
               member, MessageKind.UNUSED_TYPEDEF, {'name': member.name});
         }
       }
@@ -1753,7 +1441,7 @@
 }
 
 class _CompilerCoreTypes implements CoreTypes {
-  final Compiler compiler;
+  final Resolution resolution;
 
   ClassElement objectClass;
   ClassElement boolClass;
@@ -1773,31 +1461,50 @@
   ClassElement streamClass;
   ClassElement resourceClass;
 
-  _CompilerCoreTypes(this.compiler);
+  _CompilerCoreTypes(this.resolution);
 
   @override
-  InterfaceType get objectType => objectClass.computeType(compiler);
+  InterfaceType get objectType {
+    objectClass.ensureResolved(resolution);
+    return objectClass.rawType;
+  }
 
   @override
-  InterfaceType get boolType => boolClass.computeType(compiler);
+  InterfaceType get boolType {
+    boolClass.ensureResolved(resolution);
+    return boolClass.rawType;
+  }
 
   @override
-  InterfaceType get doubleType => doubleClass.computeType(compiler);
+  InterfaceType get doubleType {
+    doubleClass.ensureResolved(resolution);
+    return doubleClass.rawType;
+  }
 
   @override
-  InterfaceType get functionType => functionClass.computeType(compiler);
+  InterfaceType get functionType {
+    functionClass.ensureResolved(resolution);
+    return functionClass.rawType;
+  }
 
   @override
-  InterfaceType get intType => intClass.computeType(compiler);
+  InterfaceType get intType {
+    intClass.ensureResolved(resolution);
+    return intClass.rawType;
+  }
 
   @override
-  InterfaceType get resourceType => resourceClass.computeType(compiler);
+  InterfaceType get resourceType {
+    resourceClass.ensureResolved(resolution);
+    return resourceClass.rawType;
+  }
 
   @override
   InterfaceType listType([DartType elementType]) {
-    InterfaceType type = listClass.computeType(compiler);
+    listClass.ensureResolved(resolution);
+    InterfaceType type = listClass.rawType;
     if (elementType == null) {
-      return listClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
@@ -1805,9 +1512,10 @@
   @override
   InterfaceType mapType([DartType keyType,
                          DartType valueType]) {
-    InterfaceType type = mapClass.computeType(compiler);
+    mapClass.ensureResolved(resolution);
+    InterfaceType type = mapClass.rawType;
     if (keyType == null && valueType == null) {
-      return mapClass.rawType;
+      return type;
     } else if (keyType == null) {
       keyType = const DynamicType();
     } else if (valueType == null) {
@@ -1817,44 +1525,498 @@
   }
 
   @override
-  InterfaceType get nullType => nullClass.computeType(compiler);
+  InterfaceType get nullType {
+    nullClass.ensureResolved(resolution);
+    return nullClass.rawType;
+  }
 
   @override
-  InterfaceType get numType => numClass.computeType(compiler);
+  InterfaceType get numType {
+    numClass.ensureResolved(resolution);
+    return numClass.rawType;
+  }
 
   @override
-  InterfaceType get stringType => stringClass.computeType(compiler);
+  InterfaceType get stringType {
+    stringClass.ensureResolved(resolution);
+    return stringClass.rawType;
+  }
 
   @override
-  InterfaceType get symbolType => symbolClass.computeType(compiler);
+  InterfaceType get symbolType {
+    symbolClass.ensureResolved(resolution);
+    return symbolClass.rawType;
+  }
 
   @override
-  InterfaceType get typeType => typeClass.computeType(compiler);
+  InterfaceType get typeType {
+    typeClass.ensureResolved(resolution);
+    return typeClass.rawType;
+  }
 
   @override
   InterfaceType iterableType([DartType elementType]) {
-    InterfaceType type = iterableClass.computeType(compiler);
+    iterableClass.ensureResolved(resolution);
+    InterfaceType type = iterableClass.rawType;
     if (elementType == null) {
-      return iterableClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 
   @override
   InterfaceType futureType([DartType elementType]) {
-    InterfaceType type = futureClass.computeType(compiler);
+    futureClass.ensureResolved(resolution);
+    InterfaceType type = futureClass.rawType;
     if (elementType == null) {
-      return futureClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 
   @override
   InterfaceType streamType([DartType elementType]) {
-    InterfaceType type = streamClass.computeType(compiler);
+    streamClass.ensureResolved(resolution);
+    InterfaceType type = streamClass.rawType;
     if (elementType == null) {
-      return streamClass.rawType;
+      return type;
     }
     return type.createInstantiation([elementType]);
   }
 }
+
+class _CompilerDiagnosticReporter extends DiagnosticReporter {
+  final Compiler compiler;
+  final DiagnosticOptions options;
+
+  Element _currentElement;
+  bool hasCrashed = false;
+
+  /// `true` if the last diagnostic was filtered, in which case the
+  /// accompanying info message should be filtered as well.
+  bool lastDiagnosticWasFiltered = false;
+
+  /// Map containing information about the warnings and hints that have been
+  /// suppressed for each library.
+  Map<Uri, SuppressionInfo> suppressedWarnings = <Uri, SuppressionInfo>{};
+
+  _CompilerDiagnosticReporter(this.compiler, this.options);
+
+  Element get currentElement => _currentElement;
+
+  DiagnosticMessage createMessage(
+      Spannable spannable,
+      MessageKind messageKind,
+      [Map arguments = const {}]) {
+    SourceSpan span = spanFromSpannable(spannable);
+    MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
+    Message message = template.message(arguments, options.terseDiagnostics);
+    return new DiagnosticMessage(span, spannable, message);
+  }
+
+  void reportError(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.ERROR);
+  }
+
+  void reportWarning(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.WARNING);
+  }
+
+  void reportHint(
+      DiagnosticMessage message,
+      [List<DiagnosticMessage> infos = const <DiagnosticMessage>[]]) {
+    reportDiagnosticInternal(message, infos, api.Diagnostic.HINT);
+  }
+
+  @deprecated
+  void reportInfo(Spannable node, MessageKind messageKind,
+                  [Map arguments = const {}]) {
+    reportDiagnosticInternal(
+        createMessage(node, messageKind, arguments),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.INFO);
+  }
+
+  void reportDiagnosticInternal(DiagnosticMessage message,
+                                List<DiagnosticMessage> infos,
+                                api.Diagnostic kind) {
+    if (!options.showPackageWarnings &&
+        message.spannable != NO_LOCATION_SPANNABLE) {
+      switch (kind) {
+      case api.Diagnostic.WARNING:
+      case api.Diagnostic.HINT:
+        Element element = elementFromSpannable(message.spannable);
+        if (!compiler.inUserCode(element, assumeInUserCode: true)) {
+          Uri uri = compiler.getCanonicalUri(element);
+          SuppressionInfo info =
+              suppressedWarnings.putIfAbsent(uri, () => new SuppressionInfo());
+          if (kind == api.Diagnostic.WARNING) {
+            info.warnings++;
+          } else {
+            info.hints++;
+          }
+          lastDiagnosticWasFiltered = true;
+          return;
+        }
+        break;
+      case api.Diagnostic.INFO:
+        if (lastDiagnosticWasFiltered) {
+          return;
+        }
+        break;
+      }
+    }
+    lastDiagnosticWasFiltered = false;
+    reportDiagnostic(message, infos, kind);
+  }
+
+  void reportDiagnostic(DiagnosticMessage message,
+                        List<DiagnosticMessage> infos,
+                        api.Diagnostic kind) {
+    compiler.reportDiagnostic(message, infos, kind);
+  }
+
+  /**
+   * Perform an operation, [f], returning the return value from [f].  If an
+   * error occurs then report it as having occurred during compilation of
+   * [element].  Can be nested.
+   */
+  withCurrentElement(Element element, f()) {
+    Element old = currentElement;
+    _currentElement = element;
+    try {
+      return f();
+    } on SpannableAssertionFailure catch (ex) {
+      if (!hasCrashed) {
+        reportAssertionFailure(ex);
+        pleaseReportCrash();
+      }
+      hasCrashed = true;
+      rethrow;
+    } on StackOverflowError {
+      // We cannot report anything useful in this case, because we
+      // do not have enough stack space.
+      rethrow;
+    } catch (ex) {
+      if (hasCrashed) rethrow;
+      try {
+        unhandledExceptionOnElement(element);
+      } catch (doubleFault) {
+        // Ignoring exceptions in exception handling.
+      }
+      rethrow;
+    } finally {
+      _currentElement = old;
+    }
+  }
+
+  void reportAssertionFailure(SpannableAssertionFailure ex) {
+    String message = (ex.message != null) ? tryToString(ex.message)
+                                          : tryToString(ex);
+    reportDiagnosticInternal(
+        createMessage(ex.node, MessageKind.GENERIC, {'text': message}),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+  }
+
+  SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) {
+    if (begin == null || end == null) {
+      // TODO(ahe): We can almost always do better. Often it is only
+      // end that is null. Otherwise, we probably know the current
+      // URI.
+      throw 'Cannot find tokens to produce error message.';
+    }
+    if (uri == null && currentElement != null) {
+      uri = currentElement.compilationUnit.script.resourceUri;
+    }
+    return new SourceSpan.fromTokens(uri, begin, end);
+  }
+
+  SourceSpan spanFromNode(Node node) {
+    return spanFromTokens(node.getBeginToken(), node.getEndToken());
+  }
+
+  SourceSpan spanFromElement(Element element) {
+    if (element != null && element.sourcePosition != null) {
+      return element.sourcePosition;
+    }
+    while (element != null && element.isSynthesized) {
+      element = element.enclosingElement;
+    }
+    if (element != null &&
+        element.sourcePosition == null &&
+        !element.isLibrary &&
+        !element.isCompilationUnit) {
+      // Sometimes, the backend fakes up elements that have no
+      // position. So we use the enclosing element instead. It is
+      // not a good error location, but cancel really is "internal
+      // error" or "not implemented yet", so the vicinity is good
+      // enough for now.
+      element = element.enclosingElement;
+      // TODO(ahe): I plan to overhaul this infrastructure anyways.
+    }
+    if (element == null) {
+      element = currentElement;
+    }
+    if (element == null) {
+      return null;
+    }
+
+    if (element.sourcePosition != null) {
+      return element.sourcePosition;
+    }
+    Token position = element.position;
+    Uri uri = element.compilationUnit.script.resourceUri;
+    return (position == null)
+        ? new SourceSpan(uri, 0, 0)
+        : spanFromTokens(position, position, uri);
+  }
+
+  SourceSpan spanFromHInstruction(HInstruction instruction) {
+    Element element = _elementFromHInstruction(instruction);
+    if (element == null) element = currentElement;
+    SourceInformation position = instruction.sourceInformation;
+    if (position == null) return spanFromElement(element);
+    return position.sourceSpan;
+  }
+
+  SourceSpan spanFromSpannable(Spannable node) {
+    // TODO(johnniwinther): Disallow `node == null` ?
+    if (node == null) return null;
+    if (node == CURRENT_ELEMENT_SPANNABLE) {
+      node = currentElement;
+    } else if (node == NO_LOCATION_SPANNABLE) {
+      if (currentElement == null) return null;
+      node = currentElement;
+    }
+    if (node is SourceSpan) {
+      return node;
+    } else if (node is Node) {
+      return spanFromNode(node);
+    } else if (node is TokenPair) {
+      return spanFromTokens(node.begin, node.end);
+    } else if (node is Token) {
+      return spanFromTokens(node, node);
+    } else if (node is HInstruction) {
+      return spanFromHInstruction(node);
+    } else if (node is Element) {
+      return spanFromElement(node);
+    } else if (node is MetadataAnnotation) {
+      Uri uri = node.annotatedElement.compilationUnit.script.resourceUri;
+      return spanFromTokens(node.beginToken, node.endToken, uri);
+    } else if (node is Local) {
+      Local local = node;
+      return spanFromElement(local.executableContext);
+    } else {
+      throw 'No error location.';
+    }
+  }
+
+  Element _elementFromHInstruction(HInstruction instruction) {
+    return instruction.sourceElement is Element
+        ? instruction.sourceElement : null;
+  }
+
+  internalError(Spannable node, reason) {
+    String message = tryToString(reason);
+    reportDiagnosticInternal(
+        createMessage(node, MessageKind.GENERIC, {'text': message}),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+    throw 'Internal Error: $message';
+  }
+
+  void unhandledExceptionOnElement(Element element) {
+    if (hasCrashed) return;
+    hasCrashed = true;
+    reportDiagnostic(
+        createMessage(element, MessageKind.COMPILER_CRASHED),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.CRASH);
+    pleaseReportCrash();
+  }
+
+  void pleaseReportCrash() {
+    print(
+        MessageTemplate.TEMPLATES[MessageKind.PLEASE_REPORT_THE_CRASH]
+            .message({'buildId': compiler.buildId}));
+  }
+
+  /// Finds the approximate [Element] for [node]. [currentElement] is used as
+  /// the default value.
+  Element elementFromSpannable(Spannable node) {
+    Element element;
+    if (node is Element) {
+      element = node;
+    } else if (node is HInstruction) {
+      element = _elementFromHInstruction(node);
+    } else if (node is MetadataAnnotation) {
+      element = node.annotatedElement;
+    }
+    return element != null ? element : currentElement;
+  }
+
+  void log(message) {
+    Message msg = MessageTemplate.TEMPLATES[MessageKind.GENERIC]
+        .message({'text': '$message'});
+    reportDiagnostic(
+        new DiagnosticMessage(null, null, msg),
+        const <DiagnosticMessage>[],
+        api.Diagnostic.VERBOSE_INFO);
+  }
+
+  String tryToString(object) {
+    try {
+      return object.toString();
+    } catch (_) {
+      return '<exception in toString()>';
+    }
+  }
+
+  onError(Uri uri, error) {
+    try {
+      if (!hasCrashed) {
+        hasCrashed = true;
+        if (error is SpannableAssertionFailure) {
+          reportAssertionFailure(error);
+        } else {
+          reportDiagnostic(
+              createMessage(
+                  new SourceSpan(uri, 0, 0),
+                  MessageKind.COMPILER_CRASHED),
+              const <DiagnosticMessage>[],
+              api.Diagnostic.CRASH);
+        }
+        pleaseReportCrash();
+      }
+    } catch (doubleFault) {
+      // Ignoring exceptions in exception handling.
+    }
+    throw error;
+  }
+
+  void onCrashInUserCode(String message, exception, stackTrace) {
+    hasCrashed = true;
+    print('$message: ${tryToString(exception)}');
+    print(tryToString(stackTrace));
+  }
+
+  void reportSuppressedMessagesSummary() {
+    if (!options.showPackageWarnings && !options.suppressWarnings) {
+      suppressedWarnings.forEach((Uri uri, SuppressionInfo info) {
+        MessageKind kind = MessageKind.HIDDEN_WARNINGS_HINTS;
+        if (info.warnings == 0) {
+          kind = MessageKind.HIDDEN_HINTS;
+        } else if (info.hints == 0) {
+          kind = MessageKind.HIDDEN_WARNINGS;
+        }
+        MessageTemplate template = MessageTemplate.TEMPLATES[kind];
+        Message message = template.message(
+            {'warnings': info.warnings,
+             'hints': info.hints,
+             'uri': uri},
+             options.terseDiagnostics);
+        reportDiagnostic(
+            new DiagnosticMessage(null, null, message),
+            const <DiagnosticMessage>[],
+            api.Diagnostic.HINT);
+      });
+    }
+  }
+}
+
+// TODO(johnniwinther): Move [ResolverTask] here.
+class _CompilerResolution implements Resolution {
+  final Compiler compiler;
+  final Map<Element, ResolutionWorldImpact> _worldImpactCache =
+      <Element, ResolutionWorldImpact>{};
+
+  _CompilerResolution(this.compiler);
+
+  @override
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  @override
+  Parsing get parsing => compiler.parsing;
+
+  @override
+  CoreTypes get coreTypes => compiler.coreTypes;
+
+  @override
+  void registerClass(ClassElement cls) {
+    compiler.world.registerClass(cls);
+  }
+
+  @override
+  void resolveClass(ClassElement cls) {
+    compiler.resolver.resolveClass(cls);
+  }
+
+  @override
+  void resolveTypedef(TypedefElement typdef) {
+    compiler.resolver.resolve(typdef);
+  }
+
+  @override
+  void resolveMetadataAnnotation(MetadataAnnotation metadataAnnotation) {
+    compiler.resolver.resolveMetadataAnnotation(metadataAnnotation);
+  }
+
+  @override
+  FunctionSignature resolveSignature(FunctionElement function) {
+    return compiler.resolver.resolveSignature(function);
+  }
+
+  @override
+  DartType resolveTypeAnnotation(Element element, TypeAnnotation node) {
+    return compiler.resolver.resolveTypeAnnotation(element, node);
+  }
+
+  ResolutionWorldImpact analyzeElement(Element element) {
+    return _worldImpactCache.putIfAbsent(element, () {
+      assert(compiler.parser != null);
+      Node tree = compiler.parser.parse(element);
+      assert(invariant(element, !element.isSynthesized || tree == null));
+      ResolutionWorldImpact worldImpact = compiler.resolver.resolve(element);
+      if (tree != null &&
+          !compiler.analyzeSignaturesOnly &&
+          !reporter.options.suppressWarnings) {
+        // Only analyze nodes with a corresponding [TreeElements].
+        compiler.checker.check(element);
+      }
+      return worldImpact;
+    });
+  }
+
+  @override
+  bool hasBeenResolved(Element element) {
+    return _worldImpactCache.containsKey(element);
+  }
+}
+
+// TODO(johnniwinther): Move [ParserTask], [PatchParserTask], [DietParserTask]
+// and [ScannerTask] here.
+class _CompilerParsing implements Parsing {
+  final Compiler compiler;
+
+  _CompilerParsing(this.compiler);
+
+  @override
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  @override
+  measure(f()) => compiler.parser.measure(f);
+
+  @override
+  void parsePatchClass(ClassElement cls) {
+    compiler.patchParser.measure(() {
+      if (cls.isPatch) {
+        compiler.patchParser.parsePatchClassNode(cls);
+      }
+    });
+  }
+}
diff --git a/pkg/compiler/lib/src/constant_system_dart.dart b/pkg/compiler/lib/src/constant_system_dart.dart
index 940e764..4a15ac9 100644
--- a/pkg/compiler/lib/src/constant_system_dart.dart
+++ b/pkg/compiler/lib/src/constant_system_dart.dart
@@ -434,7 +434,7 @@
     // `compiler.coreTypes.typeType` and check the backend specific value in
     // [checkConstMapKeysDontOverrideEquals] in 'members.dart'.
     return new TypeConstantValue(type,
-        compiler.backend.typeImplementation.computeType(compiler));
+        compiler.backend.typeImplementation.computeType(compiler.resolution));
   }
 
   bool isInt(ConstantValue constant) => constant.isInt;
diff --git a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
index 09c6b0d..3d168d3 100644
--- a/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
+++ b/pkg/compiler/lib/src/cps_ir/cps_ir_builder_task.dart
@@ -15,6 +15,8 @@
     Compiler;
 import '../constants/expressions.dart';
 import '../dart_types.dart';
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     invariant;
 import '../elements/elements.dart';
@@ -83,7 +85,7 @@
 
       TreeElements elementsMapping = element.resolvedAst.elements;
       element = element.implementation;
-      return compiler.withCurrentElement(element, () {
+      return reporter.withCurrentElement(element, () {
         SourceInformationBuilder sourceInformationBuilder =
             sourceInformationStrategy.createBuilderForContext(element);
 
@@ -160,6 +162,8 @@
                    this.compiler,
                    this.sourceInformationBuilder);
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   String bailoutMessage = null;
 
   @override
@@ -235,14 +239,14 @@
 
   ir.Primitive visitBreakStatement(ast.BreakStatement node) {
     if (!irBuilder.buildBreak(elements.getTargetOf(node))) {
-      compiler.internalError(node, "'break' target not found");
+      reporter.internalError(node, "'break' target not found");
     }
     return null;
   }
 
   ir.Primitive visitContinueStatement(ast.ContinueStatement node) {
     if (!irBuilder.buildContinue(elements.getTargetOf(node))) {
-      compiler.internalError(node, "'continue' target not found");
+      reporter.internalError(node, "'continue' target not found");
     }
     return null;
   }
@@ -2065,8 +2069,7 @@
   }
 
   @override
-  ir.Primitive bulkHandleError(ast.Send node, ErroneousElement error, _) {
-    assert(compiler.compilationFailed);
+  ir.Primitive bulkHandleError(ast.Node node, ErroneousElement error, _) {
     return irBuilder.buildNullConstant();
   }
 
@@ -2259,7 +2262,7 @@
   }
 
   internalError(ast.Node node, String message) {
-    compiler.internalError(node, message);
+    reporter.internalError(node, message);
   }
 
   @override
@@ -2496,7 +2499,7 @@
 
   ClassElement get nullClass => _compiler.nullClass;
 
-  DartType unaliasType(DartType type) => type.unalias(_compiler);
+  DartType unaliasType(DartType type) => type.unalias(_compiler.resolution);
 
   TypeMask getTypeMaskForForeign(NativeBehavior behavior) {
     if (behavior == null) {
@@ -2647,7 +2650,7 @@
           break;
 
         default:
-          compiler.internalError(element, "Unexpected element type $element");
+          reporter.internalError(element, "Unexpected element type $element");
       }
       return root;
     });
@@ -2906,7 +2909,7 @@
               fieldValues);
           hasConstructorCall = true;
         } else {
-          compiler.internalError(initializer,
+          reporter.internalError(initializer,
                                  "Unexpected initializer type $initializer");
         }
       }
@@ -2916,7 +2919,7 @@
       ClassElement superClass = enclosingClass.superclass;
       FunctionElement target = superClass.lookupDefaultConstructor();
       if (target == null) {
-        compiler.internalError(superClass, "No default constructor available.");
+        reporter.internalError(superClass, "No default constructor available.");
       }
       target = target.implementation;
       evaluateConstructorCallFromInitializer(
@@ -3372,7 +3375,7 @@
                                               CallStructure callStructure) {
       Element element = backend.isolateHelperLibrary.find(helperName);
       if (element == null) {
-        compiler.internalError(node,
+        reporter.internalError(node,
             'Isolate library and compiler mismatch.');
       }
       List<ir.Primitive> arguments = translateStaticArguments(argumentList,
diff --git a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
index b9b6b09..4de0cab 100644
--- a/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
+++ b/pkg/compiler/lib/src/cps_ir/scalar_replacement.dart
@@ -43,7 +43,7 @@
   final World _classWorld;
 
   ScalarReplacer(dart2js.Compiler compiler)
-      : _internalError = compiler.internalError,
+      : _internalError = compiler.reporter.internalError,
         _classWorld = compiler.world;
 
   @override
diff --git a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
index 893113f..a84d28d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_mask_system.dart
@@ -133,10 +133,7 @@
     if (!mask.isValue) return null;
     if (mask.isNullable) return null;  // e.g. 'true or null'.
     ValueTypeMask valueMask = mask;
-    var value = valueMask.value;
-    // TODO(sra): Why is ValueTypeMask.value not a ConstantValue?
-    if (value == false) return new FalseConstantValue();
-    if (value == true) return new TrueConstantValue();
+    if (valueMask.value.isBool) return valueMask.value;
     // TODO(sra): Consider other values. Be careful with large strings.
     return null;
   }
diff --git a/pkg/compiler/lib/src/cps_ir/type_propagation.dart b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
index 383b39f..ecf555d 100644
--- a/pkg/compiler/lib/src/cps_ir/type_propagation.dart
+++ b/pkg/compiler/lib/src/cps_ir/type_propagation.dart
@@ -355,7 +355,7 @@
                  TypeMaskSystem typeSystem,
                  this._functionCompiler)
       : _compiler = compiler,
-        _internalError = compiler.internalError,
+        _internalError = compiler.reporter.internalError,
         _typeSystem = typeSystem,
         _lattice = new ConstantPropagationLattice(
             typeSystem,
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index c250be1..bc511e4 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -329,9 +329,6 @@
                       (_) => diagnosticHandler.enableColors = true),
     new OptionHandler('--enable[_-]checked[_-]mode|--checked',
                       (_) => setCheckedMode(Flags.enableCheckedMode)),
-    new OptionHandler(Flags.enableConcreteTypeInference,
-                      (_) => implyCompilation(
-                          Flags.enableConcreteTypeInference)),
     new OptionHandler(Flags.trustTypeAnnotations,
                       (_) => setTrustTypeAnnotations(
                           Flags.trustTypeAnnotations)),
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index c29ae0e..85427b1 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -52,7 +52,7 @@
       new Set<ClassElement>();
 
   bool enableCodegenWithErrorsIfSupported(Spannable node) {
-    compiler.reportHintMessage(
+    reporter.reportHintMessage(
         node,
         MessageKind.GENERIC,
         {'text': "Generation of code with compile time errors is not "
@@ -108,7 +108,7 @@
         stripAsserts = strips.indexOf('asserts') != -1,
         constantCompilerTask = new DartConstantTask(compiler),
         outputter = new DartOutputter(
-            compiler, compiler.outputProvider,
+            compiler.reporter, compiler.outputProvider,
             forceStripTypes: strips.indexOf('types') != -1,
             multiFile: multiFile,
             enableMinification: compiler.enableMinification),
@@ -116,6 +116,11 @@
     resolutionCallbacks = new DartResolutionCallbacks(this);
   }
 
+
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   bool classNeedsRti(ClassElement cls) => false;
   bool methodNeedsRti(FunctionElement function) => false;
 
@@ -128,7 +133,7 @@
     final coreLibrary = compiler.coreLibrary;
     for (final name in LITERAL_TYPE_NAMES) {
       ClassElement classElement = coreLibrary.findLocal(name);
-      classElement.ensureResolved(compiler);
+      classElement.ensureResolved(resolution);
     }
     // Enqueue the methods that the VM might invoke on user objects because
     // we don't trust the resolution to always get these included.
@@ -167,7 +172,7 @@
         newTypedefElementCallback,
         newClassElementCallback) {
       ReferencedElementCollector collector =
-          new ReferencedElementCollector(compiler,
+          new ReferencedElementCollector(reporter,
                                          element,
                                          elementAst,
                                          newTypedefElementCallback,
@@ -178,7 +183,7 @@
     int totalSize = outputter.assembleProgram(
         libraries: compiler.libraryLoader.libraries,
         instantiatedClasses: compiler.resolverWorld.directlyInstantiatedClasses,
-        resolvedElements: compiler.enqueuer.resolution.resolvedElements,
+        resolvedElements: compiler.enqueuer.resolution.processedElements,
         usedTypeLiterals: usedTypeLiterals,
         postProcessElementAst: postProcessElementAst,
         computeElementAst: computeElementAst,
@@ -214,7 +219,7 @@
         'Output total size: $totalOutputSize bytes (${percentage}%)');
   }
 
-  log(String message) => compiler.log('[DartBackend] $message');
+  log(String message) => reporter.log('[DartBackend] $message');
 
   @override
   Future onLibrariesLoaded(LoadedLibraries loadedLibraries) {
@@ -225,7 +230,7 @@
         library.forEachLocalMember((Element element) {
           if (element.isClass) {
             ClassElement classElement = element;
-            classElement.ensureResolved(compiler);
+            classElement.ensureResolved(resolution);
           }
         });
       }
@@ -306,7 +311,7 @@
               if (element.isConstructor || element.isStatic) return;
 
               FunctionElement function = element.asFunctionElement();
-              element.computeType(compiler);
+              element.computeType(resolution);
               Selector selector = new Selector.fromElement(element);
               if (selector.isGetter) {
                 registry.registerDynamicGetter(
@@ -330,7 +335,7 @@
   @override
   bool enableDeferredLoadingIfSupported(Spannable node, Registry registry) {
     // TODO(sigurdm): Implement deferred loading for dart2dart.
-    compiler.reportWarningMessage(
+    reporter.reportWarningMessage(
         node, MessageKind.DEFERRED_LIBRARY_DART_2_DART);
     return false;
   }
@@ -341,6 +346,24 @@
 
   DartResolutionCallbacks(this.backend);
 
+  @override
+  WorldImpact transformImpact(ResolutionWorldImpact worldImpact) {
+    TransformedWorldImpact transformed =
+        new TransformedWorldImpact(worldImpact);
+    for (DartType typeLiteral in worldImpact.typeLiterals) {
+      onTypeLiteral(typeLiteral, transformed);
+    }
+    for (InterfaceType instantiatedType in worldImpact.instantiatedTypes) {
+      // TODO(johnniwinther): Remove this when dependency tracking is done on
+      // the world impact itself.
+      transformed.registerInstantiation(instantiatedType);
+      backend.registerInstantiatedType(
+          instantiatedType, backend.compiler.enqueuer.resolution, transformed);
+    }
+    return transformed;
+  }
+
+  @override
   void onTypeLiteral(DartType type, Registry registry) {
     if (type.isInterfaceType) {
       backend.usedTypeLiterals.add(type.element);
@@ -385,13 +408,13 @@
  * (just to name a few).  Retraverse AST to pick those up.
  */
 class ReferencedElementCollector extends Visitor {
-  final Compiler compiler;
+  final DiagnosticReporter reporter;
   final Element element;
   final ElementAst elementAst;
   final newTypedefElementCallback;
   final newClassElementCallback;
 
-  ReferencedElementCollector(this.compiler,
+  ReferencedElementCollector(this.reporter,
                              this.element,
                              this.elementAst,
                              this.newTypedefElementCallback,
@@ -412,7 +435,7 @@
   }
 
   void collect() {
-    compiler.withCurrentElement(element, () {
+    reporter.withCurrentElement(element, () {
       elementAst.ast.accept(this);
     });
   }
diff --git a/pkg/compiler/lib/src/dart_backend/dart_backend.dart b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
index 9c42e1d..fcfc0c8 100644
--- a/pkg/compiler/lib/src/dart_backend/dart_backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/dart_backend.dart
@@ -19,7 +19,10 @@
 import '../common/registry.dart' show
     Registry;
 import '../common/resolution.dart' show
-    ResolutionCallbacks;
+    Resolution,
+    ResolutionCallbacks,
+    ResolutionWorldImpact,
+    TransformedWorldImpact;
 import '../common/tasks.dart' show
     CompilerTask;
 import '../compiler.dart' show
diff --git a/pkg/compiler/lib/src/dart_backend/outputter.dart b/pkg/compiler/lib/src/dart_backend/outputter.dart
index a8240ad..3e6f564 100644
--- a/pkg/compiler/lib/src/dart_backend/outputter.dart
+++ b/pkg/compiler/lib/src/dart_backend/outputter.dart
@@ -18,7 +18,7 @@
 /// Output engine for dart2dart that is shared between the dart2js and the
 /// analyzer implementations of dart2dart.
 class DartOutputter {
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
   final CompilerOutputProvider outputProvider;
   final bool forceStripTypes;
 
@@ -37,7 +37,7 @@
   ElementInfo elementInfo;
 
   // TODO(johnniwinther): Support recompilation.
-  DartOutputter(this.listener, this.outputProvider,
+  DartOutputter(this.reporter, this.outputProvider,
                 {bool this.forceStripTypes: false,
                  bool this.enableMinification: false,
                  bool this.multiFile: false});
@@ -97,7 +97,7 @@
     }
 
     libraryInfo = LibraryInfo.processLibraries(
-        listener, libraries, resolvedElements);
+        reporter, libraries, resolvedElements);
 
     elementInfo = ElementInfoProcessor.createElementInfo(
         instantiatedClasses,
@@ -109,7 +109,7 @@
         sortElements: sortElements);
 
     PlaceholderCollector collector = collectPlaceholders(
-        listener,
+        reporter,
         mirrorRenamer,
         mainFunction,
         libraryInfo,
@@ -124,7 +124,7 @@
         isSafeToRemoveTypeDeclarations: isSafeToRemoveTypeDeclarations);
 
     if (outputAst) {
-      String code = astOutput(listener, elementInfo);
+      String code = astOutput(reporter, elementInfo);
       outputProvider("", "dart")
                  ..add(code)
                  ..close();
@@ -147,14 +147,14 @@
   }
 
   static PlaceholderCollector collectPlaceholders(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       MirrorRenamer mirrorRenamer,
       FunctionElement mainFunction,
       LibraryInfo libraryInfo,
       ElementInfo elementInfo) {
     // Create all necessary placeholders.
     PlaceholderCollector collector = new PlaceholderCollector(
-        listener,
+        reporter,
         mirrorRenamer,
         libraryInfo.fixedDynamicNames,
         elementInfo.elementAsts,
@@ -194,13 +194,13 @@
     return placeholderRenamer;
   }
 
-  static String astOutput(DiagnosticListener listener,
+  static String astOutput(DiagnosticReporter reporter,
                           ElementInfo elementInfo) {
     // TODO(antonm): Ideally XML should be a separate backend.
     // TODO(antonm): obey renames and minification, at least as an option.
     StringBuffer sb = new StringBuffer();
     outputElement(element) {
-      sb.write(element.parseNode(listener).toDebugString());
+      sb.write(element.parseNode(reporter).toDebugString());
     }
 
     // Emit XML for AST instead of the program.
@@ -229,7 +229,7 @@
               this.userLibraries);
 
   static LibraryInfo processLibraries(
-      DiagnosticListener listener,
+      DiagnosticReporter reporter,
       Iterable<LibraryElement> libraries,
       Iterable<AstElement> resolvedElements) {
     Set<String> fixedStaticNames = new Set<String>();
@@ -299,14 +299,14 @@
         ClassElement existingEnumClass =
             enumClassMap.putIfAbsent(cls.name, () => cls);
         if (existingEnumClass != cls) {
-          listener.reportError(
-              listener.createMessage(
+          reporter.reportError(
+              reporter.createMessage(
                   cls,
                   MessageKind.GENERIC,
                   {'text': "Duplicate enum names are not supported "
                            "in dart2dart."}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   existingEnumClass,
                   MessageKind.GENERIC,
                   {'text': "This is the other declaration of '${cls.name}'."}),
diff --git a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
index b15e76a..42c15f9 100644
--- a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
+++ b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
@@ -170,7 +170,7 @@
 }
 
 class PlaceholderCollector extends Visitor {
-  final DiagnosticListener listener;
+  final DiagnosticReporter reporter;
   final MirrorRenamer mirrorRenamer;
   final FunctionElement mainFunction;
   final Set<String> fixedMemberNames; // member names which cannot be renamed.
@@ -196,7 +196,7 @@
   get currentFunctionScope => functionScopes.putIfAbsent(
       topmostEnclosingFunction, () => new FunctionScope());
 
-  PlaceholderCollector(this.listener, this.mirrorRenamer,
+  PlaceholderCollector(this.reporter, this.mirrorRenamer,
                        this.fixedMemberNames, this.elementAsts,
                        this.mainFunction);
 
@@ -258,7 +258,7 @@
     currentLocalPlaceholders = new Map<String, LocalPlaceholder>();
     if (!(element is ConstructorElement && element.isRedirectingFactory)) {
       // Do not visit the body of redirecting factories.
-      listener.withCurrentElement(element, () {
+      reporter.withCurrentElement(element, () {
         elementNode.accept(this);
       });
     }
@@ -475,7 +475,7 @@
   }
 
   void internalError(String reason, {Node node}) {
-    listener.internalError(node, reason);
+    reporter.internalError(node, reason);
   }
 
   visit(Node node) => (node == null) ? null : node.accept(this);
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index 1686c5a..353c00a 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -6,9 +6,13 @@
 
 import 'dart:math' show min;
 
-import 'core_types.dart';
+import 'common/resolution.dart' show
+    Resolution;
 import 'compiler.dart' show
     Compiler;
+import 'core_types.dart';
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/spannable.dart' show
@@ -82,7 +86,7 @@
    * function type [: (B) -> A :] and the unaliased type of
    * [: Func<int,String> :] is the function type [: (String) -> int :].
    */
-  DartType unalias(Compiler compiler);
+  DartType unalias(Resolution resolution);
 
   /**
    * If this type is malformed or a generic type created with the wrong number
@@ -215,7 +219,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   TypeVariableType get typeVariableOccurrence => this;
 
@@ -249,7 +253,7 @@
 
   DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitStatementType(this, argument);
@@ -270,7 +274,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitVoidType(this, argument);
@@ -320,7 +324,7 @@
   // Malformed types are treated as dynamic.
   bool get treatAsDynamic => true;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   accept(DartTypeVisitor visitor, var argument) {
     return visitor.visitMalformedType(this, argument);
@@ -487,7 +491,7 @@
     return null;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   MemberSignature lookupInterfaceMember(Name name) {
     MemberSignature member = element.lookupInterfaceMember(name);
@@ -613,8 +617,6 @@
     assert(namedParameters.length == namedParameterTypes.length);
   }
 
-
-
   TypeKind get kind => TypeKind.FUNCTION;
 
   DartType getNamedParameterType(String name) {
@@ -658,7 +660,7 @@
     return this;
   }
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   TypeVariableType get typeVariableOccurrence {
     TypeVariableType typeVariableType = returnType.typeVariableOccurrence;
@@ -783,10 +785,10 @@
     return new TypedefType(element, newTypeArguments);
   }
 
-  DartType unalias(Compiler compiler) {
-    element.ensureResolved(compiler);
-    element.checkCyclicReference(compiler);
-    DartType definition = element.alias.unalias(compiler);
+  DartType unalias(Resolution resolution) {
+    element.ensureResolved(resolution);
+    element.checkCyclicReference(resolution);
+    DartType definition = element.alias.unalias(resolution);
     return definition.substByContext(this);
   }
 
@@ -811,7 +813,7 @@
         message: 'Alias must be non-null on $element.'));
   }
 
-  FunctionType unalias(Compiler compiler) => alias;
+  FunctionType unalias(Resolution resolution) => alias;
 }
 
 /**
@@ -828,7 +830,7 @@
 
   TypeKind get kind => TypeKind.DYNAMIC;
 
-  DartType unalias(Compiler compiler) => this;
+  DartType unalias(Resolution resolution) => this;
 
   DartType subst(List<DartType> arguments, List<DartType> parameters) => this;
 
@@ -949,6 +951,7 @@
     extends BaseDartTypeVisitor<bool, DartType> {
   final Compiler compiler;
   CoreTypes get coreTypes => compiler.coreTypes;
+  Resolution get resolution => compiler.resolution;
 
   AbstractTypeRelation(this.compiler);
 
@@ -977,7 +980,7 @@
 
     // TODO(johnniwinther): Currently needed since literal types like int,
     // double, bool etc. might not have been resolved yet.
-    t.element.ensureResolved(compiler);
+    t.element.ensureResolved(resolution);
 
     bool checkTypeArguments(InterfaceType instance, InterfaceType other) {
       List<DartType> tTypeArgs = instance.typeArguments;
@@ -1142,8 +1145,8 @@
     if (s == coreTypes.objectType) {
       return true;
     }
-    t = t.unalias(compiler);
-    s = s.unalias(compiler);
+    t = t.unalias(resolution);
+    s = s.unalias(resolution);
 
     return t.accept(this, s);
   }
@@ -1242,6 +1245,10 @@
 
   CoreTypes get coreTypes => compiler.coreTypes;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
+  Resolution get resolution => compiler.resolution;
+
   Types(Compiler compiler)
       : this.compiler = compiler,
         this.moreSpecificVisitor = new MoreSpecificVisitor(compiler),
@@ -1541,7 +1548,7 @@
       }
     }
 
-    compiler.internalError(CURRENT_ELEMENT_SPANNABLE,
+    reporter.internalError(CURRENT_ELEMENT_SPANNABLE,
         'No least upper bound computed for $a and $b.');
     return null;
   }
@@ -1642,8 +1649,8 @@
       return computeLeastUpperBoundTypeVariableTypes(a, b);
     }
 
-    a = a.unalias(compiler);
-    b = b.unalias(compiler);
+    a = a.unalias(resolution);
+    b = b.unalias(resolution);
 
     if (a.treatAsDynamic || b.treatAsDynamic) return const DynamicType();
     if (a.isVoid || b.isVoid) return const VoidType();
@@ -1704,7 +1711,7 @@
     if (type.isMalformed) {
       return const DynamicType();
     }
-    return type.unalias(compiler);
+    return type.unalias(compiler.resolution);
   }
 
   /// Computes the interface type of [type], which is the type that defines
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 9615406..d0f3120 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -6,6 +6,8 @@
 
 import 'common/backend_api.dart' show
     Backend;
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/tasks.dart' show
     CompilerTask;
 import 'compiler.dart' show
@@ -201,7 +203,7 @@
     String name =
         _importDeferName[new _DeclaredDeferredImport(prefix.deferredImport)];
     if (name == null) {
-      compiler.internalError(node, "No deferred name for $prefix.");
+      reporter.internalError(node, "No deferred name for $prefix.");
     }
     return name;
   }
@@ -283,7 +285,7 @@
         collectTypeDependencies(type.returnType);
       } else if (type is TypedefType) {
         elements.add(type.element);
-        collectTypeDependencies(type.unalias(compiler));
+        collectTypeDependencies(type.unalias(compiler.resolution));
       } else if (type is InterfaceType) {
         elements.add(type.element);
       }
@@ -302,7 +304,7 @@
       // TODO(sigurdm): We want to be more specific about this - need a better
       // way to query "liveness".
       if (astElement is! TypedefElement &&
-          !compiler.enqueuer.resolution.hasBeenResolved(astElement)) {
+          !compiler.enqueuer.resolution.hasBeenProcessed(astElement)) {
         return;
       }
 
@@ -354,7 +356,7 @@
       // to.  Static members are not relevant, unless we are processing
       // extra dependencies due to mirrors.
       void addLiveInstanceMember(Element element) {
-        if (!compiler.enqueuer.resolution.hasBeenResolved(element)) return;
+        if (!compiler.enqueuer.resolution.hasBeenProcessed(element)) return;
         if (!isMirrorUsage && !element.isInstanceMember) return;
         collectDependencies(element.implementation);
       }
@@ -714,7 +716,7 @@
     Map<String, ImportElement> prefixDeferredImport =
         new Map<String, ImportElement>();
     for (LibraryElement library in compiler.libraryLoader.libraries) {
-      compiler.withCurrentElement(library, () {
+      reporter.withCurrentElement(library, () {
         prefixDeferredImport.clear();
         usedPrefixes.clear();
         // TODO(sigurdm): Make helper getLibraryImportTags when tags is a List
@@ -724,12 +726,12 @@
           List<MetadataAnnotation> metadataList = import.metadata;
           if (metadataList != null) {
             for (MetadataAnnotation metadata in metadataList) {
-              metadata.ensureResolved(compiler);
+              metadata.ensureResolved(compiler.resolution);
               ConstantValue value =
                   compiler.constants.getConstantValue(metadata.constant);
               Element element = value.getType(compiler.coreTypes).element;
               if (element == deferredLibraryClass) {
-                 compiler.reportErrorMessage(
+                 reporter.reportErrorMessage(
                      import, MessageKind.DEFERRED_OLD_SYNTAX);
               }
             }
@@ -746,7 +748,7 @@
             _allDeferredImports[key] = importedLibrary;
 
             if (prefix == null) {
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   import,
                   MessageKind.DEFERRED_LIBRARY_WITHOUT_PREFIX);
             } else {
@@ -763,7 +765,7 @@
               ImportElement failingImport = (previousDeferredImport != null)
                   ? previousDeferredImport
                   : import;
-              compiler.reportErrorMessage(
+              reporter.reportErrorMessage(
                   failingImport.prefix,
                   MessageKind.DEFERRED_LIBRARY_DUPLICATE_PREFIX);
             }
@@ -922,7 +924,7 @@
       List<MetadataAnnotation> metadatas = declaration.metadata;
       assert(metadatas != null);
       for (MetadataAnnotation metadata in metadatas) {
-        metadata.ensureResolved(compiler);
+        metadata.ensureResolved(compiler.resolution);
         ConstantValue value =
             compiler.constants.getConstantValue(metadata.constant);
         Element element = value.getType(compiler.coreTypes).element;
diff --git a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
index e2e4d1a..7d624b2 100644
--- a/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
+++ b/pkg/compiler/lib/src/diagnostics/diagnostic_listener.dart
@@ -12,8 +12,35 @@
     Element;
 import 'messages.dart';
 
+class DiagnosticOptions {
+
+  /// Emit terse diagnostics without howToFix.
+  final bool terseDiagnostics;
+
+  /// If `true`, warnings and hints not from user code are reported.
+  final bool showPackageWarnings;
+
+  /// If `true`, warnings are not reported.
+  final bool suppressWarnings;
+
+  /// If `true`, warnings cause the compilation to fail.
+  final bool fatalWarnings;
+
+  /// If `true`, hints are not reported.
+  final bool suppressHints;
+
+  const DiagnosticOptions({
+    this.suppressWarnings: false,
+    this.fatalWarnings: false,
+    this.suppressHints: false,
+    this.terseDiagnostics: false,
+    this.showPackageWarnings: false});
+}
+
 // TODO(johnniwinther): Rename and cleanup this interface. Add severity enum.
-abstract class DiagnosticListener {
+abstract class DiagnosticReporter {
+  DiagnosticOptions get options => const DiagnosticOptions();
+
   // TODO(karlklose): rename log to something like reportInfo.
   void log(message);
 
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index 33a6ba3..347b25b 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -3352,7 +3352,11 @@
       MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND:
         const MessageTemplate(
           MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND,
-          "dart:mirrors library is not supported when using this backend."),
+          """
+dart:mirrors library is not supported when using this backend.
+
+Your app imports dart:mirrors via:""""""
+$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
 
       MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS:
         const MessageTemplate(MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
@@ -3393,6 +3397,10 @@
   static const String IMPORT_EXPERIMENTAL_MIRRORS_PADDING = '\n*   ';
 
   /// Padding used before and between import chains in the message for
+  /// [MessageKind.MIRRORS_LIBRARY_NOT_SUPPORT_BY_BACKEND].
+  static const String MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING = '\n   ';
+
+  /// Padding used before and between import chains in the message for
   /// [MessageKind.DISALLOWED_LIBRARY_IMPORT].
   static const String DISALLOWED_LIBRARY_IMPORT_PADDING = '\n  ';
 
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 88d1be1..e9d7c05 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -31,6 +31,7 @@
 import 'js/js.dart' as jsAst;
 import 'universe/universe.dart' show
     UniverseSelector;
+import 'info/send_info.dart' show collectSendMeasurements;
 
 class ElementInfoCollector extends BaseElementVisitor<Info, dynamic> {
   final Compiler compiler;
@@ -226,6 +227,8 @@
 
   FunctionInfo visitFunctionElement(FunctionElement element, _) {
     int size = compiler.dumpInfoTask.sizeOf(element);
+    // TODO(sigmund): consider adding a small info to represent unreachable
+    // code here.
     if (size == 0 && !shouldKeep(element)) return null;
 
     String name = element.name;
@@ -317,6 +320,9 @@
     }
     info.closures = nestedClosures;
     result.functions.add(info);
+    if (const bool.fromEnvironment('send_stats')) {
+      info.measurements = collectSendMeasurements(element, compiler);
+    }
     return info;
   }
 
@@ -486,16 +492,9 @@
     return sb.toString();
   }
 
-  void collectInfo() {
-    infoCollector = new ElementInfoCollector(compiler)..run();
-  }
-
   void dumpInfo() {
     measure(() {
-      if (infoCollector == null) {
-        collectInfo();
-      }
-
+      infoCollector = new ElementInfoCollector(compiler)..run();
       StringBuffer jsonBuffer = new StringBuffer();
       dumpInfoJson(jsonBuffer);
       compiler.outputProvider('', 'info.json')
@@ -561,7 +560,7 @@
     ChunkedConversionSink<Object> sink = encoder.startChunkedConversion(
         new StringConversionSink.fromStringSink(buffer));
     sink.add(result.toJson());
-    compiler.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
+    reporter.reportInfo(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
       'text': "View the dumped .info.json file at "
           "https://dart-lang.github.io/dump-info-visualizer"
     });
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index d3e5d5d..d10bf45 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -4,6 +4,8 @@
 
 library elements;
 
+import '../common/resolution.dart' show
+    Resolution;
 import '../compiler.dart' show
     Compiler;
 import '../constants/constructors.dart';
@@ -425,7 +427,7 @@
 
   /// Unwraps [element] reporting any warnings attached to it, if any.
   static Element unwrap(Element element,
-                        DiagnosticListener listener,
+                        DiagnosticReporter listener,
                         Spannable spannable) {
     if (element != null && element.isWarnOnUse) {
       WarnOnUseElement wrappedElement = element;
@@ -804,7 +806,7 @@
   /// Reports the attached warning and returns the wrapped element.
   /// [usageSpannable] is used to report messages on the reference of
   /// [wrappedElement].
-  Element unwrap(DiagnosticListener listener, Spannable usageSpannable);
+  Element unwrap(DiagnosticReporter listener, Spannable usageSpannable);
 }
 
 /// An ambiguous element represents multiple elements accessible by the same
@@ -821,7 +823,7 @@
 
   /// Compute the info messages associated with an error/warning on [context].
   List<DiagnosticMessage> computeInfos(
-      Element context, DiagnosticListener listener);
+      Element context, DiagnosticReporter listener);
 }
 
 // TODO(kasperl): This probably shouldn't be called an element. It's
@@ -967,7 +969,7 @@
   /// For instance `(int)->void` for `typedef void F(int)`.
   DartType get alias;
 
-  void checkCyclicReference(Compiler compiler);
+  void checkCyclicReference(Resolution resolution);
 }
 
 /// An executable element is an element that can hold code.
@@ -1315,7 +1317,7 @@
   /// error and calling [computeType] covers that error.
   /// This method will go away!
   @deprecated
-  GenericType computeType(Compiler compiler);
+  GenericType computeType(Resolution resolution);
 
   /**
    * The `this type` for this type declaration.
@@ -1355,7 +1357,7 @@
 
   bool get isResolved;
 
-  void ensureResolved(Compiler compiler);
+  void ensureResolved(Resolution resolution);
 }
 
 abstract class ClassElement extends TypeDeclarationElement
@@ -1570,7 +1572,7 @@
   bool get hasNode;
   Node get node;
 
-  MetadataAnnotation ensureResolved(Compiler compiler);
+  MetadataAnnotation ensureResolved(Resolution resolution);
 }
 
 /// An [Element] that has a type.
@@ -1582,7 +1584,7 @@
   /// error and calling [computeType] covers that error.
   /// This method will go away!
   @deprecated
-  DartType computeType(Compiler compiler);
+  DartType computeType(Resolution resolution);
 
   DartType get type;
 }
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index c576f8d..488c7e1 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -4,6 +4,9 @@
 
 library elements.modelx;
 
+import '../common/resolution.dart' show
+    Resolution,
+    Parsing;
 import '../compiler.dart' show
     Compiler;
 import '../constants/constant_constructors.dart';
@@ -67,8 +70,8 @@
 
   Modifiers get modifiers => Modifiers.EMPTY;
 
-  Node parseNode(DiagnosticListener listener) {
-    listener.internalError(this,
+  Node parseNode(Parsing parsing) {
+    parsing.reporter.internalError(this,
         'parseNode not implemented on $this.');
     return null;
   }
@@ -312,8 +315,7 @@
   bool get isRedirectingGenerative => unsupported();
   bool get isRedirectingFactory => unsupported();
 
-  computeSignature(compiler) => unsupported();
-  computeType(compiler) => unsupported();
+  computeType(Resolution resolution) => unsupported();
 
   bool get hasFunctionSignature => false;
 
@@ -393,6 +395,10 @@
     throw new UnsupportedError("effectiveTargetType=");
   }
 
+  void _computeSignature(Resolution resolution) {
+    throw new UnsupportedError("_computeSignature");
+  }
+
   get typeCache {
     throw new UnsupportedError("typeCache");
   }
@@ -409,14 +415,18 @@
     throw new UnsupportedError("immediateRedirectionTarget=");
   }
 
-  get functionSignatureCache {
+  get _functionSignatureCache {
     throw new UnsupportedError("functionSignatureCache");
   }
 
-  set functionSignatureCache(_) {
+  set _functionSignatureCache(_) {
     throw new UnsupportedError("functionSignatureCache=");
   }
 
+  set functionSignature(_) {
+    throw new UnsupportedError("functionSignature=");
+  }
+
   get nestedClosures {
     throw new UnsupportedError("nestedClosures");
   }
@@ -468,24 +478,24 @@
       : this.wrappedElement = wrappedElement,
         super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
 
-  Element unwrap(DiagnosticListener listener, Spannable usageSpannable) {
+  Element unwrap(DiagnosticReporter reporter, Spannable usageSpannable) {
     var unwrapped = wrappedElement;
     if (warning != null) {
       Spannable spannable = warning.spannable;
       if (spannable == null) spannable = usageSpannable;
-      DiagnosticMessage warningMessage = listener.createMessage(
+      DiagnosticMessage warningMessage = reporter.createMessage(
           spannable, warning.messageKind, warning.messageArguments);
       List<DiagnosticMessage> infos = <DiagnosticMessage>[];
       if (info != null) {
         Spannable spannable = info.spannable;
         if (spannable == null) spannable = usageSpannable;
-        infos.add(listener.createMessage(
+        infos.add(reporter.createMessage(
             spannable, info.messageKind, info.messageArguments));
       }
-      listener.reportWarning(warningMessage, infos);
+      reporter.reportWarning(warningMessage, infos);
     }
     if (unwrapped.isWarnOnUse) {
-      unwrapped = unwrapped.unwrap(listener, usageSpannable);
+      unwrapped = unwrapped.unwrap(reporter, usageSpannable);
     }
     return unwrapped;
   }
@@ -535,7 +545,7 @@
   }
 
   List<DiagnosticMessage> computeInfos(Element context,
-                                   DiagnosticListener listener) {
+                                       DiagnosticReporter reporter) {
     return const <DiagnosticMessage>[];
   }
 
@@ -559,7 +569,7 @@
 
   List<DiagnosticMessage> computeInfos(
       Element context,
-      DiagnosticListener listener) {
+      DiagnosticReporter reporter) {
     List<DiagnosticMessage> infos = <DiagnosticMessage>[];
     Setlet ambiguousElements = flatten();
     MessageKind code = (ambiguousElements.length == 1)
@@ -567,10 +577,10 @@
     LibraryElementX importer = context.library;
     for (Element element in ambiguousElements) {
       Map arguments = {'name': element.name};
-      infos.add(listener.createMessage(element, code, arguments));
-      listener.withCurrentElement(importer, () {
+      infos.add(reporter.createMessage(element, code, arguments));
+      reporter.withCurrentElement(importer, () {
         for (ImportElement import in importer.importers.getImports(element)) {
-          infos.add(listener.createMessage(
+          infos.add(reporter.createMessage(
               import, MessageKind.IMPORTED_HERE, arguments));
         }
       });
@@ -601,20 +611,20 @@
     return contents[name];
   }
 
-  void add(Element element, DiagnosticListener listener) {
+  void add(Element element, DiagnosticReporter reporter) {
     String name = element.name;
     if (element.isAccessor) {
-      addAccessor(element, contents[name], listener);
+      addAccessor(element, contents[name], reporter);
     } else {
       Element existing = contents.putIfAbsent(name, () => element);
       if (!identical(existing, element)) {
-        listener.reportError(
-            listener.createMessage(
+        reporter.reportError(
+            reporter.createMessage(
                 element,
                 MessageKind.DUPLICATE_DEFINITION,
                 {'name': name}),
             <DiagnosticMessage>[
-                listener.createMessage(
+                reporter.createMessage(
                     existing,
                     MessageKind.EXISTING_DEFINITION,
                     {'name': name}),
@@ -638,15 +648,15 @@
    */
   void addAccessor(AccessorElementX accessor,
                    Element existing,
-                   DiagnosticListener listener) {
+                   DiagnosticReporter reporter) {
     void reportError(Element other) {
-      listener.reportError(
-          listener.createMessage(
+      reporter.reportError(
+          reporter.createMessage(
               accessor,
               MessageKind.DUPLICATE_DEFINITION,
               {'name': accessor.name}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   other,
                   MessageKind.EXISTING_DEFINITION,
                   {'name': accessor.name}),
@@ -689,7 +699,7 @@
       } else {
         field.setter = accessor;
       }
-      add(field, listener);
+      add(field, reporter);
     }
   }
 }
@@ -729,32 +739,32 @@
     localMembers.forEach(f);
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     // Keep a list of top level members.
     localMembers = localMembers.prepend(element);
     // Provide the member to the library to build scope.
     if (enclosingElement.isPatch) {
-      implementationLibrary.addMember(element, listener);
+      implementationLibrary.addMember(element, reporter);
     } else {
-      library.addMember(element, listener);
+      library.addMember(element, reporter);
     }
   }
 
-  void setPartOf(PartOf tag, DiagnosticListener listener) {
+  void setPartOf(PartOf tag, DiagnosticReporter reporter) {
     LibraryElementX library = enclosingElement;
     if (library.entryCompilationUnit == this) {
       partTag = tag;
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           tag, MessageKind.IMPORT_PART_OF);
       return;
     }
     if (!localMembers.isEmpty) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           tag, MessageKind.BEFORE_TOP_LEVEL);
       return;
     }
     if (partTag != null) {
-      listener.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
+      reporter.reportWarningMessage(tag, MessageKind.DUPLICATED_PART_OF);
       return;
     }
     partTag = tag;
@@ -763,19 +773,19 @@
     if (libraryTag != null) {
       String expectedName = libraryTag.name.toString();
       if (expectedName != actualName) {
-        listener.reportWarningMessage(
+        reporter.reportWarningMessage(
             tag.name,
             MessageKind.LIBRARY_NAME_MISMATCH,
             {'libraryName': expectedName});
       }
     } else {
-      listener.reportWarning(
-          listener.createMessage(
+      reporter.reportWarning(
+          reporter.createMessage(
               library,
               MessageKind.MISSING_LIBRARY_NAME,
               {'libraryName': actualName}),
           <DiagnosticMessage>[
-              listener.createMessage(
+              reporter.createMessage(
                   tag.name,
                   MessageKind.THIS_IS_THE_PART_OF_TAG),
           ]);
@@ -834,7 +844,7 @@
   void addImport(Element enclosingElement,
                  Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
+                 DiagnosticReporter reporter) {
     LibraryElementX library = enclosingElement.library;
     Importers importers = library.importers;
 
@@ -860,7 +870,7 @@
               messageKind,
               {'name': name, 'hiddenUri': hiddenUri, 'hidingUri': hidingUri}),
           new WrappedMessage(
-              listener.spanFromSpannable(import),
+              reporter.spanFromSpannable(import),
               MessageKind.IMPORTED_HERE,
               {'name': name}),
           enclosingElement, hidingElement);
@@ -1062,9 +1072,9 @@
     compilationUnits = compilationUnits.prepend(element);
   }
 
-  void addTag(LibraryTag tag, DiagnosticListener listener) {
+  void addTag(LibraryTag tag, DiagnosticReporter reporter) {
     if (tagsCache != null) {
-      listener.internalError(tag,
+      reporter.internalError(tag,
           "Library tags for $this have already been computed.");
     }
     tagsBuilder.addLast(tag);
@@ -1099,17 +1109,17 @@
    */
   void addImport(Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
-    importScope.addImport(this, element, import, listener);
+                 DiagnosticReporter reporter) {
+    importScope.addImport(this, element, import, reporter);
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     localMembers = localMembers.prepend(element);
-    addToScope(element, listener);
+    addToScope(element, reporter);
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
-    localScope.add(element, listener);
+  void addToScope(Element element, DiagnosticReporter reporter) {
+    localScope.add(element, reporter);
   }
 
   Element localLookup(String elementName) {
@@ -1281,14 +1291,14 @@
 
   Element lookupLocalMember(String memberName) => importScope[memberName];
 
-  DartType computeType(Compiler compiler) => const DynamicType();
+  DartType computeType(Resolution resolution) => const DynamicType();
 
   Token get position => firstPosition;
 
   void addImport(Element element,
                  ImportElement import,
-                 DiagnosticListener listener) {
-    importScope.addImport(this, element, import, listener);
+                 DiagnosticReporter reporter) {
+    importScope.addImport(this, element, import, reporter);
   }
 
   accept(ElementVisitor visitor, arg) {
@@ -1336,17 +1346,17 @@
    */
   FunctionSignature functionSignature;
 
-  TypedefType computeType(Compiler compiler) {
+  TypedefType computeType(Resolution resolution) {
     if (thisTypeCache != null) return thisTypeCache;
-    Typedef node = parseNode(compiler);
-    setThisAndRawTypes(compiler, createTypeVariables(node.typeParameters));
-    ensureResolved(compiler);
+    Typedef node = parseNode(resolution.parsing);
+    setThisAndRawTypes(createTypeVariables(node.typeParameters));
+    ensureResolved(resolution);
     return thisTypeCache;
   }
 
-  void ensureResolved(Compiler compiler) {
+  void ensureResolved(Resolution resolution) {
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolve(this);
+      resolution.resolveTypedef(this);
     }
   }
 
@@ -1358,10 +1368,11 @@
     return new TypeDeclarationScope(enclosingElement.buildScope(), this);
   }
 
-  void checkCyclicReference(Compiler compiler) {
+  void checkCyclicReference(Resolution resolution) {
     if (hasBeenCheckedForCycles) return;
-    var visitor = new TypedefCyclicVisitor(compiler, this);
-    computeType(compiler).accept(visitor, null);
+    TypedefCyclicVisitor visitor =
+        new TypedefCyclicVisitor(resolution.reporter, this);
+    computeType(resolution).accept(visitor, null);
     hasBeenCheckedForCycles = true;
   }
 
@@ -1409,11 +1420,11 @@
     metadataInternal = metadata;
   }
 
-  VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
+  VariableDefinitions parseNode(Element element, Parsing parsing) {
     return definitions;
   }
 
-  DartType computeType(Element element, Compiler compiler) => type;
+  DartType computeType(Element element, Resolution resolution) => type;
 }
 
 abstract class ConstantVariableMixin implements VariableElement {
@@ -1492,10 +1503,10 @@
     return initializerCache;
   }
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     if (definitionsCache != null) return definitionsCache;
 
-    VariableDefinitions definitions = variables.parseNode(this, listener);
+    VariableDefinitions definitions = variables.parseNode(this, parsing);
     createDefinitions(definitions);
     return definitionsCache;
   }
@@ -1535,14 +1546,12 @@
     }
   }
 
-  DartType computeType(Compiler compiler) {
+  DartType computeType(Resolution resolution) {
     if (variables.type != null) return variables.type;
     // Call [parseNode] to ensure that [definitionsCache] and [initializerCache]
     // are set as a consequence of calling [computeType].
-    return compiler.withCurrentElement(this, () {
-      parseNode(compiler);
-      return variables.computeType(this, compiler);
-    });
+    parseNode(resolution.parsing);
+    return variables.computeType(this, resolution);
   }
 
   DartType get type {
@@ -1683,7 +1692,7 @@
     throw new UnsupportedError("copyWithEnclosing");
   }
 
-  DartType computeType(Compiler compiler) => type;
+  DartType computeType(Resolution resolution) => type;
 }
 
 /// [Element] for a parameter-like element.
@@ -1699,7 +1708,7 @@
    * kept to provide full information about parameter names through the mirror
    * system.
    */
-  FunctionSignature functionSignatureCache;
+  FunctionSignature _functionSignatureCache;
 
   FormalElementX(ElementKind elementKind,
                  FunctionTypedElement enclosingElement,
@@ -1714,9 +1723,9 @@
 
   Token get position => identifier.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => definitions;
+  Node parseNode(Parsing parsing) => definitions;
 
-  DartType computeType(Compiler compiler) {
+  DartType computeType(Resolution resolution) {
     assert(invariant(this, type != null,
         message: "Parameter type has not been set for $this."));
     return type;
@@ -1729,9 +1738,16 @@
   }
 
   FunctionSignature get functionSignature {
-    assert(invariant(this, typeCache != null,
-            message: "Parameter signature has not been set for $this."));
-    return functionSignatureCache;
+    assert(invariant(this, _functionSignatureCache != null,
+        message: "Parameter signature has not been computed for $this."));
+    return _functionSignatureCache;
+  }
+
+  void set functionSignature(FunctionSignature value) {
+    assert(invariant(this, _functionSignatureCache == null,
+        message: "Parameter signature has already been computed for $this."));
+    _functionSignatureCache = value;
+    typeCache = _functionSignatureCache.type;
   }
 
   bool get hasNode => true;
@@ -1869,7 +1885,7 @@
     throw "internal error: AbstractFieldElement has no type";
   }
 
-  Node parseNode(DiagnosticListener listener) {
+  Node parseNode(Parsing parsing) {
     throw "internal error: AbstractFieldElement has no node";
   }
 
@@ -1951,7 +1967,7 @@
 
   List<FunctionElement> nestedClosures = new List<FunctionElement>();
 
-  FunctionSignature functionSignatureCache;
+  FunctionSignature _functionSignatureCache;
 
   AsyncMarker asyncMarker = AsyncMarker.SYNC;
 
@@ -1971,20 +1987,26 @@
            && !isStatic;
   }
 
-  bool get hasFunctionSignature => functionSignatureCache != null;
+  bool get hasFunctionSignature => _functionSignatureCache != null;
 
-  FunctionSignature computeSignature(Compiler compiler) {
-    if (functionSignatureCache != null) return functionSignatureCache;
-    compiler.withCurrentElement(this, () {
-      functionSignatureCache = compiler.resolver.resolveSignature(this);
-    });
-    return functionSignatureCache;
+  void _computeSignature(Resolution resolution) {
+    if (hasFunctionSignature) return;
+    functionSignature = resolution.resolveSignature(this);
   }
 
   FunctionSignature get functionSignature {
-    assert(invariant(this, functionSignatureCache != null,
+    assert(invariant(this, hasFunctionSignature,
         message: "Function signature has not been computed for $this."));
-    return functionSignatureCache;
+    return _functionSignatureCache;
+  }
+
+  void set functionSignature(FunctionSignature value) {
+    // TODO(johnniwinther): Strengthen the invariant to `!hasFunctionSignature`
+    // when checked mode checks are not enqueued eagerly.
+    assert(invariant(this, !hasFunctionSignature || type == value.type,
+        message: "Function signature has already been computed for $this."));
+    _functionSignatureCache = value;
+    typeCache = _functionSignatureCache.type;
   }
 
   List<ParameterElement> get parameters {
@@ -1995,9 +2017,11 @@
     return list;
   }
 
-  FunctionType computeType(Compiler compiler) {
+  FunctionType computeType(Resolution resolution) {
     if (typeCache != null) return typeCache;
-    typeCache = computeSignature(compiler).type;
+    _computeSignature(resolution);
+    assert(invariant(this, typeCache != null,
+        message: "Type cache expected to be set on $this."));
     return typeCache;
   }
 
@@ -2043,7 +2067,7 @@
   void reuseElement() {
     super.reuseElement();
     nestedClosures.clear();
-    functionSignatureCache = null;
+    _functionSignatureCache = null;
     typeCache = null;
   }
 }
@@ -2114,7 +2138,7 @@
 
   bool get hasNode => true;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 
   Token get position {
     // Use the name as position if this is not an unnamed closure.
@@ -2233,15 +2257,8 @@
         super("loadLibrary",
               Modifiers.EMPTY,
               prefix,
-              false);
-
-  FunctionSignature computeSignature(Compiler compiler) {
-    if (functionSignatureCache != null) return functionSignature;
-    compiler.withCurrentElement(this, () {
-      DartType inner = new FunctionType(this);
-      functionSignatureCache = new FunctionSignatureX(type: inner);
-    });
-    return functionSignatureCache;
+              false) {
+    functionSignature = new FunctionSignatureX(type: new FunctionType(this));
   }
 
   bool get isClassMember => false;
@@ -2255,7 +2272,7 @@
   // error messages.
   Token get position => null;
 
-  FunctionExpression parseNode(DiagnosticListener listener) => null;
+  FunctionExpression parseNode(Parsing parsing) => null;
 
   bool get hasNode => false;
 
@@ -2275,7 +2292,7 @@
               ElementKind.GENERATIVE_CONSTRUCTOR_BODY,
               Modifiers.EMPTY,
               constructor.enclosingElement) {
-    functionSignatureCache = constructor.functionSignature;
+    functionSignature = constructor.functionSignature;
   }
 
   bool get hasNode => constructor.hasNode;
@@ -2286,8 +2303,9 @@
 
   bool get isInstanceMember => true;
 
-  FunctionType computeType(Compiler compiler) {
-    compiler.internalError(this, '$this.computeType.');
+  FunctionType computeType(Resolution resolution) {
+    DiagnosticReporter reporter = resolution.reporter;
+    reporter.internalError(this, '$this.computeType.');
     return null;
   }
 
@@ -2331,11 +2349,11 @@
               ElementKind.GENERATIVE_CONSTRUCTOR,
               Modifiers.EMPTY,
               enclosing) {
-    typeCache = new FunctionType.synthesized(enclosingClass.thisType);
-    functionSignatureCache = new FunctionSignatureX(type: type);
+    functionSignature = new FunctionSignatureX(
+        type: new FunctionType.synthesized(enclosingClass.thisType));
   }
 
-  FunctionExpression parseNode(DiagnosticListener listener) => null;
+  FunctionExpression parseNode(Parsing parsing) => null;
 
   bool get hasNode => false;
 
@@ -2355,18 +2373,16 @@
     }
   }
 
-  FunctionSignature computeSignature(compiler) {
-    if (functionSignatureCache != null) return functionSignatureCache;
+  void _computeSignature(Resolution resolution) {
+    if (hasFunctionSignature) return;
     if (definingConstructor.isErroneous) {
-      return functionSignatureCache =
-          compiler.objectClass.localLookup('').computeSignature(compiler);
+      functionSignature = new FunctionSignatureX(
+          type: new FunctionType.synthesized(enclosingClass.thisType));
     }
     // TODO(johnniwinther): Ensure that the function signature (and with it the
     // function type) substitutes type variables correctly.
-    definingConstructor.computeType(compiler);
-    functionSignatureCache = definingConstructor.functionSignature;
-    typeCache = definingConstructor.type;
-    return functionSignatureCache;
+    definingConstructor.computeType(resolution);
+    functionSignature = definingConstructor.functionSignature;
   }
 
   accept(ElementVisitor visitor, arg) {
@@ -2423,7 +2439,7 @@
 
   T createType(List<DartType> typeArguments);
 
-  void setThisAndRawTypes(Compiler compiler, List<DartType> typeParameters) {
+  void setThisAndRawTypes(List<DartType> typeParameters) {
     assert(invariant(this, thisTypeCache == null,
         message: "This type has already been set on $this."));
     assert(invariant(this, rawTypeCache == null,
@@ -2510,23 +2526,25 @@
   @override
   bool get isEnumClass => false;
 
-  InterfaceType computeType(Compiler compiler) {
+  InterfaceType computeType(Resolution resolution) {
     if (isPatch) {
-      origin.computeType(compiler);
+      origin.computeType(resolution);
       thisTypeCache = origin.thisType;
       rawTypeCache = origin.rawType;
     } else if (thisTypeCache == null) {
-      computeThisAndRawType(compiler, computeTypeParameters(compiler));
+      computeThisAndRawType(
+          resolution, computeTypeParameters(resolution.parsing));
     }
     return thisTypeCache;
   }
 
-  void computeThisAndRawType(Compiler compiler, List<DartType> typeVariables) {
+  void computeThisAndRawType(Resolution resolution,
+                             List<DartType> typeVariables) {
     if (thisTypeCache == null) {
       if (origin == null) {
-        setThisAndRawTypes(compiler, typeVariables);
+        setThisAndRawTypes(typeVariables);
       } else {
-        thisTypeCache = origin.computeType(compiler);
+        thisTypeCache = origin.computeType(resolution);
         rawTypeCache = origin.rawType;
       }
     }
@@ -2537,7 +2555,7 @@
     return new InterfaceType(this, typeArguments);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler);
+  List<DartType> computeTypeParameters(Parsing parsing);
 
   bool get isObject {
     assert(invariant(this, isResolved,
@@ -2545,14 +2563,15 @@
     return supertype == null;
   }
 
-  void ensureResolved(Compiler compiler) {
+  void ensureResolved(Resolution resolution) {
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolveClass(this);
-      compiler.world.registerClass(this);
+      resolution.resolveClass(this);
+      resolution.registerClass(this);
     }
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler);
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter);
 
   void addBackendMember(Element member) {
     // TODO(ngeoffray): Deprecate this method.
@@ -2593,7 +2612,8 @@
    * The returned element may not be resolved yet.
    */
   ClassElement get superclass {
-    assert(supertypeLoadState == STATE_DONE);
+    assert(invariant(this, supertypeLoadState == STATE_DONE,
+        message: "Superclass has not been computed for $this."));
     return supertype == null ? null : supertype.element;
   }
 
@@ -2645,18 +2665,18 @@
   bool get isMixinApplication => false;
   bool get hasLocalScopeMembers => !localScope.isEmpty;
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     localMembersCache = null;
     localMembersReversed = localMembersReversed.prepend(element);
-    addToScope(element, listener);
+    addToScope(element, reporter);
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
+  void addToScope(Element element, DiagnosticReporter reporter) {
     if (element.isField && element.name == name) {
-      listener.reportErrorMessage(
+      reporter.reportErrorMessage(
           element, MessageKind.MEMBER_USES_CLASS_NAME);
     }
-    localScope.add(element, listener);
+    localScope.add(element, reporter);
   }
 
   Element localLookup(String elementName) {
@@ -2679,13 +2699,14 @@
     return false;
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter) {
     // The default constructor, although synthetic, is part of a class' API.
-    addMember(constructor, compiler);
+    addMember(constructor, reporter);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) {
-    ClassNode node = parseNode(compiler);
+  List<DartType> computeTypeParameters(Parsing parsing) {
+    ClassNode node = parseNode(parsing);
     return createTypeVariables(node.typeParameters);
   }
 
@@ -2719,14 +2740,14 @@
   bool get isEnumClass => true;
 
   @override
-  Node parseNode(Compiler compiler) => node;
+  Node parseNode(Parsing parsing) => node;
 
   @override
   accept(ElementVisitor visitor, arg) {
     return visitor.visitEnumClassElement(this, arg);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) => const <DartType>[];
+  List<DartType> computeTypeParameters(Parsing parsing) => const <DartType>[];
 
   List<FieldElement> get enumValues {
     assert(invariant(this, _enumValues != null,
@@ -2756,7 +2777,7 @@
   bool get hasNode => true;
 
   @override
-  FunctionExpression parseNode(Compiler compiler) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 }
 
 class EnumMethodElementX extends MethodElementX {
@@ -2772,7 +2793,7 @@
   bool get hasNode => true;
 
   @override
-  FunctionExpression parseNode(Compiler compiler) => node;
+  FunctionExpression parseNode(Parsing parsing) => node;
 }
 
 class EnumFormalElementX extends InitializingFormalElementX {
@@ -2826,7 +2847,7 @@
 
   Token get position => node.getBeginToken();
 
-  Node parseNode(DiagnosticListener listener) => node;
+  Node parseNode(Parsing parsing) => node;
 
   FunctionElement lookupLocalConstructor(String name) {
     for (Link<Element> link = constructors;
@@ -2853,24 +2874,25 @@
     });
   }
 
-  void addMember(Element element, DiagnosticListener listener) {
+  void addMember(Element element, DiagnosticReporter reporter) {
     throw new UnsupportedError("Cannot add member to $this.");
   }
 
-  void addToScope(Element element, DiagnosticListener listener) {
-    listener.internalError(this, 'Cannot add to scope of $this.');
+  void addToScope(Element element, DiagnosticReporter reporter) {
+    reporter.internalError(this, 'Cannot add to scope of $this.');
   }
 
   void addConstructor(FunctionElement constructor) {
     constructors = constructors.prepend(constructor);
   }
 
-  void setDefaultConstructor(FunctionElement constructor, Compiler compiler) {
+  void setDefaultConstructor(FunctionElement constructor,
+                             DiagnosticReporter reporter) {
     assert(!hasConstructor);
     addConstructor(constructor);
   }
 
-  List<DartType> computeTypeParameters(Compiler compiler) {
+  List<DartType> computeTypeParameters(Parsing parsing) {
     NamedMixinApplication named = node.asNamedMixinApplication();
     if (named == null) {
       throw new SpannableAssertionFailure(node,
@@ -2955,7 +2977,7 @@
 
   TypeDeclarationElement get typeDeclaration => enclosingElement;
 
-  TypeVariableType computeType(compiler) => type;
+  TypeVariableType computeType(Resolution resolution) => type;
 
   TypeVariableType get type {
     assert(invariant(this, typeCache != null,
@@ -2971,7 +2993,7 @@
 
   bool get hasNode => true;
 
-  Node parseNode(compiler) => node;
+  Node parseNode(Parsing parsing) => node;
 
   Token get position => node.getBeginToken();
 
@@ -3023,18 +3045,18 @@
 
   MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);
 
-  MetadataAnnotation ensureResolved(Compiler compiler) {
+  MetadataAnnotation ensureResolved(Resolution resolution) {
     if (annotatedElement.isClass || annotatedElement.isTypedef) {
       TypeDeclarationElement typeDeclaration = annotatedElement;
-      typeDeclaration.ensureResolved(compiler);
+      typeDeclaration.ensureResolved(resolution);
     }
     if (resolutionState == STATE_NOT_STARTED) {
-      compiler.resolver.resolveMetadataAnnotation(this);
+      resolution.resolveMetadataAnnotation(this);
     }
     return this;
   }
 
-  Node parseNode(DiagnosticListener listener);
+  Node parseNode(Parsing parsing);
 
   String toString() => 'MetadataAnnotation($constant, $resolutionState)';
 }
@@ -3045,7 +3067,7 @@
 
   ParameterMetadataAnnotation(Metadata this.metadata);
 
-  Node parseNode(DiagnosticListener listener) => metadata.expression;
+  Node parseNode(Parsing parsing) => metadata.expression;
 
   Token get beginToken => metadata.getBeginToken();
 
diff --git a/pkg/compiler/lib/src/enqueue.dart b/pkg/compiler/lib/src/enqueue.dart
index b6ecbad..212218d 100644
--- a/pkg/compiler/lib/src/enqueue.dart
+++ b/pkg/compiler/lib/src/enqueue.dart
@@ -9,6 +9,8 @@
 
 import 'common/names.dart' show
     Identifiers;
+import 'common/resolution.dart' show
+    Resolution;
 import 'common/work.dart' show
     ItemCompilationContext,
     WorkItem;
@@ -25,6 +27,8 @@
 import 'dart_types.dart' show
     DartType,
     InterfaceType;
+import 'diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import 'diagnostics/invariant.dart' show
     invariant;
 import 'diagnostics/spannable.dart' show
@@ -108,9 +112,15 @@
 
   // TODO(johnniwinther): Collect checked types for checked mode separately to
   // support serialization.
-  Iterable<DartType> get checkedTypes => const <DartType>[];
+  Iterable<DartType> get isChecks => const <DartType>[];
+
+  Iterable<DartType> get checkedModeChecks => const <DartType>[];
+
+  Iterable<DartType> get asCasts => const <DartType>[];
 
   Iterable<MethodElement> get closurizedFunctions => const <MethodElement>[];
+
+  Iterable<LocalFunctionElement> get closures => const <LocalFunctionElement>[];
 }
 
 abstract class Enqueuer {
@@ -141,6 +151,9 @@
            this.itemCompilationContextCreator,
            this.strategy);
 
+  // TODO(johnniwinther): Move this to [ResolutionEnqueuer].
+  Resolution get resolution => compiler.resolution;
+
   Queue<WorkItem> get queue;
   bool get queueIsEmpty => queue.isEmpty;
 
@@ -149,9 +162,15 @@
 
   QueueFilter get filter => compiler.enqueuerFilter;
 
+  DiagnosticReporter get reporter => compiler.reporter;
+
   /// Returns [:true:] if [member] has been processed by this enqueuer.
   bool isProcessed(Element member);
 
+  bool isClassProcessed(ClassElement cls) => _processedClasses.contains(cls);
+
+  Iterable<ClassElement> get processedClasses => _processedClasses;
+
   /**
    * Documentation wanted -- johnniwinther
    *
@@ -181,10 +200,14 @@
     worldImpact.dynamicGetters.forEach(registerDynamicGetter);
     worldImpact.dynamicSetters.forEach(registerDynamicSetter);
     worldImpact.staticUses.forEach(registerStaticUse);
-    // TODO(johnniwinther): Register [worldImpact.instantiatedTypes] when it
-    // doesn't require a [Registry].
-    worldImpact.checkedTypes.forEach(registerIsCheck);
+    worldImpact.instantiatedTypes.forEach(registerInstantiatedType);
+    worldImpact.isChecks.forEach(registerIsCheck);
+    worldImpact.asCasts.forEach(registerIsCheck);
+    if (compiler.enableTypeAssertions) {
+      worldImpact.checkedModeChecks.forEach(registerIsCheck);
+    }
     worldImpact.closurizedFunctions.forEach(registerGetOfStaticFunction);
+    worldImpact.closures.forEach(registerClosure);
   }
 
   // TODO(johnniwinther): Remove the need for passing the [registry].
@@ -192,7 +215,7 @@
                                 {bool mirrorUsage: false}) {
     task.measure(() {
       ClassElement cls = type.element;
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
       universe.registerTypeInstantiation(
           type,
           byMirrors: mirrorUsage,
@@ -261,7 +284,7 @@
       }
     } else if (member.isFunction) {
       FunctionElement function = member;
-      function.computeType(compiler);
+      function.computeType(resolution);
       if (function.name == Identifiers.noSuchMethod_) {
         registerNoSuchMethod(function);
       }
@@ -286,7 +309,7 @@
       }
     } else if (member.isGetter) {
       FunctionElement getter = member;
-      getter.computeType(compiler);
+      getter.computeType(resolution);
       if (universe.hasInvokedGetter(getter, compiler.world)) {
         addToWorkList(getter);
         return;
@@ -299,7 +322,7 @@
       }
     } else if (member.isSetter) {
       FunctionElement setter = member;
-      setter.computeType(compiler);
+      setter.computeType(resolution);
       if (universe.hasInvokedSetter(setter, compiler.world)) {
         addToWorkList(setter);
         return;
@@ -321,14 +344,23 @@
       if (_processedClasses.contains(cls)) return;
       // The class must be resolved to compute the set of all
       // supertypes.
-      cls.ensureResolved(compiler);
+      cls.ensureResolved(resolution);
 
       void processClass(ClassElement superclass) {
         if (_processedClasses.contains(superclass)) return;
+        // TODO(johnniwinther): Re-insert this invariant when unittests don't
+        // fail. There is already a similar invariant on the members.
+        /*if (!isResolutionQueue) {
+          assert(invariant(superclass,
+              superclass.isClosure ||
+              compiler.enqueuer.resolution.isClassProcessed(superclass),
+              message: "Class $superclass has not been "
+                       "processed in resolution."));
+        }*/
 
         _processedClasses.add(superclass);
         recentClasses.add(superclass);
-        superclass.ensureResolved(compiler);
+        superclass.ensureResolved(resolution);
         superclass.implementation.forEachMember(processInstantiatedClassMember);
         if (isResolutionQueue && !superclass.isSynthesized) {
           compiler.resolver.checkClass(superclass);
@@ -416,7 +448,7 @@
       logEnqueueReflectiveAction(element);
       if (element.isTypedef) {
         TypedefElement typedef = element;
-        typedef.ensureResolved(compiler);
+        typedef.ensureResolved(resolution);
         compiler.world.allTypedefs.add(element);
       } else if (Elements.isStaticOrTopLevel(element)) {
         registerStaticUse(element.declaration);
@@ -450,7 +482,7 @@
     if (includeClass) {
       logEnqueueReflectiveAction(cls, "register");
       ClassElement decl = cls.declaration;
-      decl.ensureResolved(compiler);
+      decl.ensureResolved(resolution);
       compiler.backend.registerInstantiatedType(
           decl.rawType,
           this,
@@ -484,7 +516,7 @@
     for (ClassElement cls in classes) {
       if (compiler.backend.referencedFromMirrorSystem(cls)) {
         logEnqueueReflectiveAction(cls);
-        cls.ensureResolved(compiler);
+        cls.ensureResolved(resolution);
         compiler.backend.registerInstantiatedType(
             cls.rawType,
             this,
@@ -521,7 +553,7 @@
       // have run before tree shaking is disabled and thus everything is
       // enqueued.
       recents = _processedClasses.toSet();
-      compiler.log('Enqueuing everything');
+      reporter.log('Enqueuing everything');
       for (LibraryElement lib in compiler.libraryLoader.libraries) {
         enqueueReflectiveElementsInLibrary(lib, recents);
       }
@@ -700,7 +732,7 @@
 
   void registerClosurizedMember(TypedElement element) {
     assert(element.isInstanceMember);
-    if (element.computeType(compiler).containsTypeVariables) {
+    if (element.computeType(resolution).containsTypeVariables) {
       compiler.backend.registerClosureWithFreeTypeVariables(
           element, this, compiler.globalDependencies);
     }
@@ -758,7 +790,7 @@
    *
    * Invariant: Key elements are declaration elements.
    */
-  final Set<AstElement> resolvedElements;
+  final Set<AstElement> processedElements;
 
   final Queue<ResolutionWorkItem> queue;
 
@@ -775,22 +807,22 @@
               compiler,
               itemCompilationContextCreator,
               strategy),
-        resolvedElements = new Set<AstElement>(),
+        processedElements = new Set<AstElement>(),
         queue = new Queue<ResolutionWorkItem>(),
         deferredTaskQueue = new Queue<DeferredTask>();
 
   bool get isResolutionQueue => true;
 
-  bool isProcessed(Element member) => resolvedElements.contains(member);
+  bool isProcessed(Element member) => processedElements.contains(member);
 
   /// Returns `true` if [element] has been processed by the resolution enqueuer.
-  bool hasBeenResolved(Element element) {
-    return resolvedElements.contains(element.analyzableElement.declaration);
+  bool hasBeenProcessed(Element element) {
+    return processedElements.contains(element.analyzableElement.declaration);
   }
 
-  /// Registers [element] as resolved for the resolution enqueuer.
-  void registerResolvedElement(AstElement element) {
-    resolvedElements.add(element);
+  /// Registers [element] as processed by the resolution enqueuer.
+  void registerProcessedElement(AstElement element) {
+    processedElements.add(element);
   }
 
   /**
@@ -811,7 +843,7 @@
 
     assert(invariant(element, element is AnalyzableElement,
         message: 'Element $element is not analyzable.'));
-    if (hasBeenResolved(element)) return false;
+    if (hasBeenProcessed(element)) return false;
     if (queueIsClosed) {
       throw new SpannableAssertionFailure(element,
           "Resolution work list is closed. Trying to add $element.");
@@ -898,29 +930,17 @@
   void emptyDeferredTaskQueue() {
     while (!deferredTaskQueue.isEmpty) {
       DeferredTask task = deferredTaskQueue.removeFirst();
-      compiler.withCurrentElement(task.element, task.action);
+      reporter.withCurrentElement(task.element, task.action);
     }
   }
 
-  void registerJsCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsCall(node, resolver);
-  }
-
-  void registerJsEmbeddedGlobalCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsEmbeddedGlobalCall(node, resolver);
-  }
-
-  void registerJsBuiltinCall(Send node, ResolverVisitor resolver) {
-    nativeEnqueuer.registerJsBuiltinCall(node, resolver);
-  }
-
   void _logSpecificSummary(log(message)) {
-    log('Resolved ${resolvedElements.length} elements.');
+    log('Resolved ${processedElements.length} elements.');
   }
 
   void forgetElement(Element element) {
     super.forgetElement(element);
-    resolvedElements.remove(element);
+    processedElements.remove(element);
   }
 }
 
diff --git a/pkg/compiler/lib/src/helpers/helpers.dart b/pkg/compiler/lib/src/helpers/helpers.dart
index 3a67978..6b3e787 100644
--- a/pkg/compiler/lib/src/helpers/helpers.dart
+++ b/pkg/compiler/lib/src/helpers/helpers.dart
@@ -15,6 +15,8 @@
 import '../../compiler.dart';
 import '../compiler.dart' show
     Compiler;
+import '../diagnostics/diagnostic_listener.dart' show
+    DiagnosticReporter;
 import '../diagnostics/invariant.dart' show
     DEBUG_MODE;
 import '../diagnostics/messages.dart' show
@@ -88,7 +90,9 @@
 }
 
 /// Function signature of [reportHere].
-typedef ReportHere(Compiler compiler, Spannable node, String debugMessage);
+typedef ReportHere(DiagnosticReporter reporter,
+                   Spannable node,
+                   String debugMessage);
 
 /// Print a message with a source location.
 ReportHere get reportHere {
@@ -97,8 +101,8 @@
 }
 
 /// Implementation of [reportHere]
-_reportHere(Compiler compiler, Spannable node, String debugMessage) {
-  compiler.reportInfo(node,
+_reportHere(DiagnosticReporter reporter, Spannable node, String debugMessage) {
+  reporter.reportInfo(node,
       MessageKind.GENERIC, {'text': 'HERE: $debugMessage'});
 }
 
diff --git a/pkg/compiler/lib/src/helpers/trace.dart b/pkg/compiler/lib/src/helpers/trace.dart
index b928bb6..0889efd 100644
--- a/pkg/compiler/lib/src/helpers/trace.dart
+++ b/pkg/compiler/lib/src/helpers/trace.dart
@@ -60,8 +60,11 @@
 }
 
 /// Function signature of [traceAndReport].
-typedef void TraceAndReport(Compiler compiler, Spannable node, String message,
-                            {bool condition(String stackTrace), int limit,
+typedef void TraceAndReport(DiagnosticReporter reporter,
+                            Spannable node,
+                            String message,
+                            {bool condition(String stackTrace),
+                             int limit,
                              bool throwOnPrint});
 
 /// Calls [reportHere] and [trace] with the same message.
@@ -74,7 +77,9 @@
 TraceAndReport get reportAndTrace => traceAndReport;
 
 /// Implementation of [traceAndReport].
-void _traceAndReport(Compiler compiler, Spannable node, String message,
+void _traceAndReport(DiagnosticReporter reporter,
+                     Spannable node,
+                     String message,
                      {bool condition(String stackTrace), int limit,
                       bool throwOnPrint: false}) {
 
@@ -82,7 +87,7 @@
         condition: (String stackTrace) {
     bool result = condition != null ? condition(stackTrace) : true;
     if (result) {
-      reportHere(compiler, node, message);
+      reportHere(reporter, node, message);
     }
     return result;
   });
diff --git a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart b/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
deleted file mode 100644
index 7b0cf06..0000000
--- a/pkg/compiler/lib/src/inferrer/concrete_types_inferrer.dart
+++ /dev/null
@@ -1,2405 +0,0 @@
-// Copyright (c) 2012, 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 concrete_types_inferrer;
-
-import 'dart:collection' show
-    Queue,
-    IterableBase;
-
-import '../native/native.dart' as native;
-import '../closure.dart' show
-    BoxFieldElement;
-import '../compiler.dart' show
-    Compiler;
-import '../dart_types.dart' show
-    DartType,
-    TypeKind;
-import '../diagnostics/spannable.dart' show
-    Spannable;
-import '../elements/elements.dart';
-import '../tree/tree.dart';
-import '../types/types.dart' show
-    FlatTypeMask,
-    TypeMask,
-    TypesInferrer,
-    UnionTypeMask;
-import '../universe/selector.dart' show
-    Selector,
-    SelectorKind;
-import '../universe/side_effects.dart' show
-    SideEffects;
-import '../world.dart' show
-    ClassWorld;
-
-import 'inferrer_visitor.dart';
-import 'simple_types_inferrer.dart';
-
-/**
- * A singleton concrete type. More precisely, a [BaseType] is one of the
- * following:
- *
- *   - a non-asbtract class like [:int:] or [:Uri:] (but not [:List:])
- *   - the null base type
- *   - the unknown base type
- */
-abstract class BaseType {
-  bool isClass();
-  bool isUnknown();
-  bool isNull();
-}
-
-/**
- * A non-asbtract class like [:int:] or [:Uri:] (but not [:List:]).
- */
-class ClassBaseType implements BaseType {
-  final ClassElement element;
-
-  ClassBaseType(this.element);
-
-  bool operator ==(var other) {
-    if (identical(this, other)) return true;
-    if (other is! ClassBaseType) return false;
-    return element == other.element;
-  }
-  int get hashCode => element.hashCode;
-  String toString() {
-    return element == null ? 'toplevel' : element.name;
-  }
-  bool isClass() => true;
-  bool isUnknown() => false;
-  bool isNull() => false;
-}
-
-/**
- * The unknown base type.
- */
-class UnknownBaseType implements BaseType {
-  const UnknownBaseType();
-  bool operator ==(BaseType other) => other is UnknownBaseType;
-  int get hashCode => 0;
-  bool isClass() => false;
-  bool isUnknown() => true;
-  bool isNull() => false;
-  toString() => "unknown";
-}
-
-/**
- * The null base type.
- */
-class NullBaseType implements BaseType {
-  const NullBaseType();
-  bool operator ==(BaseType other) => identical(other, this);
-  int get hashCode => 1;
-  bool isClass() => false;
-  bool isUnknown() => false;
-  bool isNull() => true;
-  toString() => "null";
-}
-
-/**
- * An immutable set of base types like [:{int, bool}:], or the unknown concrete
- * type.
- */
-abstract class ConcreteType {
-  ConcreteType();
-
-  factory ConcreteType.empty(int maxConcreteTypeSize,
-                             BaseTypes classBaseTypes) {
-    return new UnionType(maxConcreteTypeSize, classBaseTypes,
-                         new Set<BaseType>());
-  }
-
-  /**
-   * The singleton constituted of the unknown base type is the unknown concrete
-   * type.
-   */
-  factory ConcreteType.singleton(int maxConcreteTypeSize,
-                                 BaseTypes classBaseTypes,
-                                 BaseType baseType) {
-    if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
-      return const UnknownConcreteType();
-    }
-    Set<BaseType> singletonSet = new Set<BaseType>();
-    singletonSet.add(baseType);
-    return new UnionType(maxConcreteTypeSize, classBaseTypes, singletonSet);
-  }
-
-  factory ConcreteType.unknown() {
-    return const UnknownConcreteType();
-  }
-
-  ConcreteType union(ConcreteType other);
-  ConcreteType intersection(ConcreteType other);
-  ConcreteType refine(Selector selector, Compiler compiler);
-  bool isUnknown();
-  bool isEmpty();
-  Set<BaseType> get baseTypes;
-
-  /**
-   * Returns the unique element of [:this:] if [:this:] is a singleton, null
-   * otherwise.
-   */
-  ClassElement getUniqueType();
-}
-
-/**
- * The unkown concrete type: it is absorbing for the union.
- */
-class UnknownConcreteType implements ConcreteType {
-  const UnknownConcreteType();
-  bool isUnknown() => true;
-  bool isEmpty() => false;
-  bool operator ==(ConcreteType other) => identical(this, other);
-  Set<BaseType> get baseTypes =>
-      new Set<BaseType>.from([const UnknownBaseType()]);
-  int get hashCode => 0;
-  ConcreteType union(ConcreteType other) => this;
-  ConcreteType intersection(ConcreteType other) => other;
-  ConcreteType refine(Selector selector, Compiler compiler) => this;
-  ClassElement getUniqueType() => null;
-  toString() => "unknown";
-}
-
-/**
- * An immutable set of base types, like [: {int, bool} :].
- */
-class UnionType implements ConcreteType {
-  final int maxConcreteTypeSize;
-  final BaseTypes classBaseTypes;
-
-  final Set<BaseType> baseTypes;
-
-  /**
-   * The argument should NOT be mutated later. Do not call directly, use
-   * ConcreteType.singleton instead.
-   */
-  UnionType(this.maxConcreteTypeSize, this.classBaseTypes, this.baseTypes);
-
-  bool isUnknown() => false;
-  bool isEmpty() => baseTypes.isEmpty;
-
-  bool operator ==(ConcreteType other) {
-    if (other is! UnionType) return false;
-    if (baseTypes.length != other.baseTypes.length) return false;
-    return baseTypes.containsAll(other.baseTypes);
-  }
-
-  int get hashCode {
-    int result = 1;
-    for (final baseType in baseTypes) {
-      result = 31 * result + baseType.hashCode;
-    }
-    return result;
-  }
-
-  ConcreteType _simplify(Set<BaseType> baseTypes) {
-    // normalize all flavors of ints to int
-    // TODO(polux): handle different ints better
-    if (baseTypes.contains(classBaseTypes.uint31Type)) {
-      baseTypes.remove(classBaseTypes.uint31Type);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    if (baseTypes.contains(classBaseTypes.uint32Type)) {
-      baseTypes.remove(classBaseTypes.uint32Type);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    if (baseTypes.contains(classBaseTypes.positiveIntType)) {
-      baseTypes.remove(classBaseTypes.positiveIntType);
-      baseTypes.add(classBaseTypes.intBaseType);
-    }
-    // normalize {int, float}, {int, num} or {float, num} into num
-    // TODO(polux): generalize this to all types when we extend the concept of
-    //     "concrete type" to other abstract classes than num
-    if (baseTypes.contains(classBaseTypes.numBaseType) ||
-        (baseTypes.contains(classBaseTypes.intBaseType)
-            && baseTypes.contains(classBaseTypes.doubleBaseType))) {
-      baseTypes.remove(classBaseTypes.intBaseType);
-      baseTypes.remove(classBaseTypes.doubleBaseType);
-      baseTypes.add(classBaseTypes.numBaseType);
-    }
-
-    // widen big types to dynamic
-    return baseTypes.length > maxConcreteTypeSize
-        ? const UnknownConcreteType()
-        : new UnionType(maxConcreteTypeSize, classBaseTypes, baseTypes);
-  }
-
-  ConcreteType union(ConcreteType other) {
-    if (other.isUnknown()) {
-      return const UnknownConcreteType();
-    }
-    UnionType otherUnion = other;  // cast
-    Set<BaseType> newBaseTypes = new Set<BaseType>.from(baseTypes);
-    newBaseTypes.addAll(otherUnion.baseTypes);
-    return _simplify(newBaseTypes);
-  }
-
-  ConcreteType intersection(ConcreteType other) {
-    if (other.isUnknown()) {
-      return this;
-    }
-    Set<BaseType> thisBaseTypes = new Set<BaseType>.from(baseTypes);
-    Set<BaseType> otherBaseTypes = new Set<BaseType>.from(other.baseTypes);
-    return _simplify(thisBaseTypes.intersection(otherBaseTypes));
-  }
-
-  ConcreteType refine(Selector selector, Compiler compiler) {
-    Set<BaseType> newBaseTypes = new Set<BaseType>();
-    for (BaseType baseType in baseTypes) {
-      if (baseType.isClass()) {
-        ClassBaseType classBaseType = baseType;
-        if (classBaseType.element.lookupByName(selector.memberName) != null) {
-          newBaseTypes.add(baseType);
-        }
-      } else {
-        newBaseTypes.add(baseType);
-      }
-    }
-    return _simplify(newBaseTypes);
-  }
-
-  ClassElement getUniqueType() {
-    if (baseTypes.length == 1) {
-      var iterator = baseTypes.iterator;
-      iterator.moveNext();
-      BaseType uniqueBaseType = iterator.current;
-      if (uniqueBaseType.isClass()) {
-        ClassBaseType uniqueClassType = uniqueBaseType;
-        return uniqueClassType.element;
-      }
-    }
-    return null;
-  }
-
-  String toString() => baseTypes.toString();
-}
-
-class ConcreteTypeSystem extends TypeSystem<ConcreteType> {
-  final Compiler compiler;
-  final ConcreteTypesInferrer inferrer;
-  final BaseTypes baseTypes;
-
-  final ConcreteType nullType;
-  final ConcreteType _intType;
-  final ConcreteType _uint31Type;
-  final ConcreteType _uint32Type;
-  final ConcreteType _positiveIntType;
-  final ConcreteType _doubleType;
-  final ConcreteType _numType;
-  final ConcreteType _boolType;
-  final ConcreteType _functionType;
-  final ConcreteType _listType;
-  final ConcreteType _constListType;
-  final ConcreteType _fixedListType;
-  final ConcreteType _growableListType;
-  final ConcreteType _mapType;
-  final ConcreteType _constMapType;
-  final ConcreteType _stringType;
-
-  final ConcreteType dynamicType;
-  final ConcreteType typeType;
-  final ConcreteType nonNullEmptyType;
-
-  ConcreteTypeSystem.internal(ConcreteTypesInferrer inferrer,
-                              BaseTypes baseTypes,
-                              ConcreteType singleton(BaseType baseType))
-      : this.compiler = inferrer.compiler
-      , this.inferrer = inferrer
-      , this.baseTypes = baseTypes
-      , this._constListType = singleton(baseTypes.constMapBaseType)
-      , this._constMapType = singleton(baseTypes.constMapBaseType)
-      , this._doubleType = singleton(baseTypes.doubleBaseType)
-      , this._fixedListType = singleton(baseTypes.fixedListBaseType)
-      , this._functionType = singleton(baseTypes.functionBaseType)
-      , this._growableListType = singleton(baseTypes.growableListBaseType)
-      , this._intType = singleton(baseTypes.intBaseType)
-      , this._listType = singleton(baseTypes.listBaseType)
-      , this._mapType = singleton(baseTypes.mapBaseType)
-      , this._numType = singleton(baseTypes.numBaseType)
-      , this._boolType = singleton(baseTypes.boolBaseType)
-      , this._stringType = singleton(baseTypes.stringBaseType)
-      , this.typeType = singleton(baseTypes.typeBaseType)
-      , this.dynamicType = const UnknownConcreteType()
-      , this.nullType = singleton(const NullBaseType())
-      , this.nonNullEmptyType = new ConcreteType.empty(
-          inferrer.compiler.maxConcreteTypeSize, baseTypes)
-      // TODO(polux): have better types here
-      , this._uint31Type = singleton(baseTypes.intBaseType)
-      , this._uint32Type = singleton(baseTypes.intBaseType)
-      , this._positiveIntType = singleton(baseTypes.intBaseType);
-
-  factory ConcreteTypeSystem(ConcreteTypesInferrer inferrer) {
-    Compiler compiler = inferrer.compiler;
-    BaseTypes baseTypes = new BaseTypes(compiler);
-    return new ConcreteTypeSystem.internal(
-        inferrer,
-        baseTypes,
-        (BaseType baseType) => new ConcreteType.singleton(
-            compiler.maxConcreteTypeSize, baseTypes, baseType));
-  }
-
-  @override
-  ConcreteType get intType {
-    inferrer.augmentSeenClasses(compiler.backend.intImplementation);
-    return _intType;
-  }
-
-  @override
-  ConcreteType get uint31Type {
-    inferrer.augmentSeenClasses(compiler.backend.uint31Implementation);
-    return _uint31Type;
-  }
-
-  @override
-  ConcreteType get uint32Type {
-    inferrer.augmentSeenClasses(compiler.backend.uint32Implementation);
-    return _uint32Type;
-  }
-
-  @override
-  ConcreteType get positiveIntType {
-    inferrer.augmentSeenClasses(compiler.backend.positiveIntImplementation);
-    return _positiveIntType;
-  }
-
-  @override
-  ConcreteType get doubleType {
-    inferrer.augmentSeenClasses(compiler.backend.doubleImplementation);
-    return _doubleType;
-  }
-
-  @override
-  ConcreteType get numType {
-    inferrer.augmentSeenClasses(compiler.backend.numImplementation);
-    return _numType;
-  }
-
-  @override
-  ConcreteType get boolType {
-    inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
-    return _boolType;
-  }
-
-  @override
-  ConcreteType get functionType {
-    inferrer.augmentSeenClasses(compiler.backend.functionImplementation);
-    return _functionType;
-  }
-
-  @override
-  ConcreteType get listType {
-    inferrer.augmentSeenClasses(compiler.backend.listImplementation);
-    return _listType;
-  }
-
-  @override
-  ConcreteType get constListType {
-    inferrer.augmentSeenClasses(compiler.backend.constListImplementation);
-    return _constListType;
-  }
-
-  @override
-  ConcreteType get fixedListType {
-    inferrer.augmentSeenClasses(compiler.backend.fixedListImplementation);
-    return _fixedListType;
-  }
-
-  @override
-  ConcreteType get growableListType {
-    inferrer.augmentSeenClasses(compiler.backend.growableListImplementation);
-    return _growableListType;
-  }
-
-  @override
-  ConcreteType get mapType {
-    inferrer.augmentSeenClasses(compiler.backend.mapImplementation);
-    return _mapType;
-  }
-
-  @override
-  ConcreteType get constMapType {
-    inferrer.augmentSeenClasses(compiler.backend.constMapImplementation);
-    return _constMapType;
-  }
-
-  @override
-  ConcreteType get stringType {
-    inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
-    return _stringType;
-  }
-
-  @override
-  ConcreteType stringLiteralType(_) {
-    inferrer.augmentSeenClasses(compiler.backend.stringImplementation);
-    return _stringType;
-  }
-
-  @override
-  ConcreteType boolLiteralType(_) {
-    inferrer.augmentSeenClasses(compiler.backend.boolImplementation);
-    return _boolType;
-  }
-
-  /**
-   * Returns the [TypeMask] representation of [baseType].
-   */
-  TypeMask baseTypeToTypeMask(BaseType baseType) {
-    if (baseType.isUnknown()) {
-      return const DynamicTypeMask();
-    } else if (baseType.isNull()) {
-      return new TypeMask.empty();
-    } else {
-      ClassBaseType classBaseType = baseType;
-      final element = classBaseType.element;
-      assert(element != null);
-      if (element == compiler.backend.numImplementation) {
-        return new TypeMask.nonNullSubclass(compiler.backend.numImplementation,
-                                            compiler.world);
-      } else if (element == compiler.backend.intImplementation) {
-        return new TypeMask.nonNullSubclass(compiler.backend.intImplementation,
-                                            compiler.world);
-      } else if (!compiler.world.isInstantiated(element.declaration)) {
-        return new TypeMask.nonNullSubtype(element.declaration, compiler.world);
-      } else {
-        return new TypeMask.nonNullExact(element.declaration, compiler.world);
-      }
-    }
-  }
-
-  /**
-   * Returns the [TypeMask] representation of [concreteType].
-   */
-  TypeMask concreteTypeToTypeMask(ConcreteType concreteType) {
-    if (concreteType == null) return null;
-    TypeMask typeMask = new TypeMask.nonNullEmpty();
-    for (BaseType baseType in concreteType.baseTypes) {
-      TypeMask baseMask = baseTypeToTypeMask(baseType);
-      if (baseMask == const DynamicTypeMask()) return baseMask;
-      typeMask = typeMask.union(baseMask, compiler.world);
-    }
-    return typeMask;
-  }
-
-  @override
-  ConcreteType addPhiInput(Local variable,
-                           ConcreteType phiType,
-                           ConcreteType newType) {
-    return computeLUB(phiType, newType);
-  }
-
-  @override
-  ConcreteType allocateDiamondPhi(ConcreteType firstInput,
-                                  ConcreteType secondInput) {
-    return computeLUB(firstInput, secondInput);
-  }
-
-  @override
-  ConcreteType allocatePhi(Node node, Local variable, ConcreteType inputType) {
-    return inputType;
-  }
-
-  @override
-  ConcreteType allocateLoopPhi(Node node, Local variable,
-                               ConcreteType inputType) {
-    return inputType;
-  }
-
-  @override
-  ConcreteType computeLUB(ConcreteType firstType, ConcreteType secondType) {
-    if (firstType == null) {
-      return secondType;
-    } else if (secondType == null) {
-      return firstType;
-    } else {
-      return firstType.union(secondType);
-    }
-  }
-
-  // Implementation Inspired by
-  // type_graph_inferrer.TypeInformationSystem.narrowType
-  @override
-  ConcreteType narrowType(ConcreteType type,
-                          DartType annotation,
-                          {bool isNullable: true}) {
-    if (annotation.treatAsDynamic) return type;
-    if (annotation.isVoid) return nullType;
-    if (annotation.element == compiler.objectClass) return type;
-    ConcreteType otherType;
-    if (annotation.isTypedef || annotation.isFunctionType) {
-      otherType = functionType;
-    } else if (annotation.isTypeVariable) {
-      // TODO(polux): Narrow to bound.
-      return type;
-    } else {
-      assert(annotation.isInterfaceType);
-      otherType = nonNullSubtype(annotation.element);
-    }
-    if (isNullable) otherType = otherType.union(nullType);
-    if (type == null) return otherType;
-    return type.intersection(otherType);
-  }
-
-  @override
-  TypeMask newTypedSelector(ConcreteType receiver, TypeMask mask) {
-    return concreteTypeToTypeMask(receiver);
-  }
-
-  @override
-  ConcreteType nonNullEmpty() {
-    return nonNullEmptyType;
-  }
-
-  @override
-  ConcreteType nonNullExact(ClassElement cls) {
-    return nonNullSubtype(cls);
-  }
-
-  /**
-   * Helper method for [nonNullSubtype] and [nonNullSubclass].
-   */
-  ConcreteType nonNullSubX(ClassElement cls,
-                           Iterable<ClassElement> extractor(ClassElement cls)) {
-    if (cls == compiler.objectClass) {
-      return dynamicType;
-    }
-    ConcreteType result = nonNullEmptyType;
-    void registerClass(ClassElement element) {
-      if (!element.isAbstract) {
-        result = result.union(
-            new ConcreteType.singleton(compiler.maxConcreteTypeSize,
-                                       baseTypes,
-                                       new ClassBaseType(element)));
-        inferrer.augmentSeenClasses(element);
-      }
-    }
-    registerClass(cls);
-    Iterable<ClassElement> subtypes = extractor(cls);
-    subtypes.forEach(registerClass);
-    return result;
-  }
-
-  @override
-  ConcreteType nonNullSubclass(ClassElement cls) {
-    return nonNullSubX(cls, compiler.world.strictSubclassesOf);
-  }
-
-  @override
-  ConcreteType nonNullSubtype(ClassElement cls) {
-    return nonNullSubX(cls, compiler.world.strictSubtypesOf);
-  }
-
-  @override
-  ConcreteType simplifyPhi(Node node,
-                           Local variable,
-                           ConcreteType phiType) {
-    return phiType;
-  }
-
-  @override
-  bool selectorNeedsUpdate(ConcreteType type, TypeMask mask) {
-    return concreteTypeToTypeMask(type) != mask;
-  }
-
-  @override
-  ConcreteType refineReceiver(Selector selector,
-                              TypeMask mask,
-                              ConcreteType receiverType,
-      bool isConditional) {
-    if (isConditional) {
-      throw new UnimplementedError("isConditional in concrete type inferrer");
-    }
-    return receiverType.refine(selector, compiler);
-  }
-
-  @override
-  bool isNull(ConcreteType type) {
-    return (type.baseTypes.length == 1) && (type.baseTypes.first.isNull());
-  }
-
-  @override
-  ConcreteType allocateClosure(Node node, Element element) {
-    // TODO(polux): register closure here instead of in visitor?
-    return functionType;
-  }
-
-  @override
-  ConcreteType allocateList(ConcreteType type,
-                            Node node,
-                            Element enclosing,
-                            [ConcreteType elementType, int length]) {
-    if (elementType != null) {
-      inferrer.augmentListElementType(elementType);
-    }
-    return type;
-  }
-
-  @override
-  ConcreteType allocateMap(ConcreteType type,
-                           Node node,
-                           Element element,
-                           [List<ConcreteType> keyTypes,
-                            List<ConcreteType> valueTypes]) {
-    // TODO(polux): treat maps the same way we treat lists
-    return type;
-  }
-
-  @override
-  ConcreteType getConcreteTypeFor(TypeMask mask) {
-    if (mask.isUnion) {
-      UnionTypeMask union = mask;
-      return union.disjointMasks.fold(
-          nonNullEmptyType,
-          (type1, type2) => type1.union(getConcreteTypeFor(type2)));
-    } else {
-      FlatTypeMask flat = mask;
-      ConcreteType result;
-      if (flat.isEmpty) {
-        result = nonNullEmptyType;
-      } else if (flat.isExact) {
-        result = nonNullExact(flat.base);
-      } else if (flat.isSubclass) {
-        result = nonNullSubclass(flat.base);
-      } else if (flat.isSubtype) {
-        result = nonNullSubtype(flat.base);
-      } else {
-        throw new ArgumentError("unexpected mask");
-      }
-      return flat.isNullable ? result.union(nullType) : result;
-    }
-  }
-}
-
-/**
- * The cartesian product of concrete types: an iterable of
- * [ConcreteTypesEnvironment]s.
- */
-class ConcreteTypeCartesianProduct
-    extends IterableBase<ConcreteTypesEnvironment> {
-  final ConcreteTypesInferrer inferrer;
-  final ClassElement typeOfThis;
-  final Map<Element, ConcreteType> concreteTypes;
-  ConcreteTypeCartesianProduct(this.inferrer, this.typeOfThis,
-                               this.concreteTypes);
-  Iterator get iterator => concreteTypes.isEmpty
-      ? [new ConcreteTypesEnvironment(typeOfThis)].iterator
-      : new ConcreteTypeCartesianProductIterator(inferrer, typeOfThis,
-                                                 concreteTypes);
-  String toString() => this.toList().toString();
-}
-
-/**
- * An helper class for [ConcreteTypeCartesianProduct].
- */
-class ConcreteTypeCartesianProductIterator
-    implements Iterator<ConcreteTypesEnvironment> {
-  final ConcreteTypesInferrer inferrer;
-  final ClassElement classOfThis;
-  final Map<Element, ConcreteType> concreteTypes;
-  final Map<Element, BaseType> nextValues;
-  final Map<Element, Iterator> state;
-  int size = 1;
-  int counter = 0;
-  ConcreteTypesEnvironment _current;
-
-  ConcreteTypeCartesianProductIterator(this.inferrer, this.classOfThis,
-      Map<Element, ConcreteType> concreteTypes)
-      : this.concreteTypes = concreteTypes,
-        nextValues = new Map<Element, BaseType>(),
-        state = new Map<Element, Iterator>() {
-    if (concreteTypes.isEmpty) {
-      size = 0;
-      return;
-    }
-    for (final e in concreteTypes.keys) {
-      final baseTypes = concreteTypes[e].baseTypes;
-      size *= baseTypes.length;
-    }
-  }
-
-  ConcreteTypesEnvironment get current => _current;
-
-  ConcreteTypesEnvironment takeSnapshot() {
-    Map<Element, ConcreteType> result = new Map<Element, ConcreteType>();
-    nextValues.forEach((k, v) {
-      result[k] = inferrer.singletonConcreteType(v);
-    });
-    return new ConcreteTypesEnvironment.of(result, classOfThis);
-  }
-
-  bool moveNext() {
-    if (counter >= size) {
-      _current = null;
-      return false;
-    }
-    for (final key in concreteTypes.keys) {
-      final iterator = state[key];
-      if (iterator != null && iterator.moveNext()) {
-        nextValues[key] = state[key].current;
-        break;
-      }
-      Iterator newIterator = concreteTypes[key].baseTypes.iterator;
-      state[key] = newIterator;
-      newIterator.moveNext();
-      nextValues[key] = newIterator.current;
-    }
-    counter++;
-    _current = takeSnapshot();
-    return true;
-  }
-}
-
-/**
- * [BaseType] Constants.
- */
-class BaseTypes {
-  final ClassBaseType intBaseType;
-  final ClassBaseType doubleBaseType;
-  final ClassBaseType numBaseType;
-  final ClassBaseType boolBaseType;
-  final ClassBaseType stringBaseType;
-  final ClassBaseType listBaseType;
-  final ClassBaseType growableListBaseType;
-  final ClassBaseType fixedListBaseType;
-  final ClassBaseType constListBaseType;
-  final ClassBaseType mapBaseType;
-  final ClassBaseType constMapBaseType;
-  final ClassBaseType objectBaseType;
-  final ClassBaseType typeBaseType;
-  final ClassBaseType functionBaseType;
-  final ClassBaseType uint31Type;
-  final ClassBaseType uint32Type;
-  final ClassBaseType positiveIntType;
-
-  BaseTypes(Compiler compiler) :
-    intBaseType = new ClassBaseType(compiler.backend.intImplementation),
-    doubleBaseType = new ClassBaseType(compiler.backend.doubleImplementation),
-    numBaseType = new ClassBaseType(compiler.backend.numImplementation),
-    boolBaseType = new ClassBaseType(compiler.backend.boolImplementation),
-    stringBaseType = new ClassBaseType(compiler.backend.stringImplementation),
-    listBaseType = new ClassBaseType(compiler.backend.listImplementation),
-    growableListBaseType =
-        new ClassBaseType(compiler.backend.growableListImplementation),
-    fixedListBaseType =
-        new ClassBaseType(compiler.backend.fixedListImplementation),
-    constListBaseType =
-        new ClassBaseType(compiler.backend.constListImplementation),
-    mapBaseType = new ClassBaseType(compiler.backend.mapImplementation),
-    constMapBaseType =
-        new ClassBaseType(compiler.backend.constMapImplementation),
-    objectBaseType = new ClassBaseType(compiler.objectClass),
-    typeBaseType = new ClassBaseType(compiler.backend.typeImplementation),
-    functionBaseType =
-        new ClassBaseType(compiler.backend.functionImplementation),
-    uint31Type = new ClassBaseType(compiler.backend.uint31Implementation),
-    uint32Type = new ClassBaseType(compiler.backend.uint32Implementation),
-    positiveIntType =
-        new ClassBaseType(compiler.backend.positiveIntImplementation);
-}
-
-/**
- * An immutable mapping from method arguments to [ConcreteTypes].
- */
-class ConcreteTypesEnvironment {
-  final Map<Element, ConcreteType> environment;
-  final ClassElement classOfThis;
-
-  ConcreteTypesEnvironment([this.classOfThis]) :
-      environment = new Map<Element, ConcreteType>();
-  ConcreteTypesEnvironment.of(this.environment, this.classOfThis);
-
-  ConcreteType lookupType(Element element) => environment[element];
-
-  bool operator ==(ConcreteTypesEnvironment other) {
-    if (other is! ConcreteTypesEnvironment) return false;
-    if (classOfThis != other.classOfThis) return false;
-    if (environment.length != other.environment.length) return false;
-    for (Element key in environment.keys) {
-      if (!other.environment.containsKey(key)
-          || (environment[key] != other.environment[key])) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  int get hashCode {
-    int result = (classOfThis != null) ? classOfThis.hashCode : 1;
-    environment.forEach((element, concreteType) {
-      result = 31 * (31 * result + element.hashCode) + concreteType.hashCode;
-    });
-    return result;
-  }
-
-  String toString() => "{ this: $classOfThis, env: $environment }";
-}
-
-class ClosureEnvironment {
-  ConcreteType thisType;
-  final LocalsHandler locals;
-
-  ClosureEnvironment(this.thisType, this.locals);
-
-  bool mergeLocals(LocalsHandler newLocals) {
-    assert((locals == null) == (newLocals == null));
-    return (locals != null) ? locals.mergeAll([newLocals]) : false;
-  }
-
-  /// Returns true if changed.
-  bool merge(ConcreteType thisType, LocalsHandler locals) {
-    ConcreteType oldThisType = this.thisType;
-    if (this.thisType == null) {
-      this.thisType = thisType;
-    } else if (thisType != null) {
-      this.thisType = this.thisType.union(thisType);
-    }
-    return mergeLocals(locals) || (this.thisType != oldThisType);
-  }
-
-  toString() => "ClosureEnvironment { thisType = $thisType, locals = ... }";
-}
-
-/**
- * A set of encoutered closures.
- */
-class Closures {
-  final Compiler compiler;
-  final Map<FunctionElement, ClosureEnvironment> closures =
-      new Map<FunctionElement, ClosureEnvironment>();
-
-  Closures(this.compiler);
-
-  /// Returns true if the environment of the closure has changed.
-  bool put(FunctionElement closure,
-           ConcreteType typeOfThis,
-           LocalsHandler locals) {
-    ClosureEnvironment oldEnvironent = closures[closure];
-    if (oldEnvironent == null) {
-      closures[closure] = new ClosureEnvironment(typeOfThis, locals);
-      return true;
-    } else {
-      return oldEnvironent.merge(typeOfThis, locals);
-    }
-  }
-
-  ClosureEnvironment getEnvironmentOrNull(FunctionElement function) {
-    return closures[function];
-  }
-
-  Iterable<FunctionElement> get functionElements => closures.keys;
-
-  bool contains(FunctionElement function) => closures.containsKey(function);
-
-  String toString() => closures.toString();
-}
-
-/**
- * A work item for the type inference queue.
- */
-class InferenceWorkItem {
-  Element method;
-  ConcreteTypesEnvironment environment;
-  InferenceWorkItem(this.method, this.environment);
-
-  toString() => "{ method = $method, environment = $environment }";
-
-  bool operator ==(other) {
-    return (other is InferenceWorkItem)
-        && method == other.method
-        && environment == other.environment;
-  }
-
-  int get hashCode => 31 * method.hashCode + environment.hashCode;
-}
-
-/**
- * A sentinel type mask class representing the dynamicType. It is absorbing
- * for [:ConcreteTypesEnvironment.typeMaskUnion:].
- */
-class DynamicTypeMask implements TypeMask {
-  const DynamicTypeMask();
-
-  String toString() => 'sentinel type mask';
-
-  TypeMask nullable() {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask nonNullable() {
-    throw new UnsupportedError("");
-  }
-
-  bool get isEmpty {
-    throw new UnsupportedError("");
-  }
-
-  bool get isNullable {
-    throw new UnsupportedError("");
-  }
-
-  bool get isExact {
-    throw new UnsupportedError("");
-  }
-
-  bool get isUnion {
-    throw new UnsupportedError("");
-  }
-
-  bool get isContainer {
-    throw new UnsupportedError("");
-  }
-
-  bool get isMap {
-    throw new UnsupportedError("");
-  }
-
-  bool get isDictionary {
-    throw new UnsupportedError("");
-  }
-
-  bool get isForwarding {
-    throw new UnsupportedError("");
-  }
-
-  bool get isValue {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyInt(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyDouble(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyNum(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyBool(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnlyString(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsOnly(ClassElement element) {
-    throw new UnsupportedError("");
-  }
-
-  bool satisfies(ClassElement cls, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool contains(ClassElement type, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsAll(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  ClassElement singleClass(ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask union(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  TypeMask intersection(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool canHit(Element element, Selector selector, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  Element locateSingleElement(Selector selector,
-                              TypeMask mask,
-                              Compiler compiler) {
-    throw new UnsupportedError("");
-  }
-
-  bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool isInMask(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-
-  bool containsMask(TypeMask other, ClassWorld classWorld) {
-    throw new UnsupportedError("");
-  }
-}
-
-class WorkQueue {
-  final Queue<InferenceWorkItem> queue = new Queue<InferenceWorkItem>();
-
-  void add(InferenceWorkItem workItem) {
-    if (!queue.contains(workItem)) {
-      queue.addLast(workItem);
-    }
-  }
-
-  InferenceWorkItem remove() {
-    return queue.removeFirst();
-  }
-
-  bool get isEmpty => queue.isEmpty;
-}
-
-/**
- * A task which conservatively infers a [ConcreteType] for each sub expression
- * of the program. The entry point is [analyzeMain].
- */
-class ConcreteTypesInferrer
-    extends InferrerEngine<ConcreteType, ConcreteTypeSystem>
-    implements TypesInferrer {
-
-  final String name = "Type inferrer";
-
-  /**
-   * When true, the string literal [:"__dynamic_for_test":] is inferred to
-   * have the unknown type.
-   */
-  // TODO(polux): get rid of this hack once we have a natural way of inferring
-  // the unknown type.
-  bool testMode = false;
-
-  // --- constants ---
-
-  /**
-   * Constants representing builtin base types. Initialized by [initialize]
-   * and not by the constructor because the compiler elements are not yet
-   * populated.
-   */
-  BaseTypes baseTypes;
-
-  /** The associated type system */
-  ConcreteTypeSystem types;
-
-  /**
-   * Constant representing [:ConcreteList#[]:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listIndex;
-
-  /**
-   * Constant representing [:ConcreteList#[]=:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listIndexSet;
-
-  /**
-   * Constant representing [:ConcreteList#add:] where [:ConcreteList:] is the
-   * concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listAdd;
-
-  /**
-   * Constant representing [:ConcreteList#removeAt:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listRemoveAt;
-
-  /**
-   * Constant representing [:ConcreteList#insert:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listInsert;
-
-  /**
-   * Constant representing [:ConcreteList#removeLast:] where [:ConcreteList:] is
-   * the concrete implementation of lists for the selected backend.
-   */
-  FunctionElement listRemoveLast;
-
-  /** Constant representing [:List():]. */
-  FunctionElement listConstructor;
-
-  /** The unknown concrete type */
-  final ConcreteType unknownConcreteType;
-
-  /** The empty concrete type */
-  ConcreteType emptyConcreteType;
-
-  /** The null concrete type */
-  ConcreteType nullConcreteType;
-
-  // --- state updated by the inference ---
-
-  /**
-   * A map from (function x argument base types) to their inferred concrete
-   * type. Another way of seeing [methodToTemplates] is as a map from
-   * [FunctionElement]s to "templates" in the sense of "The Cartesian Product
-   * Algorithm - Simple and Precise Type Inference of Parametric Polymorphism"
-   * by Ole Agesen.
-   */
-  // TODO(polux): build a better abstraction, like Closures
-  final Map<FunctionElement, Map<ConcreteTypesEnvironment, ConcreteType>>
-      methodToTemplates;
-
-  /** The set of encountered closures. */
-  final Closures closures;
-
-  /** A map from expressions to their inferred concrete types. */
-  final Map<Node, ConcreteType> inferredTypes;
-
-  /** A map from fields to their inferred concrete types. */
-  final Map<Element, ConcreteType> inferredFieldTypes;
-
-  /**
-   * [:callers[f]:] is the list of [:f:]'s possible callers or fields
-   * whose initialization is a call to [:f:].
-   */
-  final Map<FunctionElement, Set<Element>> callers;
-
-  /**
-   * [:readers[field]:] is the list of [:field:]'s possible readers or fields
-   * whose initialization is a read of [:field:].
-   */
-  final Map<Element, Set<Element>> fieldReaders;
-
-  /**
-   * [:readers[local]:] is the list of [:local:]'s possible readers.
-   */
-  final Map<Local, Set<FunctionElement>> capturedLocalsReaders;
-
-  /// The set of classes encountered so far.
-  final Set<ClassElement> seenClasses;
-
-  /**
-   * A map from selector names to callers of methods with this name on objects
-   * of unknown inferred type.
-   */
-  final Map<String, Set<FunctionElement>> dynamicCallers;
-
-  /** The inferred type of elements stored in Lists. */
-  ConcreteType listElementType;
-
-  /**
-   * A map from parameters to their inferred concrete types. It plays no role
-   * in the analysis, it is write only.
-   */
-  final Map<VariableElement, ConcreteType> inferredParameterTypes;
-
-  /**
-   * A map from selectors to their inferred type masks, indexed by the mask
-   * of the receiver. It plays no role in the analysis, it is write only.
-   */
-  final Map<Selector, Map<TypeMask, TypeMask>> inferredSelectorTypes;
-
-  /** The work queue consumed by [analyzeMain]. */
-  final WorkQueue workQueue;
-
-  /** The item being worked on. */
-  InferenceWorkItem currentWorkItem;
-
-  ConcreteTypesInferrer(Compiler compiler)
-      : methodToTemplates = new Map<FunctionElement,
-            Map<ConcreteTypesEnvironment, ConcreteType>>(),
-        closures = new Closures(compiler),
-        inferredTypes = new Map<Node, ConcreteType>(),
-        inferredFieldTypes = new Map<Element, ConcreteType>(),
-        inferredParameterTypes = new Map<VariableElement, ConcreteType>(),
-        workQueue = new WorkQueue(),
-        callers = new Map<FunctionElement, Set<Element>>(),
-        fieldReaders = new Map<Element, Set<Element>>(),
-        capturedLocalsReaders = new Map<Local, Set<FunctionElement>>(),
-        seenClasses = new Set<ClassElement>(),
-        dynamicCallers = new Map<String, Set<FunctionElement>>(),
-        inferredSelectorTypes = new Map<Selector, Map<TypeMask, TypeMask>>(),
-        unknownConcreteType = new ConcreteType.unknown(),
-        super(compiler, null);
-
-  /* Initialization code that cannot be run in the constructor because it
-   * requires the compiler's elements to be populated.
-   */
-  void initialize() {
-    baseTypes = new BaseTypes(compiler);
-    types = new ConcreteTypeSystem(this);
-    ClassElement jsArrayClass = baseTypes.listBaseType.element;
-    listIndex = jsArrayClass.lookupMember('[]');
-    listIndexSet = jsArrayClass.lookupMember('[]=');
-    listAdd = jsArrayClass.lookupMember('add');
-    listRemoveAt = jsArrayClass.lookupMember('removeAt');
-    listInsert = jsArrayClass.lookupMember('insert');
-    listRemoveLast =
-        jsArrayClass.lookupMember('removeLast');
-    listConstructor =
-        compiler.listClass.lookupDefaultConstructor();
-    if (listConstructor != null) {
-      listConstructor = listConstructor.implementation;
-    }
-    emptyConcreteType = new ConcreteType.empty(compiler.maxConcreteTypeSize,
-                                               baseTypes);
-    nullConcreteType = singletonConcreteType(const NullBaseType());
-    listElementType = emptyConcreteType;
-  }
-
-  // --- utility methods ---
-
-  /** Creates a singleton concrete type containing [baseType]. */
-  ConcreteType singletonConcreteType(BaseType baseType) {
-    return new ConcreteType.singleton(compiler.maxConcreteTypeSize, baseTypes,
-                                      baseType);
-  }
-
-  /**
-   * Computes the union of [mask1] and [mask2] where [mask1] and [mask2] are
-   * possibly equal to [: DynamicTypeMask.instance :].
-   */
-  TypeMask typeMaskUnion(TypeMask mask1, TypeMask mask2) {
-    if (mask1 == const DynamicTypeMask() || mask2 == const DynamicTypeMask()) {
-      return const DynamicTypeMask();
-    }
-    return mask1.union(mask2, compiler.world);
-  }
-
-  /**
-   * Returns all the members matching [selector].
-   */
-  Set<Element> getMembersBySelector(Selector selector) {
-    // TODO(polux): memoize?
-    Set<Element> result = new Set<Element>();
-    for (ClassElement cls in seenClasses) {
-      Element elem = cls.lookupByName(selector.memberName);
-      if (elem != null) {
-        result.add(elem.implementation);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Returns all the subtypes of [cls], [cls] included.
-   */
-  Set<ClassElement> getReflexiveSubtypesOf(ClassElement cls) {
-    // TODO(polux): memoize?
-    Set<ClassElement> result = new Set<ClassElement>()..add(cls);
-    for (ClassElement candidate in seenClasses) {
-      if (compiler.world.isSubtypeOf(candidate, cls)) {
-        result.add(candidate);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Sets the concrete type associated to [node] to the union of the inferred
-   * concrete type so far and of [type].
-   */
-  void augmentInferredType(Node node, ConcreteType type) {
-    ConcreteType currentType = inferredTypes[node];
-    inferredTypes[node] =
-        (currentType == null) ? type : currentType.union(type);
-  }
-
-  /**
-   * Sets the concrete type associated to [selector] to the union of the
-   * inferred concrete type so far and of [returnType].
-   *
-   * Precondition: [:(typeOfThis != null) && (returnType != null):]
-   */
-  void augmentInferredSelectorType(Selector selector,
-                                   TypeMask typeOfThis,
-                                   TypeMask returnType) {
-    assert(returnType != null);
-    assert(typeOfThis != null);
-
-    Map<TypeMask, TypeMask> currentMap = inferredSelectorTypes.putIfAbsent(
-        selector, () => new Map<TypeMask, TypeMask>());
-    TypeMask currentReturnType = currentMap[typeOfThis];
-    currentMap[typeOfThis] = (currentReturnType == null)
-        ? returnType
-        : typeMaskUnion(currentReturnType, returnType);
-  }
-
-  /**
-   * Returns the current inferred concrete type of [field].
-   */
-  ConcreteType getFieldType(Selector selector, Element field) {
-    ensureFieldInitialized(field);
-    ConcreteType result = inferredFieldTypes[field];
-    result = (result == null) ? emptyConcreteType : result;
-    if (selector != null) {
-      Element enclosing = field.enclosingElement;
-      if (enclosing.isClass) {
-        ClassElement cls = enclosing;
-        TypeMask receiverMask = new TypeMask.exact(cls.declaration, classWorld);
-        TypeMask resultMask = types.concreteTypeToTypeMask(result);
-        augmentInferredSelectorType(selector, receiverMask, resultMask);
-      }
-    }
-    return result;
-  }
-
-  /**
-   * Sets the concrete type associated to [field] to the union of the inferred
-   * concrete type so far and of [type].
-   */
-  void augmentFieldType(Element field, ConcreteType type) {
-    ensureFieldInitialized(field);
-    ConcreteType oldType = inferredFieldTypes[field];
-    ConcreteType newType = (oldType != null) ? oldType.union(type) : type;
-    if (oldType != newType) {
-      inferredFieldTypes[field] = newType;
-      invalidateReaders(field);
-    }
-  }
-
-  /** Augment the inferred type of elements stored in Lists. */
-  void augmentListElementType(ConcreteType type) {
-    ConcreteType newType = listElementType.union(type);
-    if (newType != listElementType) {
-      invalidateCallers(listIndex);
-      listElementType = newType;
-    }
-  }
-
-  /**
-   * Sets the concrete type associated to [parameter] to the union of the
-   * inferred concrete type so far and of [type].
-   */
-  void augmentParameterType(VariableElement parameter, ConcreteType type) {
-    ConcreteType oldType = inferredParameterTypes[parameter];
-    inferredParameterTypes[parameter] =
-        (oldType == null) ? type : oldType.union(type);
-  }
-
-  /** Augments the set of classes encountered so far. */
-  void augmentSeenClasses(ClassElement cls) {
-    if (!seenClasses.contains(cls)) {
-      seenClasses.add(cls);
-      cls.forEachMember((_, Element member) {
-        Set<FunctionElement> functions = dynamicCallers[member.name];
-        if (functions != null) {
-          functions.forEach(invalidate);
-        }
-      }, includeSuperAndInjectedMembers: true);
-    }
-  }
-
-  /**
-   * Add [caller] to the set of [callee]'s callers.
-   */
-  void addCaller(FunctionElement callee, Element caller) {
-    callers.putIfAbsent(callee, () => new Set<Element>())
-           .add(caller);
-  }
-
-  /**
-   * Add [caller] to the set of [callee]'s dynamic callers.
-   */
-  void addDynamicCaller(Selector callee, FunctionElement caller) {
-      dynamicCallers
-          .putIfAbsent(callee.name, () => new Set<FunctionElement>())
-          .add(caller);
-  }
-
-  /**
-   * Add [reader] to the set of [field]'s readers.
-   */
-  void addFieldReader(Element field, Element reader) {
-    fieldReaders.putIfAbsent(field, () => new Set<Element>())
-                .add(reader);
-  }
-
-  /**
-   * Add [reader] to the set of [local]'s readers.
-   */
-  void addCapturedLocalReader(Local local, FunctionElement reader) {
-    capturedLocalsReaders.putIfAbsent(local, () => new Set<FunctionElement>())
-                         .add(reader);
-  }
-
-  /**
-   * Add a closure to the set of seen closures. Invalidate callers if
-   * the set of locals has changed.
-   */
-  void addClosure(FunctionElement closure,
-                  ConcreteType typeOfThis,
-                  LocalsHandler locals) {
-    if (closures.put(closure, typeOfThis, locals)) {
-      invalidateCallers(closure);
-    }
-  }
-
-  /**
-   * Invalidate all callers of [function].
-   */
-  void invalidateCallers(FunctionElement function) {
-    Set<Element> methodCallers = callers[function];
-    if (methodCallers != null) {
-      methodCallers.forEach(invalidate);
-    }
-  }
-
-  /**
-   * Invalidate all reader of [field].
-   */
-  void invalidateReaders(Element field) {
-    Set<Element> readers = fieldReaders[field];
-    if (readers != null) {
-      readers.forEach(invalidate);
-    }
-  }
-
-  /**
-   * Add all templates of [methodOrField] to the workqueue.
-   */
-  void invalidate(Element methodOrField) {
-    if (methodOrField.isField) {
-      workQueue.add(new InferenceWorkItem(
-          methodOrField, new ConcreteTypesEnvironment()));
-    } else {
-      Map<ConcreteTypesEnvironment, ConcreteType> templates =
-          methodToTemplates[methodOrField];
-      if (templates != null) {
-        templates.forEach((environment, _) {
-          workQueue.add(
-              new InferenceWorkItem(methodOrField, environment));
-        });
-      }
-    }
-  }
-
-  /**
-   * Returns the template associated to [function] or create an empty template
-   * for [function] return it.
-   */
-  // TODO(polux): encapsulate this in an abstraction for templates
-  Map<ConcreteTypesEnvironment, ConcreteType>
-      getTemplatesOrEmpty(FunctionElement function) {
-    return methodToTemplates.putIfAbsent(
-        function,
-        () => new Map<ConcreteTypesEnvironment, ConcreteType>());
-  }
-
-  // -- methods of types.TypesInferrer (interface with the backend) --
-
-  /** Get the inferred concrete type of [node]. */
-  @override
-  TypeMask getTypeOfNode(Element owner, Node node) {
-    TypeMask result = types.concreteTypeToTypeMask(inferredTypes[node]);
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /** Get the inferred concrete type of [element]. */
-  @override
-  TypeMask getTypeOfElement(Element element) {
-    final result = types.concreteTypeToTypeMask(typeOfElement(element));
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /**
-   * Get the inferred concrete return type of [element]. A null return value
-   * means "I don't know".
-   */
-  @override
-  TypeMask getReturnTypeOfElement(Element element) {
-    assert(element is FunctionElement);
-    Map<ConcreteTypesEnvironment, ConcreteType> templates =
-        methodToTemplates[element];
-    if (templates == null) return null;
-    ConcreteType returnType = emptyConcreteType;
-    templates.forEach((_, concreteType) {
-      returnType = returnType.union(concreteType);
-    });
-    TypeMask result = types.concreteTypeToTypeMask(returnType);
-    return (result == const DynamicTypeMask()) ? null : result;
-  }
-
-  /**
-   * Get the inferred concrete type of [selector]. A null return value means
-   * "I don't know".
-   */
-  @override
-  TypeMask getTypeOfSelector(Selector selector, TypeMask mask) {
-    Map<TypeMask, TypeMask> candidates = inferredSelectorTypes[selector];
-    if (candidates == null) {
-      return null;
-    }
-    TypeMask result = new TypeMask.nonNullEmpty();
-    if (mask == null) {
-      candidates.forEach((TypeMask receiverType, TypeMask returnType) {
-        result = typeMaskUnion(result, returnType);
-      });
-    } else {
-      candidates.forEach((TypeMask receiverType, TypeMask returnType) {
-        TypeMask intersection = receiverType.intersection(mask, compiler.world);
-        if (!intersection.isEmpty || intersection.isNullable) {
-          result = typeMaskUnion(result, returnType);
-        }
-      });
-    }
-    return result == const DynamicTypeMask() ? null : result;
-  }
-
-  @override
-  void clear() {
-    throw new UnsupportedError("clearing is not yet implemented");
-  }
-
-  @override
-  bool isCalledOnce(Element element) {
-    // Never called by SimpleTypeInferrer.
-    throw new UnsupportedError("");
-  }
-
-  @override
-  bool isFixedArrayCheckedForGrowable(Node node) {
-    // Never called by SimpleTypeInferrer.
-    throw new UnsupportedError("");
-  }
-
-  // --- analysis ---
-
-  /**
-   * Returns the concrete type returned by [function] given arguments of
-   * concrete types [argumentsTypes]. If [function] is static then
-   * [receiverType] must be null, else [function] must be a member of
-   * [receiverType].
-   */
-  ConcreteType getSendReturnType(Selector selector,
-                                 FunctionElement function,
-                                 ClassElement receiverType,
-                                 ArgumentsTypes<ConcreteType> argumentsTypes) {
-    assert(function != null);
-
-    ConcreteType result = emptyConcreteType;
-    Map<Element, ConcreteType> argumentMap =
-        associateArguments(function, argumentsTypes);