Version 2.10.0-118.0.dev

Merge commit 'dfc411cb90910835ae14a1d3abc99e539c42433d' into 'dev'
diff --git a/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
new file mode 100644
index 0000000..4261b2b
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/EventLoopLatencyJson.dart
@@ -0,0 +1,35 @@
+// 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:isolate';
+
+import 'json_benchmark.dart';
+import 'latency.dart';
+
+main() async {
+  // Start GC pressure from helper isolate.
+  final exitPort = ReceivePort();
+  final exitFuture = exitPort.first;
+  final isolate =
+      await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+
+  // Measure event loop latency.
+  const tickDuration = const Duration(milliseconds: 1);
+  const numberOfTicks = 8 * 1000; // min 8 seconds.
+  final EventLoopLatencyStats stats =
+      await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+  // Kill isolate & wait until it's dead.
+  isolate.kill(priority: Isolate.immediate);
+  await exitFuture;
+
+  // Report event loop latency statistics.
+  stats.report('EventLoopLatencyJson');
+}
+
+void runSplay(dynamic msg) async {
+  while (true) {
+    JsonRoundTripBenchmark().run();
+  }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart b/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart
new file mode 100644
index 0000000..c29a5b5
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/json_benchmark.dart
@@ -0,0 +1,47 @@
+// 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:math';
+import 'dart:convert';
+
+class JsonRoundTripBenchmark {
+  void run() {
+    final res = json.decode(jsonData);
+    final out = json.encode(res);
+    if (out[0] != jsonData[0]) {
+      throw 'json conversion error';
+    }
+  }
+}
+
+// Builds around 4.5 MB of json data - big enough so the decoded object graph
+// does not fit into new space.
+final String jsonData = () {
+  final rnd = Random(42);
+  dynamic buildTree(int depth) {
+    final int coin = rnd.nextInt(1000);
+    if (depth == 0) {
+      if (coin % 2 == 0) return coin;
+      return 'foo-$coin';
+    }
+
+    if (coin % 2 == 0) {
+      final map = <String, dynamic>{};
+      final int length = rnd.nextInt(18);
+      for (int i = 0; i < length; ++i) {
+        map['bar-$i'] = buildTree(depth - 1);
+      }
+      return map;
+    } else {
+      final list = <dynamic>[];
+      final int length = rnd.nextInt(18);
+      for (int i = 0; i < length; ++i) {
+        list.add(buildTree(depth - 1));
+      }
+      return list;
+    }
+  }
+
+  return json.encode({'data': buildTree(6)});
+}();
diff --git a/benchmarks/EventLoopLatencyJson/dart/latency.dart b/benchmarks/EventLoopLatencyJson/dart/latency.dart
new file mode 100644
index 0000000..c368802
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart/latency.dart
@@ -0,0 +1,135 @@
+// 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:async';
+import 'dart:io';
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+/// Measures event loop responsiveness.
+///
+/// Schedules new timer events, [tickDuration] in the future, and measures how
+/// long it takes for these events to actually arrive.
+///
+/// Runs [numberOfTicks] times before completing with [EventLoopLatencyStats].
+Future<EventLoopLatencyStats> measureEventLoopLatency(
+    Duration tickDuration, int numberOfTicks) {
+  final completer = Completer<EventLoopLatencyStats>();
+
+  final tickDurationInUs = tickDuration.inMicroseconds;
+  final buffer = _TickLatencies(numberOfTicks);
+  final sw = Stopwatch()..start();
+  int lastTimestamp = 0;
+
+  void trigger() {
+    final int currentTimestamp = sw.elapsedMicroseconds;
+
+    // Every tick we missed to schedule we'll add with difference to when we
+    // would've scheduled it and when we became responsive again.
+    bool done = false;
+    while (!done && lastTimestamp < (currentTimestamp - tickDurationInUs)) {
+      done = !buffer.add(currentTimestamp - lastTimestamp - tickDurationInUs);
+      lastTimestamp += tickDurationInUs;
+    }
+
+    if (!done) {
+      lastTimestamp = currentTimestamp;
+      Timer(tickDuration, trigger);
+    } else {
+      completer.complete(buffer.makeStats());
+    }
+  }
+
+  Timer(tickDuration, trigger);
+
+  return completer.future;
+}
+
+/// Result of the event loop latency measurement.
+class EventLoopLatencyStats {
+  /// Minimum latency between scheduling a tick and it's arrival (in ms).
+  final double minLatency;
+
+  /// Average latency between scheduling a tick and it's arrival (in ms).
+  final double avgLatency;
+
+  /// Maximum latency between scheduling a tick and it's arrival (in ms).
+  final double maxLatency;
+
+  /// The 50th percentile (median) (in ms).
+  final double percentile50th;
+
+  /// The 90th percentile (in ms).
+  final double percentile90th;
+
+  /// The 95th percentile (in ms).
+  final double percentile95th;
+
+  /// The 99th percentile (in ms).
+  final double percentile99th;
+
+  /// The maximum RSS of the process.
+  final int maxRss;
+
+  EventLoopLatencyStats(
+      this.minLatency,
+      this.avgLatency,
+      this.maxLatency,
+      this.percentile50th,
+      this.percentile90th,
+      this.percentile95th,
+      this.percentile99th,
+      this.maxRss);
+
+  void report(String name) {
+    print('$name.Min(RunTime): $minLatency ms.');
+    print('$name.Avg(RunTime): $avgLatency ms.');
+    print('$name.Percentile50(RunTime): $percentile50th ms.');
+    print('$name.Percentile90(RunTime): $percentile90th ms.');
+    print('$name.Percentile95(RunTime): $percentile95th ms.');
+    print('$name.Percentile99(RunTime): $percentile99th ms.');
+    print('$name.Max(RunTime): $maxLatency ms.');
+    print('$name.MaxRss(MemoryUse): $maxRss');
+  }
+}
+
+/// Accumulates tick latencies and makes statistics for it.
+class _TickLatencies {
+  final Uint64List _timestamps;
+  int _index = 0;
+
+  _TickLatencies(int numberOfTicks) : _timestamps = Uint64List(numberOfTicks);
+
+  /// Returns `true` while the buffer has not been filled yet.
+  bool add(int latencyInUs) {
+    _timestamps[_index++] = latencyInUs;
+    return _index < _timestamps.length;
+  }
+
+  EventLoopLatencyStats makeStats() {
+    if (_index != _timestamps.length) {
+      throw 'Buffer has not been fully filled yet.';
+    }
+
+    _timestamps.sort();
+    final length = _timestamps.length;
+    final double avg = _timestamps.fold(0, (int a, int b) => a + b) / length;
+    final int min = _timestamps.fold(0x7fffffffffffffff, math.min);
+    final int max = _timestamps.fold(0, math.max);
+    final percentile50th = _timestamps[50 * length ~/ 100];
+    final percentile90th = _timestamps[90 * length ~/ 100];
+    final percentile95th = _timestamps[95 * length ~/ 100];
+    final percentile99th = _timestamps[99 * length ~/ 100];
+
+    return EventLoopLatencyStats(
+        min / 1000,
+        avg / 1000,
+        max / 1000,
+        percentile50th / 1000,
+        percentile90th / 1000,
+        percentile95th / 1000,
+        percentile99th / 1000,
+        ProcessInfo.maxRss);
+  }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
new file mode 100644
index 0000000..4261b2b
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/EventLoopLatencyJson.dart
@@ -0,0 +1,35 @@
+// 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:isolate';
+
+import 'json_benchmark.dart';
+import 'latency.dart';
+
+main() async {
+  // Start GC pressure from helper isolate.
+  final exitPort = ReceivePort();
+  final exitFuture = exitPort.first;
+  final isolate =
+      await Isolate.spawn(runSplay, null, onExit: exitPort.sendPort);
+
+  // Measure event loop latency.
+  const tickDuration = const Duration(milliseconds: 1);
+  const numberOfTicks = 8 * 1000; // min 8 seconds.
+  final EventLoopLatencyStats stats =
+      await measureEventLoopLatency(tickDuration, numberOfTicks);
+
+  // Kill isolate & wait until it's dead.
+  isolate.kill(priority: Isolate.immediate);
+  await exitFuture;
+
+  // Report event loop latency statistics.
+  stats.report('EventLoopLatencyJson');
+}
+
+void runSplay(dynamic msg) async {
+  while (true) {
+    JsonRoundTripBenchmark().run();
+  }
+}
diff --git a/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart b/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart
new file mode 100644
index 0000000..c29a5b5
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/json_benchmark.dart
@@ -0,0 +1,47 @@
+// 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:math';
+import 'dart:convert';
+
+class JsonRoundTripBenchmark {
+  void run() {
+    final res = json.decode(jsonData);
+    final out = json.encode(res);
+    if (out[0] != jsonData[0]) {
+      throw 'json conversion error';
+    }
+  }
+}
+
+// Builds around 4.5 MB of json data - big enough so the decoded object graph
+// does not fit into new space.
+final String jsonData = () {
+  final rnd = Random(42);
+  dynamic buildTree(int depth) {
+    final int coin = rnd.nextInt(1000);
+    if (depth == 0) {
+      if (coin % 2 == 0) return coin;
+      return 'foo-$coin';
+    }
+
+    if (coin % 2 == 0) {
+      final map = <String, dynamic>{};
+      final int length = rnd.nextInt(18);
+      for (int i = 0; i < length; ++i) {
+        map['bar-$i'] = buildTree(depth - 1);
+      }
+      return map;
+    } else {
+      final list = <dynamic>[];
+      final int length = rnd.nextInt(18);
+      for (int i = 0; i < length; ++i) {
+        list.add(buildTree(depth - 1));
+      }
+      return list;
+    }
+  }
+
+  return json.encode({'data': buildTree(6)});
+}();
diff --git a/benchmarks/EventLoopLatencyJson/dart2/latency.dart b/benchmarks/EventLoopLatencyJson/dart2/latency.dart
new file mode 100644
index 0000000..c368802
--- /dev/null
+++ b/benchmarks/EventLoopLatencyJson/dart2/latency.dart
@@ -0,0 +1,135 @@
+// 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:async';
+import 'dart:io';
+import 'dart:math' as math;
+import 'dart:typed_data';
+
+/// Measures event loop responsiveness.
+///
+/// Schedules new timer events, [tickDuration] in the future, and measures how
+/// long it takes for these events to actually arrive.
+///
+/// Runs [numberOfTicks] times before completing with [EventLoopLatencyStats].
+Future<EventLoopLatencyStats> measureEventLoopLatency(
+    Duration tickDuration, int numberOfTicks) {
+  final completer = Completer<EventLoopLatencyStats>();
+
+  final tickDurationInUs = tickDuration.inMicroseconds;
+  final buffer = _TickLatencies(numberOfTicks);
+  final sw = Stopwatch()..start();
+  int lastTimestamp = 0;
+
+  void trigger() {
+    final int currentTimestamp = sw.elapsedMicroseconds;
+
+    // Every tick we missed to schedule we'll add with difference to when we
+    // would've scheduled it and when we became responsive again.
+    bool done = false;
+    while (!done && lastTimestamp < (currentTimestamp - tickDurationInUs)) {
+      done = !buffer.add(currentTimestamp - lastTimestamp - tickDurationInUs);
+      lastTimestamp += tickDurationInUs;
+    }
+
+    if (!done) {
+      lastTimestamp = currentTimestamp;
+      Timer(tickDuration, trigger);
+    } else {
+      completer.complete(buffer.makeStats());
+    }
+  }
+
+  Timer(tickDuration, trigger);
+
+  return completer.future;
+}
+
+/// Result of the event loop latency measurement.
+class EventLoopLatencyStats {
+  /// Minimum latency between scheduling a tick and it's arrival (in ms).
+  final double minLatency;
+
+  /// Average latency between scheduling a tick and it's arrival (in ms).
+  final double avgLatency;
+
+  /// Maximum latency between scheduling a tick and it's arrival (in ms).
+  final double maxLatency;
+
+  /// The 50th percentile (median) (in ms).
+  final double percentile50th;
+
+  /// The 90th percentile (in ms).
+  final double percentile90th;
+
+  /// The 95th percentile (in ms).
+  final double percentile95th;
+
+  /// The 99th percentile (in ms).
+  final double percentile99th;
+
+  /// The maximum RSS of the process.
+  final int maxRss;
+
+  EventLoopLatencyStats(
+      this.minLatency,
+      this.avgLatency,
+      this.maxLatency,
+      this.percentile50th,
+      this.percentile90th,
+      this.percentile95th,
+      this.percentile99th,
+      this.maxRss);
+
+  void report(String name) {
+    print('$name.Min(RunTime): $minLatency ms.');
+    print('$name.Avg(RunTime): $avgLatency ms.');
+    print('$name.Percentile50(RunTime): $percentile50th ms.');
+    print('$name.Percentile90(RunTime): $percentile90th ms.');
+    print('$name.Percentile95(RunTime): $percentile95th ms.');
+    print('$name.Percentile99(RunTime): $percentile99th ms.');
+    print('$name.Max(RunTime): $maxLatency ms.');
+    print('$name.MaxRss(MemoryUse): $maxRss');
+  }
+}
+
+/// Accumulates tick latencies and makes statistics for it.
+class _TickLatencies {
+  final Uint64List _timestamps;
+  int _index = 0;
+
+  _TickLatencies(int numberOfTicks) : _timestamps = Uint64List(numberOfTicks);
+
+  /// Returns `true` while the buffer has not been filled yet.
+  bool add(int latencyInUs) {
+    _timestamps[_index++] = latencyInUs;
+    return _index < _timestamps.length;
+  }
+
+  EventLoopLatencyStats makeStats() {
+    if (_index != _timestamps.length) {
+      throw 'Buffer has not been fully filled yet.';
+    }
+
+    _timestamps.sort();
+    final length = _timestamps.length;
+    final double avg = _timestamps.fold(0, (int a, int b) => a + b) / length;
+    final int min = _timestamps.fold(0x7fffffffffffffff, math.min);
+    final int max = _timestamps.fold(0, math.max);
+    final percentile50th = _timestamps[50 * length ~/ 100];
+    final percentile90th = _timestamps[90 * length ~/ 100];
+    final percentile95th = _timestamps[95 * length ~/ 100];
+    final percentile99th = _timestamps[99 * length ~/ 100];
+
+    return EventLoopLatencyStats(
+        min / 1000,
+        avg / 1000,
+        max / 1000,
+        percentile50th / 1000,
+        percentile90th / 1000,
+        percentile95th / 1000,
+        percentile99th / 1000,
+        ProcessInfo.maxRss);
+  }
+}
diff --git a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
index 6e6309a..152ba37 100644
--- a/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
+++ b/pkg/analysis_server/lib/src/lsp/handlers/handler_text_document_changes.dart
@@ -126,7 +126,7 @@
       );
       server.onOverlayCreated(path, doc.text);
 
-      final driver = server.contextManager.getDriverFor(path);
+      final driver = server.getAnalysisDriver(path);
       // If the file did not exist, and is "overlay only", it still should be
       // analyzed. Add it to driver to which it should have been added.
 
diff --git a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
index 3b42924..95e11f4 100644
--- a/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
+++ b/pkg/analysis_server/test/lsp/change_workspace_folders_test.dart
@@ -192,6 +192,43 @@
     );
   }
 
+  Future<void> test_changeWorkspaceFolders_openFileOutsideRoot() async {
+    // When a file is opened that is outside of the analysis roots, the first
+    // analysis driver will be used (see [AbstractAnalysisServer.getAnalysisDriver]).
+    // This means as long as there is already an analysis root, the implicit root
+    // will be the original root and not the path of the opened file.
+    // For example, Go-to-Definition into a file in PubCache must *not* result in
+    // the pub cache folder being added as an analysis root, it should be analyzed
+    // by the existing project's driver.
+    final workspace1FilePath = join(workspaceFolder1Path, 'test.dart');
+    await newFile(workspace1FilePath);
+    final workspace2FilePath = join(workspaceFolder2Path, 'test.dart');
+    final workspace2FileUri = Uri.file(workspace2FilePath);
+    await newFile(workspace2FilePath);
+
+    await initialize(workspaceFolders: [workspaceFolder1Uri]);
+
+    // Expect explicit root for the workspace folder.
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path]),
+    );
+
+    // Open a file in workspaceFolder2 (which is not in the analysis roots).
+    await openFile(workspace2FileUri, '');
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path]),
+    );
+
+    // Closing the file should not result in the project being removed.
+    await closeFile(workspace2FileUri);
+    expect(
+      server.contextManager.includedPaths,
+      unorderedEquals([workspaceFolder1Path]),
+    );
+  }
+
   Future<void> test_changeWorkspaceFolders_remove() async {
     await initialize(
       workspaceFolders: [workspaceFolder1Uri, workspaceFolder2Uri],
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 0dfd4db..9e26d98 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -6967,21 +6967,7 @@
   }
 
   @override
-  DartType get returnTypeInternal {
-    var returnType = variable.type;
-
-    // While performing inference during linking, the first step is to collect
-    // dependencies. During this step we resolve the expression, but we might
-    // reference elements that don't have their types inferred yet. So, here
-    // we give some type. A better solution would be to infer recursively, but
-    // we are not doing this yet.
-    if (returnType == null) {
-      assert(linkedContext.isLinking);
-      return DynamicTypeImpl.instance;
-    }
-
-    return returnType;
-  }
+  DartType get returnTypeInternal => variable.type;
 
   @override
   FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
@@ -7138,7 +7124,19 @@
   DartType get typeInternal {
     if (linkedNode != null) {
       if (_type != null) return _type;
-      return _type = linkedContext.getType(linkedNode);
+      _type = linkedContext.getType(linkedNode);
+
+      // While performing inference during linking, the first step is to collect
+      // dependencies. During this step we resolve the expression, but we might
+      // reference elements that don't have their types inferred yet. So, here
+      // we give some type. A better solution would be to infer recursively, but
+      // we are not doing this yet.
+      if (_type == null) {
+        assert(linkedContext.isLinking);
+        return DynamicTypeImpl.instance;
+      }
+
+      return _type;
     }
     if (isSynthetic && _type == null) {
       if (getter != null) {
diff --git a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
index 4fd07d6..1a4c879 100644
--- a/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/assignment_expression_resolver.dart
@@ -15,13 +15,13 @@
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/flow_analysis_visitor.dart';
 import 'package:analyzer/src/dart/resolver/invocation_inference_helper.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
+import 'package:analyzer/src/error/assignment_verifier.dart';
 import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/error/nullable_dereference_verifier.dart';
 import 'package:analyzer/src/generated/migration.dart';
 import 'package:analyzer/src/generated/resolver.dart';
-import 'package:analyzer/src/task/strong/checker.dart';
 import 'package:meta/meta.dart';
 
 /// Helper for resolving [AssignmentExpression]s.
@@ -52,9 +52,6 @@
     return _resolver.migrationResolutionHooks;
   }
 
-  NullableDereferenceVerifier get _nullableDereferenceVerifier =>
-      _resolver.nullableDereferenceVerifier;
-
   TypeProvider get _typeProvider => _resolver.typeProvider;
 
   TypeSystemImpl get _typeSystem => _resolver.typeSystem;
@@ -63,6 +60,11 @@
     var left = node.leftHandSide;
     var right = node.rightHandSide;
 
+    if (left is PropertyAccess) {
+      _resolve_PropertyAccess(node, left);
+      return;
+    }
+
     if (left is SimpleIdentifier) {
       _resolve_SimpleIdentifier(node, left);
       return;
@@ -81,23 +83,7 @@
       _resolver.setWriteElement(left, null);
     }
 
-    _resolve1(node, getReadType(left));
-
-    _setRhsContext(node, left.staticType, operator, right);
-
-    _flowAnalysis?.assignmentExpression(node);
-
-    if (operator != TokenType.EQ &&
-        operator != TokenType.QUESTION_QUESTION_EQ) {
-      _nullableDereferenceVerifier.expression(left);
-    }
-
-    right?.accept(_resolver);
-    right = node.rightHandSide;
-
-    _resolve2(node);
-
-    _flowAnalysis?.assignmentExpression_afterRight(node);
+    _resolve3(node, left, operator, right);
   }
 
   void _checkForInvalidAssignment(
@@ -175,90 +161,6 @@
     }
   }
 
-  void _reportNotSetter(
-    Expression left,
-    Element requested,
-    Element recovery,
-  ) {
-    if (requested != null) {
-      if (requested is VariableElement) {
-        if (requested.isConst) {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
-            left,
-          );
-        } else if (requested.isFinal) {
-          if (_isNonNullableByDefault) {
-            // Handled during resolution, with flow analysis.
-          } else {
-            _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
-              left,
-              [requested.name],
-            );
-          }
-        }
-      }
-      return;
-    }
-
-    if (recovery is ClassElement ||
-        recovery is DynamicElementImpl ||
-        recovery is FunctionTypeAliasElement ||
-        recovery is TypeParameterElement) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
-        left,
-      );
-    } else if (recovery is FunctionElement) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.ASSIGNMENT_TO_FUNCTION,
-        left,
-      );
-    } else if (recovery is MethodElement) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
-        left,
-      );
-    } else if (recovery is PrefixElement) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
-        left,
-        [recovery.name],
-      );
-    } else if (recovery is PropertyAccessorElement && recovery.isGetter) {
-      var variable = recovery.variable;
-      if (variable.isConst) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
-          left,
-        );
-      } else if (variable is FieldElement && variable.isSynthetic) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
-          left,
-          [variable.name, variable.enclosingElement.displayName],
-        );
-      } else {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
-          left,
-          [variable.name],
-        );
-      }
-    } else if (recovery is MultiplyDefinedElementImpl) {
-      // Will be reported in ErrorVerifier.
-    } else {
-      if (left is SimpleIdentifier && !left.isSynthetic) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
-          left,
-          [left.name],
-        );
-      }
-    }
-  }
-
   void _resolve1(AssignmentExpressionImpl node, DartType leftType) {
     Token operator = node.operator;
     TokenType operatorType = operator.type;
@@ -310,7 +212,9 @@
     }
   }
 
-  void _resolve2(AssignmentExpressionImpl node) {
+  /// TODO(scheglov) Replace [leftWriteType] with `node.writeType`
+  void _resolve2(AssignmentExpressionImpl node, DartType leftWriteType,
+      {@required bool doNullShortingTermination}) {
     TokenType operator = node.operator.type;
     if (operator == TokenType.EQ) {
       var rightType = node.rightHandSide.staticType;
@@ -333,7 +237,7 @@
     } else {
       var rightType = node.rightHandSide.staticType;
 
-      var leftReadType = getReadType(node.leftHandSide);
+      var leftReadType = node.readType;
       if (identical(leftReadType, NeverTypeImpl.instance)) {
         _inferenceHelper.recordStaticType(node, rightType);
         return;
@@ -350,7 +254,6 @@
       );
       _inferenceHelper.recordStaticType(node, type);
 
-      var leftWriteType = _getWriteType(node.leftHandSide);
       if (!_typeSystem.isAssignableTo2(type, leftWriteType)) {
         _resolver.errorReporter.reportErrorForNode(
           CompileTimeErrorCode.INVALID_ASSIGNMENT,
@@ -359,50 +262,14 @@
         );
       }
     }
-    _resolver.nullShortingTermination(node);
+
+    if (doNullShortingTermination) {
+      _resolver.nullShortingTermination(node);
+    }
   }
 
-  void _resolve_SimpleIdentifier(
-    AssignmentExpressionImpl node,
-    SimpleIdentifier left,
-  ) {
-    var right = node.rightHandSide;
-    var operator = node.operator.type;
-
-    if (operator != TokenType.EQ) {
-      var readLookup = _resolver.lexicalLookup(node: left, setter: false);
-      var readElement = readLookup.requested;
-      _resolver.setReadElement(left, readElement);
-    }
-
-    var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
-    var writeElement = writeLookup.requested ?? writeLookup.recovery;
-    _resolver.setWriteElement(left, writeElement);
-    _reportNotSetter(left, writeLookup.requested, writeLookup.recovery);
-
-    // TODO(scheglov) This is mostly necessary for backward compatibility.
-    // Although we also use `staticElement` for `getType(left)` below.
-    {
-      if (operator != TokenType.EQ) {
-        var readElement = node.readElement;
-        if (readElement is PropertyAccessorElement) {
-          left.auxiliaryElements = AuxiliaryElements(readElement);
-        }
-      }
-      left.staticElement = node.writeElement;
-      if (node.readElement is VariableElement) {
-        var leftType = _resolver.localVariableTypeProvider.getType(left);
-        _recordStaticType(left, leftType);
-      } else {
-        _recordStaticType(left, node.writeType);
-      }
-    }
-
-    if (operator != TokenType.EQ) {
-      // TODO(scheglov) Change this method to work with elements.
-      _resolver.checkReadOfNotAssignedLocalVariable(left);
-    }
-
+  void _resolve3(AssignmentExpressionImpl node, Expression left,
+      TokenType operator, Expression right) {
     _resolve1(node, node.readType);
 
     {
@@ -421,7 +288,7 @@
     right?.accept(_resolver);
     right = node.rightHandSide;
 
-    _resolve2(node);
+    _resolve2(node, node.writeType, doNullShortingTermination: false);
 
     // TODO(scheglov) inline into resolve2().
     DartType assignedType;
@@ -433,9 +300,11 @@
     }
     _checkForInvalidAssignment(node.writeType, right, assignedType);
 
+    _resolver.nullShortingTermination(node);
+
     if (flow != null) {
-      if (writeElement is VariableElement) {
-        flow.write(writeElement, node.staticType);
+      if (node.writeElement is VariableElement) {
+        flow.write(node.writeElement, node.staticType);
       }
       if (node.operator.type == TokenType.QUESTION_QUESTION_EQ) {
         flow.ifNullExpression_end();
@@ -443,6 +312,107 @@
     }
   }
 
+  void _resolve_PropertyAccess(
+    AssignmentExpressionImpl node,
+    PropertyAccess left,
+  ) {
+    left.target?.accept(_resolver);
+
+    var propertyName = left.propertyName;
+    var operator = node.operator.type;
+    var hasRead = operator != TokenType.EQ;
+
+    _resolver.startNullAwarePropertyAccess(left);
+
+    ExecutableElement readElement;
+    ExecutableElement writeElement;
+
+    var resolver = PropertyElementResolver(_resolver);
+    var result = resolver.resolvePropertyAccess(
+      node: left,
+      hasRead: hasRead,
+      hasWrite: true,
+    );
+
+    readElement = result.readElement;
+    writeElement = result.writeElement;
+
+    if (hasRead) {
+      _resolver.setReadElement(left, readElement);
+    }
+
+    // var writeElement = result.setter ?? result.getter;
+    _resolver.setWriteElement(left, writeElement);
+
+    _setBackwardCompatibility(node, propertyName);
+
+    var right = node.rightHandSide;
+    _resolve3(node, left, operator, right);
+  }
+
+  void _resolve_SimpleIdentifier(
+    AssignmentExpressionImpl node,
+    SimpleIdentifier left,
+  ) {
+    var right = node.rightHandSide;
+    var operator = node.operator.type;
+
+    if (operator != TokenType.EQ) {
+      var readLookup = _resolver.lexicalLookup(node: left, setter: false);
+      var readElement = readLookup.requested;
+      _resolver.setReadElement(left, readElement);
+    }
+
+    var writeLookup = _resolver.lexicalLookup(node: left, setter: true);
+    var writeElement = writeLookup.requested ?? writeLookup.recovery;
+    _resolver.setWriteElement(left, writeElement);
+
+    AssignmentVerifier(_resolver.definingLibrary, _errorReporter).verify(
+      node: left,
+      requested: writeLookup.requested,
+      recovery: writeLookup.recovery,
+      receiverTypeObject: null,
+    );
+
+    _setBackwardCompatibility(node, left);
+
+    if (operator != TokenType.EQ) {
+      // TODO(scheglov) Change this method to work with elements.
+      _resolver.checkReadOfNotAssignedLocalVariable(left);
+    }
+
+    _resolve3(node, left, operator, right);
+  }
+
+  /// TODO(scheglov) This is mostly necessary for backward compatibility.
+  /// Although we also use `staticElement` for `getType(left)` below.
+  void _setBackwardCompatibility(
+    AssignmentExpressionImpl node,
+    SimpleIdentifier left,
+  ) {
+    var operator = node.operator.type;
+
+    if (operator != TokenType.EQ) {
+      var readElement = node.readElement;
+      if (readElement is PropertyAccessorElement) {
+        left.auxiliaryElements = AuxiliaryElements(readElement);
+      }
+    }
+
+    left.staticElement = node.writeElement;
+    if (node.readElement is VariableElement) {
+      var leftType = _resolver.localVariableTypeProvider.getType(left);
+      _recordStaticType(left, leftType);
+    } else {
+      _recordStaticType(left, node.writeType);
+    }
+
+    var parent = left.parent;
+    if (parent is PropertyAccess && parent.propertyName == left) {
+      _recordStaticType(parent, node.writeType);
+    }
+  }
+
   void _setRhsContext(AssignmentExpressionImpl node, DartType leftType,
       TokenType operator, Expression right) {
     switch (operator) {
@@ -482,19 +452,6 @@
     }
     return false;
   }
-
-  /// The type of the RHS assigned to [left] must be subtype of the return.
-  static DartType _getWriteType(Expression left) {
-    // We are writing, so ignore promotions.
-    if (left is SimpleIdentifier) {
-      var element = left.staticElement;
-      if (element is PromotableElement) {
-        return element.type;
-      }
-    }
-
-    return left.staticType;
-  }
 }
 
 class AssignmentExpressionShared {
diff --git a/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
new file mode 100644
index 0000000..70dcfbf
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/resolver/property_element_resolver.dart
@@ -0,0 +1,503 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
+import 'package:analyzer/src/dart/element/type.dart';
+import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
+import 'package:analyzer/src/error/assignment_verifier.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:analyzer/src/generated/resolver.dart';
+import 'package:analyzer/src/generated/super_context.dart';
+import 'package:meta/meta.dart';
+
+class PropertyElementResolver {
+  final ResolverVisitor _resolver;
+
+  PropertyElementResolver(this._resolver);
+
+  LibraryElement get _definingLibrary => _resolver.definingLibrary;
+
+  ErrorReporter get _errorReporter => _resolver.errorReporter;
+
+  ExtensionMemberResolver get _extensionResolver => _resolver.extensionResolver;
+
+  PropertyElementResolverResult resolve2({
+    @required Expression target,
+    @required bool isCascaded,
+    @required bool isNullAware,
+    @required SimpleIdentifier propertyName,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    if (target is ExtensionOverride) {
+      return _resolveTargetExtensionOverride(
+        target: target,
+        propertyName: propertyName,
+        hasRead: hasRead,
+        hasWrite: hasWrite,
+      );
+    }
+
+    //
+    // If this property access is of the form 'C.m' where 'C' is a class,
+    // then we don't call resolveProperty(...) which walks up the class
+    // hierarchy, instead we just look for the member in the type only.  This
+    // does not apply to conditional property accesses (i.e. 'C?.m').
+    //
+    if (target is Identifier) {
+      var targetElement = target.staticElement;
+      if (targetElement is ClassElement) {
+        if (isCascaded) {
+          targetElement = _resolver.typeProvider.typeType.element;
+        }
+        return _resolveTargetClassElement(
+          typeReference: targetElement,
+          propertyName: propertyName,
+          hasRead: hasRead,
+          hasWrite: hasWrite,
+        );
+      }
+    }
+
+    //
+    // If this property access is of the form 'E.m' where 'E' is an extension,
+    // then look for the member in the extension. This does not apply to
+    // conditional property accesses (i.e. 'C?.m').
+    //
+    if (target is Identifier) {
+      var targetElement = target.staticElement;
+      if (targetElement is ExtensionElement) {
+        return _resolveTargetExtensionElement(
+          extension: targetElement,
+          propertyName: propertyName,
+          hasRead: hasRead,
+          hasWrite: hasWrite,
+        );
+      }
+    }
+
+    if (target is SuperExpression) {
+      return _resolveTargetSuperExpression(
+        target: target,
+        propertyName: propertyName,
+        hasRead: hasRead,
+        hasWrite: hasWrite,
+      );
+    }
+
+    var targetType = target.staticType;
+    targetType = _resolveTypeParameter(targetType);
+
+    if (targetType.isVoid) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.USE_OF_VOID_RESULT,
+        propertyName,
+      );
+      return PropertyElementResolverResult();
+    }
+
+    if (isNullAware) {
+      targetType = _resolver.typeSystem.promoteToNonNull(targetType);
+    }
+
+    var result = _resolver.typePropertyResolver.resolve(
+      receiver: target,
+      receiverType: targetType,
+      name: propertyName.name,
+      receiverErrorNode: target,
+      nameErrorNode: propertyName,
+    );
+
+    if (targetType is DynamicTypeImpl || targetType is NeverTypeImpl) {
+      // OK
+    } else {
+      // TODO(scheglov) It is not nice that we check for `call` here.
+      // We can find `call` in these types, is should be `single`, but `null`.
+      if (hasRead && result.getter == null && !result.isAmbiguous) {
+        if (targetType is FunctionType &&
+            propertyName.name == FunctionElement.CALL_METHOD_NAME) {
+          // Referencing `.call` on a FunctionType is OK.
+        } else if (targetType is InterfaceType &&
+            targetType.isDartCoreFunction &&
+            propertyName.name == FunctionElement.CALL_METHOD_NAME) {
+          // Referencing `.call` on a `Function` type is OK.
+        } else {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.UNDEFINED_GETTER,
+            propertyName,
+            [propertyName.name, targetType],
+          );
+        }
+      }
+
+      if (hasWrite && result.setter == null && !result.isAmbiguous) {
+        AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+          node: propertyName,
+          requested: null,
+          recovery: result.getter,
+          receiverTypeObject: targetType,
+        );
+      }
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: result.getter,
+      readElementRecovery: result.setter,
+      writeElementRequested: result.setter,
+      writeElementRecovery: result.getter,
+    );
+  }
+
+  PropertyElementResolverResult resolvePrefixedIdentifier({
+    @required PrefixedIdentifier node,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    return resolve2(
+      target: node.prefix,
+      isCascaded: false,
+      isNullAware: false,
+      propertyName: node.identifier,
+      hasRead: hasRead,
+      hasWrite: hasWrite,
+    );
+  }
+
+  PropertyElementResolverResult resolvePropertyAccess({
+    @required PropertyAccess node,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    return resolve2(
+      target: node.realTarget,
+      isCascaded: node.target == null,
+      isNullAware: node.isNullAware,
+      propertyName: node.propertyName,
+      hasRead: hasRead,
+      hasWrite: hasWrite,
+    );
+  }
+
+  void _checkExtensionOverrideStaticMember(
+    SimpleIdentifier propertyName,
+    ExecutableElement element,
+  ) {
+    if (element != null && element.isStatic) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
+        propertyName,
+      );
+    }
+  }
+
+  /// If the [element] is not static, report the error on the [identifier].
+  void _checkForStaticAccessToInstanceMember(
+    SimpleIdentifier identifier,
+    ExecutableElement element,
+  ) {
+    if (element.isStatic) return;
+
+    _errorReporter.reportErrorForNode(
+      CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
+      identifier,
+      [identifier.name],
+    );
+  }
+
+  bool _isAccessible(ExecutableElement element) {
+    return element.isAccessibleIn(_definingLibrary);
+  }
+
+  PropertyElementResolverResult _resolveTargetClassElement({
+    @required ClassElement typeReference,
+    @required SimpleIdentifier propertyName,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    ExecutableElement readElement;
+    if (hasRead) {
+      readElement = typeReference.getGetter(propertyName.name);
+      if (readElement != null && !_isAccessible(readElement)) {
+        readElement = null;
+      }
+
+      if (readElement == null) {
+        readElement = typeReference.getMethod(propertyName.name);
+        if (readElement != null && !_isAccessible(readElement)) {
+          readElement = null;
+        }
+      }
+
+      if (readElement != null) {
+        readElement = _resolver.toLegacyElement(readElement);
+        _checkForStaticAccessToInstanceMember(propertyName, readElement);
+      } else {
+        var code = typeReference.isEnum
+            ? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
+            : CompileTimeErrorCode.UNDEFINED_GETTER;
+        _errorReporter.reportErrorForNode(
+          code,
+          propertyName,
+          [propertyName.name, typeReference.name],
+        );
+      }
+    }
+
+    ExecutableElement writeElement;
+    ExecutableElement writeElementRecovery;
+    if (hasWrite) {
+      writeElement = typeReference.getSetter(propertyName.name);
+      if (writeElement != null) {
+        writeElement = _resolver.toLegacyElement(writeElement);
+        if (!_isAccessible(writeElement)) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.PRIVATE_SETTER,
+            propertyName,
+            [propertyName.name, typeReference.name],
+          );
+        }
+        _checkForStaticAccessToInstanceMember(propertyName, writeElement);
+      } else {
+        // Recovery, try to use getter.
+        writeElementRecovery = typeReference.getGetter(propertyName.name);
+        AssignmentVerifier(_definingLibrary, _errorReporter).verify(
+          node: propertyName,
+          requested: null,
+          recovery: writeElementRecovery,
+          receiverTypeObject: typeReference.displayName,
+        );
+      }
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElement,
+      writeElementRequested: writeElement,
+      writeElementRecovery: writeElementRecovery,
+    );
+  }
+
+  PropertyElementResolverResult _resolveTargetExtensionElement({
+    @required ExtensionElement extension,
+    @required SimpleIdentifier propertyName,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    var memberName = propertyName.name;
+
+    ExecutableElement readElement;
+    if (hasRead) {
+      readElement ??= extension.getGetter(memberName);
+      readElement ??= extension.getMethod(memberName);
+
+      if (readElement == null) {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
+          propertyName,
+          [memberName, extension.name],
+        );
+      } else {
+        readElement = _resolver.toLegacyElement(readElement);
+        _checkForStaticAccessToInstanceMember(propertyName, readElement);
+      }
+    }
+
+    ExecutableElement writeElement;
+    if (hasWrite) {
+      writeElement = extension.getSetter(memberName);
+
+      if (writeElement == null) {
+        _resolver.errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
+          propertyName,
+          [memberName, extension.name],
+        );
+      } else {
+        writeElement = _resolver.toLegacyElement(writeElement);
+        _checkForStaticAccessToInstanceMember(propertyName, writeElement);
+      }
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElement,
+      writeElementRequested: writeElement,
+    );
+  }
+
+  PropertyElementResolverResult _resolveTargetExtensionOverride({
+    @required ExtensionOverride target,
+    @required SimpleIdentifier propertyName,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    if (target.parent is CascadeExpression) {
+      // Report this error and recover by treating it like a non-cascade.
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
+        target.extensionName,
+      );
+    }
+
+    ExtensionElement element = target.extensionName.staticElement;
+    String memberName = propertyName.name;
+
+    var result = _extensionResolver.getOverrideMember(target, memberName);
+
+    ExecutableElement readElement;
+    if (hasRead) {
+      readElement = result.getter;
+      if (readElement == null) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
+          propertyName,
+          [memberName, element.name],
+        );
+      }
+      _checkExtensionOverrideStaticMember(propertyName, readElement);
+    }
+
+    ExecutableElement writeElement;
+    if (hasWrite) {
+      writeElement = result.setter;
+      if (writeElement == null) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
+          propertyName,
+          [memberName, element.name],
+        );
+      }
+      _checkExtensionOverrideStaticMember(propertyName, writeElement);
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElement,
+      writeElementRequested: writeElement,
+    );
+  }
+
+  PropertyElementResolverResult _resolveTargetSuperExpression({
+    @required SuperExpression target,
+    @required SimpleIdentifier propertyName,
+    @required bool hasRead,
+    @required bool hasWrite,
+  }) {
+    if (SuperContext.of(target) != SuperContext.valid) {
+      return PropertyElementResolverResult();
+    }
+    var targetType = target.staticType;
+
+    ExecutableElement readElement;
+    ExecutableElement writeElement;
+
+    if (targetType is InterfaceTypeImpl) {
+      if (hasRead) {
+        var name = Name(_definingLibrary.source.uri, propertyName.name);
+        readElement = _resolver.inheritance
+            .getMember2(targetType.element, name, forSuper: true);
+
+        if (readElement != null) {
+          readElement = _resolver.toLegacyElement(readElement);
+        } else {
+          // We were not able to find the concrete dispatch target.
+          // But we would like to give the user at least some resolution.
+          // So, we retry simply looking for an inherited member.
+          readElement =
+              _resolver.inheritance.getInherited2(targetType.element, name);
+          if (readElement != null) {
+            _errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
+              propertyName,
+              [readElement.kind.displayName, propertyName.name],
+            );
+          } else {
+            _errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
+              propertyName,
+              [propertyName.name, targetType],
+            );
+          }
+        }
+      }
+
+      if (hasWrite) {
+        writeElement = targetType.lookUpSetter2(
+          propertyName.name,
+          _definingLibrary,
+          concrete: true,
+          inherited: true,
+        );
+
+        if (writeElement != null) {
+          writeElement = _resolver.toLegacyElement(writeElement);
+        } else {
+          // We were not able to find the concrete dispatch target.
+          // But we would like to give the user at least some resolution.
+          // So, we retry without the "concrete" requirement.
+          writeElement = targetType.lookUpSetter2(
+            propertyName.name,
+            _definingLibrary,
+            inherited: true,
+          );
+          if (writeElement != null) {
+            ClassElementImpl receiverSuperClass =
+                targetType.element.supertype.element;
+            if (!receiverSuperClass.hasNoSuchMethod) {
+              _errorReporter.reportErrorForNode(
+                CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
+                propertyName,
+                [writeElement.kind.displayName, propertyName.name],
+              );
+            }
+          } else {
+            _errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.UNDEFINED_SUPER_SETTER,
+              propertyName,
+              [propertyName.name, targetType],
+            );
+          }
+        }
+      }
+    }
+
+    return PropertyElementResolverResult(
+      readElementRequested: readElement,
+      writeElementRequested: writeElement,
+    );
+  }
+
+  /// If the given [type] is a type parameter, replace with its bound.
+  /// Otherwise, return the original type.
+  DartType _resolveTypeParameter(DartType type) {
+    if (type is TypeParameterType) {
+      return type.resolveToBound(_resolver.typeProvider.objectType);
+    }
+    return type;
+  }
+}
+
+class PropertyElementResolverResult {
+  final ExecutableElement readElementRequested;
+  final ExecutableElement readElementRecovery;
+  final ExecutableElement writeElementRequested;
+  final ExecutableElement writeElementRecovery;
+
+  PropertyElementResolverResult({
+    this.readElementRequested,
+    this.readElementRecovery,
+    this.writeElementRequested,
+    this.writeElementRecovery,
+  });
+
+  ExecutableElement get readElement {
+    return readElementRequested ?? readElementRecovery;
+  }
+
+  ExecutableElement get writeElement {
+    return writeElementRequested ?? writeElementRecovery;
+  }
+}
diff --git a/pkg/analyzer/lib/src/error/assignment_verifier.dart b/pkg/analyzer/lib/src/error/assignment_verifier.dart
new file mode 100644
index 0000000..54f0b21
--- /dev/null
+++ b/pkg/analyzer/lib/src/error/assignment_verifier.dart
@@ -0,0 +1,125 @@
+// 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:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/error/listener.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/error/codes.dart';
+import 'package:meta/meta.dart';
+
+/// Helper for verifying resolution of assignments, in form of explicit
+/// an [AssignmentExpression], or a [PrefixExpression] or [PostfixExpression]
+/// when the operator is an increment operator.
+class AssignmentVerifier {
+  final LibraryElement _definingLibrary;
+  final ErrorReporter _errorReporter;
+
+  AssignmentVerifier(this._definingLibrary, this._errorReporter);
+
+  /// We resolved [node] and found that it references the [requested] element.
+  /// Verify that this element is actually writable.
+  ///
+  /// If the [requested] element is `null`, we might have the [recovery]
+  /// element, which is definitely not a valid write target. We want to report
+  /// a good error about this.
+  ///
+  /// The [receiverTypeObject] might be a [DartType] or [String], and when
+  /// it is not `null`, we report [CompileTimeErrorCode.UNDEFINED_SETTER]
+  /// instead of a more generic [CompileTimeErrorCode.UNDEFINED_IDENTIFIER].
+  void verify({
+    @required SimpleIdentifier node,
+    @required Element requested,
+    @required Element recovery,
+    @required Object receiverTypeObject,
+  }) {
+    if (requested != null) {
+      if (requested is VariableElement) {
+        if (requested.isConst) {
+          _errorReporter.reportErrorForNode(
+            CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
+            node,
+          );
+        } else if (requested.isFinal) {
+          if (_definingLibrary.isNonNullableByDefault) {
+            // Handled during resolution, with flow analysis.
+          } else {
+            _errorReporter.reportErrorForNode(
+              CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_LOCAL,
+              node,
+              [requested.name],
+            );
+          }
+        }
+      }
+      return;
+    }
+
+    if (recovery is ClassElement ||
+        recovery is DynamicElementImpl ||
+        recovery is FunctionTypeAliasElement ||
+        recovery is TypeParameterElement) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.ASSIGNMENT_TO_TYPE,
+        node,
+      );
+    } else if (recovery is FunctionElement) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.ASSIGNMENT_TO_FUNCTION,
+        node,
+      );
+    } else if (recovery is MethodElement) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.ASSIGNMENT_TO_METHOD,
+        node,
+      );
+    } else if (recovery is PrefixElement) {
+      _errorReporter.reportErrorForNode(
+        CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+        node,
+        [recovery.name],
+      );
+    } else if (recovery is PropertyAccessorElement && recovery.isGetter) {
+      var variable = recovery.variable;
+      if (variable.isConst) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.ASSIGNMENT_TO_CONST,
+          node,
+        );
+      } else if (variable is FieldElement && variable.isSynthetic) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.ASSIGNMENT_TO_FINAL_NO_SETTER,
+          node,
+          [variable.name, variable.enclosingElement.displayName],
+        );
+      } else {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.ASSIGNMENT_TO_FINAL,
+          node,
+          [variable.name],
+        );
+      }
+    } else if (recovery is MultiplyDefinedElementImpl) {
+      // Will be reported in ErrorVerifier.
+    } else if (node is SimpleIdentifier) {
+      if (node.isSynthetic) {
+        return;
+      }
+      if (receiverTypeObject != null) {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_SETTER,
+          node,
+          [node.name, receiverTypeObject],
+        );
+      } else {
+        _errorReporter.reportErrorForNode(
+          CompileTimeErrorCode.UNDEFINED_IDENTIFIER,
+          node,
+          [node.name],
+        );
+      }
+    }
+  }
+}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index 0ae3509..469a0ce 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -9,12 +9,12 @@
 import 'package:analyzer/dart/element/type.dart';
 import 'package:analyzer/error/listener.dart';
 import 'package:analyzer/src/dart/element/element.dart';
-import 'package:analyzer/src/dart/element/inheritance_manager3.dart';
 import 'package:analyzer/src/dart/element/type.dart';
 import 'package:analyzer/src/dart/element/type_provider.dart';
 import 'package:analyzer/src/dart/element/type_system.dart';
 import 'package:analyzer/src/dart/resolver/extension_member_resolver.dart';
 import 'package:analyzer/src/dart/resolver/method_invocation_resolver.dart';
+import 'package:analyzer/src/dart/resolver/property_element_resolver.dart';
 import 'package:analyzer/src/dart/resolver/resolution_result.dart';
 import 'package:analyzer/src/dart/resolver/scope.dart';
 import 'package:analyzer/src/dart/resolver/type_property_resolver.dart';
@@ -23,7 +23,6 @@
 import 'package:analyzer/src/generated/resolver.dart';
 import 'package:analyzer/src/generated/super_context.dart';
 import 'package:analyzer/src/task/strong/checker.dart';
-import 'package:meta/meta.dart';
 
 /// An object used by instances of [ResolverVisitor] to resolve references
 /// within the AST structure to the elements being referenced. The requirements
@@ -91,9 +90,6 @@
   /// The type representing the type 'dynamic'.
   DartType _dynamicType;
 
-  /// The type representing the type 'Type'.
-  InterfaceType _typeType;
-
   /// Whether constant evaluation errors should be reported during resolution.
   @Deprecated('This field is no longer used')
   final bool reportConstEvaluationErrors;
@@ -116,7 +112,6 @@
         _extensionResolver = _resolver.extensionResolver,
         _typePropertyResolver = _resolver.typePropertyResolver {
     _dynamicType = _typeProvider.dynamicType;
-    _typeType = _typeProvider.typeType;
     _methodInvocationResolver = MethodInvocationResolver(
       _resolver,
       migratableAstInfoProvider,
@@ -577,81 +572,69 @@
     // Otherwise, the prefix is really an expression that happens to be a simple
     // identifier and this is really equivalent to a property access node.
     //
-    _resolvePropertyAccess(
-      node,
-      prefix,
-      identifier,
-      isCascaded: false,
-      isNullAware: false,
-    );
+    {
+      var hasRead = identifier.inGetterContext();
+      var hasWrite = identifier.inSetterContext();
+
+      var resolver = PropertyElementResolver(_resolver);
+      var result = resolver.resolvePrefixedIdentifier(
+        node: node,
+        hasRead: hasRead,
+        hasWrite: hasWrite,
+      );
+
+      if (hasRead) {
+        _resolver.setReadElement(node, result.readElement);
+      }
+
+      if (hasWrite) {
+        _resolver.setWriteElement(node, result.writeElement);
+      }
+
+      if (hasWrite) {
+        identifier.staticElement = result.writeElement;
+        if (hasRead) {
+          identifier.auxiliaryElements = AuxiliaryElements(
+            result.readElement,
+          );
+        }
+      } else if (hasRead) {
+        identifier.staticElement = result.readElement;
+      }
+    }
   }
 
   @override
   void visitPropertyAccess(PropertyAccess node) {
-    Expression target = node.realTarget;
-    if (target is SuperExpression &&
-        SuperContext.of(target) != SuperContext.valid) {
-      return;
-    } else if (target is ExtensionOverride) {
-      if (target.parent is CascadeExpression) {
-        // Report this error and recover by treating it like a non-cascade.
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.EXTENSION_OVERRIDE_WITH_CASCADE,
-          target.extensionName,
+    var propertyName = node.propertyName;
+    var hasRead = propertyName.inGetterContext();
+    var hasWrite = propertyName.inSetterContext();
+
+    var resolver = PropertyElementResolver(_resolver);
+    var result = resolver.resolvePropertyAccess(
+      node: node,
+      hasRead: hasRead,
+      hasWrite: hasWrite,
+    );
+
+    if (hasRead) {
+      _resolver.setReadElement(node, result.readElement);
+    }
+
+    if (hasWrite) {
+      _resolver.setWriteElement(node, result.writeElement);
+    }
+
+    if (hasWrite) {
+      propertyName.staticElement = result.writeElement;
+      if (hasRead) {
+        propertyName.auxiliaryElements = AuxiliaryElements(
+          result.readElement,
         );
       }
-      ExtensionElement element = target.extensionName.staticElement;
-      SimpleIdentifier propertyName = node.propertyName;
-      String memberName = propertyName.name;
-      ExecutableElement member;
-      var result = _extensionResolver.getOverrideMember(target, memberName);
-      if (propertyName.inSetterContext()) {
-        _resolver.setWriteElement(node, result.setter);
-        member = result.setter;
-        if (member == null) {
-          _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
-              propertyName,
-              [memberName, element.name]);
-        }
-        if (propertyName.inGetterContext()) {
-          _resolver.setReadElement(node, result.getter);
-          ExecutableElement getter = result.getter;
-          if (getter == null) {
-            _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
-                propertyName,
-                [memberName, element.name]);
-          }
-          propertyName.auxiliaryElements = AuxiliaryElements(getter);
-        }
-      } else if (propertyName.inGetterContext()) {
-        _resolver.setReadElement(node, result.getter);
-        member = result.getter;
-        if (member == null) {
-          _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
-              propertyName,
-              [memberName, element.name]);
-        }
-      }
-      if (member != null && member.isStatic) {
-        _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.EXTENSION_OVERRIDE_ACCESS_TO_STATIC_MEMBER,
-            propertyName);
-      }
-
-      propertyName.staticElement = member;
-      return;
+    } else if (hasRead) {
+      propertyName.staticElement = result.readElement;
     }
-    SimpleIdentifier propertyName = node.propertyName;
-    _resolvePropertyAccess(
-      node,
-      target,
-      propertyName,
-      isCascaded: node.isCascaded,
-      isNullAware: node.isNullAware,
-    );
   }
 
   @override
@@ -886,20 +869,6 @@
     _resolveAnnotations(node.metadata);
   }
 
-  /// If the [element] is not static, report the error on the [identifier].
-  void _checkForStaticAccessToInstanceMember(
-    SimpleIdentifier identifier,
-    ExecutableElement element,
-  ) {
-    if (element.isStatic) return;
-
-    _errorReporter.reportErrorForNode(
-      CompileTimeErrorCode.STATIC_ACCESS_TO_INSTANCE_MEMBER,
-      identifier,
-      [identifier.name],
-    );
-  }
-
   /// Check that the given index [expression] was resolved, otherwise a
   /// [CompileTimeErrorCode.UNDEFINED_OPERATOR] is generated. The [target] is
   /// the target of the expression. The [methodName] is the name of the operator
@@ -1283,311 +1252,6 @@
     _resolveAnnotations(node.metadata);
   }
 
-  void _resolvePropertyAccess(
-    Expression node,
-    Expression target,
-    SimpleIdentifier propertyName, {
-    @required bool isCascaded,
-    @required bool isNullAware,
-  }) {
-    DartType staticType = _getStaticType(target);
-
-    //
-    // If this property access is of the form 'E.m' where 'E' is an extension,
-    // then look for the member in the extension. This does not apply to
-    // conditional property accesses (i.e. 'C?.m').
-    //
-    if (target is Identifier && target.staticElement is ExtensionElement) {
-      ExtensionElement extension = target.staticElement;
-      String memberName = propertyName.name;
-
-      if (propertyName.inGetterContext()) {
-        ExecutableElement element;
-        element ??= extension.getGetter(memberName);
-        element ??= extension.getMethod(memberName);
-        if (element != null) {
-          element = _resolver.toLegacyElement(element);
-          propertyName.staticElement = element;
-          _checkForStaticAccessToInstanceMember(propertyName, element);
-        } else {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_EXTENSION_GETTER,
-            propertyName,
-            [memberName, extension.name],
-          );
-        }
-      }
-
-      if (propertyName.inSetterContext()) {
-        var element = extension.getSetter(memberName);
-        if (element != null) {
-          element = _resolver.toLegacyElement(element);
-          propertyName.staticElement = element;
-          _checkForStaticAccessToInstanceMember(propertyName, element);
-        } else {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_EXTENSION_SETTER,
-            propertyName,
-            [memberName, extension.name],
-          );
-        }
-      }
-
-      return;
-    }
-
-    //
-    // If this property access is of the form 'C.m' where 'C' is a class,
-    // then we don't call resolveProperty(...) which walks up the class
-    // hierarchy, instead we just look for the member in the type only.  This
-    // does not apply to conditional property accesses (i.e. 'C?.m').
-    //
-    ClassElement typeReference = getTypeReference(target);
-    if (typeReference != null) {
-      if (isCascaded) {
-        typeReference = _typeType.element;
-      }
-
-      if (propertyName.inGetterContext()) {
-        ExecutableElement element;
-
-        if (element == null) {
-          var getter = typeReference.getGetter(propertyName.name);
-          if (getter != null && getter.isAccessibleIn(_definingLibrary)) {
-            element = getter;
-          }
-        }
-
-        if (element == null) {
-          var method = typeReference.getMethod(propertyName.name);
-          if (method != null && method.isAccessibleIn(_definingLibrary)) {
-            element = method;
-          }
-        }
-
-        element = _resolver.toLegacyElement(element);
-        _resolver.setReadElement(node, element);
-
-        if (element != null) {
-          propertyName.staticElement = element;
-          _checkForStaticAccessToInstanceMember(propertyName, element);
-        } else {
-          var code = typeReference.isEnum
-              ? CompileTimeErrorCode.UNDEFINED_ENUM_CONSTANT
-              : CompileTimeErrorCode.UNDEFINED_GETTER;
-          _errorReporter.reportErrorForNode(
-            code,
-            propertyName,
-            [propertyName.name, typeReference.name],
-          );
-        }
-      }
-
-      if (propertyName.inSetterContext()) {
-        ExecutableElement element;
-
-        var setter = typeReference.getSetter(propertyName.name);
-        setter = _resolver.toLegacyElement(setter);
-
-        _resolver.setWriteElement(node, setter);
-
-        if (setter != null) {
-          element = setter;
-          if (!setter.isAccessibleIn(_definingLibrary)) {
-            _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.PRIVATE_SETTER,
-              propertyName,
-              [propertyName.name, typeReference.name],
-            );
-          }
-        }
-
-        if (element != null) {
-          propertyName.staticElement = element;
-          _checkForStaticAccessToInstanceMember(propertyName, element);
-        } else {
-          var getter = typeReference.getGetter(propertyName.name);
-          if (getter != null) {
-            propertyName.staticElement = getter;
-            _resolver.setWriteElement(node, getter);
-            // The error will be reported in ErrorVerifier.
-          } else {
-            _errorReporter.reportErrorForNode(
-              CompileTimeErrorCode.UNDEFINED_SETTER,
-              propertyName,
-              [propertyName.name, typeReference.name],
-            );
-          }
-        }
-      }
-
-      return;
-    }
-
-    if (target is SuperExpression) {
-      if (staticType is InterfaceTypeImpl) {
-        if (propertyName.inGetterContext()) {
-          var name = Name(_definingLibrary.source.uri, propertyName.name);
-          var element = _resolver.inheritance
-              .getMember2(staticType.element, name, forSuper: true);
-          _resolver.setReadElement(node, element);
-
-          if (element != null) {
-            element = _resolver.toLegacyElement(element);
-            propertyName.staticElement = element;
-          } else {
-            // We were not able to find the concrete dispatch target.
-            // But we would like to give the user at least some resolution.
-            // So, we retry simply looking for an inherited member.
-            var element =
-                _resolver.inheritance.getInherited2(staticType.element, name);
-            if (element != null) {
-              propertyName.staticElement = element;
-              _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
-                propertyName,
-                [element.kind.displayName, propertyName.name],
-              );
-            } else {
-              _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.UNDEFINED_SUPER_GETTER,
-                propertyName,
-                [propertyName.name, staticType],
-              );
-            }
-          }
-        }
-
-        if (propertyName.inSetterContext()) {
-          var element = staticType.lookUpSetter2(
-            propertyName.name,
-            _definingLibrary,
-            concrete: true,
-            inherited: true,
-          );
-          _resolver.setWriteElement(node, element);
-
-          if (element != null) {
-            element = _resolver.toLegacyElement(element);
-            propertyName.staticElement = element;
-          } else {
-            // We were not able to find the concrete dispatch target.
-            // But we would like to give the user at least some resolution.
-            // So, we retry without the "concrete" requirement.
-            var element = staticType.lookUpSetter2(
-              propertyName.name,
-              _definingLibrary,
-              inherited: true,
-            );
-            if (element != null) {
-              propertyName.staticElement = element;
-              ClassElementImpl receiverSuperClass =
-                  staticType.element.supertype.element;
-              if (!receiverSuperClass.hasNoSuchMethod) {
-                _errorReporter.reportErrorForNode(
-                  CompileTimeErrorCode.ABSTRACT_SUPER_MEMBER_REFERENCE,
-                  propertyName,
-                  [element.kind.displayName, propertyName.name],
-                );
-              }
-            } else {
-              _errorReporter.reportErrorForNode(
-                CompileTimeErrorCode.UNDEFINED_SUPER_SETTER,
-                propertyName,
-                [propertyName.name, staticType],
-              );
-            }
-          }
-        }
-      }
-
-      return;
-    }
-
-    if (staticType == null || staticType.isDynamic) {
-      return;
-    }
-
-    if (isNullAware) {
-      staticType = _typeSystem.promoteToNonNull(staticType);
-    }
-
-    if (staticType.isVoid) {
-      _errorReporter.reportErrorForNode(
-        CompileTimeErrorCode.USE_OF_VOID_RESULT,
-        propertyName,
-      );
-      return;
-    }
-
-    var result = _typePropertyResolver.resolve(
-      receiver: target,
-      receiverType: staticType,
-      name: propertyName.name,
-      receiverErrorNode: target,
-      nameErrorNode: propertyName,
-    );
-
-    if (propertyName.inGetterContext()) {
-      _resolver.setReadElement(node, result.getter);
-      var shouldReportUndefinedGetter = false;
-      if (result.isSingle) {
-        var getter = result.getter;
-        if (getter != null) {
-          propertyName.staticElement = getter;
-        } else {
-          shouldReportUndefinedGetter = true;
-        }
-      } else if (result.isNone) {
-        if (staticType is FunctionType &&
-            propertyName.name == FunctionElement.CALL_METHOD_NAME) {
-          // Referencing `.call` on a `Function` type is OK.
-        } else if (staticType is InterfaceType &&
-            staticType.isDartCoreFunction &&
-            propertyName.name == FunctionElement.CALL_METHOD_NAME) {
-          // Referencing `.call` on a `Function` type is OK.
-        } else if (staticType is NeverTypeImpl) {
-          shouldReportUndefinedGetter = false;
-        } else {
-          shouldReportUndefinedGetter = true;
-        }
-      }
-      if (shouldReportUndefinedGetter) {
-        _errorReporter.reportErrorForNode(
-          CompileTimeErrorCode.UNDEFINED_GETTER,
-          propertyName,
-          [propertyName.name, staticType],
-        );
-      }
-    }
-
-    if (propertyName.inSetterContext()) {
-      _resolver.setWriteElement(node, result.setter);
-      if (result.isSingle) {
-        var setter = result.setter;
-        if (setter != null) {
-          propertyName.staticElement = setter;
-          propertyName.auxiliaryElements = AuxiliaryElements(result.getter);
-        } else {
-          var getter = result.getter;
-          propertyName.staticElement = getter;
-          _resolver.setWriteElement(node, getter);
-          // A more specific error will be reported in ErrorVerifier.
-        }
-      } else if (result.isNone) {
-        if (staticType is NeverTypeImpl) {
-          // OK
-        } else {
-          _errorReporter.reportErrorForNode(
-            CompileTimeErrorCode.UNDEFINED_SETTER,
-            propertyName,
-            [propertyName.name, staticType],
-          );
-        }
-      }
-    }
-  }
-
   /// Resolve the given simple [identifier] if possible. Return the element to
   /// which it could be resolved, or `null` if it could not be resolved. This
   /// does not record the results of the resolution.
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 8abc401..75fcfb7 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -1628,6 +1628,9 @@
   /// [StaticWarningCode.ASSIGNMENT_TO_FINAL], and
   /// [StaticWarningCode.ASSIGNMENT_TO_METHOD].
   void _checkForAssignmentToFinal(Expression expression) {
+    // TODO(scheglov) Check SimpleIdentifier(s) as all other nodes.
+    if (expression is! SimpleIdentifier) return;
+
     // Already handled in the assignment resolver.
     if (expression is SimpleIdentifier &&
         expression.parent is AssignmentExpression) {
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index d1fedd3..43d1494 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -664,6 +664,22 @@
     }
   }
 
+  void startNullAwarePropertyAccess(
+    PropertyAccess node,
+  ) {
+    if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
+        _isNonNullableByDefault) {
+      var target = node.target;
+      if (target is SimpleIdentifier && target.staticElement is ClassElement) {
+        // `?.` to access static methods is equivalent to `.`, so do nothing.
+      } else {
+        _flowAnalysis.flow.nullAwareAccess_rightBegin(
+            target, node.realTarget.staticType ?? typeProvider.dynamicType);
+        _unfinishedNullShorts.add(node.nullShortingTermination);
+      }
+    }
+  }
+
   /// If in a legacy library, return the legacy view on the [element].
   /// Otherwise, return the original element.
   T toLegacyElement<T extends Element>(T element) {
@@ -1642,16 +1658,7 @@
     //
     var target = node.target;
     target?.accept(this);
-    if (_migratableAstInfoProvider.isPropertyAccessNullAware(node) &&
-        _isNonNullableByDefault) {
-      if (target is SimpleIdentifier && target.staticElement is ClassElement) {
-        // `?.` to access static methods is equivalent to `.`, so do nothing.
-      } else {
-        _flowAnalysis.flow.nullAwareAccess_rightBegin(
-            target, node.realTarget.staticType ?? typeProvider.dynamicType);
-        _unfinishedNullShorts.add(node.nullShortingTermination);
-      }
-    }
+    startNullAwarePropertyAccess(node);
     node.accept(elementResolver);
     node.accept(typeAnalyzer);
   }
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index f219504..7f232fc 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -3495,36 +3495,36 @@
   }
 
   test_instantiateToBounds_class_error_recursion() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C<T0 extends List<T1>, T1 extends List<T0>> {}
 C c;
-''', []);
+''');
     _assertTopVarType('c', 'C<List<dynamic>, List<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_recursion_self() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C<T extends C<T>> {}
 C c;
-''', []);
+''');
     _assertTopVarType('c', 'C<C<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_recursion_self2() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class A<E> {}
 class C<T extends A<T>> {}
 C c;
-''', []);
+''');
     _assertTopVarType('c', 'C<A<dynamic>>');
   }
 
   test_instantiateToBounds_class_error_typedef() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 typedef T F<T>(T x);
 class C<T extends F<T>> {}
 C c;
-''', []);
+''');
     _assertTopVarType('c', 'C<dynamic Function(dynamic)>');
   }
 
diff --git a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
index d8b9392..0c06671 100644
--- a/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/assignment_test.dart
@@ -352,7 +352,6 @@
 ''', [
       error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 35, 5),
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 35, 5),
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 44, 1),
     ]);
 
     var assignment = findNode.assignment('= c');
@@ -362,11 +361,8 @@
       readType: 'dynamic',
       writeElement: null,
       writeType: 'dynamic',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isNullSafetySdkAndLegacyLibrary,
-      ),
-      type: 'double',
+      operatorElement: null,
+      type: 'dynamic',
     );
 
     assertElement(findNode.simple('a +'), findElement.parameter('a'));
@@ -382,7 +378,6 @@
 ''', [
       error(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 35, 7),
       error(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 35, 7),
-      error(CompileTimeErrorCode.INVALID_ASSIGNMENT, 46, 1),
     ]);
 
     var assignment = findNode.assignment('= c');
@@ -392,11 +387,8 @@
       readType: 'dynamic',
       writeElement: null,
       writeType: 'dynamic',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isNullSafetySdkAndLegacyLibrary,
-      ),
-      type: 'double',
+      operatorElement: null,
+      type: 'dynamic',
     );
   }
 
@@ -461,11 +453,8 @@
       readType: 'dynamic',
       writeElement: null,
       writeType: 'dynamic',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isNullSafetySdkAndLegacyLibrary,
-      ),
-      type: 'num',
+      operatorElement: null,
+      type: 'dynamic',
     );
 
     assertSimpleIdentifier(
@@ -555,11 +544,8 @@
       readType: 'dynamic',
       writeElement: null,
       writeType: 'dynamic',
-      operatorElement: elementMatcher(
-        numElement.getMethod('+'),
-        isLegacy: isNullSafetySdkAndLegacyLibrary,
-      ),
-      type: 'num',
+      operatorElement: null,
+      type: 'dynamic',
     );
 
     assertSimpleIdentifier(
diff --git a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
index 38ca656..d35a83b 100644
--- a/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
+++ b/pkg/analyzer/test/src/dart/resolution/binary_expression_test.dart
@@ -776,11 +776,11 @@
   }
 
   test_plus_int_never() async {
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 f(int a, Never b) {
   a + b;
 }
-''', []);
+''');
 
     assertBinaryExpression(findNode.binary('a + b'),
         element: numElement.getMethod('+'), type: 'num');
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
index c4da4a8..9a30b49 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_const_test.dart
@@ -24,7 +24,7 @@
 f() {
   A.v = 1;
 }''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 42, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 44, 1),
     ]);
   }
 
@@ -36,7 +36,7 @@
 f() {
   A.v += 1;
 }''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 42, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_CONST, 44, 1),
     ]);
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
index 3d229b4..60d039d 100644
--- a/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/assignment_to_method_test.dart
@@ -25,23 +25,57 @@
   void set foo(int _) {}
 }
 
-f(C c) {
+void f(C c) {
   c.foo = 0;
+  c.foo += 1;
+  c.foo++;
+  --c.foo;
 }
 ''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 87, 5),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 94, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 107, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 121, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 134, 3),
     ]);
   }
 
-  test_method() async {
+  test_prefixedIdentifier_instanceMethod() async {
     await assertErrorsInCode('''
 class A {
-  m() {}
+  void foo() {}
 }
-f(A a) {
-  a.m = () {};
-}''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 32, 3),
+
+void f(A a) {
+  a.foo = 0;
+  a.foo += 1;
+  a.foo++;
+  ++a.foo;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 47, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 60, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 74, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 87, 3),
+    ]);
+  }
+
+  test_propertyAccess_instanceMethod() async {
+    await assertErrorsInCode('''
+class A {
+  void foo() {}
+}
+
+void f(A a) {
+  (a).foo = 0;
+  (a).foo += 1;
+  (a).foo++;
+  ++(a).foo;
+}
+''', [
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 49, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 64, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 80, 3),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 95, 3),
     ]);
   }
 
@@ -59,7 +93,7 @@
   }
 }
 ''', [
-      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 86, 8),
+      error(CompileTimeErrorCode.ASSIGNMENT_TO_METHOD, 91, 3),
     ]);
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart b/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
index a669585..e5abe38 100644
--- a/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/binary_operator_written_out_test.dart
@@ -26,11 +26,11 @@
   }
 
   test_using_and_no_error() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(var x, var y) {
   return x & y;
 }
-''', []);
+''');
   }
 
   test_using_or() async {
@@ -44,11 +44,11 @@
   }
 
   test_using_or_no_error() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(var x, var y) {
   return x | y;
 }
-''', []);
+''');
   }
 
   test_using_shl() async {
@@ -62,11 +62,11 @@
   }
 
   test_using_shl_no_error() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(var x) {
   return x << 2;
 }
-''', []);
+''');
   }
 
   test_using_shr() async {
@@ -80,11 +80,11 @@
   }
 
   test_using_shr_no_error() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(var x) {
   return x >> 2;
 }
-''', []);
+''');
   }
 
   test_using_xor() async {
@@ -98,10 +98,10 @@
   }
 
   test_using_xor_no_error() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 f(var x, var y) {
   return x ^ y;
 }
-''', []);
+''');
   }
 }
diff --git a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
index a5edc42..207edcb 100644
--- a/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/receiver_of_type_never_test.dart
@@ -446,7 +446,7 @@
       writeElement: null,
       writeType: 'dynamic',
       operatorElement: null,
-      type: 'int',
+      type: 'dynamic',
     );
   }
 
diff --git a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
index a668a46..35eb115 100644
--- a/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
+++ b/pkg/analyzer/test/src/diagnostics/undefined_getter_test.dart
@@ -123,11 +123,11 @@
     // Referencing `.call` on a `Function` type works similarly to referencing
     // it on `dynamic`--the reference is accepted at compile time, and all type
     // checking is deferred until runtime.
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 f(Function f) {
   return f.call;
 }
-''', []);
+''');
   }
 
   test_ifElement_inList_notPromoted() async {
@@ -263,6 +263,26 @@
     ]);
   }
 
+  test_propertyAccess_functionClass_call() async {
+    await assertNoErrorsInCode('''
+void f(Function a) {
+  return (a).call;
+}
+''');
+  }
+
+  test_propertyAccess_functionType_call() async {
+    await assertNoErrorsInCode('''
+class A {
+  void staticMethod() {}
+}
+
+void f(A a) {
+  return a.staticMethod.call;
+}
+''');
+  }
+
   test_proxy_annotation_fakeProxy() async {
     await assertErrorsInCode(r'''
 library L;
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 2a30b09..826a082 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -10335,6 +10335,20 @@
 ''');
   }
 
+  test_type_inference_assignmentExpression_references_onTopLevelVariable() async {
+    var library = await checkLibrary('''
+var a = () {
+  b += 0;
+  return 0;
+};
+var b = 0;
+''');
+    checkElementText(library, '''
+int Function() a;
+int b;
+''');
+  }
+
   test_type_inference_based_on_loadLibrary() async {
     addLibrarySource('/a.dart', '');
     var library = await checkLibrary('''
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 41ea625..b71fb4b 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -418,7 +418,7 @@
 
   test_constantGenericTypeArg_infer() async {
     // Regression test for https://github.com/dart-lang/sdk/issues/26141
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 abstract class Equality<Q> {}
 abstract class EqualityBase<R> implements Equality<R> {
   final C<R> c = const C();
@@ -439,7 +439,7 @@
 main() {
   const SetEquality<String>();
 }
-''', []);
+''');
   }
 
   test_constructorInvalid() async {
@@ -2298,7 +2298,7 @@
   }
 
   test_genericMethodOverride() async {
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 class Future<T> {
   S then<S>(S onValue(T t)) => null;
 }
@@ -2318,7 +2318,7 @@
 class DerivedFuture4<A> extends Future<A> {
   B then<B>(Object onValue(A a)) => null;
 }
-''', []);
+''');
   }
 
   test_genericMethodSuper() async {
@@ -2348,7 +2348,7 @@
   }
 
   test_genericMethodSuperSubstitute() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class Cloneable<T> {}
 class G<T> {
   create<A extends Cloneable<T>, B extends Iterable<A>>() => null;
@@ -2356,7 +2356,7 @@
 class H extends G<num> {
   create2() => super.create<Cloneable<int>, List<Cloneable<int>>>();
 }
-''', []);
+''');
   }
 
   test_getterGetterOverride() async {
@@ -3103,7 +3103,7 @@
 
   test_implicitDynamic_static() async {
     _disableTestPackageImplicitDynamic();
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class C {
   static void test(int body()) {}
 }
@@ -3113,7 +3113,7 @@
     return 42;
   });
 }
-''', []);
+''');
   }
 
   test_implicitDynamic_type() async {
@@ -3223,7 +3223,7 @@
 
   test_interfacesFromMixinsOnlyConsiderMostDerivedMember() {
     // Regression test for dart2js interface pattern in strong mode.
-    return assertErrorsInCode(r'''
+    return assertNoErrorsInCode(r'''
 abstract class I1 { num get x; }
 abstract class I2 extends I1 { int get x; }
 
@@ -3234,7 +3234,7 @@
 class Child extends Base with M2 implements I2 {}
 
 class C extends Object with M1, M2 implements I1, I2 {}
-''', []);
+''');
   }
 
   test_interfacesFromMixinsUsedTwiceAreChecked() {
@@ -3548,7 +3548,7 @@
     // This is a regression test for a bug in an earlier implementation were
     // names were hiding errors if the first mixin override looked correct,
     // but subsequent ones did not.
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 class A {}
 class B {}
 
@@ -3571,7 +3571,7 @@
 class T1 extends Base with M1, M2, M3 {}
 
 class U1 = Base with M1, M2, M3;
-''', []);
+''');
   }
 
   test_invalidOverrides_noErrorsIfSubclassCorrectlyOverrideBaseAndInterface() async {
@@ -3785,14 +3785,14 @@
 
   test_methodTearoffStrictArrow() async {
     // Regression test for https://github.com/dart-lang/sdk/issues/26393
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 class A {
   void foo(dynamic x) {}
   void test(void f(int x)) {
     test(foo);
   }
 }
-''', []);
+''');
   }
 
   test_mixinApplicationIsConcrete() {
@@ -4092,7 +4092,7 @@
   }
 
   test_nullCoalescingOperator() async {
-    await assertErrorsInCode('''
+    await assertNoErrorsInCode('''
 class A {}
 class C<T> {}
 main() {
@@ -4105,11 +4105,11 @@
   c ??= new C();
   d = d ?? new C();
 }
-''', []);
+''');
   }
 
   test_nullCoalescingStrictArrow() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 bool _alwaysTrue(x) => true;
 typedef bool TakesA<T>(T t);
 class C<T> {
@@ -4118,7 +4118,7 @@
     : g = f ?? _alwaysTrue;
   C.a() : g = _alwaysTrue;
 }
-''', []);
+''');
   }
 
   test_optionalParams() async {
@@ -4155,13 +4155,13 @@
 
   test_overrideNarrowsType_legalWithChecked() async {
     // Regression test for https://github.com/dart-lang/sdk/issues/25232
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 abstract class A { void test(A arg) { } }
 abstract class B extends A { void test(covariant B arg) { } }
 abstract class X implements A { }
 class C extends B with X { }
 class D extends B implements A { }
-''', []);
+''');
   }
 
   test_overrideNarrowsType_noDuplicateError() {
@@ -4643,7 +4643,7 @@
   }
 
   test_tearOffTreatedConsistentlyAsStrictArrow() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 void foo(void f(String x)) {}
 
 class A {
@@ -4666,11 +4666,11 @@
   foo(baz2);
   foo(baz3);
 }
-''', []);
+''');
   }
 
   test_tearOffTreatedConsistentlyAsStrictArrowNamedParam() async {
-    await assertErrorsInCode(r'''
+    await assertNoErrorsInCode(r'''
 typedef void Handler(String x);
 void foo({Handler f}) {}
 
@@ -4694,7 +4694,7 @@
   foo(f: baz2);
   foo(f: baz3);
 }
-''', []);
+''');
   }
 
   test_ternaryOperator() async {
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 4aa804c..365500e 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -1502,7 +1502,20 @@
   }
 
   @override
-  AbstractValue computeType(InferrerEngine inferrer) => safeType(inferrer);
+  AbstractValue computeType(InferrerEngine inferrer) {
+    AbstractValueDomain abstractValueDomain = inferrer.abstractValueDomain;
+    AbstractValue closureType = closure.type;
+    // We are not tracking closure calls, but if the receiver is not callable,
+    // the call will fail. The abstract value domain does not have a convenient
+    // method for detecting callable types, but we know `null` and unreachable
+    // code have no result type.  This is helpful for propagating
+    // unreachability, i.e. tree-shaking.
+    if (abstractValueDomain.isEmpty(closureType).isDefinitelyTrue ||
+        abstractValueDomain.isNull(closureType).isDefinitelyTrue) {
+      return abstractValueDomain.emptyType;
+    }
+    return safeType(inferrer);
+  }
 
   @override
   Iterable<MemberEntity> get callees {
diff --git a/pkg/compiler/lib/src/inferrer/types.dart b/pkg/compiler/lib/src/inferrer/types.dart
index 25305e4..bafd5cc3 100644
--- a/pkg/compiler/lib/src/inferrer/types.dart
+++ b/pkg/compiler/lib/src/inferrer/types.dart
@@ -310,22 +310,29 @@
   @override
   AbstractValue resultTypeOfSelector(
       Selector selector, AbstractValue receiver) {
-    // Bailout for closure calls. We're not tracking types of
-    // closures.
-    if (selector.isClosureCall)
-      return closedWorld.abstractValueDomain.dynamicType;
+    AbstractValueDomain abstractValueDomain = closedWorld.abstractValueDomain;
+
+    // Bailout for closure calls. We're not tracking types of closures.
+    if (selector.isClosureCall) {
+      // But if the receiver is not callable, the call will fail.
+      if (abstractValueDomain.isEmpty(receiver).isDefinitelyTrue ||
+          abstractValueDomain.isNull(receiver).isDefinitelyTrue) {
+        return abstractValueDomain.emptyType;
+      }
+      return abstractValueDomain.dynamicType;
+    }
     if (selector.isSetter || selector.isIndexSet) {
-      return closedWorld.abstractValueDomain.dynamicType;
+      return abstractValueDomain.dynamicType;
     }
     if (returnsListElementType(selector, receiver)) {
-      return closedWorld.abstractValueDomain.getContainerElementType(receiver);
+      return abstractValueDomain.getContainerElementType(receiver);
     }
     if (returnsMapValueType(selector, receiver)) {
-      return closedWorld.abstractValueDomain.getMapValueType(receiver);
+      return abstractValueDomain.getMapValueType(receiver);
     }
 
     if (closedWorld.includesClosureCall(selector, receiver)) {
-      return closedWorld.abstractValueDomain.dynamicType;
+      return abstractValueDomain.dynamicType;
     } else {
       Iterable<MemberEntity> elements =
           closedWorld.locateMembers(selector, receiver);
@@ -334,7 +341,7 @@
         AbstractValue type = typeOfMemberWithSelector(element, selector);
         types.add(type);
       }
-      return closedWorld.abstractValueDomain.unionOfMany(types);
+      return abstractValueDomain.unionOfMany(types);
     }
   }
 
diff --git a/pkg/compiler/lib/src/js_model/closure.dart b/pkg/compiler/lib/src/js_model/closure.dart
index 8a3c266..e0dd7a2 100644
--- a/pkg/compiler/lib/src/js_model/closure.dart
+++ b/pkg/compiler/lib/src/js_model/closure.dart
@@ -239,9 +239,9 @@
             }
             break;
           case VariableUseKind.localReturnType:
-            // SSA requires the element type of generators.
             if (usage.localFunction.function.asyncMarker !=
                 ir.AsyncMarker.Sync) {
+              // The Future/Iterator/Stream implementation requires the type.
               return true;
             }
             if (rtiNeed.localFunctionNeedsSignature(usage.localFunction)) {
diff --git a/pkg/compiler/test/inference/data/static.dart b/pkg/compiler/test/inference/data/static.dart
index f641d1a..d34d4fc 100644
--- a/pkg/compiler/test/inference/data/static.dart
+++ b/pkg/compiler/test/inference/data/static.dart
@@ -181,7 +181,7 @@
 /*member: _field1:[null]*/
 dynamic _field1;
 
-/*member: invokeStaticFieldUninitialized:[null|subclass=Object]*/
+/*member: invokeStaticFieldUninitialized:[empty]*/
 invokeStaticFieldUninitialized() => _field1();
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,15 +11,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::EmptyClass;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,15 +11,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::EmptyClass;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,15 +11,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::EmptyClass;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
index 96207aa..129465c 100644
--- a/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/empty.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,15 +11,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::EmptyClass;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///empty.dartEmptyClass".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
index 9fe3384..c465cf0 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -37,15 +40,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::F;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
index fa46235..93db2ab 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -32,6 +35,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class F extends self::B implements self::C /*isEliminatedMixin*/  {
   synthetic constructor •() → self::F
@@ -39,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::F;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
index 9fe3384..c465cf0 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -37,15 +40,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::F;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
index fa46235..93db2ab 100644
--- a/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/explicit_mixin.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -32,6 +35,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartA".{core::String::hashCode});
 }
 class F extends self::B implements self::C /*isEliminatedMixin*/  {
   synthetic constructor •() → self::F
@@ -39,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::F;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///explicit_mixin.dartF".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.expect
@@ -8,6 +8,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -18,15 +19,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.strong.transformed.expect
@@ -8,6 +8,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -18,15 +19,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.expect
@@ -8,6 +8,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -18,15 +19,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
index fa2785e..32fe546 100644
--- a/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_final_field_error.dart.weak.transformed.expect
@@ -8,6 +8,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -18,15 +19,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_final_field_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.expect
@@ -9,6 +9,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -19,6 +20,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.strong.transformed.expect
@@ -9,6 +9,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -19,6 +20,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.expect
@@ -9,6 +9,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -19,6 +20,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
index a5978c5..e0bd784 100644
--- a/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_extends_value_error.dart.weak.transformed.expect
@@ -9,6 +9,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -19,6 +20,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_extends_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends self::Animal {
   synthetic constructor •() → self::Cat
@@ -28,11 +31,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.expect
@@ -14,6 +14,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -24,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.strong.transformed.expect
@@ -14,6 +14,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -24,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.expect
@@ -14,6 +14,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -24,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
index dc47c2a..67b715f 100644
--- a/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/non_value_implements_value_error.dart.weak.transformed.expect
@@ -14,6 +14,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -24,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///non_value_implements_value_error.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 class Cat extends core::Object implements self::Animal {
   final field core::int numberOfLegs = null;
@@ -34,11 +37,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
index eb9f0d0..218ec9f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -40,6 +41,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
index ea02301..9845aaa 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.strong.transformed.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -40,6 +41,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
index eb9f0d0..218ec9f 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -40,6 +41,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
index ea02301..9845aaa 100644
--- a/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/simple.dart.weak.transformed.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -40,6 +41,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Animal && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Animal}.{self::Animal::numberOfLegs});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine("org-dartlang-testcase:///simple.dartAnimal".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Animal firstAnimal = invalid-expression "pkg/front_end/testcases/value_class/simple.dart:13:31: Error: No named parameter with the name 'numberOfLegs'.
@@ -62,11 +65,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
index aa94e2f..d3224ed 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -46,6 +47,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
index 0a9d8aa..bf869ee 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.strong.transformed.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -46,6 +47,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
index aa94e2f..d3224ed 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -46,6 +47,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
index 0a9d8aa..bf869ee 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value.dart.weak.transformed.expect
@@ -30,6 +30,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -46,6 +47,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Animal::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Animal::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_extends_non_value.dartCat".{core::String::hashCode}, this.{self::Animal::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_extends_non_value.dart:18:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -68,11 +71,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.expect
@@ -13,6 +13,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -28,6 +29,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.strong.transformed.expect
@@ -13,6 +13,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -28,6 +29,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.expect
@@ -13,6 +13,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -28,6 +29,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
index e0bd837..b1b9373 100644
--- a/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_extends_non_value_error.dart.weak.transformed.expect
@@ -13,6 +13,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -28,6 +29,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat".{core::String::hashCode});
 }
 class Animal2 extends core::Object {
   final field core::int numberOfLegs = null;
@@ -41,15 +44,17 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_extends_non_value_error.dartCat2".{core::String::hashCode});
 }
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
index 28a8793..a0f49ac 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.expect
@@ -71,6 +71,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
 import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self3::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
index 4a66e5d..e412416 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.strong.transformed.expect
@@ -71,6 +71,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
 import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self3::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
index 21d4e29..7ff4c88 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.expect
@@ -71,6 +71,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
 import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self3::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
index 39979d6..939015f 100644
--- a/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_implements_non_value.dart.weak.transformed.expect
@@ -71,6 +71,7 @@
 //
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase-sdk:///pkg/front_end/testcases/nnbd_mixed/nnbd_opt_out_language_version.dart";
 import "org-dartlang-testcase:///value_class_support_lib.dart";
@@ -89,6 +90,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat && this.{self::Cat::numberOfLegs}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfLegs}) && this.{self::Cat::numberOfWhiskers}.{core::num::==}(other{self::Cat}.{self::Cat::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat".{core::String::hashCode}, this.{self::Cat::numberOfLegs}.{core::num::hashCode}), this.{self::Cat::numberOfWhiskers}.{core::num::hashCode}));
 }
 abstract class Animal2 extends core::Object {
   synthetic constructor •() → self::Animal2
@@ -104,6 +107,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::Cat2 && this.{self::Cat2::numberOfLegs}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfLegs}) && this.{self::Cat2::numberOfWhiskers}.{core::num::==}(other{self::Cat2}.{self::Cat2::numberOfWhiskers});
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish(val::JenkinsSmiHash::combine(val::JenkinsSmiHash::combine("org-dartlang-testcase:///value_implements_non_value.dartCat2".{core::String::hashCode}, this.{self::Cat2::numberOfLegs}.{core::num::hashCode}), this.{self::Cat2::numberOfWhiskers}.{core::num::hashCode}));
 }
 static method main() → dynamic {
   self::Cat firstCat = invalid-expression "pkg/front_end/testcases/value_class/value_implements_non_value.dart:30:22: Error: No named parameter with the name 'numberOfLegs'.
@@ -201,11 +206,11 @@
 }
 
 library /*isNonNullableByDefault*/;
-import self as self3;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self3::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
index 18d691c..7e226a5 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -39,11 +42,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
index 338f201..6ae17d2 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.strong.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -22,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class C extends self::_C&B&A {
   synthetic constructor •() → self::C
@@ -41,11 +46,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
index 18d691c..7e226a5 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -39,11 +42,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
index 338f201..6ae17d2 100644
--- a/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/value_class/value_mixin_error.dart.weak.transformed.expect
@@ -1,6 +1,7 @@
 library /*isNonNullableByDefault*/;
 import self as self;
 import "dart:core" as core;
+import "value_class_support_lib.dart" as val;
 
 import "org-dartlang-testcase:///value_class_support_lib.dart";
 
@@ -10,6 +11,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class B extends core::Object {
   synthetic constructor •() → self::B
@@ -22,6 +25,8 @@
     ;
   operator /*isNullableByDefault*/ ==(core::Object other) → core::bool
     return other is self::A;
+  get /*isNullableByDefault*/ hashCode() → core::int
+    return val::JenkinsSmiHash::finish("org-dartlang-testcase:///value_mixin_error.dartA".{core::String::hashCode});
 }
 class C extends self::_C&B&A {
   synthetic constructor •() → self::C
@@ -41,11 +46,11 @@
 static method main() → dynamic {}
 
 library /*isNonNullableByDefault*/;
-import self as self2;
+import self as val;
 import "dart:core" as core;
 
 class JenkinsSmiHash extends core::Object {
-  synthetic constructor •() → self2::JenkinsSmiHash
+  synthetic constructor •() → val::JenkinsSmiHash
     : super core::Object::•()
     ;
   static method combine(core::int hash, core::int value) → core::int {
diff --git a/pkg/kernel/lib/transformations/scanner.dart b/pkg/kernel/lib/transformations/scanner.dart
index 5083fa6..6d4a690 100644
--- a/pkg/kernel/lib/transformations/scanner.dart
+++ b/pkg/kernel/lib/transformations/scanner.dart
@@ -27,25 +27,136 @@
   ScanResult<Class, Y> scan(TreeNode node) {
     ScanResult<Class, Y> result = new ScanResult();
     result.targets = new Map();
+
     if (node is Class) {
       if (predicate(node)) {
         result.targets[node] = next?.scan(node);
       }
     } else if (node is Library) {
-      for (Class cls in node.classes) {
-        if (predicate(cls)) {
-          result.targets[cls] = next?.scan(cls);
-        }
-      }
+      _scanLibrary(node, result);
     } else if (node is Component) {
-      for (Library library in node.libraries) {
-        for (Class cls in library.classes) {
-          if (predicate(cls)) {
-            result.targets[cls] = next?.scan(cls);
-          }
-        }
+      _scanComponent(node, result);
+    }
+
+    return result;
+  }
+
+  void _scanLibrary(Library library, ScanResult<Class, Y> result) {
+    for (Class cls in library.classes) {
+      if (predicate(cls)) {
+        result.targets[cls] = next?.scan(cls);
       }
     }
+  }
+
+  void _scanComponent(Component component, ScanResult<Class, Y> result) {
+    for (Library library in component.libraries) {
+      _scanLibrary(library, result);
+    }
+  }
+}
+
+abstract class FieldScanner<Y extends TreeNode> implements Scanner<Field, Y> {
+  final Scanner<Y, TreeNode> next;
+
+  FieldScanner(this.next);
+
+  bool predicate(Field node);
+
+  ScanResult<Field, Y> scan(TreeNode node) {
+    ScanResult<Field, Y> result = new ScanResult();
+    result.targets = new Map();
+
+    if (node is Field) {
+      if (predicate(node)) {
+        result.targets[node] = next?.scan(node);
+      }
+    } else if (node is Class) {
+      _scanClass(node, result);
+    } else if (node is Library) {
+      _scanLibrary(node, result);
+    } else if (node is Component) {
+      _scanComponent(node, result);
+    }
+
     return result;
   }
+
+  void _scanClass(Class cls, ScanResult<Field, Y> result) {
+    for (Field field in cls.fields) {
+      if (predicate(field)) {
+        result.targets[field] = next?.scan(field);
+      }
+    }
+  }
+
+  void _scanLibrary(Library library, ScanResult<Field, Y> result) {
+    for (Class cls in library.classes) {
+      _scanClass(cls, result);
+    }
+    for (Field field in library.fields) {
+      if (predicate(field)) {
+        result.targets[field] = next?.scan(field);
+      }
+    }
+  }
+
+  void _scanComponent(Component component, ScanResult<Field, Y> result) {
+    for (Library library in component.libraries) {
+      _scanLibrary(library, result);
+    }
+  }
+}
+
+abstract class ProcedureScanner<Y extends TreeNode>
+    implements Scanner<Procedure, Y> {
+  final Scanner<Y, TreeNode> next;
+
+  ProcedureScanner(this.next);
+
+  bool predicate(Procedure node);
+
+  ScanResult<Procedure, Y> scan(TreeNode node) {
+    ScanResult<Procedure, Y> result = new ScanResult();
+    result.targets = new Map();
+
+    if (node is Procedure) {
+      if (predicate(node)) {
+        result.targets[node] = next?.scan(node);
+      }
+    } else if (node is Class) {
+      _scanClass(node, result);
+    } else if (node is Library) {
+      _scanLibrary(node, result);
+    } else if (node is Component) {
+      _scanComponent(node, result);
+    }
+
+    return result;
+  }
+
+  void _scanClass(Class cls, ScanResult<Procedure, Y> result) {
+    for (Procedure procedure in cls.procedures) {
+      if (predicate(procedure)) {
+        result.targets[procedure] = next?.scan(procedure);
+      }
+    }
+  }
+
+  void _scanLibrary(Library library, ScanResult<Procedure, Y> result) {
+    for (Class cls in library.classes) {
+      _scanClass(cls, result);
+    }
+    for (Procedure procedure in library.procedures) {
+      if (predicate(procedure)) {
+        result.targets[procedure] = next?.scan(procedure);
+      }
+    }
+  }
+
+  void _scanComponent(Component component, ScanResult<Procedure, Y> result) {
+    for (Library library in component.libraries) {
+      _scanLibrary(library, result);
+    }
+  }
 }
diff --git a/pkg/kernel/lib/transformations/value_class.dart b/pkg/kernel/lib/transformations/value_class.dart
index 9e38786..dc2d71a 100644
--- a/pkg/kernel/lib/transformations/value_class.dart
+++ b/pkg/kernel/lib/transformations/value_class.dart
@@ -27,6 +27,22 @@
   }
 }
 
+class JenkinsClassScanner extends ClassScanner<Procedure> {
+  JenkinsClassScanner(Scanner<Procedure, TreeNode> next) : super(next);
+
+  bool predicate(Class node) {
+    return node.name == "JenkinsSmiHash";
+  }
+}
+
+class HashCombineMethodsScanner extends ProcedureScanner<Null> {
+  HashCombineMethodsScanner() : super(null);
+
+  bool predicate(Procedure node) {
+    return node.name.name == "combine" || node.name.name == "finish";
+  }
+}
+
 void transformComponent(
     Component node, CoreTypes coreTypes, ClassHierarchy hierarchy) {
   ValueClassScanner scanner = new ValueClassScanner();
@@ -40,7 +56,7 @@
     Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
   addConstructor(cls, coreTypes);
   addEqualsOperator(cls, coreTypes, hierarchy);
-  // addHashCode(cls, coreTypes);
+  addHashCode(cls, coreTypes, hierarchy);
   // addCopyWith(cls);
 }
 
@@ -170,34 +186,90 @@
   cls.addMember(equalsOperator);
 }
 
-/*
-void addHashCode(Class cls, CoreTypes coreTypes) {
-  Map<String, VariableDeclaration> environment = Map.fromIterable(cls.fields,
-      key: (f) => f.name.name,
-      value: (f) => VariableDeclaration(f.name.name, type: f.type));
+void addHashCode(Class cls, CoreTypes coreTypes, ClassHierarchy hierarchy) {
+  for (Procedure procedure in cls.procedures) {
+    if (procedure.kind == ProcedureKind.Getter &&
+        procedure.name.name == "hashCode") {
+      // hashCode getter is already implemented, spec is to do nothing
+      return;
+    }
+  }
+  DartType returnType = cls.enclosingLibrary.isNonNullableByDefault
+      ? coreTypes.intNonNullableRawType
+      : coreTypes.intLegacyRawType;
 
-  VariableDeclaration other = VariableDeclaration("other");
+  Constructor superConstructor = null;
+  for (Constructor constructor in cls.superclass.constructors) {
+    if (constructor.name.name == "") {
+      superConstructor = constructor;
+    }
+  }
 
-  var returnType = cls.enclosingLibrary.isNonNullableByDefault
-      ? coreTypes.boolNonNullableRawType
-      : coreTypes.boolLegacyRawType;
+  Procedure hashCombine, hashFinish;
+  HashCombineMethodsScanner hashCombineMethodsScanner =
+      new HashCombineMethodsScanner();
+  JenkinsClassScanner jenkinsScanner =
+      new JenkinsClassScanner(hashCombineMethodsScanner);
+  ScanResult<Class, Procedure> hashMethodsResult =
+      jenkinsScanner.scan(cls.enclosingLibrary.enclosingComponent);
+  for (Class clazz in hashMethodsResult.targets.keys) {
+    for (Procedure procedure in hashMethodsResult.targets[clazz].targets.keys) {
+      if (procedure.name.name == "combine") hashCombine = procedure;
+      if (procedure.name.name == "finish") hashFinish = procedure;
+    }
+  }
 
+  List<VariableDeclaration> allVariables = superConstructor
+      .function.namedParameters
+      .map<VariableDeclaration>(
+          (f) => VariableDeclaration(f.name, type: f.type))
+      .toList()
+        ..addAll(cls.fields.map<VariableDeclaration>(
+            (f) => VariableDeclaration(f.name.name, type: f.type)));
+
+  Map<VariableDeclaration, Member> targetsHashcode = new Map();
+  Map<VariableDeclaration, Member> targets = new Map();
+  for (VariableDeclaration variable in allVariables) {
+    Member target = coreTypes.objectEquals;
+    Member targetHashcode = coreTypes.objectEquals;
+    DartType fieldsType = variable.type;
+    if (fieldsType is InterfaceType) {
+      targetHashcode =
+          hierarchy.getInterfaceMember(fieldsType.classNode, Name("hashCode"));
+      target = hierarchy.getInterfaceMember(cls, Name(variable.name));
+    }
+    targetsHashcode[variable] = targetHashcode;
+    targets[variable] = target;
+  }
   cls.addMember(Procedure(
       Name("hashCode"),
       ProcedureKind.Getter,
-      FunctionNode(ReturnStatement(cls.fields
-          .map((f) => DirectPropertyGet(
-              VariableGet(environment[f.name.name]),
-              Procedure(Name("hashCode"), ProcedureKind.Getter,
-                  null) // TODO(jlcontreras): Add ref to the real hashCode getter, dont create a new one
-              ))
-          .toList()
-          .fold(
-              IntLiteral(0),
-              (previousValue, element) => MethodInvocation(
-                  previousValue, Name("*"), Arguments([element])))))));
+      FunctionNode(
+          ReturnStatement(StaticInvocation(
+              hashFinish,
+              Arguments([
+                allVariables
+                    .map((f) => (PropertyGet(
+                        PropertyGet(ThisExpression(), Name(f.name), targets[f]),
+                        Name("hashCode"),
+                        targetsHashcode[f])))
+                    .fold(
+                        PropertyGet(
+                            StringLiteral(
+                                cls.enclosingLibrary.importUri.toString() +
+                                    cls.name),
+                            Name("hashCode"),
+                            hierarchy.getInterfaceMember(
+                                coreTypes.stringClass, Name("hashCode"))),
+                        (previousValue, element) => StaticInvocation(
+                            hashCombine, Arguments([previousValue, element])))
+              ]))),
+          returnType: returnType),
+      fileUri: cls.fileUri)
+    ..fileOffset = cls.fileOffset);
 }
 
+/*
 void addCopyWith(Class cls) {
   Map<String, VariableDeclaration> environment = Map.fromIterable(cls.fields,
       key: (f) => f.name.name,
@@ -228,16 +300,3 @@
               cls.fields.map((f) => environment[f.name.name]).toList())));
 }
 */
-
-bool isValueClass(Class cls) {
-  for (Expression annotation in cls.annotations) {
-    if (annotation is ConstantExpression &&
-        annotation.constant is StringConstant) {
-      StringConstant constant = annotation.constant;
-      if (constant.value == 'valueClass') {
-        return true;
-      }
-    }
-  }
-  return false;
-}
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 60a36ec..d901ed9 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -186,11 +186,6 @@
     return Utils::StrDup("VM already initialized or flags not initialized.");
   }
 
-  if (FLAG_causal_async_stacks && FLAG_lazy_async_stacks) {
-    return Utils::StrDup(
-        "To use --lazy-async-stacks, please disable --causal-async-stacks!");
-  }
-
   const Snapshot* snapshot = nullptr;
   if (vm_isolate_snapshot != nullptr) {
     snapshot = Snapshot::SetupFromBuffer(vm_isolate_snapshot);
@@ -210,6 +205,10 @@
       return error;
     }
   }
+  if (FLAG_causal_async_stacks && FLAG_lazy_async_stacks) {
+    return Utils::StrDup(
+        "To use --lazy-async-stacks, please disable --causal-async-stacks!");
+  }
 
   FrameLayout::Init();
 
diff --git a/tests/dart2js/sync_star_element_rti_need_test.dart b/tests/dart2js/sync_star_element_rti_need_test.dart
new file mode 100644
index 0000000..d82ee28
--- /dev/null
+++ b/tests/dart2js/sync_star_element_rti_need_test.dart
@@ -0,0 +1,19 @@
+// 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:expect/expect.dart";
+
+main() {
+  var x = [1, 2, 3];
+  Expect.listEquals(x, nop(x).toList());
+}
+
+Iterable<T> nop<T>(Iterable<T> values) {
+  Iterable<T> inner() sync* {
+    yield* values;
+    return;
+  }
+
+  return inner();
+}
diff --git a/tests/dart2js_2/sync_star_element_rti_need_test.dart b/tests/dart2js_2/sync_star_element_rti_need_test.dart
new file mode 100644
index 0000000..d82ee28
--- /dev/null
+++ b/tests/dart2js_2/sync_star_element_rti_need_test.dart
@@ -0,0 +1,19 @@
+// 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:expect/expect.dart";
+
+main() {
+  var x = [1, 2, 3];
+  Expect.listEquals(x, nop(x).toList());
+}
+
+Iterable<T> nop<T>(Iterable<T> values) {
+  Iterable<T> inner() sync* {
+    yield* values;
+    return;
+  }
+
+  return inner();
+}
diff --git a/tests/language/static/final_field2_test.dart b/tests/language/static/final_field2_test.dart
index 6430471..da8ea37 100644
--- a/tests/language/static/final_field2_test.dart
+++ b/tests/language/static/final_field2_test.dart
@@ -19,9 +19,8 @@
 
 main() {
   A.x = 2;
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
 //  ^
+// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
 // [cfe] Setter not found: 'x'.
   new B();
   print(B.b);
diff --git a/tests/language_2/static/final_field2_test.dart b/tests/language_2/static/final_field2_test.dart
index 6430471..da8ea37 100644
--- a/tests/language_2/static/final_field2_test.dart
+++ b/tests/language_2/static/final_field2_test.dart
@@ -19,9 +19,8 @@
 
 main() {
   A.x = 2;
-//^^^
-// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
 //  ^
+// [analyzer] COMPILE_TIME_ERROR.ASSIGNMENT_TO_CONST
 // [cfe] Setter not found: 'x'.
   new B();
   print(B.b);
diff --git a/tools/VERSION b/tools/VERSION
index 06eb9dd..1813698 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 10
 PATCH 0
-PRERELEASE 117
+PRERELEASE 118
 PRERELEASE_PATCH 0
\ No newline at end of file