Version 2.10.0-51.0.dev

Merge commit 'db9b25dc7c52407328d680ac672c2607e04ed5a1' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index 515b734..052e071 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2020-08-17T14:05:33.104579",
+  "generated": "2020-08-18T11:26:08.472483",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
@@ -515,7 +515,7 @@
       "name": "shelf",
       "rootUri": "../third_party/pkg/shelf",
       "packageUri": "lib/",
-      "languageVersion": "2.0"
+      "languageVersion": "2.1"
     },
     {
       "name": "shelf_packages_handler",
@@ -716,6 +716,12 @@
       "languageVersion": "2.8"
     },
     {
+      "name": "wasm",
+      "rootUri": "../pkg/wasm",
+      "packageUri": "lib/",
+      "languageVersion": "2.6"
+    },
+    {
       "name": "watcher",
       "rootUri": "../third_party/pkg/watcher",
       "packageUri": "lib/",
diff --git a/.packages b/.packages
index ee073a7..ebac358 100644
--- a/.packages
+++ b/.packages
@@ -116,6 +116,7 @@
 vm:pkg/vm/lib
 vm_service:pkg/vm_service/lib
 vm_snapshot_analysis:pkg/vm_snapshot_analysis/lib
+wasm:pkg/wasm/lib
 watcher:third_party/pkg/watcher/lib
 webdriver:third_party/pkg/webdriver/lib
 web_components:third_party/pkg/web_components/lib
diff --git a/DEPS b/DEPS
index 8ddee13..0353d74 100644
--- a/DEPS
+++ b/DEPS
@@ -133,7 +133,7 @@
   "quiver-dart_tag": "246e754fe45cecb6aa5f3f13b4ed61037ff0d784",
   "resource_rev": "f8e37558a1c4f54550aa463b88a6a831e3e33cd6",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
-  "rust_revision": "60960a260f7b5c695fd0717311d72ce62dd4eb43",
+  "rust_revision": "cbe7c5ce705896d4e22bf6096590bc1f17993b78",
   "shelf_static_rev": "v0.2.8",
   "shelf_packages_handler_tag": "2.0.0",
   "shelf_proxy_tag": "0.1.0+7",
diff --git a/build/rust/rust.gni b/build/rust/rust.gni
index caabcc8..c3fb4dc 100644
--- a/build/rust/rust.gni
+++ b/build/rust/rust.gni
@@ -2,40 +2,103 @@
 # 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.
 
+_dart_root = get_path_info("../..", "abspath")
+
 template("rust_library") {
   manifest = rebase_path("Cargo.toml")
   if (defined(invoker.manifest)) {
     manifest = invoker.manifest
   }
 
+  debug = defined(invoker.debug) && invoker.debug
+  shared = defined(invoker.shared) && invoker.shared
+
   cmd = [
-    rebase_path("//buildtools/${current_os}-${current_cpu}/rust/bin/cargo"),
+    rebase_path("//buildtools/${host_os}-${host_cpu}/rust/bin/cargo"),
     "build",
     "--target-dir",
     rebase_path(target_out_dir),
     "--manifest-path",
     manifest,
   ]
-  output = "$target_out_dir/lib${invoker.lib_name}.a"
-  debug = defined(invoker.debug) && invoker.debug
 
-  if (!debug) {
+  # For cross compilation, figure out the target triple. You can get a full list
+  # of the targets that rust supports like this: rustc --print target-list
+  cargo_out_dir = target_out_dir
+  if (is_linux) {
+    rust_os = "unknown-linux-gnu"
+  } else if (is_mac) {
+    rust_os = "apple-darwin"
+  } else if (is_win) {
+    rust_os = "pc-windows-gnu"
+  } else if (is_android) {
+    rust_os = "linux-android"
+  } else if (is_fuchsia) {
+    rust_os = "fuchsia"
+  }
+  if (defined(rust_os)) {
+    if (current_cpu == "x86") {
+      rust_target = "i686-${rust_os}"
+    } else if (current_cpu == "x64") {
+      rust_target = "x86_64-${rust_os}"
+    } else if (current_cpu == "arm") {
+      rust_target = "arm-${rust_os}eabi"
+    } else if (current_cpu == "arm64") {
+      rust_target = "aarch64-${rust_os}"
+    }
+  }
+  if (defined(rust_target)) {
+    cmd += [
+      "--target",
+      rust_target,
+    ]
+    cargo_out_dir += "/${rust_target}"
+  }
+
+  if (debug) {
+    cargo_out_dir += "/debug"
+  } else {
+    cargo_out_dir += "/release"
     cmd += [ "--release" ]
   }
 
-  action(target_name) {
-    script = "//build/rust/run.py"
+  output_file = ""
+  if (shared) {
+    if (is_win) {
+      output_file = "${invoker.lib_name}.dll"
+    } else if (is_mac) {
+      output_file = "lib${invoker.lib_name}.dylib"
+    } else {
+      output_file = "lib${invoker.lib_name}.so"
+    }
+  } else {
+    if (is_win) {
+      output_file = "${invoker.lib_name}.lib"
+    }else {
+      output_file = "lib${invoker.lib_name}.a"
+    }
+  }
+
+  action("${target_name}_cargo") {
+    script = "${_dart_root}/build/rust/run.py"
     args = cmd
-    outputs = [ output ]
+    outputs = [ "${cargo_out_dir}/${output_file}" ]
     public_configs = [ ":${target_name}_config" ]
   }
 
-  config("${target_name}_config") {
-    libs = [ "wasmer" ]
-    if (debug) {
-      lib_dirs = [ "$target_out_dir/debug" ]
-    } else {
-      lib_dirs = [ "$target_out_dir/release" ]
+  config("${target_name}_cargo_config") {
+    if (!shared) {
+      libs = [ invoker.lib_name ]
+      lib_dirs = [ out_dir ]
     }
   }
+
+  # Cargo leaves the library in cargo_out_dir, which varies based on the target.
+  # So we need to copy it to target_out_dir to make it easier for dependees to
+  # locate the library.
+  copy(target_name) {
+    deps = [ ":${target_name}_cargo" ]
+    sources = [ "${cargo_out_dir}/${output_file}" ]
+    outputs = [ "${target_out_dir}/${output_file}" ]
+  }
 }
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
new file mode 100644
index 0000000..3a8456c
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, 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.
+
+// ignore_for_file: prefer_single_quotes, slash_for_doc_comments
+import 'package:analyzer/error/error.dart';
+
+/// An error code representing a problem in a file containing an encoding of a
+/// transform set.
+class TransformSetErrorCode extends ErrorCode {
+  /**
+   * Parameters:
+   * 0: the unsupported key
+   */
+  static const TransformSetErrorCode unsupportedKey = TransformSetErrorCode(
+      'unsupported_key', "The key '{0}' isn't supported.");
+
+  /**
+   * Parameters:
+   * 0: the message produced by the YAML parser
+   */
+  static const TransformSetErrorCode yamlSyntaxError =
+      TransformSetErrorCode('yaml_syntax_error', "{0}");
+
+  /// Initialize a newly created error code.
+  const TransformSetErrorCode(String name, String message,
+      {String correction, bool hasPublishedDocs = false})
+      : super.temporary(name, message,
+            correction: correction, hasPublishedDocs: hasPublishedDocs);
+
+  @override
+  ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
+
+  @override
+  ErrorType get type => ErrorType.COMPILE_TIME_ERROR;
+}
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
new file mode 100644
index 0000000..3a3af62
--- /dev/null
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -0,0 +1,240 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/change.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/rename.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:analysis_server/src/utilities/extensions/yaml.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:yaml/yaml.dart';
+
+/// A parser used to read a transform set from a file.
+class TransformSetParser {
+  static const String _changesKey = 'changes';
+
+  static const String _componentsKey = 'components';
+
+  static const String _elementKey = 'element';
+
+  static const String _kindKey = 'kind';
+
+  static const String _newNameKey = 'newName';
+
+  static const String _titleKey = 'title';
+
+  static const String _transformsKey = 'transforms';
+
+  static const String _urisKey = 'uris';
+
+  static const String _versionKey = 'version';
+
+  static const String _renameKind = 'rename';
+
+  static const int currentVersion = 1;
+
+  /// The error reporter to which diagnostics will be reported.
+  final ErrorReporter errorReporter;
+
+  /// Initialize a newly created parser to report diagnostics to the
+  /// [errorReporter].
+  TransformSetParser(this.errorReporter);
+
+  /// Return the result of parsing the file [content] into a transform set.
+  TransformSet parse(String content) {
+    assert(content != null);
+    var map = _parseYaml(content);
+    if (map == null) {
+      return TransformSet();
+    }
+    return _translateTransformSet(map);
+  }
+
+  /// Return the result of parsing the file [content] into a YAML node.
+  YamlNode _parseYaml(String content) {
+    try {
+      return loadYamlNode(content);
+    } on YamlException catch (e) {
+      var span = e.span;
+      errorReporter.reportErrorForOffset(TransformSetErrorCode.yamlSyntaxError,
+          span.start.offset, span.length, [e.message]);
+    }
+    return null;
+  }
+
+  /// Report a diagnostic with the given [code] associated with the given
+  /// [node]. A list of [arguments] should be provided if the diagnostic message
+  /// has parameters.
+  void _reportError(TransformSetErrorCode code, YamlNode node,
+      [List<String> arguments]) {
+    var span = node.span;
+    errorReporter.reportErrorForOffset(
+        code, span.start.offset, span.length, arguments);
+  }
+
+  /// Report any keys in the [map] whose values are not in [validKeys].
+  void _reportUnsupportedKeys(YamlMap map, Set<String> validKeys) {
+    for (var keyNode in map.nodes.keys) {
+      if (keyNode is YamlScalar) {
+        var key = _translateString(keyNode);
+        if (key != null && !validKeys.contains(key)) {
+          _reportError(TransformSetErrorCode.unsupportedKey, keyNode, [key]);
+        }
+      } else {
+        // TODO(brianwilkerson) Report the unsupported key.
+      }
+    }
+  }
+
+  /// Translate the [node] into a change.
+  Change _translateChange(YamlNode node) {
+    if (node is YamlMap) {
+      var kind = _translateString(node.valueAt(_kindKey));
+      // TODO(brianwilkerson) Implement additional change kinds.
+      if (kind == _renameKind) {
+        return _translateRenameChange(node);
+      }
+      // TODO(brianwilkerson) Report the invalid change kind.
+      return null;
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into an element descriptor.
+  ElementDescriptor _translateElement(YamlNode node) {
+    if (node is YamlMap) {
+      var uris = _translateList(node.valueAt(_urisKey), _translateString);
+      var components =
+          _translateList(node.valueAt(_componentsKey), _translateString);
+      return ElementDescriptor(libraryUris: uris, components: components);
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into an integer.
+  int _translateInteger(YamlNode node) {
+    if (node is YamlScalar) {
+      var value = node.value;
+      if (value is int) {
+        return value;
+      }
+      // TODO(brianwilkerson) Report the invalid YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into a list of objects using the [elementTranslator].
+  List<R> _translateList<R>(
+      YamlNode node, R Function(YamlNode) elementTranslator) {
+    if (node is YamlList) {
+      var translatedList = <R>[];
+      for (var element in node.nodes) {
+        var result = elementTranslator(element);
+        if (result != null) {
+          translatedList.add(result);
+        }
+      }
+      return translatedList;
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into a rename change.
+  Change _translateRenameChange(YamlMap node) {
+    _reportUnsupportedKeys(node, const {_kindKey, _newNameKey});
+    var newName = _translateString(node.valueAt(_newNameKey));
+    return Rename(newName: newName);
+  }
+
+  /// Translate the [node] into a string.
+  String _translateString(YamlNode node) {
+    if (node is YamlScalar) {
+      var value = node.value;
+      if (value is String) {
+        return value;
+      }
+      // TODO(brianwilkerson) Report the invalid YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML. For the best UX we
+      //  probably need to pass in the code to report.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into a transform.
+  Transform _translateTransform(YamlNode node) {
+    if (node is YamlMap) {
+      _reportUnsupportedKeys(node, const {_changesKey, _elementKey, _titleKey});
+      var title = _translateString(node.valueAt(_titleKey));
+      var element = _translateElement(node.valueAt(_elementKey));
+      var changes =
+          _translateList<Change>(node.valueAt(_changesKey), _translateChange);
+      return Transform(title: title, element: element, changes: changes);
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML.
+      return null;
+    }
+  }
+
+  /// Translate the [node] into a transform set.
+  TransformSet _translateTransformSet(YamlNode node) {
+    if (node is YamlMap) {
+      _reportUnsupportedKeys(node, const {_transformsKey, _versionKey});
+      var set = TransformSet();
+      // TODO(brianwilkerson) Version information is currently being ignored,
+      //  but needs to be used to select a translator.
+      var version = _translateInteger(node.valueAt(_versionKey));
+      if (version != currentVersion) {
+        // TODO(brianwilkerson) Report the unsupported version.
+      }
+      var transformations =
+          _translateList(node.valueAt(_transformsKey), _translateTransform);
+      for (var transform in transformations) {
+        set.addTransform(transform);
+      }
+      return set;
+    } else if (node == null) {
+      // TODO(brianwilkerson) Report the missing YAML.
+      return null;
+    } else {
+      // TODO(brianwilkerson) Report the invalid YAML.
+      return null;
+    }
+  }
+}
diff --git a/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart b/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart
new file mode 100644
index 0000000..0107f62
--- /dev/null
+++ b/pkg/analysis_server/lib/src/utilities/extensions/yaml.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, 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.
+
+import 'package:yaml/yaml.dart';
+
+extension YamlMapExtensions on YamlMap {
+  /// Return the value associated with the key whose value matches the given
+  /// [key], or `null` if there is no matching key.
+  YamlNode valueAt(String key) {
+    for (var keyNode in nodes.keys) {
+      if (keyNode is YamlScalar && keyNode.value == key) {
+        return nodes[key];
+      }
+    }
+    return null;
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
new file mode 100644
index 0000000..6f035e1
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.
+
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'unsupported_key_test.dart' as unsupported_key;
+import 'yaml_syntax_error_test.dart' as yaml_syntax_error;
+
+void main() {
+  defineReflectiveSuite(() {
+    unsupported_key.main();
+    yaml_syntax_error.main();
+  });
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_key_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_key_test.dart
new file mode 100644
index 0000000..9358bee
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_key_test.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnsupportedKeyTest);
+  });
+}
+
+@reflectiveTest
+class UnsupportedKeyTest extends AbstractTransformSetParserTest {
+  void test_rename() {
+    assertErrors('''
+version: 1
+transforms:
+- title: 'Rename A'
+  element:
+    uris:
+      - 'test.dart'
+    components:
+      - 'A'
+  changes:
+    - kind: 'rename'
+      oldName: 'A'
+      newName: 'B'
+''', [
+      error(TransformSetErrorCode.unsupportedKey, 150, 7),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/yaml_syntax_error_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/yaml_syntax_error_test.dart
new file mode 100644
index 0000000..dfa3444
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/yaml_syntax_error_test.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(YamlSyntaxErrorTest);
+  });
+}
+
+@reflectiveTest
+class YamlSyntaxErrorTest extends AbstractTransformSetParserTest {
+  void test_syntaxError() {
+    assertErrors('''
+{
+''', [
+      error(TransformSetErrorCode.yamlSyntaxError, 2, 0),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
index 1a39ea9..b6be18f 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/test_all.dart
@@ -5,13 +5,17 @@
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
 import 'add_type_parameter_test.dart' as add_type_parameter_change;
+import 'diagnostics/test_all.dart' as diagnostics;
 import 'modify_parameters_test.dart' as modify_parameters;
 import 'rename_test.dart' as rename_change;
+import 'transform_set_parser_test.dart' as transform_set_parser;
 
 void main() {
   defineReflectiveSuite(() {
     add_type_parameter_change.main();
+    diagnostics.main();
     modify_parameters.main();
     rename_change.main();
+    transform_set_parser.main();
   });
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
new file mode 100644
index 0000000..543f5ac
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/rename.dart';
+import 'package:matcher/matcher.dart';
+import 'package:test/test.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import 'transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(TransformSetParserTest);
+  });
+}
+
+@reflectiveTest
+class TransformSetParserTest extends AbstractTransformSetParserTest {
+  void test_rename() {
+    parse('''
+version: 1
+transforms:
+- title: 'Rename A'
+  element:
+    uris:
+      - 'test.dart'
+    components:
+      - 'A'
+  changes:
+    - kind: 'rename'
+      newName: 'B'
+''');
+    var transforms = result.transformsFor('A', ['test.dart']);
+    expect(transforms, hasLength(1));
+    var transform = transforms[0];
+    expect(transform.title, 'Rename A');
+    expect(transform.changes, hasLength(1));
+    var rename = transform.changes[0] as Rename;
+    expect(rename.newName, 'B');
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
new file mode 100644
index 0000000..1fa4200
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test_support.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2020, 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.
+
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set.dart';
+import 'package:analysis_server/src/services/correction/fix/data_driven/transform_set_parser.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+
+import '../../../../../mocks.dart';
+import '../../../../../utils/test_support.dart';
+
+/// Utilities shared between tests of the [TransformSetParser].
+abstract class AbstractTransformSetParserTest {
+  /// The listener to which errors will be reported.
+  GatheringErrorListener errorListener;
+
+  /// The result of parsing the test file's content.
+  TransformSet result;
+
+  Future<void> assertErrors(
+      String code, List<ExpectedError> expectedErrors) async {
+    parse(code);
+    errorListener.assertErrors(expectedErrors);
+  }
+
+  ExpectedError error(ErrorCode code, int offset, int length,
+          {String text,
+          Pattern messageContains,
+          List<ExpectedContextMessage> contextMessages =
+              const <ExpectedContextMessage>[]}) =>
+      ExpectedError(code, offset, length,
+          message: text,
+          messageContains: messageContains,
+          expectedContextMessages: contextMessages);
+
+  void parse(String content) {
+    errorListener = GatheringErrorListener();
+    var errorReporter = ErrorReporter(errorListener, MockSource('data.yaml'));
+    var parser = TransformSetParser(errorReporter);
+    result = parser.parse(content);
+  }
+}
diff --git a/pkg/analysis_server/test/utils/test_support.dart b/pkg/analysis_server/test/utils/test_support.dart
new file mode 100644
index 0000000..959be9b
--- /dev/null
+++ b/pkg/analysis_server/test/utils/test_support.dart
@@ -0,0 +1,384 @@
+// Copyright (c) 2020, 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.
+
+/// These classes were copied from `analyzer`. They should be moved into the
+/// `analyzer/lib/src/test_utilities` directory so that they can be shared.
+/// (This version has been converted to a more modern style.)
+import 'package:analyzer/diagnostic/diagnostic.dart';
+import 'package:analyzer/error/error.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test/test.dart';
+
+/// A description of a message that is expected to be reported with an error.
+class ExpectedContextMessage {
+  /// The path of the file with which the message is associated.
+  final String filePath;
+
+  /// The offset of the beginning of the error's region.
+  final int offset;
+
+  /// The offset of the beginning of the error's region.
+  final int length;
+
+  /// The message text for the error.
+  final String text;
+
+  ExpectedContextMessage(this.filePath, this.offset, this.length, {this.text});
+
+  /// Return `true` if the [message] matches this description of what the state
+  /// of the [message] is expected to be.
+  bool matches(DiagnosticMessage message) {
+    return message.filePath == filePath &&
+        message.offset == offset &&
+        message.length == length &&
+        (text == null || message.message == text);
+  }
+}
+
+/// A description of an error that is expected to be reported.
+class ExpectedError {
+  /// An empty array of error descriptors used when no errors are expected.
+  static List<ExpectedError> NO_ERRORS = <ExpectedError>[];
+
+  /// The error code associated with the error.
+  final ErrorCode code;
+
+  /// The offset of the beginning of the error's region.
+  final int offset;
+
+  /// The offset of the beginning of the error's region.
+  final int length;
+
+  /// The message text of the error or `null` if the message should not be checked.
+  final String message;
+
+  /// A pattern that should be contained in the error message or `null` if the message
+  /// contents should not be checked.
+  final Pattern messageContains;
+
+  /// The list of context messages that are expected to be associated with the
+  /// error.
+  final List<ExpectedContextMessage> expectedContextMessages;
+
+  /// Initialize a newly created error description.
+  ExpectedError(this.code, this.offset, this.length,
+      {this.message,
+      this.messageContains,
+      this.expectedContextMessages = const <ExpectedContextMessage>[]});
+
+  /// Return `true` if the [error] matches this description of what the state
+  /// of the [error] is expected to be.
+  bool matches(AnalysisError error) {
+    if (error.offset != offset ||
+        error.length != length ||
+        error.errorCode != code) {
+      return false;
+    }
+    if (message != null && error.message != message) {
+      return false;
+    }
+    if (messageContains != null &&
+        error.message?.contains(messageContains) != true) {
+      return false;
+    }
+    var contextMessages = error.contextMessages.toList();
+    contextMessages.sort((first, second) {
+      var result = first.filePath.compareTo(second.filePath);
+      if (result != 0) {
+        return result;
+      }
+      return second.offset - first.offset;
+    });
+    if (contextMessages.length != expectedContextMessages.length) {
+      return false;
+    }
+    for (var i = 0; i < expectedContextMessages.length; i++) {
+      if (!expectedContextMessages[i].matches(contextMessages[i])) {
+        return false;
+      }
+    }
+    return true;
+  }
+}
+
+/// An error listener that collects all of the errors passed to it for later
+/// examination.
+class GatheringErrorListener implements AnalysisErrorListener {
+  /// A flag indicating whether error ranges are to be compared when comparing
+  /// expected and actual errors.
+  final bool checkRanges;
+
+  /// A list containing the errors that were collected.
+  final List<AnalysisError> _errors = <AnalysisError>[];
+
+  /// A table mapping sources to the line information for the source.
+  final Map<Source, LineInfo> _lineInfoMap = <Source, LineInfo>{};
+
+  /// Initialize a newly created error listener to collect errors.
+  GatheringErrorListener({this.checkRanges = Parser.useFasta});
+
+  /// Return the errors that were collected.
+  List<AnalysisError> get errors => _errors;
+
+  /// Return `true` if at least one error has been gathered.
+  bool get hasErrors => _errors.isNotEmpty;
+
+  /// Add the given [errors] to this listener.
+  void addAll(List<AnalysisError> errors) {
+    for (var error in errors) {
+      onError(error);
+    }
+  }
+
+  /// Add all of the errors recorded by the given [listener] to this listener.
+  void addAll2(RecordingErrorListener listener) {
+    addAll(listener.errors);
+  }
+
+  /// Assert that the number of errors that have been gathered matches the
+  /// number of [expectedErrors] and that they have the expected error codes and
+  /// locations. The order in which the errors were gathered is ignored.
+  void assertErrors(List<ExpectedError> expectedErrors) {
+    //
+    // Match actual errors to expected errors.
+    //
+    var unmatchedActual = errors.toList();
+    var unmatchedExpected = expectedErrors.toList();
+    var actualIndex = 0;
+    while (actualIndex < unmatchedActual.length) {
+      var matchFound = false;
+      var expectedIndex = 0;
+      while (expectedIndex < unmatchedExpected.length) {
+        if (unmatchedExpected[expectedIndex]
+            .matches(unmatchedActual[actualIndex])) {
+          matchFound = true;
+          unmatchedActual.removeAt(actualIndex);
+          unmatchedExpected.removeAt(expectedIndex);
+          break;
+        }
+        expectedIndex++;
+      }
+      if (!matchFound) {
+        actualIndex++;
+      }
+    }
+    //
+    // Write the results.
+    //
+    var buffer = StringBuffer();
+    if (unmatchedExpected.isNotEmpty) {
+      buffer.writeln('Expected but did not find:');
+      for (var expected in unmatchedExpected) {
+        buffer.write('  ');
+        buffer.write(expected.code);
+        buffer.write(' [');
+        buffer.write(expected.offset);
+        buffer.write(', ');
+        buffer.write(expected.length);
+        if (expected.message != null) {
+          buffer.write(', ');
+          buffer.write(expected.message);
+        }
+        buffer.writeln(']');
+      }
+    }
+    if (unmatchedActual.isNotEmpty) {
+      if (buffer.isNotEmpty) {
+        buffer.writeln();
+      }
+      buffer.writeln('Found but did not expect:');
+      for (var actual in unmatchedActual) {
+        buffer.write('  ');
+        buffer.write(actual.errorCode);
+        buffer.write(' [');
+        buffer.write(actual.offset);
+        buffer.write(', ');
+        buffer.write(actual.length);
+        buffer.write(', ');
+        buffer.write(actual.message);
+        buffer.writeln(']');
+      }
+    }
+    if (buffer.isNotEmpty) {
+      errors.sort((first, second) => first.offset.compareTo(second.offset));
+      buffer.writeln();
+      buffer.writeln('To accept the current state, expect:');
+      for (var actual in errors) {
+        var contextMessages = actual.contextMessages;
+        buffer.write('  error(');
+        buffer.write(actual.errorCode);
+        buffer.write(', ');
+        buffer.write(actual.offset);
+        buffer.write(', ');
+        buffer.write(actual.length);
+        if (contextMessages.isNotEmpty) {
+          buffer.write(', contextMessages: [');
+          for (var i = 0; i < contextMessages.length; i++) {
+            var message = contextMessages[i];
+            if (i > 0) {
+              buffer.write(', ');
+            }
+            buffer.write('message(\'');
+            buffer.write(message.filePath);
+            buffer.write('\', ');
+            buffer.write(message.offset);
+            buffer.write(', ');
+            buffer.write(message.length);
+            buffer.write(')');
+          }
+          buffer.write(']');
+        }
+        buffer.writeln('),');
+      }
+      fail(buffer.toString());
+    }
+  }
+
+  /// Assert that the number of errors that have been gathered matches the
+  /// number of [expectedErrorCodes] and that they have the expected error
+  /// codes. The order in which the errors were gathered is ignored.
+  void assertErrorsWithCodes(
+      [List<ErrorCode> expectedErrorCodes = const <ErrorCode>[]]) {
+    var buffer = StringBuffer();
+    //
+    // Compute the expected number of each type of error.
+    //
+    var expectedCounts = <ErrorCode, int>{};
+    for (var code in expectedErrorCodes) {
+      var count = expectedCounts[code];
+      if (count == null) {
+        count = 1;
+      } else {
+        count = count + 1;
+      }
+      expectedCounts[code] = count;
+    }
+    //
+    // Compute the actual number of each type of error.
+    //
+    var errorsByCode = <ErrorCode, List<AnalysisError>>{};
+    for (var error in _errors) {
+      errorsByCode
+          .putIfAbsent(error.errorCode, () => <AnalysisError>[])
+          .add(error);
+    }
+    //
+    // Compare the expected and actual number of each type of error.
+    //
+    expectedCounts.forEach((ErrorCode code, int expectedCount) {
+      int actualCount;
+      var list = errorsByCode.remove(code);
+      if (list == null) {
+        actualCount = 0;
+      } else {
+        actualCount = list.length;
+      }
+      if (actualCount != expectedCount) {
+        if (buffer.length == 0) {
+          buffer.write('Expected ');
+        } else {
+          buffer.write('; ');
+        }
+        buffer.write(expectedCount);
+        buffer.write(' errors of type ');
+        buffer.write(code.uniqueName);
+        buffer.write(', found ');
+        buffer.write(actualCount);
+      }
+    });
+    //
+    // Check that there are no more errors in the actual-errors map,
+    // otherwise record message.
+    //
+    errorsByCode.forEach((ErrorCode code, List<AnalysisError> actualErrors) {
+      var actualCount = actualErrors.length;
+      if (buffer.length == 0) {
+        buffer.write('Expected ');
+      } else {
+        buffer.write('; ');
+      }
+      buffer.write('0 errors of type ');
+      buffer.write(code.uniqueName);
+      buffer.write(', found ');
+      buffer.write(actualCount);
+      buffer.write(' (');
+      for (var i = 0; i < actualErrors.length; i++) {
+        var error = actualErrors[i];
+        if (i > 0) {
+          buffer.write(', ');
+        }
+        buffer.write(error.offset);
+      }
+      buffer.write(')');
+    });
+    if (buffer.length > 0) {
+      fail(buffer.toString());
+    }
+  }
+
+  /// Assert that the number of errors that have been gathered matches the
+  /// number of [expectedSeverities] and that there are the same number of
+  /// errors and warnings as specified by the argument. The order in which the
+  /// errors were gathered is ignored.
+  void assertErrorsWithSeverities(List<ErrorSeverity> expectedSeverities) {
+    var expectedErrorCount = 0;
+    var expectedWarningCount = 0;
+    for (var severity in expectedSeverities) {
+      if (severity == ErrorSeverity.ERROR) {
+        expectedErrorCount++;
+      } else {
+        expectedWarningCount++;
+      }
+    }
+    var actualErrorCount = 0;
+    var actualWarningCount = 0;
+    for (var error in _errors) {
+      if (error.errorCode.errorSeverity == ErrorSeverity.ERROR) {
+        actualErrorCount++;
+      } else {
+        actualWarningCount++;
+      }
+    }
+    if (expectedErrorCount != actualErrorCount ||
+        expectedWarningCount != actualWarningCount) {
+      fail('Expected $expectedErrorCount errors '
+          'and $expectedWarningCount warnings, '
+          'found $actualErrorCount errors '
+          'and $actualWarningCount warnings');
+    }
+  }
+
+  /// Assert that no errors have been gathered.
+  void assertNoErrors() {
+    assertErrors(ExpectedError.NO_ERRORS);
+  }
+
+  /// Return the line information associated with the given [source], or `null`
+  /// if no line information has been associated with the source.
+  LineInfo getLineInfo(Source source) => _lineInfoMap[source];
+
+  /// Return `true` if an error with the given [errorCode] has been gathered.
+  bool hasError(ErrorCode errorCode) {
+    for (var error in _errors) {
+      if (identical(error.errorCode, errorCode)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  @override
+  void onError(AnalysisError error) {
+    _errors.add(error);
+  }
+
+  /// Set the line information associated with the given [source] to the given
+  /// list of [lineStarts].
+  void setLineInfo(Source source, List<int> lineStarts) {
+    _lineInfoMap[source] = LineInfo(lineStarts);
+  }
+}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index b6f824d..7ff78e1 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.40.1-dev
+* Added `LocalVariableElement.hasInitializer`,
+  `PropertyInducingElement.hasInitializer`, `ParameterElement.hasDefaultValue`.
+
 ## 0.40.0
 * Added `LibraryElement.featureSet`.
 * Removed deprecated `EmbedderSdk` and related classes.
diff --git a/pkg/analyzer/lib/dart/element/element.dart b/pkg/analyzer/lib/dart/element/element.dart
index d605b1c..31dadf0 100644
--- a/pkg/analyzer/lib/dart/element/element.dart
+++ b/pkg/analyzer/lib/dart/element/element.dart
@@ -1388,7 +1388,10 @@
 /// A local variable.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class LocalVariableElement implements PromotableElement {}
+abstract class LocalVariableElement implements PromotableElement {
+  /// Return `true` if this variable has an initializer at declaration.
+  bool get hasInitializer;
+}
 
 /// An element that represents a method defined within a class.
 ///
@@ -1440,6 +1443,9 @@
   /// Return the Dart code of the default value, or `null` if no default value.
   String get defaultValueCode;
 
+  /// Return `true` if this parameter has a default value.
+  bool get hasDefaultValue;
+
   /// Return `true` if this parameter is covariant, meaning it is allowed to
   /// have a narrower type in an override.
   bool get isCovariant;
@@ -1598,6 +1604,9 @@
   /// will be synthetic.
   PropertyAccessorElement get getter;
 
+  /// Return `true` if this variable has an initializer at declaration.
+  bool get hasInitializer;
+
   /// Return the setter associated with this variable, or `null` if the variable
   /// is effectively `final` and therefore does not have a setter associated
   /// with it. (This can happen either because the variable is explicitly
@@ -1728,6 +1737,7 @@
   /// `null` if this variable does not have an initializer. The function will
   /// have no parameters. The return type of the function will be the
   /// compile-time type of the initialization expression.
+  @deprecated
   FunctionElement get initializer;
 
   /// Return `true` if this variable was declared with the 'const' modifier.
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 9a4651c..191f7af 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -369,7 +369,7 @@
           // that we won't be confused by incorrect code.
           if ((field.isFinal || field.isConst) &&
               !field.isStatic &&
-              field.initializer != null) {
+              field.hasInitializer) {
             callback(field);
           }
         }
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 3ad2cf9..46b2b3e 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1784,6 +1784,9 @@
   }
 
   @override
+  bool get hasInitializer => false;
+
+  @override
   String get name {
     if (linkedNode != null) {
       return reference.name;
@@ -5615,6 +5618,9 @@
 /// A concrete implementation of a [LocalVariableElement].
 class LocalVariableElementImpl extends NonParameterVariableElementImpl
     implements LocalVariableElement {
+  @override
+  bool hasInitializer;
+
   /// Initialize a newly created method element to have the given [name] and
   /// [offset].
   LocalVariableElementImpl(String name, int offset) : super(name, offset);
@@ -6218,24 +6224,26 @@
     super.hasImplicitType = hasImplicitType;
   }
 
+  bool get hasInitializer {
+    return linkedNode != null && linkedContext.hasInitializer(linkedNode);
+  }
+
+  @deprecated
   @override
   FunctionElement get initializer {
-    if (_initializer == null) {
-      if (linkedNode != null) {
-        if (linkedContext.hasInitializer(linkedNode)) {
-          _initializer = FunctionElementImpl('', -1)
-            ..isSynthetic = true
-            .._type = FunctionTypeImpl(
-              typeFormals: const [],
-              parameters: const [],
-              returnType: type,
-              nullabilitySuffix: NullabilitySuffix.star,
-            )
-            ..enclosingElement = this;
-        }
-      }
+    if (hasInitializer) {
+      return FunctionElementImpl('', -1)
+        ..enclosingElement = this
+        ..isSynthetic = true
+        ..returnType = type
+        .._type = FunctionTypeImpl(
+          typeFormals: const [],
+          parameters: const [],
+          returnType: type,
+          nullabilitySuffix: NullabilitySuffix.star,
+        );
     }
-    return super.initializer;
+    return null;
   }
 
   @override
@@ -6278,19 +6286,16 @@
     return null;
   }
 
-  bool get _hasInitializer {
-    return linkedNode != null && linkedContext.hasInitializer(linkedNode);
-  }
-
   /// Return `true` if this variable needs the setter.
   bool get _hasSetter {
     if (isConst) {
       return false;
     }
 
+    // TODO(scheglov) is this right?
     if (isLate) {
       if (isFinal) {
-        return !_hasInitializer;
+        return !hasInitializer;
       }
       return true;
     }
@@ -6389,6 +6394,11 @@
   }
 
   @override
+  bool get hasDefaultValue {
+    return defaultValueCode != null;
+  }
+
+  @override
   bool get hasImplicitType {
     if (linkedNode != null) {
       return linkedContext.hasImplicitType(linkedNode);
@@ -6421,28 +6431,6 @@
   }
 
   @override
-  FunctionElement get initializer {
-    if (_initializer != null) return _initializer;
-
-    if (linkedNode != null) {
-      if (linkedContext.hasDefaultValue(linkedNode)) {
-        _initializer = FunctionElementImpl('', -1)
-          ..enclosingElement = this
-          ..isSynthetic = true;
-      }
-    }
-
-    return super.initializer;
-  }
-
-  /// Set the function representing this variable's initializer to the given
-  /// [function].
-  @override
-  set initializer(FunctionElement function) {
-    super.initializer = function;
-  }
-
-  @override
   bool get isCovariant {
     if (isExplicitlyCovariant || inheritsCovariant) {
       return true;
@@ -7112,6 +7100,10 @@
   @override
   PropertyAccessorElement setter;
 
+  /// This field is set during linking, and performs type inference for
+  /// this property. After linking this field is always `null`.
+  PropertyInducingElementTypeInference typeInference;
+
   /// Initialize a newly created synthetic element to have the given [name] and
   /// [offset].
   PropertyInducingElementImpl(String name, int offset) : super(name, offset);
@@ -7156,6 +7148,12 @@
   }
 }
 
+/// Instances of this class are set for fields and top-level variables
+/// to perform top-level type inference during linking.
+abstract class PropertyInducingElementTypeInference {
+  void perform();
+}
+
 /// A concrete implementation of a [ShowElementCombinator].
 class ShowElementCombinatorImpl implements ShowElementCombinator {
   final LinkedUnitContext linkedContext;
@@ -7557,10 +7555,6 @@
   /// The type of this variable.
   DartType _type;
 
-  /// A synthetic function representing this variable's initializer, or `null
-  ///` if this variable does not have an initializer.
-  FunctionElement _initializer;
-
   /// Initialize a newly created variable element to have the given [name] and
   /// [offset].
   VariableElementImpl(String name, int offset) : super(name, offset);
@@ -7613,17 +7607,9 @@
     setModifier(Modifier.IMPLICIT_TYPE, hasImplicitType);
   }
 
+  @deprecated
   @override
-  FunctionElement get initializer => _initializer;
-
-  /// Set the function representing this variable's initializer to the given
-  /// [function].
-  set initializer(FunctionElement function) {
-    if (function != null) {
-      (function as FunctionElementImpl).enclosingElement = this;
-    }
-    _initializer = function;
-  }
+  FunctionElement get initializer => null;
 
   @override
   bool get isConst {
@@ -7684,6 +7670,7 @@
   @override
   void visitChildren(ElementVisitor visitor) {
     super.visitChildren(visitor);
-    _initializer?.accept(visitor);
+    // ignore: deprecated_member_use_from_same_package
+    initializer?.accept(visitor);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
index 52fab94..641f80f 100644
--- a/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
+++ b/pkg/analyzer/lib/src/dart/element/generic_inferrer.dart
@@ -166,14 +166,19 @@
     for (int i = 0; i < typeFormals.length; i++) {
       TypeParameterElement typeParam = typeFormals[i];
       var constraints = _constraints[typeParam];
-      var typeParamBound = typeParam.bound != null
-          ? Substitution.fromPairs(typeFormals, inferredTypes)
-              .substituteType(typeParam.bound)
-          : typeProvider.dynamicType;
+
+      var typeParamBound = typeParam.bound;
+      if (typeParamBound != null) {
+        typeParamBound = Substitution.fromPairs(typeFormals, inferredTypes)
+            .substituteType(typeParamBound);
+        typeParamBound = _toLegacyElementIfOptOut(typeParamBound);
+      } else {
+        typeParamBound = typeProvider.dynamicType;
+      }
 
       var inferred = inferredTypes[i];
       bool success =
-          constraints.every((c) => c.isSatisifedBy(_typeSystem, inferred));
+          constraints.every((c) => c.isSatisfiedBy(_typeSystem, inferred));
       if (success && !typeParamBound.isDynamic) {
         // If everything else succeeded, check the `extends` constraint.
         var extendsConstraint = _TypeConstraint.fromExtends(
@@ -182,7 +187,7 @@
           isNonNullableByDefault: isNonNullableByDefault,
         );
         constraints.add(extendsConstraint);
-        success = extendsConstraint.isSatisifedBy(_typeSystem, inferred);
+        success = extendsConstraint.isSatisfiedBy(_typeSystem, inferred);
       }
 
       if (!success) {
@@ -344,8 +349,8 @@
       // will fail.
       upper = _typeSystem.getGreatestLowerBound(upper, constraint.upperBound);
       lower = _typeSystem.getLeastUpperBound(lower, constraint.lowerBound);
-      upper = _toLegacyType(upper);
-      lower = _toLegacyType(lower);
+      upper = _toLegacyElementIfOptOut(upper);
+      lower = _toLegacyElementIfOptOut(lower);
     }
 
     // Prefer the known bound, if any.
@@ -405,7 +410,7 @@
     Iterable<_TypeConstraint> isSatisified(bool expected) => constraintsByOrigin
         .values
         .where((l) =>
-            l.every((c) => c.isSatisifedBy(_typeSystem, inferred)) == expected)
+            l.every((c) => c.isSatisfiedBy(_typeSystem, inferred)) == expected)
         .expand((i) => i);
 
     String unsatisified = _formatConstraints(isSatisified(false));
@@ -479,7 +484,7 @@
 
   /// If in a legacy library, return the legacy version of the [type].
   /// Otherwise, return the original type.
-  DartType _toLegacyType(DartType type) {
+  DartType _toLegacyElementIfOptOut(DartType type) {
     if (isNonNullableByDefault) return type;
     return NullabilityEliminator.perform(typeProvider, type);
   }
@@ -542,8 +547,10 @@
 
   bool get isDownwards => origin is! _TypeConstraintFromArgument;
 
-  bool isSatisifedBy(TypeSystemImpl ts, DartType type) =>
-      ts.isSubtypeOf2(lowerBound, type) && ts.isSubtypeOf2(type, upperBound);
+  bool isSatisfiedBy(TypeSystemImpl ts, DartType type) {
+    return ts.isSubtypeOf2(lowerBound, type) &&
+        ts.isSubtypeOf2(type, upperBound);
+  }
 
   /// Converts this constraint to a message suitable for a type inference error.
   @override
diff --git a/pkg/analyzer/lib/src/dart/element/member.dart b/pkg/analyzer/lib/src/dart/element/member.dart
index 655578d..29c863b 100644
--- a/pkg/analyzer/lib/src/dart/element/member.dart
+++ b/pkg/analyzer/lib/src/dart/element/member.dart
@@ -211,8 +211,6 @@
 
   @override
   void visitChildren(ElementVisitor visitor) {
-    // TODO(brianwilkerson) We need to finish implementing the accessors used
-    // below so that we can safely invoke them.
     super.visitChildren(visitor);
     safelyVisitChildren(parameters, visitor);
   }
@@ -296,6 +294,9 @@
   }
 
   @override
+  bool get hasDefaultValue => declaration.hasDefaultValue;
+
+  @override
   bool get isCovariant => declaration.isCovariant;
 
   @override
@@ -334,6 +335,9 @@
   }
 
   @override
+  bool get hasInitializer => declaration.hasInitializer;
+
+  @override
   bool get isAbstract => declaration.isAbstract;
 
   @override
@@ -772,6 +776,9 @@
   Element get enclosingElement => declaration.enclosingElement;
 
   @override
+  bool get hasDefaultValue => declaration.hasDefaultValue;
+
+  @override
   int get hashCode => declaration.hashCode;
 
   @override
@@ -951,6 +958,9 @@
   }
 
   @override
+  bool get hasInitializer => declaration.hasInitializer;
+
+  @override
   bool get isExternal => declaration.isExternal;
 
   @override
@@ -1039,9 +1049,8 @@
 
   @override
   void visitChildren(ElementVisitor visitor) {
-    // TODO(brianwilkerson) We need to finish implementing the accessors used
-    // below so that we can safely invoke them.
     super.visitChildren(visitor);
+    // ignore: deprecated_member_use_from_same_package
     declaration.initializer?.accept(visitor);
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
index 92e70c1..1c2938f1 100644
--- a/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/flow_analysis_visitor.dart
@@ -344,7 +344,7 @@
   bool isLocalVariableWithoutDeclaredType(PromotableElement variable) {
     return variable is LocalVariableElement &&
         variable.hasImplicitType &&
-        variable.initializer == null;
+        !variable.hasInitializer;
   }
 
   @override
diff --git a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
index 7dd4335..81255f6 100644
--- a/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/resolution_visitor.dart
@@ -369,14 +369,7 @@
     var defaultValue = node.defaultValue;
     if (defaultValue != null) {
       _withElementWalker(null, () {
-        var offset = defaultValue.offset;
-        var initializer = FunctionElementImpl.forOffset(offset);
-        element.initializer = initializer;
-
-        initializer.hasImplicitReturnType = true;
-        initializer.isSynthetic = true;
-
-        _withElementHolder(ElementHolder(initializer), () {
+        _withElementHolder(ElementHolder(element), () {
           defaultValue.accept(this);
         });
       });
@@ -962,19 +955,13 @@
 
       VariableDeclarationList varList = node.parent;
       localElement.hasImplicitType = varList.type == null;
+      localElement.hasInitializer = initializerNode != null;
       localElement.type = varList.type?.type ?? _dynamicType;
     }
 
     if (initializerNode != null) {
       _withElementWalker(null, () {
-        var offset = initializerNode.offset;
-        var initializer = FunctionElementImpl.forOffset(offset);
-        element.initializer = initializer;
-
-        initializer.hasImplicitReturnType = true;
-        initializer.isSynthetic = true;
-
-        _withElementHolder(ElementHolder(initializer), () {
+        _withElementHolder(ElementHolder(element), () {
           initializerNode.accept(this);
         });
       });
diff --git a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
index ce9ed26..fb59963 100644
--- a/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/variable_declaration_resolver.dart
@@ -61,11 +61,6 @@
       _setInferredType(element, initializer.staticType);
     }
 
-    if (element.initializer != null) {
-      var initializerFunction = element.initializer as FunctionElementImpl;
-      initializerFunction.returnType = initializer.staticType;
-    }
-
     if (isTopLevel) {
       _flowAnalysis?.topLevelDeclaration_exit();
     }
diff --git a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
index efefa53..f3cea21 100644
--- a/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
+++ b/pkg/analyzer/lib/src/error/constructor_fields_verifier.dart
@@ -98,9 +98,9 @@
     _initialFieldMap = <FieldElement, _InitState>{};
     for (var field in element.fields) {
       if (!field.isSynthetic) {
-        _initialFieldMap[field] = field.initializer == null
-            ? _InitState.notInit
-            : _InitState.initInDeclaration;
+        _initialFieldMap[field] = field.hasInitializer
+            ? _InitState.initInDeclaration
+            : _InitState.notInit;
       }
     }
   }
diff --git a/pkg/analyzer/lib/src/error/inheritance_override.dart b/pkg/analyzer/lib/src/error/inheritance_override.dart
index cac6440..159b36d 100644
--- a/pkg/analyzer/lib/src/error/inheritance_override.dart
+++ b/pkg/analyzer/lib/src/error/inheritance_override.dart
@@ -422,13 +422,13 @@
         var derivedElement = derivedOptionalElements[i];
         if (_isNonNullableByDefault &&
             derivedIsAbstract &&
-            derivedElement.initializer == null) {
+            !derivedElement.hasDefaultValue) {
           continue;
         }
         var name = derivedElement.name;
         for (var j = 0; j < baseOptionalElements.length; j++) {
           var baseParameter = baseOptionalElements[j];
-          if (name == baseParameter.name && baseParameter.initializer != null) {
+          if (name == baseParameter.name && baseParameter.hasDefaultValue) {
             var baseValue = baseParameter.computeConstantValue();
             var derivedResult = derivedElement.evaluationResult;
             if (!_constantValuesEqual(derivedResult.value, baseValue)) {
@@ -453,11 +453,11 @@
         var derivedElement = derivedOptionalElements[i];
         if (_isNonNullableByDefault &&
             derivedIsAbstract &&
-            derivedElement.initializer == null) {
+            !derivedElement.hasDefaultValue) {
           continue;
         }
         var baseElement = baseOptionalElements[i];
-        if (baseElement.initializer != null) {
+        if (baseElement.hasDefaultValue) {
           var baseValue = baseElement.computeConstantValue();
           var derivedResult = derivedElement.evaluationResult;
           if (!_constantValuesEqual(derivedResult.value, baseValue)) {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 32fd184..3b5fb67 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -1003,10 +1003,6 @@
     super.visitDefaultFormalParameter(node);
     ParameterElement element = node.declaredElement;
 
-    if (element.initializer != null && node.defaultValue != null) {
-      (element.initializer as FunctionElementImpl).returnType =
-          node.defaultValue.staticType;
-    }
     // Clone the ASTs for default formal parameters, so that we can use them
     // during constant evaluation.
     if (element is ConstVariableElement &&
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 2bd5727..0918c70 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -11,7 +11,6 @@
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_demotion.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
-import 'package:analyzer/src/generated/element_type_provider.dart';
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/summary/format.dart';
 import 'package:analyzer/src/summary/idl.dart';
@@ -197,31 +196,6 @@
   }
 }
 
-class _FunctionElementForLink_Initializer
-    implements FunctionElementImpl, ElementImplWithFunctionType {
-  final _VariableInferenceNode _node;
-
-  @override
-  Element enclosingElement;
-
-  _FunctionElementForLink_Initializer(this._node);
-
-  @override
-  DartType get returnType =>
-      ElementTypeProvider.current.getExecutableReturnType(this);
-
-  @override
-  DartType get returnTypeInternal {
-    if (!_node.isEvaluated) {
-      _node._walker.walk(_node);
-    }
-    return LazyAst.getType(_node._node);
-  }
-
-  @override
-  dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
-
 class _InferenceDependenciesCollector extends RecursiveAstVisitor<void> {
   final Set<Element> _set = Set.identity();
 
@@ -356,14 +330,28 @@
       var inferenceNode =
           _VariableInferenceNode(_walker, _unitElement, _scope, node);
       _walker._nodes[element] = inferenceNode;
-      (element as PropertyInducingElementImpl).initializer =
-          _FunctionElementForLink_Initializer(inferenceNode);
+      (element as PropertyInducingElementImpl).typeInference =
+          _PropertyInducingElementTypeInference(inferenceNode);
     } else {
       LazyAst.setType(node, DynamicTypeImpl.instance);
     }
   }
 }
 
+class _PropertyInducingElementTypeInference
+    implements PropertyInducingElementTypeInference {
+  final _VariableInferenceNode _node;
+
+  _PropertyInducingElementTypeInference(this._node);
+
+  @override
+  void perform() {
+    if (!_node.isEvaluated) {
+      _node._walker.walk(_node);
+    }
+  }
+}
+
 class _VariableInferenceNode extends _InferenceNode {
   final _InferenceWalker _walker;
   final CompilationUnitElement _unitElement;
diff --git a/pkg/analyzer/lib/src/task/strong_mode.dart b/pkg/analyzer/lib/src/task/strong_mode.dart
index d4f9bc9..7e2636a 100644
--- a/pkg/analyzer/lib/src/task/strong_mode.dart
+++ b/pkg/analyzer/lib/src/task/strong_mode.dart
@@ -292,15 +292,7 @@
 
       // Otherwise, declarations of static variables and fields that omit a
       // type will be inferred from their initializer if present.
-      var initializer = field.initializer;
-      if (initializer != null) {
-        var initializerType = initializer.returnType;
-        if (initializerType == null || initializerType.isDartCoreNull) {
-          initializerType = _dynamicType;
-        }
-        field.type = initializerType;
-        return;
-      }
+      field.typeInference?.perform();
 
       return;
     }
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index e2d78c9..ce9a46b 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
 name: analyzer
-version: 0.40.0
+version: 0.40.1-dev
 description: This package provides a library that performs static analysis of Dart code.
 homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
 
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index 33c55da..0aae50a 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -1056,12 +1056,11 @@
     ClassDeclaration c = unit.declarations[0];
     FieldDeclaration declaration = c.members[0];
     VariableDeclaration field = declaration.fields.variables[0];
-    FunctionElement fieldInitializer = field.declaredElement.initializer;
 
     FunctionExpressionInvocation invocation = field.initializer;
     FunctionExpression closure = invocation.function.unParenthesized;
     FunctionElementImpl closureElement = closure.declaredElement;
-    expect(closureElement.enclosingElement, same(fieldInitializer));
+    expect(closureElement, isNotNull);
   }
 
   test_closure_inTopLevelVariable() async {
@@ -1073,13 +1072,11 @@
 
     TopLevelVariableDeclaration declaration = unit.declarations[0];
     VariableDeclaration variable = declaration.variables.variables[0];
-    TopLevelVariableElement variableElement = variable.declaredElement;
-    FunctionElement variableInitializer = variableElement.initializer;
 
     FunctionExpressionInvocation invocation = variable.initializer;
     FunctionExpression closure = invocation.function.unParenthesized;
     FunctionElementImpl closureElement = closure.declaredElement;
-    expect(closureElement.enclosingElement, same(variableInitializer));
+    expect(closureElement, isNotNull);
   }
 
   test_conditionalExpression() async {
diff --git a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
index bc84dbd..970191b 100644
--- a/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
+++ b/pkg/analyzer/test/src/dart/element/generic_inferrer_test.dart
@@ -192,6 +192,27 @@
     );
   }
 
+  void test_fromLegacy_nonNullableBound() {
+    typeSystem = analysisContext.typeSystemLegacy;
+
+    // void Function<T extends Object>(T)
+    var T = typeParameter('T', bound: objectNone);
+    var rawType = functionTypeNone(
+      typeFormals: [T],
+      parameters: [
+        requiredParameter(
+          type: typeParameterTypeNone(T),
+        ),
+      ],
+      returnType: voidNone,
+    );
+
+    _assertTypes(
+      _inferCall(rawType, [dynamicNone]),
+      [dynamicNone],
+    );
+  }
+
   void test_genericCastFunction() {
     // <TFrom, TTo>(TFrom) -> TTo
     var tFrom = typeParameter('TFrom');
diff --git a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
index 73ddb62..951fcbd 100644
--- a/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/could_not_infer_test.dart
@@ -10,6 +10,7 @@
 main() {
   defineReflectiveSuite(() {
     defineReflectiveTests(CouldNotInferTest);
+    defineReflectiveTests(CouldNotInferWithNullSafetyTest);
   });
 }
 
@@ -229,10 +230,10 @@
   U method<U extends T>(U u) => u;
 }
 main() {
-  new Foo<String>()./*error:COULD_NOT_INFER*/method(42);
+  new Foo<String>().method(42);
 }
 ''', [
-      error(CompileTimeErrorCode.COULD_NOT_INFER, 122, 6),
+      error(CompileTimeErrorCode.COULD_NOT_INFER, 97, 6),
     ]);
   }
 
@@ -247,3 +248,24 @@
     ]);
   }
 }
+
+@reflectiveTest
+class CouldNotInferWithNullSafetyTest extends PubPackageResolutionTest
+    with WithNullSafetyMixin {
+  test_constructor_nullSafe_fromLegacy() async {
+    newFile('$testPackageLibPath/a.dart', content: '''
+class C<T extends Object> {
+  C(T t);
+}
+''');
+
+    await assertNoErrorsInCode('''
+// @dart = 2.8
+import 'a.dart';
+
+void f(dynamic a) {
+  C(a);
+}
+''');
+  }
+}
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 43f38c7..3484cc7 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -354,26 +354,19 @@
   }
 
   test_bottom() async {
-    // When a type is inferred from the expression `null`, the inferred type is
-    // `dynamic`, but the inferred type of the initializer is `bottom`.
-    // TODO(paulberry): Is this intentional/desirable?
     await assertNoErrorsInCode('''
 var v = null;
 ''');
     var v = _resultUnitElement.topLevelVariables[0];
     _assertTypeStr(v.type, 'dynamic');
-    _assertTypeStr(v.initializer.type, 'Null Function()');
   }
 
   test_bottom_inClosure() async {
-    // When a closure's return type is inferred from the expression `null`, the
-    // inferred type is `dynamic`.
     await assertNoErrorsInCode('''
 var v = () => null;
 ''');
     var v = _resultUnitElement.topLevelVariables[0];
     _assertTypeStr(v.type, 'Null Function()');
-    _assertTypeStr(v.initializer.type, 'Null Function() Function()');
   }
 
   test_circularReference_viaClosures() async {
@@ -406,8 +399,8 @@
     var y = _resultUnitElement.topLevelVariables[1];
     expect(x.name, 'x');
     expect(y.name, 'y');
-    _assertTypeStr(x.initializer.returnType, 'dynamic Function()');
-    _assertTypeStr(y.initializer.returnType, 'dynamic Function()');
+    _assertTypeStr(x.type, 'dynamic');
+    _assertTypeStr(y.type, 'dynamic');
   }
 
   test_conflictsCanHappen2() async {
@@ -4117,7 +4110,7 @@
     ]);
 
     var y = findLocalVariable(_resultUnit, 'y');
-    _assertTypeStr(y.initializer.returnType, 'List<num>');
+    _assertTypeStr(y.type, 'List<num>');
   }
 
   test_nullLiteralShouldNotInferAsBottom() async {
diff --git a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
index 9dc19fc..8414450 100644
--- a/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
+++ b/pkg/compiler/lib/src/inferrer/abstract_value_domain.dart
@@ -46,6 +46,11 @@
 
   static AbstractBool maybeOrFalse(bool value) => value ? Maybe : False;
 
+  static AbstractBool strengthen(AbstractBool a, AbstractBool b) {
+    //TODO(coam): Assert arguments a and b are consistent
+    return a.isDefinitelyTrue ? True : (a.isDefinitelyFalse ? False : b);
+  }
+
   AbstractBool operator &(AbstractBool other) {
     if (isDefinitelyTrue) return other;
     if (other.isDefinitelyTrue) return this;
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
new file mode 100644
index 0000000..2078d8a
--- /dev/null
+++ b/pkg/compiler/lib/src/inferrer/powersets/powerset_bits.dart
@@ -0,0 +1,326 @@
+// Copyright (c) 2020, 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.
+
+import '../../common_elements.dart' show CommonElements;
+import '../../constants/values.dart';
+import '../../elements/entities.dart';
+import '../../elements/names.dart';
+import '../../elements/types.dart' show DartType, InterfaceType;
+import '../../ir/static_type.dart';
+import '../../universe/selector.dart';
+import '../../world.dart';
+import '../abstract_value_domain.dart';
+
+class PowersetBitsDomain {
+  // This class is used as an API by the powerset abstract value domain to help implement some queries.
+  // It stores the bitmasks as integers and has the advantage that the operations needed
+  // are relatively fast. This will pack multiple powerset domains into a single integer
+
+  final JClosedWorld _closedWorld;
+
+  static const int _trueIndex = 0;
+  static const int _falseIndex = 1;
+  static const int _nullIndex = 2;
+  static const int _otherIndex = 3;
+
+  const PowersetBitsDomain(this._closedWorld);
+
+  CommonElements get commonElements => _closedWorld.commonElements;
+
+  int get trueMask => 1 << _trueIndex;
+  int get falseMask => 1 << _falseIndex;
+  int get nullMask => 1 << _nullIndex;
+  int get otherMask => 1 << _otherIndex;
+  int get boolMask => trueMask | falseMask;
+  int get boolOrNullMask => boolMask | nullMask;
+  int get nullOrOtherMask => nullMask | otherMask;
+  int get boolNullOtherMask => boolOrNullMask | otherMask;
+
+  int get powersetBottom => 0;
+  int get powersetTop => boolNullOtherMask;
+
+  bool isPotentiallyBoolean(int value) => (value & boolMask) != 0;
+  bool isPotentiallyOther(int value) => (value & otherMask) != 0;
+  bool isPotentiallyNull(int value) => (value & nullMask) != 0;
+  bool isPotentiallyBooleanOrNull(int value) => (value & boolOrNullMask) != 0;
+  bool isPotentiallyNullOrOther(int value) => (value & nullOrOtherMask) != 0;
+
+  bool isDefinitelyTrue(int value) => (value & boolNullOtherMask) == trueMask;
+  bool isDefinitelyFalse(int value) => (value & boolNullOtherMask) == falseMask;
+  bool isDefinitelyNull(int value) => (value & boolNullOtherMask) == nullMask;
+  bool isSingleton(int value) =>
+      isDefinitelyTrue(value) ||
+      isDefinitelyFalse(value) ||
+      isDefinitelyNull(value);
+
+  AbstractBool isOther(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+  AbstractBool isNotOther(int value) =>
+      AbstractBool.trueOrMaybe(!isPotentiallyOther(value));
+
+  AbstractBool needsNoSuchMethodHandling(int receiver, Selector selector) =>
+      AbstractBool.Maybe;
+
+  AbstractBool isTargetingMember(
+          int receiver, MemberEntity member, Name name) =>
+      AbstractBool.Maybe;
+
+  int computeReceiver(Iterable<MemberEntity> members) {
+    return powersetTop;
+  }
+
+  // TODO(coam): This currently returns null if we are not sure if it's a primitive.
+  // It could be improved because we can also tell when we're certain it's not a primitive.
+  PrimitiveConstantValue getPrimitiveValue(int value) {
+    if (isDefinitelyTrue(value)) {
+      return TrueConstantValue();
+    }
+    if (isDefinitelyFalse(value)) {
+      return FalseConstantValue();
+    }
+    if (isDefinitelyNull(value)) {
+      return NullConstantValue();
+    }
+    return null;
+  }
+
+  int createPrimitiveValue(PrimitiveConstantValue value) {
+    if (value is TrueConstantValue) {
+      return trueMask;
+    }
+    if (value is FalseConstantValue) {
+      return falseMask;
+    }
+    if (value is NullConstantValue) {
+      return nullMask;
+    }
+    return otherMask;
+  }
+
+  // TODO(coam): Same as getPrimitiveValue above.
+  bool isPrimitiveValue(int value) => isSingleton(value);
+
+  AbstractBool areDisjoint(int a, int b) =>
+      AbstractBool.trueOrMaybe(a & b == powersetBottom);
+
+  int intersection(int a, int b) {
+    return a & b;
+  }
+
+  int union(int a, int b) {
+    return a | b;
+  }
+
+  AbstractBool isPrimitiveOrNull(int value) =>
+      isPrimitive(value) | isNull(value);
+
+  AbstractBool isStringOrNull(int value) => isString(value) | isNull(value);
+
+  AbstractBool isString(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isBooleanOrNull(int value) => isBoolean(value) | isNull(value);
+
+  AbstractBool isBoolean(int value) => isPotentiallyBoolean(value)
+      ? AbstractBool.trueOrMaybe(!isPotentiallyNullOrOther(value))
+      : AbstractBool.False;
+
+  AbstractBool isDoubleOrNull(int value) => isDouble(value) | isNull(value);
+
+  AbstractBool isDouble(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isNumberOrNull(int value) => isNumber(value) | isNull(value);
+
+  AbstractBool isNumber(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isIntegerOrNull(int value) => isDouble(value) | isNull(value);
+
+  AbstractBool isPositiveIntegerOrNull(int value) =>
+      isPositiveInteger(value) | isNull(value);
+
+  AbstractBool isPositiveInteger(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isUInt31(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isUInt32(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isInteger(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isInterceptor(int value) => AbstractBool.Maybe;
+
+  AbstractBool isPrimitiveString(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isMutableIndexable(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isMutableArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isExtendableArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isFixedArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isIndexablePrimitive(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isPrimitiveArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isPrimitiveBoolean(int value) => isPotentiallyBoolean(value)
+      ? AbstractBool.trueOrMaybe(
+          isDefinitelyTrue(value) || isDefinitelyFalse(value))
+      : AbstractBool.False;
+
+  AbstractBool isPrimitiveNumber(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isPrimitive(int value) =>
+      AbstractBool.trueOrMaybe(isSingleton(value));
+
+  AbstractBool isNull(int value) => isDefinitelyNull(value)
+      ? AbstractBool.True
+      : (isPotentiallyNull(value) ? AbstractBool.Maybe : AbstractBool.False);
+
+  AbstractBool isExactOrNull(int value) => AbstractBool.Maybe;
+
+  AbstractBool isExact(int value) => AbstractBool.Maybe;
+
+  AbstractBool isEmpty(int value) =>
+      AbstractBool.trueOrFalse(value == powersetBottom);
+
+  AbstractBool isInstanceOf(int value, ClassEntity cls) => AbstractBool.Maybe;
+
+  AbstractBool isInstanceOfOrNull(int value, ClassEntity cls) =>
+      AbstractBool.Maybe;
+
+  AbstractBool containsOnlyType(int value, ClassEntity cls) =>
+      AbstractBool.Maybe;
+
+  AbstractBool containsType(int value, ClassEntity cls) => AbstractBool.Maybe;
+
+  int includeNull(int value) {
+    return value | nullMask;
+  }
+
+  int excludeNull(int value) {
+    return value & (powersetTop - nullMask);
+  }
+
+  AbstractBool couldBeTypedArray(int value) =>
+      AbstractBool.maybeOrFalse(isPotentiallyOther(value));
+
+  AbstractBool isTypedArray(int value) => AbstractBool.Maybe;
+
+  bool isBoolSubtype(ClassEntity cls) {
+    return cls == commonElements.jsBoolClass || cls == commonElements.boolClass;
+  }
+
+  int createNullableSubtype(ClassEntity cls) {
+    if (isBoolSubtype(cls)) {
+      return boolOrNullMask;
+    }
+    return nullOrOtherMask;
+  }
+
+  int createNonNullSubtype(ClassEntity cls) {
+    if (isBoolSubtype(cls)) {
+      return boolMask;
+    }
+    return otherMask;
+  }
+
+  int createNonNullSubclass(ClassEntity cls) {
+    if (isBoolSubtype(cls)) {
+      return boolMask;
+    }
+    return otherMask;
+  }
+
+  int createNullableExact(ClassEntity cls) {
+    if (isBoolSubtype(cls)) {
+      return boolOrNullMask;
+    }
+    return nullOrOtherMask;
+  }
+
+  int createNonNullExact(ClassEntity cls) {
+    if (isBoolSubtype(cls)) {
+      return boolMask;
+    }
+    return otherMask;
+  }
+
+  int createFromStaticType(DartType type,
+      {ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
+    // TODO(coam): This only works for bool
+    int bits = otherMask;
+    if (type is InterfaceType && isBoolSubtype(type.element)) {
+      bits = boolMask;
+    }
+    if (nullable) {
+      bits = bits | nullMask;
+    }
+    return bits;
+  }
+
+  int get asyncStarStreamType => powersetTop;
+
+  int get asyncFutureType => powersetTop;
+
+  int get syncStarIterableType => powersetTop;
+
+  int get emptyType => powersetBottom;
+
+  int get constMapType => otherMask;
+
+  int get constSetType => otherMask;
+
+  int get constListType => otherMask;
+
+  int get positiveIntType => otherMask;
+
+  int get uint32Type => otherMask;
+
+  int get uint31Type => otherMask;
+
+  int get fixedListType => otherMask;
+
+  int get growableListType => otherMask;
+
+  int get nullType => nullMask;
+
+  int get nonNullType => otherMask;
+
+  int get mapType => otherMask;
+
+  int get setType => otherMask;
+
+  int get listType => otherMask;
+
+  int get stringType => otherMask;
+
+  int get numType => otherMask;
+
+  int get doubleType => otherMask;
+
+  int get intType => otherMask;
+
+  int get boolType => boolMask;
+
+  int get functionType => otherMask;
+
+  int get typeType => otherMask;
+}
diff --git a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
index 60f9253..91eb49a 100644
--- a/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
+++ b/pkg/compiler/lib/src/inferrer/powersets/powersets.dart
@@ -13,12 +13,16 @@
 import '../../universe/use.dart';
 import '../../world.dart';
 import '../abstract_value_domain.dart';
+import 'powerset_bits.dart';
 
 class PowersetValue implements AbstractValue {
   final AbstractValue _abstractValue;
   final int _powersetBits;
   const PowersetValue(this._abstractValue, this._powersetBits);
 
+  AbstractValue get abstractValue => _abstractValue;
+  int get powersetBits => _powersetBits;
+
   @override
   bool operator ==(var other) {
     if (identical(this, other)) return true;
@@ -51,15 +55,19 @@
 
 class PowersetDomain implements AbstractValueDomain {
   final AbstractValueDomain _abstractValueDomain;
-  const PowersetDomain(this._abstractValueDomain);
+  final PowersetBitsDomain _powersetBitsDomain;
+
+  const PowersetDomain(this._abstractValueDomain, this._powersetBitsDomain);
+
+  PowersetBitsDomain get powersetBitsDomain => _powersetBitsDomain;
 
   @override
   AbstractValue get dynamicType {
-    int powersetBits = 0;
     AbstractValue abstractValue = _abstractValueDomain.dynamicType;
-    return PowersetValue(abstractValue, powersetBits);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
+  //TODO(coam)
   @override
   void writeAbstractValueToDataSink(
       DataSink sink, covariant PowersetValue value) {
@@ -67,29 +75,37 @@
         sink, value._abstractValue);
   }
 
+  //TODO(coam)
   @override
   AbstractValue readAbstractValueFromDataSource(DataSource source) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue =
         _abstractValueDomain.readAbstractValueFromDataSource(source);
     return PowersetValue(abstractValue, powersetBits);
   }
 
+  //TODO(coam)
   @override
   String getCompactText(covariant PowersetValue value) =>
       _abstractValueDomain.getCompactText(value._abstractValue);
 
   @override
   AbstractBool isFixedLengthJsIndexable(covariant PowersetValue value) =>
-      _abstractValueDomain.isFixedLengthJsIndexable(value._abstractValue);
+      _powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue
+          ? AbstractBool.False
+          : _abstractValueDomain.isFixedLengthJsIndexable(value._abstractValue);
 
   @override
   AbstractBool isJsIndexableAndIterable(covariant PowersetValue value) =>
-      _abstractValueDomain.isJsIndexableAndIterable(unwrapOrNull(value));
+      _powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue
+          ? AbstractBool.False
+          : _abstractValueDomain.isJsIndexableAndIterable(unwrapOrNull(value));
 
   @override
   AbstractBool isJsIndexable(covariant PowersetValue value) =>
-      _abstractValueDomain.isJsIndexable(value._abstractValue);
+      _powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue
+          ? AbstractBool.False
+          : _abstractValueDomain.isJsIndexable(value._abstractValue);
 
   @override
   MemberEntity locateSingleMember(
@@ -97,10 +113,14 @@
       _abstractValueDomain.locateSingleMember(
           receiver._abstractValue, selector);
 
+  //TODO(coam): for now we are delegating this implementation to the CommonMasks domain
   @override
   AbstractBool isIn(
-          covariant PowersetValue subset, covariant PowersetValue superset) =>
-      _abstractValueDomain.isIn(subset._abstractValue, superset._abstractValue);
+      covariant PowersetValue subset, covariant PowersetValue superset) {
+    AbstractBool wrappedBool = _abstractValueDomain.isIn(
+        subset._abstractValue, superset._abstractValue);
+    return wrappedBool;
+  }
 
   @override
   AbstractBool needsNoSuchMethodHandling(
@@ -116,19 +136,20 @@
 
   @override
   AbstractValue computeReceiver(Iterable<MemberEntity> members) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue = _abstractValueDomain.computeReceiver(members);
     return PowersetValue(abstractValue, powersetBits);
   }
 
   @override
   PrimitiveConstantValue getPrimitiveValue(covariant PowersetValue value) =>
+      _powersetBitsDomain.getPrimitiveValue(value.powersetBits) ??
       _abstractValueDomain.getPrimitiveValue(value._abstractValue);
 
   @override
   AbstractValue createPrimitiveValue(
       covariant PowersetValue originalValue, PrimitiveConstantValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createPrimitiveValue(value);
     AbstractValue abstractValue = _abstractValueDomain.createPrimitiveValue(
         originalValue._abstractValue, value);
     return PowersetValue(abstractValue, powersetBits);
@@ -136,6 +157,7 @@
 
   @override
   bool isPrimitiveValue(covariant PowersetValue value) =>
+      _powersetBitsDomain.isPrimitiveValue(value.powersetBits) ||
       _abstractValueDomain.isPrimitiveValue(value._abstractValue);
 
   @override
@@ -148,7 +170,7 @@
 
   @override
   AbstractValue getGeneralization(covariant PowersetValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue =
         _abstractValueDomain.getGeneralization(unwrapOrNull(value));
     return PowersetValue(abstractValue, powersetBits);
@@ -163,14 +185,17 @@
   @override
   AbstractValue getDictionaryValueForKey(
       covariant PowersetValue value, String key) {
-    int powersetBits = 0;
+    if (_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue) {
+      return dynamicType;
+    }
     AbstractValue abstractValue = _abstractValueDomain.getDictionaryValueForKey(
         value._abstractValue, key);
-    return PowersetValue(abstractValue, powersetBits);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
   @override
   bool containsDictionaryKey(covariant PowersetValue value, String key) =>
+      _powersetBitsDomain.isNotOther(value._powersetBits).isPotentiallyFalse &&
       _abstractValueDomain.containsDictionaryKey(value._abstractValue, key);
 
   @override
@@ -181,7 +206,7 @@
       covariant PowersetValue key,
       covariant PowersetValue value,
       covariant Map<String, AbstractValue> mappings) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.otherMask;
     AbstractValue abstractValue = _abstractValueDomain.createDictionaryValue(
         originalValue._abstractValue,
         allocationNode,
@@ -196,22 +221,27 @@
 
   @override
   bool isDictionary(covariant PowersetValue value) =>
+      !_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue &&
       _abstractValueDomain.isDictionary(value._abstractValue);
 
   @override
   AbstractValue getMapValueType(covariant PowersetValue value) {
-    int powersetBits = 0;
+    if (_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue) {
+      return dynamicType;
+    }
     AbstractValue abstractValue =
         _abstractValueDomain.getMapValueType(value._abstractValue);
-    return PowersetValue(abstractValue, powersetBits);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
   @override
   AbstractValue getMapKeyType(covariant PowersetValue value) {
-    int powersetBits = 0;
+    if (_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue) {
+      return dynamicType;
+    }
     AbstractValue abstractValue =
-        _abstractValueDomain.getMapKeyType(value._abstractValue);
-    return PowersetValue(abstractValue, powersetBits);
+        _abstractValueDomain.getMapValueType(value._abstractValue);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
   @override
@@ -221,7 +251,7 @@
       MemberEntity allocationElement,
       covariant PowersetValue key,
       covariant PowersetValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.otherMask;
     AbstractValue abstractValue = _abstractValueDomain.createMapValue(
         originalValue._abstractValue,
         allocationNode,
@@ -233,14 +263,17 @@
 
   @override
   bool isMap(covariant PowersetValue value) =>
+      !_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue &&
       _abstractValueDomain.isMap(value._abstractValue);
 
   @override
   AbstractValue getSetElementType(covariant PowersetValue value) {
-    int powersetBits = 0;
+    if (_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue) {
+      return dynamicType;
+    }
     AbstractValue abstractValue =
         _abstractValueDomain.getSetElementType(value._abstractValue);
-    return PowersetValue(abstractValue, powersetBits);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
   @override
@@ -249,7 +282,7 @@
       Object allocationNode,
       MemberEntity allocationElement,
       covariant PowersetValue elementType) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.otherMask;
     AbstractValue abstractValue = _abstractValueDomain.createSetValue(
         originalValue._abstractValue,
         allocationNode,
@@ -260,18 +293,23 @@
 
   @override
   bool isSet(covariant PowersetValue value) =>
+      !_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue &&
       _abstractValueDomain.isSet(value._abstractValue);
 
   @override
   int getContainerLength(covariant PowersetValue value) =>
-      _abstractValueDomain.getContainerLength(value._abstractValue);
+      _powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue
+          ? null
+          : _abstractValueDomain.getContainerLength(value._abstractValue);
 
   @override
   AbstractValue getContainerElementType(covariant PowersetValue value) {
-    int powersetBits = 0;
+    if (_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue) {
+      return dynamicType;
+    }
     AbstractValue abstractValue =
         _abstractValueDomain.getContainerElementType(value._abstractValue);
-    return PowersetValue(abstractValue, powersetBits);
+    return PowersetValue(abstractValue, _powersetBitsDomain.powersetTop);
   }
 
   @override
@@ -281,7 +319,7 @@
       MemberEntity allocationElement,
       covariant PowersetValue elementType,
       int length) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.otherMask;
     AbstractValue abstractValue = _abstractValueDomain.createContainerValue(
         originalValue._abstractValue,
         allocationNode,
@@ -293,11 +331,14 @@
 
   @override
   bool isContainer(covariant PowersetValue value) =>
+      !_powersetBitsDomain.isNotOther(value._powersetBits).isDefinitelyTrue &&
       _abstractValueDomain.isContainer(value._abstractValue);
 
+  // TODO(coam): this can be more precise if we build a ConstantValue visitor
+  // that can tell us information about the bits given a ConstantValue
   @override
   AbstractValue computeAbstractValueForConstant(covariant ConstantValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue =
         _abstractValueDomain.computeAbstractValueForConstant(value);
     return PowersetValue(abstractValue, powersetBits);
@@ -305,7 +346,7 @@
 
   @override
   AbstractValue getAbstractValueForNativeMethodParameterType(DartType type) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.powersetTop;
     AbstractValue abstractValue =
         _abstractValueDomain.getAbstractValueForNativeMethodParameterType(type);
     return wrapOrNull(abstractValue, powersetBits);
@@ -313,17 +354,22 @@
 
   @override
   AbstractBool containsAll(covariant PowersetValue a) =>
-      _abstractValueDomain.containsAll(a._abstractValue);
+      a._powersetBits != _powersetBitsDomain.powersetTop
+          ? AbstractBool.False
+          : _abstractValueDomain.containsAll(a._abstractValue);
 
   @override
   AbstractBool areDisjoint(
           covariant PowersetValue a, covariant PowersetValue b) =>
-      _abstractValueDomain.areDisjoint(a._abstractValue, b._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.areDisjoint(a._powersetBits, b._powersetBits),
+          _abstractValueDomain.areDisjoint(a._abstractValue, b._abstractValue));
 
   @override
   AbstractValue intersection(
       covariant PowersetValue a, covariant PowersetValue b) {
-    int powersetBits = 0;
+    int powersetBits =
+        _powersetBitsDomain.intersection(a._powersetBits, b._powersetBits);
     AbstractValue abstractValue =
         _abstractValueDomain.intersection(a._abstractValue, b._abstractValue);
     return PowersetValue(abstractValue, powersetBits);
@@ -331,18 +377,18 @@
 
   @override
   AbstractValue unionOfMany(covariant Iterable<AbstractValue> values) {
-    List<AbstractValue> unwrapped_Values = values
-        .map((element) => (element as PowersetValue)._abstractValue)
-        .toList();
-    int powersetBits = 0;
-    AbstractValue abstractValue =
-        _abstractValueDomain.unionOfMany(unwrapped_Values);
-    return PowersetValue(abstractValue, powersetBits);
+    PowersetValue result = PowersetValue(
+        _abstractValueDomain.emptyType, _powersetBitsDomain.powersetBottom);
+    for (PowersetValue value in values) {
+      result = union(result, value);
+    }
+    return result;
   }
 
   @override
   AbstractValue union(covariant PowersetValue a, covariant PowersetValue b) {
-    int powersetBits = 0;
+    int powersetBits =
+        _powersetBitsDomain.union(a._powersetBits, b._powersetBits);
     AbstractValue abstractValue =
         _abstractValueDomain.union(a._abstractValue, b._abstractValue);
     return PowersetValue(abstractValue, powersetBits);
@@ -350,115 +396,164 @@
 
   @override
   AbstractBool isPrimitiveOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitiveOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitiveOrNull(value._powersetBits),
+          _abstractValueDomain.isPrimitiveOrNull(value._abstractValue));
 
   @override
   AbstractBool isStringOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isStringOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isStringOrNull(value._powersetBits),
+          _abstractValueDomain.isStringOrNull(value._abstractValue));
 
   @override
   AbstractBool isString(covariant PowersetValue value) =>
-      _abstractValueDomain.isString(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isString(value._powersetBits),
+          _abstractValueDomain.isString(value._abstractValue));
 
   @override
   AbstractBool isBooleanOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isBooleanOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isBooleanOrNull(value._powersetBits),
+          _abstractValueDomain.isBooleanOrNull(value._abstractValue));
 
   @override
   AbstractBool isBoolean(covariant PowersetValue value) =>
-      _abstractValueDomain.isBoolean(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isBoolean(value._powersetBits),
+          _abstractValueDomain.isBoolean(value._abstractValue));
 
   @override
   AbstractBool isDoubleOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isDoubleOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isDoubleOrNull(value._powersetBits),
+          _abstractValueDomain.isDoubleOrNull(value._abstractValue));
 
   @override
   AbstractBool isDouble(covariant PowersetValue value) =>
-      _abstractValueDomain.isDouble(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isDouble(value._powersetBits),
+          _abstractValueDomain.isDouble(value._abstractValue));
 
   @override
   AbstractBool isNumberOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isNumberOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isNumberOrNull(value._powersetBits),
+          _abstractValueDomain.isNumberOrNull(value._abstractValue));
 
   @override
   AbstractBool isNumber(covariant PowersetValue value) =>
-      _abstractValueDomain.isNumber(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isNumber(value._powersetBits),
+          _abstractValueDomain.isNumber(value._abstractValue));
 
   @override
   AbstractBool isIntegerOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isIntegerOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isIntegerOrNull(value._powersetBits),
+          _abstractValueDomain.isIntegerOrNull(value._abstractValue));
 
   @override
   AbstractBool isPositiveIntegerOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isPositiveIntegerOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPositiveIntegerOrNull(value._powersetBits),
+          _abstractValueDomain.isPositiveIntegerOrNull(value._abstractValue));
 
   @override
   AbstractBool isPositiveInteger(covariant PowersetValue value) =>
-      _abstractValueDomain.isPositiveInteger(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPositiveInteger(value._powersetBits),
+          _abstractValueDomain.isPositiveInteger(value._abstractValue));
 
   @override
   AbstractBool isUInt31(covariant PowersetValue value) =>
-      _abstractValueDomain.isUInt31(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isUInt31(value._powersetBits),
+          _abstractValueDomain.isUInt31(value._abstractValue));
 
   @override
   AbstractBool isUInt32(covariant PowersetValue value) =>
-      _abstractValueDomain.isUInt32(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isUInt32(value._powersetBits),
+          _abstractValueDomain.isUInt32(value._abstractValue));
 
   @override
   AbstractBool isInteger(covariant PowersetValue value) =>
-      _abstractValueDomain.isInteger(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isInteger(value._powersetBits),
+          _abstractValueDomain.isInteger(value._abstractValue));
 
   @override
   AbstractBool isInterceptor(covariant PowersetValue value) =>
-      _abstractValueDomain.isInterceptor(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isInterceptor(value._powersetBits),
+          _abstractValueDomain.isInterceptor(value._abstractValue));
 
   @override
   AbstractBool isPrimitiveString(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitiveString(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitiveString(value._powersetBits),
+          _abstractValueDomain.isPrimitiveString(value._abstractValue));
 
   @override
   AbstractBool isArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isArray(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isArray(value._powersetBits),
+          _abstractValueDomain.isArray(value._abstractValue));
 
   @override
   AbstractBool isMutableIndexable(covariant PowersetValue value) =>
-      _abstractValueDomain.isMutableIndexable(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isMutableIndexable(value._powersetBits),
+          _abstractValueDomain.isMutableIndexable(value._abstractValue));
 
   @override
   AbstractBool isMutableArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isMutableArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isMutableArray(value._powersetBits),
+          _abstractValueDomain.isMutableArray(value._abstractValue));
 
   @override
   AbstractBool isExtendableArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isExtendableArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isExtendableArray(value._powersetBits),
+          _abstractValueDomain.isExtendableArray(value._abstractValue));
 
   @override
   AbstractBool isFixedArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isFixedArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isFixedArray(value._powersetBits),
+          _abstractValueDomain.isFixedArray(value._abstractValue));
 
   @override
   AbstractBool isIndexablePrimitive(covariant PowersetValue value) =>
-      _abstractValueDomain.isIndexablePrimitive(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isIndexablePrimitive(value._powersetBits),
+          _abstractValueDomain.isIndexablePrimitive(value._abstractValue));
 
   @override
   AbstractBool isPrimitiveArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitiveArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitiveArray(value._powersetBits),
+          _abstractValueDomain.isPrimitiveArray(value._abstractValue));
 
   @override
   AbstractBool isPrimitiveBoolean(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitiveBoolean(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitiveBoolean(value._powersetBits),
+          _abstractValueDomain.isPrimitiveBoolean(value._abstractValue));
 
   @override
   AbstractBool isPrimitiveNumber(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitiveNumber(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitiveNumber(value._powersetBits),
+          _abstractValueDomain.isPrimitiveNumber(value._abstractValue));
 
   @override
   AbstractBool isPrimitive(covariant PowersetValue value) =>
-      _abstractValueDomain.isPrimitive(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isPrimitive(value._powersetBits),
+          _abstractValueDomain.isPrimitive(value._abstractValue));
 
   @override
-  AbstractBool isNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isNull(value._abstractValue);
+  AbstractBool isNull(covariant PowersetValue value) => AbstractBool.strengthen(
+      _powersetBitsDomain.isNull(value._powersetBits),
+      _abstractValueDomain.isNull(value._abstractValue));
 
   @override
   ClassEntity getExactClass(covariant PowersetValue value) =>
@@ -466,37 +561,50 @@
 
   @override
   AbstractBool isExactOrNull(covariant PowersetValue value) =>
-      _abstractValueDomain.isExactOrNull(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isExactOrNull(value._powersetBits),
+          _abstractValueDomain.isExactOrNull(value._abstractValue));
 
   @override
   AbstractBool isExact(covariant PowersetValue value) =>
-      _abstractValueDomain.isExact(value._abstractValue);
+      AbstractBool.strengthen(_powersetBitsDomain.isExact(value._powersetBits),
+          _abstractValueDomain.isExact(value._abstractValue));
 
+  // TODO(coam): For now we delegate this to the CommonMasks domain
   @override
-  AbstractBool isEmpty(covariant PowersetValue value) =>
-      _abstractValueDomain.isEmpty(value._abstractValue);
+  AbstractBool isEmpty(covariant PowersetValue value) {
+    return _abstractValueDomain.isEmpty(value._abstractValue);
+  }
 
   @override
   AbstractBool isInstanceOf(covariant PowersetValue value, ClassEntity cls) =>
-      _abstractValueDomain.isInstanceOf(value._abstractValue, cls);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isInstanceOf(value._powersetBits, cls),
+          _abstractValueDomain.isInstanceOf(value._abstractValue, cls));
 
   @override
   AbstractBool isInstanceOfOrNull(
           covariant PowersetValue value, ClassEntity cls) =>
-      _abstractValueDomain.isInstanceOfOrNull(value._abstractValue, cls);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isInstanceOfOrNull(value._powersetBits, cls),
+          _abstractValueDomain.isInstanceOfOrNull(value._abstractValue, cls));
 
   @override
   AbstractBool containsOnlyType(
           covariant PowersetValue value, ClassEntity cls) =>
-      _abstractValueDomain.containsOnlyType(value._abstractValue, cls);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.containsOnlyType(value._powersetBits, cls),
+          _abstractValueDomain.containsOnlyType(value._abstractValue, cls));
 
   @override
   AbstractBool containsType(covariant PowersetValue value, ClassEntity cls) =>
-      _abstractValueDomain.containsType(value._abstractValue, cls);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.containsType(value._powersetBits, cls),
+          _abstractValueDomain.containsType(value._abstractValue, cls));
 
   @override
   AbstractValue includeNull(covariant PowersetValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.includeNull(value._powersetBits);
     AbstractValue abstractValue =
         _abstractValueDomain.includeNull(value._abstractValue);
     return PowersetValue(abstractValue, powersetBits);
@@ -504,7 +612,7 @@
 
   @override
   AbstractValue excludeNull(covariant PowersetValue value) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.excludeNull(value._powersetBits);
     AbstractValue abstractValue =
         _abstractValueDomain.excludeNull(value._abstractValue);
     return PowersetValue(abstractValue, powersetBits);
@@ -512,15 +620,19 @@
 
   @override
   AbstractBool couldBeTypedArray(covariant PowersetValue value) =>
-      _abstractValueDomain.couldBeTypedArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.couldBeTypedArray(value._powersetBits),
+          _abstractValueDomain.couldBeTypedArray(value._abstractValue));
 
   @override
   AbstractBool isTypedArray(covariant PowersetValue value) =>
-      _abstractValueDomain.isTypedArray(value._abstractValue);
+      AbstractBool.strengthen(
+          _powersetBitsDomain.isTypedArray(value._powersetBits),
+          _abstractValueDomain.isTypedArray(value._abstractValue));
 
   @override
   AbstractValue createNullableSubtype(ClassEntity cls) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createNullableSubtype(cls);
     AbstractValue abstractValue =
         _abstractValueDomain.createNullableSubtype(cls);
     return PowersetValue(abstractValue, powersetBits);
@@ -528,7 +640,7 @@
 
   @override
   AbstractValue createNonNullSubtype(ClassEntity cls) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createNonNullSubtype(cls);
     AbstractValue abstractValue =
         _abstractValueDomain.createNonNullSubtype(cls);
     return PowersetValue(abstractValue, powersetBits);
@@ -536,7 +648,7 @@
 
   @override
   AbstractValue createNonNullSubclass(ClassEntity cls) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createNonNullSubclass(cls);
     AbstractValue abstractValue =
         _abstractValueDomain.createNonNullSubclass(cls);
     return PowersetValue(abstractValue, powersetBits);
@@ -544,14 +656,14 @@
 
   @override
   AbstractValue createNullableExact(ClassEntity cls) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createNullableExact(cls);
     AbstractValue abstractValue = _abstractValueDomain.createNullableExact(cls);
     return PowersetValue(abstractValue, powersetBits);
   }
 
   @override
   AbstractValue createNonNullExact(ClassEntity cls) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createNonNullExact(cls);
     AbstractValue abstractValue = _abstractValueDomain.createNonNullExact(cls);
     return PowersetValue(abstractValue, powersetBits);
   }
@@ -559,7 +671,8 @@
   @override
   AbstractValueWithPrecision createFromStaticType(DartType type,
       {ClassRelation classRelation = ClassRelation.subtype, bool nullable}) {
-    int powersetBits = 0;
+    int powersetBits = _powersetBitsDomain.createFromStaticType(type,
+        classRelation: classRelation, nullable: nullable);
     var unwrapped = _abstractValueDomain.createFromStaticType(type,
         classRelation: classRelation, nullable: nullable);
     return AbstractValueWithPrecision(
@@ -568,92 +681,105 @@
   }
 
   @override
-  AbstractValue get asyncStarStreamType =>
-      PowersetValue(_abstractValueDomain.asyncStarStreamType, 0);
+  AbstractValue get asyncStarStreamType => PowersetValue(
+      _abstractValueDomain.asyncStarStreamType,
+      _powersetBitsDomain.asyncStarStreamType);
 
   @override
-  AbstractValue get asyncFutureType =>
-      PowersetValue(_abstractValueDomain.asyncFutureType, 0);
+  AbstractValue get asyncFutureType => PowersetValue(
+      _abstractValueDomain.asyncFutureType,
+      _powersetBitsDomain.asyncFutureType);
 
   @override
-  AbstractValue get syncStarIterableType =>
-      PowersetValue(_abstractValueDomain.syncStarIterableType, 0);
+  AbstractValue get syncStarIterableType => PowersetValue(
+      _abstractValueDomain.syncStarIterableType,
+      _powersetBitsDomain.syncStarIterableType);
 
   @override
-  AbstractValue get emptyType =>
-      PowersetValue(_abstractValueDomain.emptyType, 0);
+  AbstractValue get emptyType => PowersetValue(
+      _abstractValueDomain.emptyType, _powersetBitsDomain.emptyType);
 
   @override
-  AbstractValue get constMapType =>
-      PowersetValue(_abstractValueDomain.constMapType, 0);
+  AbstractValue get constMapType => PowersetValue(
+      _abstractValueDomain.constMapType, _powersetBitsDomain.constMapType);
 
   @override
-  AbstractValue get constSetType =>
-      PowersetValue(_abstractValueDomain.constSetType, 0);
+  AbstractValue get constSetType => PowersetValue(
+      _abstractValueDomain.constSetType, _powersetBitsDomain.constSetType);
 
   @override
-  AbstractValue get constListType =>
-      PowersetValue(_abstractValueDomain.constListType, 0);
+  AbstractValue get constListType => PowersetValue(
+      _abstractValueDomain.constListType, _powersetBitsDomain.constListType);
 
   @override
-  AbstractValue get positiveIntType =>
-      PowersetValue(_abstractValueDomain.positiveIntType, 0);
+  AbstractValue get positiveIntType => PowersetValue(
+      _abstractValueDomain.positiveIntType,
+      _powersetBitsDomain.positiveIntType);
 
   @override
-  AbstractValue get uint32Type =>
-      PowersetValue(_abstractValueDomain.uint32Type, 0);
+  AbstractValue get uint32Type => PowersetValue(
+      _abstractValueDomain.uint32Type, _powersetBitsDomain.uint32Type);
 
   @override
-  AbstractValue get uint31Type =>
-      PowersetValue(_abstractValueDomain.uint31Type, 0);
+  AbstractValue get uint31Type => PowersetValue(
+      _abstractValueDomain.uint31Type, _powersetBitsDomain.uint31Type);
 
   @override
-  AbstractValue get fixedListType =>
-      PowersetValue(_abstractValueDomain.fixedListType, 0);
+  AbstractValue get fixedListType => PowersetValue(
+      _abstractValueDomain.fixedListType, _powersetBitsDomain.fixedListType);
 
   @override
-  AbstractValue get growableListType =>
-      PowersetValue(_abstractValueDomain.growableListType, 0);
+  AbstractValue get growableListType => PowersetValue(
+      _abstractValueDomain.growableListType,
+      _powersetBitsDomain.growableListType);
 
   @override
-  AbstractValue get nullType => PowersetValue(_abstractValueDomain.nullType, 0);
+  AbstractValue get nullType => PowersetValue(
+      _abstractValueDomain.nullType, _powersetBitsDomain.nullType);
 
   @override
-  AbstractValue get nonNullType =>
-      PowersetValue(_abstractValueDomain.nonNullType, 0);
+  AbstractValue get nonNullType => PowersetValue(
+      _abstractValueDomain.nonNullType, _powersetBitsDomain.nonNullType);
 
   @override
-  AbstractValue get mapType => PowersetValue(_abstractValueDomain.mapType, 0);
+  AbstractValue get mapType =>
+      PowersetValue(_abstractValueDomain.mapType, _powersetBitsDomain.mapType);
 
   @override
-  AbstractValue get setType => PowersetValue(_abstractValueDomain.setType, 0);
+  AbstractValue get setType =>
+      PowersetValue(_abstractValueDomain.setType, _powersetBitsDomain.setType);
 
   @override
-  AbstractValue get listType => PowersetValue(_abstractValueDomain.listType, 0);
+  AbstractValue get listType => PowersetValue(
+      _abstractValueDomain.listType, _powersetBitsDomain.listType);
 
   @override
-  AbstractValue get stringType =>
-      PowersetValue(_abstractValueDomain.stringType, 0);
+  AbstractValue get stringType => PowersetValue(
+      _abstractValueDomain.stringType, _powersetBitsDomain.stringType);
 
   @override
-  AbstractValue get numType => PowersetValue(_abstractValueDomain.numType, 0);
+  AbstractValue get numType =>
+      PowersetValue(_abstractValueDomain.numType, _powersetBitsDomain.numType);
 
   @override
-  AbstractValue get doubleType =>
-      PowersetValue(_abstractValueDomain.doubleType, 0);
+  AbstractValue get doubleType => PowersetValue(
+      _abstractValueDomain.doubleType, _powersetBitsDomain.doubleType);
 
   @override
-  AbstractValue get intType => PowersetValue(_abstractValueDomain.intType, 0);
+  AbstractValue get intType =>
+      PowersetValue(_abstractValueDomain.intType, _powersetBitsDomain.intType);
 
   @override
-  AbstractValue get boolType => PowersetValue(_abstractValueDomain.boolType, 0);
+  AbstractValue get boolType => PowersetValue(
+      _abstractValueDomain.boolType, _powersetBitsDomain.boolType);
 
   @override
-  AbstractValue get functionType =>
-      PowersetValue(_abstractValueDomain.functionType, 0);
+  AbstractValue get functionType => PowersetValue(
+      _abstractValueDomain.functionType, _powersetBitsDomain.functionType);
 
   @override
-  AbstractValue get typeType => PowersetValue(_abstractValueDomain.typeType, 0);
+  AbstractValue get typeType => PowersetValue(
+      _abstractValueDomain.typeType, _powersetBitsDomain.typeType);
 }
 
 class PowersetStrategy implements AbstractValueStrategy {
@@ -662,7 +788,8 @@
 
   @override
   AbstractValueDomain createDomain(JClosedWorld closedWorld) {
-    return PowersetDomain(_abstractValueStrategy.createDomain(closedWorld));
+    return PowersetDomain(_abstractValueStrategy.createDomain(closedWorld),
+        PowersetBitsDomain(closedWorld));
   }
 
   @override
diff --git a/pkg/compiler/test/inference/powerset_bits_test.dart b/pkg/compiler/test/inference/powerset_bits_test.dart
new file mode 100644
index 0000000..4e37897
--- /dev/null
+++ b/pkg/compiler/test/inference/powerset_bits_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2020, 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.
+
+// @dart = 2.7
+
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/common.dart';
+import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/inferrer/powersets/powersets.dart';
+import 'package:compiler/src/inferrer/powersets/powerset_bits.dart';
+import 'package:compiler/src/world.dart';
+import 'package:expect/expect.dart';
+import '../helpers/element_lookup.dart';
+import '../helpers/memory_compiler.dart';
+
+const String CODE = """
+var a = true;
+var b = true;
+var c = true;
+var d = true;
+var e = func();
+
+bool func() {
+  return false;
+}
+
+main() {
+  b = func();
+  c = b && a;
+  d = a || b;
+  e = false;
+}
+""";
+
+main() {
+  retainDataForTesting = true;
+
+  runTests() async {
+    CompilationResult result = await runCompiler(
+        memorySourceFiles: {'main.dart': CODE},
+        options: ['--experimental-powersets']);
+    Expect.isTrue(result.isSuccess);
+    Compiler compiler = result.compiler;
+    var results = compiler.globalInference.resultsForTesting;
+    JClosedWorld closedWorld = results.closedWorld;
+    PowersetDomain powersetDomain = closedWorld.abstractValueDomain;
+    PowersetBitsDomain powersetBitsDomain = powersetDomain.powersetBitsDomain;
+
+    checkBits(String name, bits) {
+      var element = findMember(closedWorld, name);
+      PowersetValue mask = results.resultOfMember(element).type;
+      Expect.equals(bits, mask.powersetBits);
+    }
+
+    checkBits('a', powersetBitsDomain.trueMask);
+    checkBits('b', powersetBitsDomain.boolMask);
+    checkBits('c', powersetBitsDomain.boolMask);
+    checkBits('d', powersetBitsDomain.boolMask);
+    checkBits('e', powersetBitsDomain.falseMask | powersetBitsDomain.nullMask);
+  }
+
+  asyncTest(() async {
+    print('--test from kernel------------------------------------------------');
+    await runTests();
+  });
+}
diff --git a/pkg/dev_compiler/pubspec.yaml b/pkg/dev_compiler/pubspec.yaml
index f77f40f..48ed14f 100644
--- a/pkg/dev_compiler/pubspec.yaml
+++ b/pkg/dev_compiler/pubspec.yaml
@@ -33,6 +33,7 @@
     path: ../modular_test
   package_config: any
   pedantic: ^1.8.0
+  pub_semver: any
   sourcemap_testing:
     path: ../sourcemap_testing
   stack_trace: any
diff --git a/pkg/kernel/pubspec.yaml b/pkg/kernel/pubspec.yaml
index 6713b64..1732869 100644
--- a/pkg/kernel/pubspec.yaml
+++ b/pkg/kernel/pubspec.yaml
@@ -8,9 +8,9 @@
 environment:
   sdk: '>=2.2.2 <3.0.0'
 dependencies:
-  args: '>=0.13.4 <2.0.0'
   meta: ^1.0.0
 dev_dependencies:
+  args: '>=0.13.4 <2.0.0'
   expect:
     path: ../expect
   front_end:
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index 187ffff..387d666 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -266,6 +266,7 @@
   fieldFormalParameter,
   fieldNotInitialized,
   forEachVariable,
+  getterSetterCorrespondence,
   greatestLowerBound,
   ifNull,
   implicitMixinSuperCall,
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index af3f31d..a376634 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -838,6 +838,23 @@
         _flowAnalysis = null;
         _assignedVariables = null;
       }
+      var declaredElement = node.declaredElement;
+      if (declaredElement is PropertyAccessorElement) {
+        if (declaredElement.isGetter) {
+          var setter = declaredElement.correspondingSetter;
+          if (setter != null) {
+            _handleGetterSetterCorrespondence(
+                node, null, declaredElement, setter.declaration);
+          }
+        } else {
+          assert(declaredElement.isSetter);
+          var getter = declaredElement.correspondingGetter;
+          if (getter != null) {
+            _handleGetterSetterCorrespondence(
+                node, null, getter.declaration, declaredElement);
+          }
+        }
+      }
     }
     return null;
   }
@@ -2341,6 +2358,63 @@
             _handleExecutableOverriddenDeclaration(node, returnType, parameters,
                 enclosingElement, overriddenElement);
           }
+          if (declaredElement is PropertyAccessorElement) {
+            if (declaredElement.isGetter) {
+              var setters = [declaredElement.correspondingSetter];
+              if (setters[0] == null && !declaredElement.isStatic) {
+                // No corresponding setter in this class; look for inherited
+                // setters.
+                var getterName = declaredElement.name;
+                var setterName = '$getterName=';
+                var inheritedMembers = _inheritanceManager.getOverridden2(
+                    enclosingElement,
+                    Name(enclosingElement.library.source.uri, setterName));
+                if (inheritedMembers != null) {
+                  setters = [
+                    for (var setter in inheritedMembers)
+                      if (setter is PropertyAccessorElement) setter
+                  ];
+                }
+              }
+              for (var setter in setters) {
+                if (setter != null) {
+                  _handleGetterSetterCorrespondence(
+                      node,
+                      declaredElement.isStatic ? null : enclosingElement,
+                      declaredElement,
+                      setter.declaration);
+                }
+              }
+            } else {
+              assert(declaredElement.isSetter);
+              assert(declaredElement.name.endsWith('='));
+              var getters = [declaredElement.correspondingGetter];
+              if (getters[0] == null && !declaredElement.isStatic) {
+                // No corresponding getter in this class; look for inherited
+                // getters.
+                var setterName = declaredElement.name;
+                var getterName = setterName.substring(0, setterName.length - 1);
+                var inheritedMembers = _inheritanceManager.getOverridden2(
+                    enclosingElement,
+                    Name(enclosingElement.library.source.uri, getterName));
+                if (inheritedMembers != null) {
+                  getters = [
+                    for (var getter in inheritedMembers)
+                      if (getter is PropertyAccessorElement) getter
+                  ];
+                }
+              }
+              for (var getter in getters) {
+                if (getter != null) {
+                  _handleGetterSetterCorrespondence(
+                      node,
+                      declaredElement.isStatic ? null : enclosingElement,
+                      getter.declaration,
+                      declaredElement);
+                }
+              }
+            }
+          }
         }
       }
       _flowAnalysis.finish();
@@ -2566,6 +2640,48 @@
     });
   }
 
+  void _handleGetterSetterCorrespondence(Declaration node, ClassElement class_,
+      PropertyAccessorElement getter, PropertyAccessorElement setter) {
+    DecoratedType getType;
+    if (getter.isSynthetic) {
+      var field = getter.variable;
+      if (field == null || field.isSynthetic) return;
+      getType = _variables.decoratedElementType(field);
+    } else {
+      getType = _variables.decoratedElementType(getter).returnType;
+    }
+    DecoratedType setType;
+    if (setter.isSynthetic) {
+      var field = setter.variable;
+      if (field == null || field.isSynthetic) return;
+      setType = _variables.decoratedElementType(field);
+    } else {
+      setType =
+          _variables.decoratedElementType(setter).positionalParameters.single;
+    }
+    Map<TypeParameterElement, DecoratedType> getterSubstitution = const {};
+    Map<TypeParameterElement, DecoratedType> setterSubstitution = const {};
+    if (class_ != null) {
+      var getterClass = getter.enclosingElement as ClassElement;
+      if (!identical(class_, getterClass)) {
+        getterSubstitution = _decoratedClassHierarchy
+            .getDecoratedSupertype(class_, getterClass)
+            .asSubstitution;
+      }
+      var setterClass = setter.enclosingElement as ClassElement;
+      if (!identical(class_, setterClass)) {
+        setterSubstitution = _decoratedClassHierarchy
+            .getDecoratedSupertype(class_, setterClass)
+            .asSubstitution;
+      }
+    }
+    _checkAssignment(
+        GetterSetterCorrespondenceOrigin(source, node), FixReasonTarget.root,
+        source: getType.substitute(getterSubstitution),
+        destination: setType.substitute(setterSubstitution),
+        hard: true);
+  }
+
   /// Instantiate [type] with [argumentTypes], assigning [argumentTypes] to
   /// [bounds].
   DecoratedType _handleInstantiation(DecoratedType type,
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 4c43bf7..61c6837 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -64,6 +64,27 @@
   EdgeOriginKind get kind => EdgeOriginKind.alwaysNullableType;
 }
 
+/// Edge origin resulting from the presence of a call to
+/// `ArgumentError.checkNotNull`.
+///
+/// For example, in the following code snippet:
+///   void f(int i) {
+///     ArgumentError.checkNotNull(i);
+///   }
+///
+/// this class is used for the edge connecting the type of f's `i` parameter to
+/// `never`, due to the `checkNotNull` call proclaiming that `i` is not `null`.
+class ArgumentErrorCheckNotNullOrigin extends EdgeOrigin {
+  ArgumentErrorCheckNotNullOrigin(Source source, SimpleIdentifier node)
+      : super(source, node);
+
+  @override
+  String get description => 'value checked to be non-null';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.argumentErrorCheckNotNull;
+}
+
 /// Edge origin resulting from the use of a value on the LHS of a compound
 /// assignment.
 class CompoundAssignmentOrigin extends EdgeOrigin {
@@ -80,6 +101,18 @@
   AssignmentExpression get node => super.node as AssignmentExpression;
 }
 
+/// Edge origin resulting from the use of an element which does not affect the
+/// nullability graph in other ways.
+class DummyOrigin extends EdgeOrigin {
+  DummyOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  String get description => 'dummy';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.dummy;
+}
+
 /// An edge origin used for edges that originated because of an assignment
 /// involving a value with a dynamic type.
 class DynamicAssignmentOrigin extends EdgeOrigin {
@@ -184,6 +217,18 @@
   EdgeOriginKind get kind => EdgeOriginKind.forEachVariable;
 }
 
+/// Edge origin resulting from the relationship between a getter and a setter.
+class GetterSetterCorrespondenceOrigin extends EdgeOrigin {
+  GetterSetterCorrespondenceOrigin(Source source, AstNode node)
+      : super(source, node);
+
+  @override
+  String get description => 'getter/setter correspondence';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.getterSetterCorrespondence;
+}
+
 /// Edge origin resulting from the use of greatest lower bound.
 ///
 /// For example, in the following code snippet:
@@ -430,49 +475,6 @@
   EdgeOriginKind get kind => EdgeOriginKind.nonNullAssertion;
 }
 
-/// Edge origin resulting from the presence of a call to quiver's
-/// `checkNotNull`.
-///
-/// For example, in the following code snippet:
-///   import 'package:quiver/check.dart';
-///   void f(int i) {
-///     checkNotNull(i);
-///   }
-///
-/// this class is used for the edge connecting the type of f's `i` parameter to
-/// `never`, due to the `checkNotNull` call proclaiming that `i` is not `null`.
-class QuiverCheckNotNullOrigin extends EdgeOrigin {
-  QuiverCheckNotNullOrigin(Source source, SimpleIdentifier node)
-      : super(source, node);
-
-  @override
-  String get description => 'value checked to be non-null';
-
-  @override
-  EdgeOriginKind get kind => EdgeOriginKind.quiverCheckNotNull;
-}
-
-/// Edge origin resulting from the presence of a call to
-/// `ArgumentError.checkNotNull`.
-///
-/// For example, in the following code snippet:
-///   void f(int i) {
-///     ArgumentError.checkNotNull(i);
-///   }
-///
-/// this class is used for the edge connecting the type of f's `i` parameter to
-/// `never`, due to the `checkNotNull` call proclaiming that `i` is not `null`.
-class ArgumentErrorCheckNotNullOrigin extends EdgeOrigin {
-  ArgumentErrorCheckNotNullOrigin(Source source, SimpleIdentifier node)
-      : super(source, node);
-
-  @override
-  String get description => 'value checked to be non-null';
-
-  @override
-  EdgeOriginKind get kind => EdgeOriginKind.argumentErrorCheckNotNull;
-}
-
 /// Edge origin resulting from the presence of an explicit nullability hint
 /// comment.
 ///
@@ -518,18 +520,6 @@
   EdgeOriginKind get kind => EdgeOriginKind.optionalFormalParameter;
 }
 
-/// Edge origin resulting from the use of an element which does not affect the
-/// nullability graph in other ways.
-class DummyOrigin extends EdgeOrigin {
-  DummyOrigin(Source source, AstNode node) : super(source, node);
-
-  @override
-  String get description => 'dummy';
-
-  @override
-  EdgeOriginKind get kind => EdgeOriginKind.dummy;
-}
-
 /// Edge origin resulting from an inheritance relationship between two method
 /// parameters.
 class ParameterInheritanceOrigin extends EdgeOrigin {
@@ -542,6 +532,28 @@
   EdgeOriginKind get kind => EdgeOriginKind.parameterInheritance;
 }
 
+/// Edge origin resulting from the presence of a call to quiver's
+/// `checkNotNull`.
+///
+/// For example, in the following code snippet:
+///   import 'package:quiver/check.dart';
+///   void f(int i) {
+///     checkNotNull(i);
+///   }
+///
+/// this class is used for the edge connecting the type of f's `i` parameter to
+/// `never`, due to the `checkNotNull` call proclaiming that `i` is not `null`.
+class QuiverCheckNotNullOrigin extends EdgeOrigin {
+  QuiverCheckNotNullOrigin(Source source, SimpleIdentifier node)
+      : super(source, node);
+
+  @override
+  String get description => 'value checked to be non-null';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.quiverCheckNotNull;
+}
+
 /// Edge origin resulting from an inheritance relationship between two method
 /// return types.
 class ReturnTypeInheritanceOrigin extends EdgeOrigin {
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index f7d889e..a4ab81c 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -3256,6 +3256,280 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_getter_setter_getter_in_interface() async {
+    var content = '''
+class B {
+  int get x => null;
+}
+abstract class C implements B {
+  void set x(int value) {}
+}
+''';
+    var expected = '''
+class B {
+  int? get x => null;
+}
+abstract class C implements B {
+  void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_getter_in_interface_field() async {
+    var content = '''
+class B {
+  final int x = null;
+}
+abstract class C implements B {
+  void set x(int value) {}
+}
+''';
+    var expected = '''
+class B {
+  final int? x = null;
+}
+abstract class C implements B {
+  void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_getter_in_interfaces() async {
+    var content = '''
+class B1 {
+  int get x => null;
+}
+class B2 {
+  int get x => null;
+}
+abstract class C implements B1, B2 {
+  void set x(int value) {}
+}
+''';
+    var expected = '''
+class B1 {
+  int? get x => null;
+}
+class B2 {
+  int? get x => null;
+}
+abstract class C implements B1, B2 {
+  void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_getter_in_superclass() async {
+    var content = '''
+class B {
+  int get x => null;
+}
+class C extends B {
+  void set x(int value) {}
+}
+''';
+    var expected = '''
+class B {
+  int? get x => null;
+}
+class C extends B {
+  void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_getter_in_superclass_substituted() async {
+    var content = '''
+class B<T> {
+  T get x => throw '';
+}
+class C extends B<List<int/*?*/>> {
+  void set x(List<int> value) {}
+}
+''';
+    var expected = '''
+class B<T> {
+  T get x => throw '';
+}
+class C extends B<List<int?>> {
+  void set x(List<int?> value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_setter_in_interface() async {
+    var content = '''
+class B {
+  void set x(int value) {}
+}
+abstract class C implements B {
+  int get x => null;
+}
+''';
+    var expected = '''
+class B {
+  void set x(int? value) {}
+}
+abstract class C implements B {
+  int? get x => null;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_setter_in_interface_field() async {
+    var content = '''
+class B {
+  int x;
+  B(this.x);
+}
+abstract class C implements B {
+  int get x => null;
+}
+''';
+    var expected = '''
+class B {
+  int? x;
+  B(this.x);
+}
+abstract class C implements B {
+  int? get x => null;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_setter_in_interfaces() async {
+    var content = '''
+class B1 {
+  void set x(int value) {}
+}
+class B2 {
+  void set x(int value) {}
+}
+abstract class C implements B1, B2 {
+  int get x => null;
+}
+''';
+    var expected = '''
+class B1 {
+  void set x(int? value) {}
+}
+class B2 {
+  void set x(int? value) {}
+}
+abstract class C implements B1, B2 {
+  int? get x => null;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_setter_in_superclass() async {
+    var content = '''
+class B {
+  void set x(int value) {}
+}
+class C extends B {
+  int get x => null;
+}
+''';
+    var expected = '''
+class B {
+  void set x(int? value) {}
+}
+class C extends B {
+  int? get x => null;
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_setter_in_superclass_substituted() async {
+    var content = '''
+class B<T> {
+  void set x(T value) {}
+}
+class C extends B<List<int>> {
+  List<int> get x => [null];
+}
+''';
+    var expected = '''
+class B<T> {
+  void set x(T value) {}
+}
+class C extends B<List<int?>> {
+  List<int?> get x => [null];
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_single_class() async {
+    var content = '''
+class C {
+  int get x => null;
+  void set x(int value) {}
+}
+''';
+    var expected = '''
+class C {
+  int? get x => null;
+  void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_single_class_generic() async {
+    var content = '''
+class C<T extends Object/*!*/> {
+  T get x => null;
+  void set x(T value) {}
+}
+''';
+    var expected = '''
+class C<T extends Object> {
+  T? get x => null;
+  void set x(T? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_static() async {
+    var content = '''
+class C {
+  static int get x => null;
+  static void set x(int value) {}
+}
+''';
+    var expected = '''
+class C {
+  static int? get x => null;
+  static void set x(int? value) {}
+}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
+  Future<void> test_getter_setter_top_level() async {
+    var content = '''
+int get x => null;
+void set x(int value) {}
+''';
+    var expected = '''
+int? get x => null;
+void set x(int? value) {}
+''';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_getter_topLevel() async {
     var content = '''
 int get g => 0;
diff --git a/pkg/status_file/lib/status_file_linter.dart b/pkg/status_file/lib/status_file_linter.dart
index c8e08c6..d1282ab 100644
--- a/pkg/status_file/lib/status_file_linter.dart
+++ b/pkg/status_file/lib/status_file_linter.dart
@@ -98,7 +98,7 @@
 Iterable<LintingError> lintAlphabeticalOrderingOfPaths(StatusSection section) {
   var entries = section.entries
       .whereType<StatusEntry>()
-      .map((entry) => (entry as StatusEntry).path)
+      .map((entry) => entry.path)
       .toList();
   var sortedList = entries.toList()..sort((a, b) => a.compareTo(b));
   var witness = _findNotEqualWitness<String>(sortedList, entries);
@@ -132,9 +132,8 @@
 /// Checks for duplicate section entries in the body of a section.
 Iterable<LintingError> lintSectionEntryDuplicates(StatusSection section) {
   var errors = <LintingError>[];
-  List<StatusEntry> statusEntries = section.entries
-      .whereType<StatusEntry>()
-      .toList();
+  List<StatusEntry> statusEntries =
+      section.entries.whereType<StatusEntry>().toList();
   for (var i = 0; i < statusEntries.length; i++) {
     var entry = statusEntries[i];
     for (var j = i + 1; j < statusEntries.length; j++) {
diff --git a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
index a63524f..78a1ac6 100644
--- a/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
+++ b/pkg/vm_snapshot_analysis/test/instruction_sizes_test.dart
@@ -2,11 +2,9 @@
 // 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.
 
-import 'dart:convert';
 import 'dart:io';
 
 import 'package:test/test.dart';
-
 import 'package:vm_snapshot_analysis/instruction_sizes.dart'
     as instruction_sizes;
 import 'package:vm_snapshot_analysis/program_info.dart';
diff --git a/pkg/wasm/.gitignore b/pkg/wasm/.gitignore
new file mode 100644
index 0000000..49ce72d
--- /dev/null
+++ b/pkg/wasm/.gitignore
@@ -0,0 +1,3 @@
+.dart_tool/
+.packages
+pubspec.lock
diff --git a/pkg/wasm/AUTHORS b/pkg/wasm/AUTHORS
new file mode 100644
index 0000000..846e4a1
--- /dev/null
+++ b/pkg/wasm/AUTHORS
@@ -0,0 +1,6 @@
+# Below is a list of people and organizations that have contributed
+# to the Dart project. Names should be added to the list like so:
+#
+#   Name/Organization <email address>
+
+Google LLC
diff --git a/pkg/wasm/LICENSE b/pkg/wasm/LICENSE
new file mode 100644
index 0000000..18daf2b
--- /dev/null
+++ b/pkg/wasm/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2020, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+    * Neither the name of Google Inc. nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/wasm/README.md b/pkg/wasm/README.md
new file mode 100644
index 0000000..8bf6c4b
--- /dev/null
+++ b/pkg/wasm/README.md
@@ -0,0 +1,4 @@
+# wasm
+
+This package provides utilities for loading and running WASM modules. It is
+built on top of the [Wasmer](https://github.com/wasmerio/wasmer) runtime.
diff --git a/pkg/wasm/analysis_options.yaml b/pkg/wasm/analysis_options.yaml
new file mode 100644
index 0000000..84a5e26
--- /dev/null
+++ b/pkg/wasm/analysis_options.yaml
@@ -0,0 +1 @@
+include: package:pedantic/analysis_options.1.8.0.yaml
diff --git a/pkg/wasm/lib/module.dart b/pkg/wasm/lib/module.dart
new file mode 100644
index 0000000..4b9cde4
--- /dev/null
+++ b/pkg/wasm/lib/module.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.
+
+import 'runtime.dart';
+import 'dart:typed_data';
+import 'dart:ffi';
+
+class WasmModule {
+  Pointer<WasmerModule> _module;
+
+  WasmModule(Uint8List data) {
+    _module = WasmRuntime().compile(data);
+  }
+}
diff --git a/pkg/wasm/lib/runtime.dart b/pkg/wasm/lib/runtime.dart
new file mode 100644
index 0000000..f26689c
--- /dev/null
+++ b/pkg/wasm/lib/runtime.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2020, 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.
+
+import 'dart:ffi';
+import 'dart:io';
+import 'dart:typed_data';
+import 'package:ffi/ffi.dart';
+import 'package:path/path.dart' as path;
+
+const int WasmerResultOk = 1;
+const int WasmerResultError = 2;
+
+const int WasmerValueTagI32 = 0;
+const int WasmerValueTagI64 = 1;
+const int WasmerValueTagF32 = 2;
+const int WasmerValueTagF64 = 3;
+
+class WasmerModule extends Struct {}
+
+typedef NativeWasmerCompileFn = Uint32 Function(
+    Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, Uint32);
+typedef WasmerCompileFn = int Function(
+    Pointer<Pointer<WasmerModule>>, Pointer<Uint8>, int);
+
+class WasmRuntime {
+  static WasmRuntime _inst;
+
+  DynamicLibrary _lib;
+  WasmerCompileFn _compile;
+
+  factory WasmRuntime() {
+    if (_inst == null) {
+      _inst = WasmRuntime._init();
+    }
+    return _inst;
+  }
+
+  static String _getLibName() {
+    if (Platform.isMacOS) return "libwasmer.dylib";
+    if (Platform.isLinux) return "libwasmer.so";
+    throw Exception("Wasm not currently supported on this platform");
+  }
+
+  static String _getLibDir() {
+    // The common case, and how cli_util.dart computes the Dart SDK directory,
+    // path.dirname called twice on Platform.resolvedExecutable.
+    var commonLibDir = path.join(
+        path.absolute(path.dirname(path.dirname(Platform.resolvedExecutable))),
+        'bin',
+        'third_party',
+        'wasmer');
+    if (Directory(commonLibDir).existsSync()) {
+      return commonLibDir;
+    }
+
+    // This is the less common case where the user is in the checked out Dart
+    // SDK, and is executing dart via:
+    // ./out/ReleaseX64/dart ...
+    var checkedOutLibDir = path.join(
+        path.absolute(path.dirname(Platform.resolvedExecutable)),
+        'dart-sdk',
+        'bin',
+        'third_party',
+        'wasmer');
+    if (Directory(checkedOutLibDir).existsSync()) {
+      return checkedOutLibDir;
+    }
+
+    // If neither returned above, we return the common case:
+    return commonLibDir;
+  }
+
+  WasmRuntime._init() {
+    var libPath = path.join(_getLibDir(), _getLibName());
+    _lib = DynamicLibrary.open(libPath);
+    _compile = _lib
+        .lookup<NativeFunction<NativeWasmerCompileFn>>('wasmer_compile')
+        .asFunction();
+  }
+
+  Pointer<WasmerModule> compile(Uint8List data) {
+    var dataPtr = allocate<Uint8>(count: data.length);
+    for (int i = 0; i < data.length; ++i) {
+      dataPtr[i] = data[i];
+    }
+
+    var modulePtrPtr = allocate<Pointer<WasmerModule>>();
+    int result = _compile(modulePtrPtr, dataPtr, data.length);
+    Pointer<WasmerModule> modulePtr = modulePtrPtr.value;
+
+    free(modulePtrPtr);
+    free(dataPtr);
+
+    if (result != WasmerResultOk) {
+      throw Exception("Wasm module compile failed");
+    }
+
+    return modulePtr;
+  }
+}
diff --git a/pkg/wasm/lib/wasm.dart b/pkg/wasm/lib/wasm.dart
new file mode 100644
index 0000000..56b2f4b
--- /dev/null
+++ b/pkg/wasm/lib/wasm.dart
@@ -0,0 +1,5 @@
+// Copyright (c) 2020, 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.
+
+export 'module.dart';
diff --git a/pkg/wasm/pubspec.yaml b/pkg/wasm/pubspec.yaml
new file mode 100644
index 0000000..04f9586
--- /dev/null
+++ b/pkg/wasm/pubspec.yaml
@@ -0,0 +1,12 @@
+name: wasm
+version: 0.1.0
+description: Load and run wasm bytecode.
+author: Dart Team <misc@dartlang.org>
+homepage: https://github.com/dart-lang/sdk/tree/master/pkg/wasm
+# This package is not intended for consumption on pub.dev. DO NOT publish.
+publish_to: none
+environment:
+  sdk: ">=2.6.0"
+dependencies:
+  ffi: ^0.1.3
+  path: ^1.0.0
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index 20efa72..332a586 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -221,10 +221,6 @@
     ":generate_version_cc_file",
     "third_party/double-conversion/src:libdouble_conversion",
   ]
-  if (dart_enable_wasm) {
-    extra_deps += [ "//third_party/wasmer" ]
-    defines = [ "DART_ENABLE_WASM" ]
-  }
   if (is_fuchsia) {
     if (using_fuchsia_gn_sdk) {
       extra_deps += [
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index 2b875cc..fafd0ca 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -136,18 +136,19 @@
 #endif
 }
 
-DEFINE_NATIVE_ENTRY(Developer_webServerControl, 0, 2) {
+DEFINE_NATIVE_ENTRY(Developer_webServerControl, 0, 3) {
   GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
 #if defined(PRODUCT)
   SendNull(port);
   return Object::null();
 #else
   GET_NON_NULL_NATIVE_ARGUMENT(Bool, enabled, arguments->NativeArgAt(1));
+  GET_NATIVE_ARGUMENT(Bool, silence_output, arguments->NativeArgAt(2));
   ServiceIsolate::WaitForServiceIsolateStartup();
   if (!ServiceIsolate::IsRunning()) {
     SendNull(port);
   } else {
-    ServiceIsolate::ControlWebServer(port, enabled.value());
+    ServiceIsolate::ControlWebServer(port, enabled.value(), silence_output);
   }
   return Object::null();
 #endif
diff --git a/runtime/observatory/lib/service_html.dart b/runtime/observatory/lib/service_html.dart
index 2bf441f..cf93d5e 100644
--- a/runtime/observatory/lib/service_html.dart
+++ b/runtime/observatory/lib/service_html.dart
@@ -22,7 +22,11 @@
     // The VM service will attempt to redirect our websocket connection request
     // to DDS, but the dart:html WebSocket doesn't follow redirects. Instead of
     // relying on a redirect, we'll request the websocket URI from the service.
-    Uri getWebSocketUriRequest = Uri.parse(target.networkAddress);
+
+    // TODO(bkonyi): re-enable when DDS is enabled. Currently causing Observatory
+    // failures when running with Flutter (see
+    // https://github.com/flutter/flutter/issues/64333)
+    /*Uri getWebSocketUriRequest = Uri.parse(target.networkAddress);
     getWebSocketUriRequest =
         getWebSocketUriRequest.replace(scheme: 'http', pathSegments: [
       ...getWebSocketUriRequest.pathSegments.where((e) => e != 'ws'),
@@ -36,10 +40,9 @@
       onError();
       return;
     }
-    _webSocket = new WebSocket(
-      response['result']['uri'],
-    );
-    target.networkAddress = _webSocket.url;
+    target.networkAddress = response['result']['uri'];
+    */
+    _webSocket = new WebSocket(target.networkAddress);
     _webSocket.onClose.listen((CloseEvent) => onClose());
     _webSocket.onError.listen((Event) => onError());
     _webSocket.onOpen.listen((Event) => onOpen());
diff --git a/runtime/observatory/tests/service/developer_server_control_test.dart b/runtime/observatory/tests/service/developer_server_control_test.dart
index 24347ea..03aa74a 100644
--- a/runtime/observatory/tests/service/developer_server_control_test.dart
+++ b/runtime/observatory/tests/service/developer_server_control_test.dart
@@ -25,7 +25,8 @@
   {
     // Now, start the web server and store the URI which is expected to be
     // non NULL in the top level variable.
-    ServiceProtocolInfo info = await Service.controlWebServer(enable: true);
+    ServiceProtocolInfo info =
+        await Service.controlWebServer(enable: true, silenceOutput: true);
     Expect.equals(info.majorVersion, majorVersion);
     Expect.equals(info.minorVersion, minorVersion);
     Expect.isNotNull(info.serverUri);
diff --git a/runtime/runtime_args.gni b/runtime/runtime_args.gni
index dca02cf..1d7c539 100644
--- a/runtime/runtime_args.gni
+++ b/runtime/runtime_args.gni
@@ -91,7 +91,7 @@
   # Whether libdart should export the symbols of the Dart API.
   dart_lib_export_symbols = true
 
-  # Whether dart:wasm should be enabled.
+  # Whether package:wasm should be enabled.
   dart_enable_wasm = false
 }
 
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index 0d1d129f..c7a33f1 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -156,9 +156,6 @@
       ]
     }
   }
-  if (dart_enable_wasm) {
-    defines = [ "DART_ENABLE_WASM" ]
-  }
   include_dirs = [ ".." ]
   allsources = async_runtime_cc_files + collection_runtime_cc_files +
                core_runtime_cc_files + developer_runtime_cc_files +
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 00f2e1c..a9e7f65 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -78,7 +78,7 @@
   V(Developer_registerExtension, 2)                                            \
   V(Developer_log, 8)                                                          \
   V(Developer_postEvent, 2)                                                    \
-  V(Developer_webServerControl, 2)                                             \
+  V(Developer_webServerControl, 3)                                             \
   V(Double_hashCode, 1)                                                        \
   V(Double_getIsNegative, 1)                                                   \
   V(Double_getIsInfinite, 1)                                                   \
diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc
index 83edc77..eab2e16 100644
--- a/runtime/vm/compiler/backend/type_propagator.cc
+++ b/runtime/vm/compiler/backend/type_propagator.cc
@@ -1751,6 +1751,16 @@
 }
 
 static AbstractTypePtr GetElementTypeFromArray(Value* array) {
+  // Sometimes type of definition may contain a static type
+  // which is useful to extract element type, but reaching type
+  // only has a cid. So try out type of definition, if any.
+  if (array->definition()->HasType()) {
+    auto& elem_type = AbstractType::Handle(ExtractElementTypeFromArrayType(
+        *(array->definition()->Type()->ToAbstractType())));
+    if (!elem_type.IsDynamicType()) {
+      return elem_type.raw();
+    }
+  }
   return ExtractElementTypeFromArrayType(*(array->Type()->ToAbstractType()));
 }
 
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index f787fb3..068d478 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -65,12 +65,14 @@
 
 static ArrayPtr MakeServerControlMessage(const SendPort& sp,
                                          intptr_t code,
-                                         bool enable = false) {
-  const Array& list = Array::Handle(Array::New(3));
+                                         bool enable,
+                                         const Bool& silenceOutput) {
+  const Array& list = Array::Handle(Array::New(4));
   ASSERT(!list.IsNull());
   list.SetAt(0, Integer::Handle(Integer::New(code)));
   list.SetAt(1, sp);
   list.SetAt(2, Bool::Get(enable));
+  list.SetAt(3, silenceOutput);
   return list.raw();
 }
 
@@ -86,16 +88,19 @@
 
 void ServiceIsolate::RequestServerInfo(const SendPort& sp) {
   const Array& message = Array::Handle(MakeServerControlMessage(
-      sp, VM_SERVICE_SERVER_INFO_MESSAGE_ID, false /* ignored */));
+      sp, VM_SERVICE_SERVER_INFO_MESSAGE_ID, false /* ignored */,
+      Bool::Handle() /* ignored */));
   ASSERT(!message.IsNull());
   MessageWriter writer(false);
   PortMap::PostMessage(
       writer.WriteMessage(message, port_, Message::kNormalPriority));
 }
 
-void ServiceIsolate::ControlWebServer(const SendPort& sp, bool enable) {
+void ServiceIsolate::ControlWebServer(const SendPort& sp,
+                                      bool enable,
+                                      const Bool& silenceOutput) {
   const Array& message = Array::Handle(MakeServerControlMessage(
-      sp, VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID, enable));
+      sp, VM_SERVICE_WEB_SERVER_CONTROL_MESSAGE_ID, enable, silenceOutput));
   ASSERT(!message.IsNull());
   MessageWriter writer(false);
   PortMap::PostMessage(
diff --git a/runtime/vm/service_isolate.h b/runtime/vm/service_isolate.h
index b8dd6b4..44cbd78 100644
--- a/runtime/vm/service_isolate.h
+++ b/runtime/vm/service_isolate.h
@@ -8,6 +8,7 @@
 #include "include/dart_api.h"
 
 #include "vm/allocation.h"
+#include "vm/object.h"
 #include "vm/os_thread.h"
 
 namespace dart {
@@ -50,7 +51,9 @@
   static void BootVmServiceLibrary();
 
   static void RequestServerInfo(const SendPort& sp);
-  static void ControlWebServer(const SendPort& sp, bool enable);
+  static void ControlWebServer(const SendPort& sp,
+                               bool enable,
+                               const Bool& silenceOutput);
 
   static void SetServerAddress(const char* address);
 
diff --git a/sdk/BUILD.gn b/sdk/BUILD.gn
index 00e51e3..72f9851 100644
--- a/sdk/BUILD.gn
+++ b/sdk/BUILD.gn
@@ -582,6 +582,22 @@
   outputs = [ "$root_out_dir/dart-sdk/lib/_internal/{{source_file_part}}" ]
 }
 
+copy("copy_wasmer") {
+  visibility = [ ":create_common_sdk" ]
+  deps = [
+    ":copy_libraries",
+    "../third_party/wasmer:wasmer_lib",
+  ]
+  outputs = [ "$root_out_dir/dart-sdk/bin/third_party/wasmer/{{source_file_part}}" ]
+  if (is_win) {
+    sources = [ "$target_out_dir/../third_party/wasmer/wasmer.dll" ]
+  } else if (is_mac) {
+    sources = [ "$target_out_dir/../third_party/wasmer/libwasmer.dylib" ]
+  } else {
+    sources = [ "$target_out_dir/../third_party/wasmer/libwasmer.so" ]
+  }
+}
+
 # This rule copies dill files to lib/_internal.
 copy("copy_vm_dill_files") {
   visibility = [ ":create_common_sdk" ]
@@ -902,6 +918,14 @@
   if (target_cpu == "x64") {
     public_deps += [ ":copy_libtensorflowlite_c" ]
   }
+
+  # CIPD only has versions of the Rust compiler for linux and mac x64 hosts.
+  # We also disallow cross-compialtion (it may be possible in future, but it
+  # isn't ready yet).
+  if (host_cpu == "x64" && (host_os == "linux" || host_os == "mac") &&
+      host_cpu == current_cpu && host_os == current_os && dart_enable_wasm) {
+    public_deps += [ ":copy_wasmer" ]
+  }
 }
 
 # Parts specific to the platform SDK.
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
index d67b6c8..73935cf 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/developer_patch.dart
@@ -147,7 +147,7 @@
 }
 
 @patch
-void _webServerControl(SendPort sendPort, bool enable) {
+void _webServerControl(SendPort sendPort, bool enable, bool? silenceOutput) {
   sendPort.send(null);
 }
 
diff --git a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
index aff3f55..e7833f5 100644
--- a/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/developer_patch.dart
@@ -103,7 +103,7 @@
 }
 
 @patch
-void _webServerControl(SendPort sendPort, bool enable) {
+void _webServerControl(SendPort sendPort, bool enable, bool? silenceOutput) {
   sendPort.send(null);
 }
 
diff --git a/sdk/lib/_internal/vm/bin/vmservice_io.dart b/sdk/lib/_internal/vm/bin/vmservice_io.dart
index 5718d46..329e505 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_io.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_io.dart
@@ -192,7 +192,10 @@
 
 Uri? serverInformationCallback() => _lazyServerBoot().serverAddress;
 
-Future<Uri?> webServerControlCallback(bool enable) async {
+Future<Uri?> webServerControlCallback(bool enable, bool? silenceOutput) async {
+  if (silenceOutput != null) {
+    silentObservatory = silenceOutput;
+  }
   final _server = _lazyServerBoot();
   if (_server.running != enable) {
     if (enable) {
diff --git a/sdk/lib/_internal/vm/bin/vmservice_server.dart b/sdk/lib/_internal/vm/bin/vmservice_server.dart
index 09ec391..f084f29 100644
--- a/sdk/lib/_internal/vm/bin/vmservice_server.dart
+++ b/sdk/lib/_internal/vm/bin/vmservice_server.dart
@@ -4,7 +4,7 @@
 
 part of vmservice_io;
 
-final bool silentObservatory = bool.fromEnvironment('SILENT_OBSERVATORY');
+bool silentObservatory = bool.fromEnvironment('SILENT_OBSERVATORY');
 
 void serverPrint(String s) {
   if (silentObservatory) {
diff --git a/sdk/lib/_internal/vm/lib/developer.dart b/sdk/lib/_internal/vm/lib/developer.dart
index 82eac19..f0b2a1c 100644
--- a/sdk/lib/_internal/vm/lib/developer.dart
+++ b/sdk/lib/_internal/vm/lib/developer.dart
@@ -161,7 +161,7 @@
 void _getServerInfo(SendPort sendPort) native "Developer_getServerInfo";
 
 @patch
-void _webServerControl(SendPort sendPort, bool enable)
+void _webServerControl(SendPort sendPort, bool enable, bool? silenceOutput)
     native "Developer_webServerControl";
 
 @patch
diff --git a/sdk/lib/developer/service.dart b/sdk/lib/developer/service.dart
index 6d90667..a563f39 100644
--- a/sdk/lib/developer/service.dart
+++ b/sdk/lib/developer/service.dart
@@ -54,10 +54,11 @@
   }
 
   /// Control the web server that the service protocol is accessed through.
-  /// The [enable] argument must be a boolean and is used as a toggle to
-  /// enable (true) or disable (false) the web server servicing requests.
+  /// [enable] is used as a toggle to enable or disable the web server
+  /// servicing requests. If [silenceOutput] is provided and is true,
+  /// the server will not output information to the console.
   static Future<ServiceProtocolInfo> controlWebServer(
-      {bool enable: false}) async {
+      {bool enable = false, bool? silenceOutput}) async {
     // TODO: When NNBD is complete, delete the following line.
     ArgumentError.checkNotNull(enable, 'enable');
     // Port to receive response from service isolate.
@@ -65,7 +66,7 @@
     final Completer<Uri> uriCompleter = new Completer<Uri>();
     receivePort.handler = (Uri uri) => uriCompleter.complete(uri);
     // Request the information from the service isolate.
-    _webServerControl(receivePort.sendPort, enable);
+    _webServerControl(receivePort.sendPort, enable, silenceOutput);
     // Await the response from the service isolate.
     Uri uri = await uriCompleter.future;
     // Close the port.
@@ -88,7 +89,8 @@
 external void _getServerInfo(SendPort sendPort);
 
 /// [sendPort] will receive a Uri or null.
-external void _webServerControl(SendPort sendPort, bool enable);
+external void _webServerControl(
+    SendPort sendPort, bool enable, bool? silenceOutput);
 
 /// Returns the major version of the service protocol.
 external int _getServiceMajorVersion();
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index c404a78..1581e70 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -169,8 +169,9 @@
 /// Called when we need information about the server.
 typedef Uri? ServerInformationCallback();
 
-/// Called when we want to [enable] or disable the web server.
-typedef Future<Uri?> WebServerControlCallback(bool enable);
+/// Called when we want to [enable] or disable the web server or silence VM
+/// service console messages.
+typedef Future<Uri?> WebServerControlCallback(bool enable, bool? silenceOutput);
 
 /// Called when we want to [enable] or disable new websocket connections to the
 /// server.
@@ -436,7 +437,8 @@
     }
   }
 
-  Future<void> _serverMessageHandler(int code, SendPort sp, bool enable) async {
+  Future<void> _serverMessageHandler(
+      int code, SendPort sp, bool enable, bool? silenceOutput) async {
     switch (code) {
       case Constants.WEB_SERVER_CONTROL_MESSAGE_ID:
         final webServerControl = VMServiceEmbedderHooks.webServerControl;
@@ -444,7 +446,7 @@
           sp.send(null);
           return;
         }
-        final uri = await webServerControl(enable);
+        final uri = await webServerControl(enable, silenceOutput);
         sp.send(uri);
         break;
       case Constants.SERVER_INFO_MESSAGE_ID:
@@ -532,27 +534,27 @@
         _exit();
         return;
       }
-      if (message.length == 3) {
-        final opcode = message[0];
-        if (opcode == Constants.METHOD_CALL_FROM_NATIVE) {
-          _handleNativeRpcCall(message[1], message[2]);
+      final opcode = message[0];
+      if (message.length == 3 && opcode == Constants.METHOD_CALL_FROM_NATIVE) {
+        _handleNativeRpcCall(message[1], message[2]);
+        return;
+      }
+      if (message.length == 4) {
+        if ((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
+            (opcode == Constants.SERVER_INFO_MESSAGE_ID)) {
+          // This is a message interacting with the web server.
+          _serverMessageHandler(message[0], message[1], message[2], message[3]);
           return;
         } else {
-          // This is a message interacting with the web server.
-          assert((opcode == Constants.WEB_SERVER_CONTROL_MESSAGE_ID) ||
-              (opcode == Constants.SERVER_INFO_MESSAGE_ID));
-          _serverMessageHandler(message[0], message[1], message[2]);
+          // This is a message informing us of the birth or death of an
+          // isolate.
+          _controlMessageHandler(
+              message[0], message[1], message[2], message[3]);
           return;
         }
       }
-      if (message.length == 4) {
-        // This is a message informing us of the birth or death of an
-        // isolate.
-        _controlMessageHandler(message[0], message[1], message[2], message[3]);
-        return;
-      }
+      print('Internal vm-service error: ignoring illegal message: $message');
     }
-    print('Internal vm-service error: ignoring illegal message: $message');
   }
 
   VMService._internal() : eventPort = isolateControlPort {
diff --git a/tests/dart2js/internal/rti/constant_type_test.dart b/tests/dart2js/internal/rti/constant_type_test.dart
index cd08db5..7e71eb7 100644
--- a/tests/dart2js/internal/rti/constant_type_test.dart
+++ b/tests/dart2js/internal/rti/constant_type_test.dart
@@ -26,9 +26,9 @@
   check<Generic<int>>(const Generic<int>());
 
   check<Generic<dynamic>>(const Generic<dynamic>());
-  check<Generic<Object>>(const Generic<Object>());
-  check<Generic<Object>>(const Generic<dynamic>());
-  check<Generic<dynamic>>(const Generic<Object>());
+  check<Generic<Object?>>(const Generic<Object?>());
+  check<Generic<Object?>>(const Generic<dynamic>());
+  check<Generic<dynamic>>(const Generic<Object?>());
 
   check<List<int>>(const [1]);
   check<List<String>>(const ['one']);
diff --git a/tests/dart2js/internal/rti/simple_is_test.dart b/tests/dart2js/internal/rti/simple_is_test.dart
index 6b79c94..fb82ac4 100644
--- a/tests/dart2js/internal/rti/simple_is_test.dart
+++ b/tests/dart2js/internal/rti/simple_is_test.dart
@@ -25,9 +25,9 @@
   check<Generic<int>>(Generic<int>());
 
   check<Generic<dynamic>>(Generic<dynamic>());
-  check<Generic<Object>>(Generic<Object>());
-  check<Generic<Object>>(Generic<dynamic>());
-  check<Generic<dynamic>>(Generic<Object>());
+  check<Generic<Object?>>(Generic<Object?>());
+  check<Generic<Object?>>(Generic<dynamic>());
+  check<Generic<dynamic>>(Generic<Object?>());
 
   Expect.isTrue(Generic<Thingy>().checkMethod(Thingy()));
   Expect.isTrue(Generic<Object>().checkMethod(Object()));
diff --git a/tests/dart2js/internal/rti/subtype_test.dart b/tests/dart2js/internal/rti/subtype_test.dart
index e4222c4..68f4de7 100644
--- a/tests/dart2js/internal/rti/subtype_test.dart
+++ b/tests/dart2js/internal/rti/subtype_test.dart
@@ -5,6 +5,7 @@
 import 'dart:_foreign_helper' show JS, JS_GET_NAME, TYPE_REF;
 import 'dart:_js_embedded_names' show JsGetName;
 import 'dart:_rti' as rti;
+import 'package:expect/expect.dart';
 
 import 'subtype_utils.dart';
 
@@ -12,6 +13,8 @@
 final String futureName = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
 final String nullName = JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
 
+final String nullableObject = "$objectName?";
+
 const typeRulesJson = r'''
 {
   "int": {"num": []},
@@ -27,6 +30,8 @@
 
 main() {
   rti.testingAddRules(universe, typeRules);
+  rti.testingUniverseEvalOverride(
+      universe, nullableObject, TYPE_REF<Object?>());
   rti.testingUniverseEvalOverride(universe, objectName, TYPE_REF<Object>());
   rti.testingUniverseEvalOverride(universe, nullName, TYPE_REF<Null>());
   runTests();
@@ -53,35 +58,46 @@
 }
 
 void testTopTypes() {
-  strictSubtype('List<int>', objectName);
-  equivalent(objectName, objectName);
+  strictSubtype('List<int>', nullableObject);
+  equivalent(nullableObject, nullableObject);
   equivalent('@', '@');
   equivalent('~', '~');
   equivalent('1&', '1&');
-  equivalent(objectName, '@');
-  equivalent(objectName, '~');
-  equivalent(objectName, '1&');
+  equivalent(nullableObject, '@');
+  equivalent(nullableObject, '~');
+  equivalent(nullableObject, '1&');
   equivalent('@', '~');
   equivalent('@', '1&');
   equivalent('~', '1&');
-  equivalent('List<$objectName>', 'List<@>');
-  equivalent('List<$objectName>', 'List<~>');
-  equivalent('List<$objectName>', 'List<1&>');
+  equivalent('List<$nullableObject>', 'List<@>');
+  equivalent('List<$nullableObject>', 'List<~>');
+  equivalent('List<$nullableObject>', 'List<1&>');
   equivalent('List<@>', 'List<~>');
   equivalent('List<@>', 'List<1&>');
   equivalent('List<~>', 'List<1&>');
 }
 
 void testNull() {
-  strictSubtype(nullName, 'int');
-  strictSubtype(nullName, 'Iterable<CodeUnits>');
-  strictSubtype(nullName, objectName);
+  if (isStrongMode) {
+    unrelated(nullName, 'int');
+    unrelated(nullName, 'Iterable<CodeUnits>');
+    unrelated(nullName, objectName);
+  } else {
+    strictSubtype(nullName, 'int');
+    strictSubtype(nullName, 'Iterable<CodeUnits>');
+    strictSubtype(nullName, objectName);
+  }
+  strictSubtype(nullName, nullableObject);
   equivalent(nullName, nullName);
 }
 
 void testBottom() {
   String never = '0&';
-  equivalent(nullName, never); // This test is run with legacy subtyping
+  if (isStrongMode) {
+    strictSubtype(never, nullName);
+  } else {
+    equivalent(never, nullName);
+  }
 }
 
 void testFutureOr() {
diff --git a/third_party/wasmer/BUILD.gn b/third_party/wasmer/BUILD.gn
index 09093b6..5549fc6 100644
--- a/third_party/wasmer/BUILD.gn
+++ b/third_party/wasmer/BUILD.gn
@@ -1,4 +1,4 @@
-import("//build/rust/rust.gni")
+import("../../build/rust/rust.gni")
 
 component("wasmer") {
   public = [ "wasmer.hh" ]
@@ -7,4 +7,5 @@
 
 rust_library("wasmer_lib") {
   lib_name = "wasmer"
+  shared = true
 }
diff --git a/third_party/wasmer/Cargo.toml b/third_party/wasmer/Cargo.toml
index bfe6172..67c601b 100644
--- a/third_party/wasmer/Cargo.toml
+++ b/third_party/wasmer/Cargo.toml
@@ -4,7 +4,7 @@
 
 [lib]
 name = "wasmer"
-crate-type = ["staticlib"]
+crate-type = ["dylib"]
 path = "wasmer.rs"
 
 [dependencies]
diff --git a/tools/VERSION b/tools/VERSION
index 87839ca..3392be0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 50
+PRERELEASE 51
 PRERELEASE_PATCH 0
\ No newline at end of file
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index 0ae5512..41dbd25 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -2971,41 +2971,41 @@
         },
         {
           "name": "analyze pkg/analysis_server",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/analysis_server"
           ]
         },
         {
           "name": "analyze pkg/analysis_server_client",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/analysis_server_client"
           ]
         },
         {
           "name": "analyze pkg/analyzer",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/analyzer"
           ]
         },
         {
           "name": "analyze pkg/analyzer_cli",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/analyzer_cli"
           ]
         },
         {
           "name": "analyze pkg/analyzer_plugin",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/analyzer_plugin"
           ]
         },
@@ -3035,9 +3035,10 @@
         },
         {
           "name": "analyze pkg/dartdev",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
+            "--fatal-infos",
             "pkg/dartdev"
           ]
         },
@@ -3140,25 +3141,25 @@
         },
         {
           "name": "analyze pkg/status_file",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/status_file"
           ]
         },
         {
           "name": "analyze pkg/telemetry",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/telemetry"
           ]
         },
         {
           "name": "analyze pkg/test_runner",
-          "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
           "arguments": [
-            "--fatal-warnings",
+            "analyze",
             "pkg/test_runner"
           ]
         },
@@ -3187,6 +3188,14 @@
           ]
         },
         {
+          "name": "analyze pkg/vm_snapshot_analysis",
+          "script": "out/ReleaseX64/dart-sdk/bin/dart",
+          "arguments": [
+            "analyze",
+            "pkg/vm_snapshot_analysis"
+          ]
+        },
+        {
           "name": "analyze pkg/dds",
           "script": "out/ReleaseX64/dart-sdk/bin/dartanalyzer",
           "arguments": [
diff --git a/tools/package_deps/bin/package_deps.dart b/tools/package_deps/bin/package_deps.dart
index 97eb5d1..e177485 100644
--- a/tools/package_deps/bin/package_deps.dart
+++ b/tools/package_deps/bin/package_deps.dart
@@ -1,10 +1,9 @@
 import 'dart:io';
 
+import 'package:cli_util/cli_logging.dart';
 import 'package:path/path.dart' as path;
 import 'package:yaml/yaml.dart' as yaml;
 
-// TODO(devoncarew): Use bold ansi chars for emphasis.
-
 // TODO(devoncarew): Validate that publishable packages don't use relative sdk
 // paths in their pubspecs.
 
@@ -12,16 +11,16 @@
 const validateDEPS = false;
 
 void main(List<String> arguments) {
+  Logger logger = Logger.standard();
+
   // validate the cwd
   if (!FileSystemEntity.isFileSync('DEPS') ||
       !FileSystemEntity.isDirectorySync('pkg')) {
-    print('Please run this tool from the root of the Dart repo.');
+    logger.stderr('Please run this tool from the root of the Dart repo.');
     exit(1);
   }
 
-  // TODO(devoncarew): Support manually added directories (outside of pkg/).
-
-  // locate all packages
+  // locate all pkg/ packages
   final packages = <Package>[];
   for (var entity in Directory('pkg').listSync()) {
     if (entity is Directory) {
@@ -32,6 +31,15 @@
     }
   }
 
+  // Manually added directories (outside of pkg/).
+  List<String> alsoValidate = [
+    'tools/package_deps',
+  ];
+
+  for (String p in alsoValidate) {
+    packages.add(Package(p));
+  }
+
   packages.sort();
 
   var validateFailure = false;
@@ -41,7 +49,7 @@
     print('validating ${package.dir}'
         '${package.publishable ? ' [publishable]' : ''}');
 
-    if (!package.validate()) {
+    if (!package.validate(logger)) {
       validateFailure = true;
     }
 
@@ -101,13 +109,11 @@
       FileSystemEntity.isFileSync(path.join(dir, 'pubspec.yaml'));
 
   @override
-  int compareTo(Package other) {
-    return dirName.compareTo(other.dirName);
-  }
+  int compareTo(Package other) => dir.compareTo(other.dir);
 
-  bool validate() {
+  bool validate(Logger logger) {
     _parseImports();
-    return _validatePubspecDeps();
+    return _validatePubspecDeps(logger);
   }
 
   void _parseImports() {
@@ -163,7 +169,7 @@
     }
   }
 
-  bool _validatePubspecDeps() {
+  bool _validatePubspecDeps(Logger logger) {
     var fail = false;
 
     if (dirName != packageName) {
@@ -184,10 +190,14 @@
     //   print('  dev deps: ${devdeps}');
     // }
 
+    var out = (String message) {
+      logger.stdout(logger.ansi.emphasized(message));
+    };
+
     var undeclaredRegularUses = Set<String>.from(deps)
       ..removeAll(_declaredDependencies);
     if (undeclaredRegularUses.isNotEmpty) {
-      print('  ${_printSet(undeclaredRegularUses)} used in lib/ but not '
+      out('  ${_printSet(undeclaredRegularUses)} used in lib/ but not '
           "declared in 'dependencies:'.");
       fail = true;
     }
@@ -196,7 +206,7 @@
       ..removeAll(_declaredDependencies)
       ..removeAll(_declaredDevDependencies);
     if (undeclaredDevUses.isNotEmpty) {
-      print('  ${_printSet(undeclaredDevUses)} used in dev dirs but not '
+      out('  ${_printSet(undeclaredDevUses)} used in dev dirs but not '
           "declared in 'dev_dependencies:'.");
       fail = true;
     }
@@ -204,7 +214,7 @@
     var extraRegularDeclarations = Set<String>.from(_declaredDependencies)
       ..removeAll(deps);
     if (extraRegularDeclarations.isNotEmpty) {
-      print('  ${_printSet(extraRegularDeclarations)} declared in '
+      out('  ${_printSet(extraRegularDeclarations)} declared in '
           "'dependencies:' but not used in lib/.");
       fail = true;
     }
@@ -215,7 +225,7 @@
     // order to bring in its analysis_options.yaml file.
     extraDevDeclarations.remove('pedantic');
     if (extraDevDeclarations.isNotEmpty) {
-      print('  ${_printSet(extraDevDeclarations)} declared in '
+      out('  ${_printSet(extraDevDeclarations)} declared in '
           "'dev_dependencies:' but not used in dev dirs.");
       fail = true;
     }
@@ -225,7 +235,7 @@
     var misplacedDeps =
         extraRegularDeclarations.intersection(Set.from(devdeps));
     if (misplacedDeps.isNotEmpty) {
-      print("  ${_printSet(misplacedDeps)} declared in 'dependencies:' but "
+      out("  ${_printSet(misplacedDeps)} declared in 'dependencies:' but "
           'only used in dev dirs.');
       fail = true;
     }
diff --git a/tools/package_deps/pubspec.yaml b/tools/package_deps/pubspec.yaml
index f581f76..ef104c9 100644
--- a/tools/package_deps/pubspec.yaml
+++ b/tools/package_deps/pubspec.yaml
@@ -8,6 +8,7 @@
   sdk: '>=2.8.1 <3.0.0'
 
 dependencies:
+  cli_util: any
   path: any
   yaml: any