Version 2.12.0-25.0.dev

Merge commit 'e769817cdc7ec8c8b1dba908988f729dedc9e364' into 'dev'
diff --git a/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart b/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart
index 23deeb1..47d6dcb 100644
--- a/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart
+++ b/pkg/analyzer/test/dart/analysis/from_environment_evaluator_test.dart
@@ -22,8 +22,8 @@
 class FromEnvironmentEvaluatorTest {
   static const String _defaultValue = 'defaultValue';
 
-  TypeProvider typeProvider;
-  TypeSystemImpl typeSystem;
+  /*late final*/ TypeProvider typeProvider;
+  /*late final*/ TypeSystemImpl typeSystem;
 
   DartObjectImpl get _boolValueFalse {
     return DartObjectImpl(
diff --git a/pkg/analyzer/test/dart/analysis/utilities_test.dart b/pkg/analyzer/test/dart/analysis/utilities_test.dart
index 745f0fe..0c2dbf0 100644
--- a/pkg/analyzer/test/dart/analysis/utilities_test.dart
+++ b/pkg/analyzer/test/dart/analysis/utilities_test.dart
@@ -59,7 +59,7 @@
     String content = '''
 void main() => print('Hello, world!')
 ''';
-    String expectedPath;
+    /*late*/ String expectedPath;
     ParseStringResult result =
         _withMemoryFile(content, (resourceProvider, path) {
       expectedPath = path;
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index bad835b..635d7ff 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -961,29 +961,29 @@
   }
 
   void test_findPrevious_basic_class() {
-    ClassDeclaration clazz = unit.declarations[0];
+    var clazz = unit.declarations[0] as ClassDeclaration;
     expect(clazz.findPrevious(findToken('A')).lexeme, 'class');
   }
 
   void test_findPrevious_basic_method() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[0];
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[0] as MethodDeclaration;
     expect(method.findPrevious(findToken('foo')).lexeme, 'B');
   }
 
   void test_findPrevious_basic_statement() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[0];
-    BlockFunctionBody body = method.body;
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[0] as MethodDeclaration;
+    var body = method.body as BlockFunctionBody;
     Statement statement = body.block.statements[0];
     expect(statement.findPrevious(findToken('bar')).lexeme, 'return');
     expect(statement.findPrevious(findToken(';')).lexeme, 'bar');
   }
 
   void test_findPrevious_missing() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[0];
-    BlockFunctionBody body = method.body;
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[0] as MethodDeclaration;
+    var body = method.body as BlockFunctionBody;
     Statement statement = body.block.statements[0];
 
     GatheringErrorListener listener = GatheringErrorListener(checkRanges: true);
@@ -1000,15 +1000,15 @@
   }
 
   void test_findPrevious_parent_method() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[0];
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[0] as MethodDeclaration;
     expect(method.findPrevious(findToken('B')).lexeme, '{');
   }
 
   void test_findPrevious_parent_statement() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[0];
-    BlockFunctionBody body = method.body;
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[0] as MethodDeclaration;
+    var body = method.body as BlockFunctionBody;
     Statement statement = body.block.statements[0];
     expect(statement.findPrevious(findToken('return')).lexeme, '{');
   }
@@ -1019,8 +1019,8 @@
   }
 
   void test_findPrevious_sibling_method() {
-    ClassDeclaration clazz = unit.declarations[0];
-    MethodDeclaration method = clazz.members[1];
+    var clazz = unit.declarations[0] as ClassDeclaration;
+    var method = clazz.members[1] as MethodDeclaration;
     expect(method.findPrevious(findToken('D')).lexeme, '}');
   }
 }
diff --git a/pkg/analyzer/test/error/error_test.dart b/pkg/analyzer/test/error/error_test.dart
index d091b8e..da20e5e 100644
--- a/pkg/analyzer/test/error/error_test.dart
+++ b/pkg/analyzer/test/error/error_test.dart
@@ -39,12 +39,13 @@
             extendsClause.superclass.name.name == 'ErrorCode') {
           String className = declaration.name.name;
           for (ClassMember member in declaration.members) {
-            if (member is FieldDeclaration &&
-                member.isStatic &&
-                (member.fields.type == null ? bad() : true) &&
-                member.fields.type.toSource() == className) {
-              String fieldName = member.fields.variables[0].name.name;
-              declaredCodes.add(className + '.' + fieldName);
+            if (member is FieldDeclaration && member.isStatic) {
+              var fields = member.fields;
+              if ((fields.type == null ? bad() : true) &&
+                  fields.type.toSource() == className) {
+                String fieldName = fields.variables[0].name.name;
+                declaredCodes.add(className + '.' + fieldName);
+              }
             }
           }
         }
@@ -63,7 +64,7 @@
                 member.variables.variables[0].name.name == 'errorCodeValues',
             orElse: () => null);
     ListLiteral listLiteral = declaration.variables.variables[0].initializer;
-    for (PrefixedIdentifier element in listLiteral.elements) {
+    for (var element in listLiteral.elements.cast<PrefixedIdentifier>()) {
       listedCodes.add(element.name);
     }
     return listedCodes;
diff --git a/pkg/analyzer/test/file_system/file_system_test_support.dart b/pkg/analyzer/test/file_system/file_system_test_support.dart
index fe6b6c9..96db954 100644
--- a/pkg/analyzer/test/file_system/file_system_test_support.dart
+++ b/pkg/analyzer/test/file_system/file_system_test_support.dart
@@ -19,17 +19,17 @@
   String get defaultFileContent;
 
   /// A path to a file within the [defaultFolderPath] that can be used by tests.
-  String get defaultFilePath;
+  String /*!*/ get defaultFilePath;
 
   /// A path to a folder within the [tempPath] that can be used by tests.
-  String get defaultFolderPath;
+  String /*!*/ get defaultFolderPath;
 
   /// Return the resource provider to be used by the tests.
   ResourceProvider get provider;
 
   /// The absolute path to the temporary directory in which all of the tests are
   /// to work.
-  String get tempPath;
+  String /*!*/ get tempPath;
 
   /// Return a file accessed through the resource provider. If [exists] is
   /// `true` then the returned file will exist, otherwise it won't. If [content]
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index 4b25786..a1fe32f 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -34,15 +34,15 @@
   /// The absolute path to the temporary directory in which all of the tests are
   /// to work.
   @override
-  String tempPath;
+  /*late*/ String tempPath;
 
   /// A path to a folder within the [tempPath] that can be used by tests.
   @override
-  String defaultFolderPath;
+  /*late*/ String defaultFolderPath;
 
   /// A path to a file within the [defaultFolderPath] that can be used by tests.
   @override
-  String defaultFilePath;
+  /*late*/ String defaultFilePath;
 
   /// The content used for the file at the [defaultFilePath] if it is created
   /// and no other content is provided.
diff --git a/pkg/analyzer/test/file_system/overlay_file_system_test.dart b/pkg/analyzer/test/file_system/overlay_file_system_test.dart
index 5819681..b93e057 100644
--- a/pkg/analyzer/test/file_system/overlay_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/overlay_file_system_test.dart
@@ -819,11 +819,11 @@
 }
 
 class OverlayTestSupport {
-  MemoryResourceProvider baseProvider;
-  OverlayResourceProvider provider;
+  /*late*/ MemoryResourceProvider baseProvider;
+  /*late*/ OverlayResourceProvider provider;
 
-  String defaultFolderPath;
-  String defaultFilePath;
+  /*late*/ String defaultFolderPath;
+  /*late*/ String defaultFilePath;
 
   void setUp() {
     baseProvider = MemoryResourceProvider();
diff --git a/pkg/analyzer/test/file_system/physical_file_system_test.dart b/pkg/analyzer/test/file_system/physical_file_system_test.dart
index 60e698a..81e3c67 100644
--- a/pkg/analyzer/test/file_system/physical_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/physical_file_system_test.dart
@@ -29,20 +29,20 @@
 
   /// A temporary directory on disk. All files and folders created by the tests
   /// should be inside this directory.
-  io.Directory tempDirectory;
+  /*late*/ io.Directory tempDirectory;
 
   /// The absolute path to the [tempDirectory]. This path will contain a
   /// symbolic link on some operating systems.
   @override
-  String tempPath;
+  /*late*/ String tempPath;
 
   /// A path to a folder within the [tempDirectory] that can be used by tests.
   @override
-  String defaultFolderPath;
+  /*late*/ String defaultFolderPath;
 
   /// A path to a file within the [defaultFolderPath] that can be used by tests.
   @override
-  String defaultFilePath;
+  /*late*/ String defaultFilePath;
 
   /// The content used for the file at the [defaultFilePath] if it is created
   /// and no other content is provided.
diff --git a/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart b/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
index 7cab103..657586c 100644
--- a/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
+++ b/pkg/analyzer/test/file_system/resource_uri_resolver_test.dart
@@ -16,7 +16,7 @@
 
 @reflectiveTest
 class ResourceUriResolverTest with ResourceProviderMixin {
-  ResourceUriResolver resolver;
+  /*late*/ ResourceUriResolver resolver;
 
   void setUp() {
     resolver = ResourceUriResolver(resourceProvider);
diff --git a/pkg/analyzer/test/src/dart/analysis/session_test.dart b/pkg/analyzer/test/src/dart/analysis/session_test.dart
index ed80e60..733f92f 100644
--- a/pkg/analyzer/test/src/dart/analysis/session_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/session_test.dart
@@ -21,15 +21,15 @@
 
 @reflectiveTest
 class AnalysisSessionImplTest with ResourceProviderMixin {
-  AnalysisContextCollection contextCollection;
-  AnalysisContext context;
-  AnalysisSessionImpl session;
+  /*late final*/ AnalysisContextCollection contextCollection;
+  /*late final*/ AnalysisContext context;
+  /*late final*/ AnalysisSessionImpl session;
 
-  String testContextPath;
-  String aaaContextPath;
-  String bbbContextPath;
+  /*late final*/ String testContextPath;
+  /*late final*/ String aaaContextPath;
+  /*late final*/ String bbbContextPath;
 
-  String testPath;
+  /*late final*/ String testPath;
 
   void setUp() {
     MockSdk(resourceProvider: resourceProvider);
diff --git a/pkg/analyzer/test/verify_docs_test.dart b/pkg/analyzer/test/verify_docs_test.dart
index 975bbf2..5107cd6 100644
--- a/pkg/analyzer/test/verify_docs_test.dart
+++ b/pkg/analyzer/test/verify_docs_test.dart
@@ -25,25 +25,28 @@
 }
 
 class SnippetTester {
-  OverlayResourceProvider provider;
-  Folder docFolder;
-  String snippetDirPath;
-  String snippetPath;
+  final OverlayResourceProvider provider;
+  final Folder docFolder;
+  final String snippetDirPath;
+  final String snippetPath;
 
-  StringBuffer output = StringBuffer();
+  final StringBuffer output = StringBuffer();
 
-  SnippetTester() {
-    provider = OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
-    String packageRoot =
-        provider.pathContext.normalize(package_root.packageRoot);
-    String analyzerPath = provider.pathContext.join(packageRoot, 'analyzer');
-    String docPath = provider.pathContext.join(analyzerPath, 'doc');
-    docFolder = provider.getFolder(docPath);
-    snippetDirPath =
+  factory SnippetTester() {
+    var provider = OverlayResourceProvider(PhysicalResourceProvider.INSTANCE);
+    var packageRoot = provider.pathContext.normalize(package_root.packageRoot);
+    var analyzerPath = provider.pathContext.join(packageRoot, 'analyzer');
+    var docPath = provider.pathContext.join(analyzerPath, 'doc');
+    var docFolder = provider.getFolder(docPath);
+    var snippetDirPath =
         provider.pathContext.join(analyzerPath, 'test', 'snippets');
-    snippetPath = provider.pathContext.join(snippetDirPath, 'snippet.dart');
+    var snippetPath = provider.pathContext.join(snippetDirPath, 'snippet.dart');
+    return SnippetTester._(provider, docFolder, snippetDirPath, snippetPath);
   }
 
+  SnippetTester._(
+      this.provider, this.docFolder, this.snippetDirPath, this.snippetPath);
+
   Future<void> verify() async {
     await verifyFolder(docFolder);
   }
diff --git a/pkg/analyzer/tool/diagnostics/generate.dart b/pkg/analyzer/tool/diagnostics/generate.dart
index bfc4eb0..5ed14e0 100644
--- a/pkg/analyzer/tool/diagnostics/generate.dart
+++ b/pkg/analyzer/tool/diagnostics/generate.dart
@@ -177,8 +177,9 @@
     List<String> includedPaths = [];
     for (CodePath codePath in codePaths) {
       includedPaths.add(codePath.documentationPath);
-      if (codePath.declarationPath != null) {
-        includedPaths.add(codePath.declarationPath);
+      var declarationPath = codePath.declarationPath;
+      if (declarationPath != null) {
+        includedPaths.add(declarationPath);
       }
     }
     AnalysisContextCollection collection = AnalysisContextCollection(
diff --git a/pkg/nnbd_migration/lib/instrumentation.dart b/pkg/nnbd_migration/lib/instrumentation.dart
index a89962a..434a003 100644
--- a/pkg/nnbd_migration/lib/instrumentation.dart
+++ b/pkg/nnbd_migration/lib/instrumentation.dart
@@ -257,6 +257,7 @@
   alreadyMigratedType,
   alwaysNullableType,
   argumentErrorCheckNotNull,
+  callTearOff,
   compoundAssignment,
   // See [DummyOrigin].
   dummy,
diff --git a/pkg/nnbd_migration/lib/migration_cli.dart b/pkg/nnbd_migration/lib/migration_cli.dart
index 2252d76..43a71e6 100644
--- a/pkg/nnbd_migration/lib/migration_cli.dart
+++ b/pkg/nnbd_migration/lib/migration_cli.dart
@@ -4,6 +4,7 @@
 
 import 'dart:async';
 import 'dart:convert' show jsonDecode;
+import 'dart:math';
 import 'dart:io' hide File;
 
 import 'package:analyzer/dart/analysis/analysis_context_collection.dart';
@@ -1124,14 +1125,14 @@
   }
 
   Future<AnalysisResult> runFirstPhase() async {
-    // All tasks should be registered; [numPhases] should be finalized.
-    _progressBar = _ProgressBar(_migrationCli.logger, pathsToProcess.length);
-
     // Process package
     _task.processPackage(context.contextRoot.root);
 
     var analysisErrors = <AnalysisError>[];
 
+    // All tasks should be registered; [numPhases] should be finalized.
+    _progressBar = _ProgressBar(_migrationCli.logger, pathsToProcess.length);
+
     // Process each source file.
     await processResources((ResolvedUnitResult result) async {
       _progressBar.tick();
@@ -1269,7 +1270,8 @@
       return;
     }
     _tickCount++;
-    var fractionComplete = _tickCount * _innerWidth ~/ _totalTickCount - 1;
+    var fractionComplete =
+        max(0, _tickCount * _innerWidth ~/ _totalTickCount - 1);
     var remaining = _innerWidth - fractionComplete - 1;
     _logger.write('\r[' + // Bring cursor back to the start of the line.
         '-' * fractionComplete + // Print complete work.
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 35f98a8..3611061 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -2904,12 +2904,27 @@
     } else {
       targetType = _handleTarget(target, propertyName.name, callee);
     }
-    if (callee == null) {
+    DecoratedType calleeType;
+    if (targetType != null &&
+        targetType.type is FunctionType &&
+        propertyName.name == 'call') {
+      // If `X` has a function type, then in the expression `X.call`, the
+      // function being torn off is `X` itself, so the callee type is simply the
+      // non-nullable counterpart to the type of `X`.
+      var nullabilityNodeTarget =
+          NullabilityNodeTarget.text('expression').withCodeRef(node);
+      var nullabilityNode =
+          NullabilityNode.forInferredType(nullabilityNodeTarget);
+      _graph.makeNonNullableUnion(
+          nullabilityNode, CallTearOffOrigin(source, node));
+      calleeType = targetType.withNode(nullabilityNode);
+    } else if (callee != null) {
+      calleeType = getOrComputeElementType(callee, targetType: targetType);
+    }
+    if (calleeType == null) {
       // Dynamic dispatch.
       return _makeNullableDynamicType(node);
     }
-    var calleeType = getOrComputeElementType(callee, targetType: targetType);
-    // TODO(paulberry): substitute if necessary
     if (propertyName.inSetterContext()) {
       if (isNullAware) {
         _conditionalNodes[node] = targetType.node;
diff --git a/pkg/nnbd_migration/lib/src/edge_origin.dart b/pkg/nnbd_migration/lib/src/edge_origin.dart
index 81bdf76..5b42111 100644
--- a/pkg/nnbd_migration/lib/src/edge_origin.dart
+++ b/pkg/nnbd_migration/lib/src/edge_origin.dart
@@ -397,6 +397,18 @@
   EdgeOriginKind get kind => EdgeOriginKind.listLengthConstructor;
 }
 
+/// An edge origin used for edges that originated because of a tear-off of
+/// `call` on a function type.
+class CallTearOffOrigin extends EdgeOrigin {
+  CallTearOffOrigin(Source source, AstNode node) : super(source, node);
+
+  @override
+  String get description => 'tear-off of .call';
+
+  @override
+  EdgeOriginKind get kind => EdgeOriginKind.callTearOff;
+}
+
 /// An edge origin used for edges that originated because a literal expression
 /// has a known nullability.
 class LiteralOrigin extends EdgeOrigin {
diff --git a/pkg/nnbd_migration/test/abstract_context.dart b/pkg/nnbd_migration/test/abstract_context.dart
index 367bb3a..a52c469 100644
--- a/pkg/nnbd_migration/test/abstract_context.dart
+++ b/pkg/nnbd_migration/test/abstract_context.dart
@@ -165,7 +165,7 @@
             'name': packageName,
             'rootUri': toUriStr('/.pub-cache/$packageName'),
             'packageUri': 'lib/',
-            'languageVersion': '2.9'
+            'languageVersion': '2.12'
           },
         {
           'name': 'tests',
diff --git a/pkg/nnbd_migration/test/api_test.dart b/pkg/nnbd_migration/test/api_test.dart
index a444f76..bfd7469 100644
--- a/pkg/nnbd_migration/test/api_test.dart
+++ b/pkg/nnbd_migration/test/api_test.dart
@@ -394,6 +394,7 @@
 }
 ''';
     var alreadyMigrated = '''
+// @dart=2.12
 extension Ext<T> on List<T> {
   g() {}
 }
@@ -5249,6 +5250,15 @@
     await _checkSingleFileChanges(content, expected);
   }
 
+  Future<void> test_null_aware_call_tearoff() async {
+    // Kind of a weird use case because `f?.call` is equivalent to `f`, but
+    // let's make sure we analyze it correctly.
+    var content =
+        'int Function(int) g(int/*?*/ Function(int)/*?*/ f) => f?.call;';
+    var expected = 'int? Function(int)? g(int? Function(int)? f) => f?.call;';
+    await _checkSingleFileChanges(content, expected);
+  }
+
   Future<void> test_null_aware_getter_invocation() async {
     var content = '''
 bool f(int i) => i?.isEven;
@@ -6600,7 +6610,10 @@
 }
 ''';
     await _checkSingleFileChanges(content, expected, migratedInput: {
-      '$projectPath/lib/migrated_typedef.dart': 'typedef F<R> = Function(R);'
+      '$projectPath/lib/migrated_typedef.dart': '''
+// @dart=2.12
+typedef F<R> = Function(R);
+'''
     });
   }
 
@@ -6636,8 +6649,10 @@
 }
 ''';
     await _checkSingleFileChanges(content, expected, migratedInput: {
-      '$projectPath/lib/migrated_typedef.dart':
-          'typedef F<T> = Function<R>(T, R);'
+      '$projectPath/lib/migrated_typedef.dart': '''
+// @dart=2.12
+typedef F<T> = Function<R>(T, R);
+'''
     });
   }
 
@@ -6655,7 +6670,10 @@
 }
 ''';
     await _checkSingleFileChanges(content, expected, migratedInput: {
-      '$projectPath/lib/migrated_typedef.dart': 'typedef F = Function<R>(R);'
+      '$projectPath/lib/migrated_typedef.dart': '''
+// @dart=2.12
+typedef F = Function<R>(R);
+'''
     });
   }
 
diff --git a/pkg/nnbd_migration/test/edge_builder_test.dart b/pkg/nnbd_migration/test/edge_builder_test.dart
index 712cd2a..001a94b 100644
--- a/pkg/nnbd_migration/test/edge_builder_test.dart
+++ b/pkg/nnbd_migration/test/edge_builder_test.dart
@@ -6613,6 +6613,47 @@
     expect(hasNullCheckHint(findNode.propertyAccess('(c).i2')), isTrue);
   }
 
+  Future<void> test_propertyAccess_call_functionTyped() async {
+    await analyze('''
+String/*1*/ Function(int/*2*/) f(String/*3*/ Function(int/*4*/) callback)
+    => callback.call;
+''');
+    assertEdge(decoratedTypeAnnotation('String/*3*/').node,
+        decoratedTypeAnnotation('String/*1*/').node,
+        hard: false, checkable: false);
+    assertEdge(decoratedTypeAnnotation('int/*2*/').node,
+        decoratedTypeAnnotation('int/*4*/').node,
+        hard: false, checkable: false);
+    var tearOffNodeMatcher = anyNode;
+    assertEdge(
+        tearOffNodeMatcher,
+        decoratedGenericFunctionTypeAnnotation('String/*1*/ Function(int/*2*/)')
+            .node,
+        hard: false);
+    assertEdge(never, tearOffNodeMatcher.matchingNode,
+        hard: true, checkable: false);
+  }
+
+  Future<void> test_propertyAccess_call_interfaceTyped() async {
+    // Make sure that we don't try to treat all methods called `call` as though
+    // the underlying type is a function type.
+    await analyze('''
+abstract class C {
+  String call(int x);
+}
+String Function(int) f(C c) => c.call;
+''');
+    assertEdge(decoratedTypeAnnotation('String call').node,
+        decoratedTypeAnnotation('String Function').node,
+        hard: false, checkable: false);
+    assertEdge(decoratedTypeAnnotation('int) f').node,
+        decoratedTypeAnnotation('int x').node,
+        hard: false, checkable: false);
+    assertEdge(never,
+        decoratedGenericFunctionTypeAnnotation('String Function(int)').node,
+        hard: false);
+  }
+
   Future<void> test_propertyAccess_dynamic() async {
     await analyze('''
 class C {
@@ -6640,6 +6681,16 @@
     assertNoEdge(decoratedTypeAnnotation('int i').node, never);
   }
 
+  Future<void> test_propertyAccess_object_property_on_function_type() async {
+    await analyze('int f(void Function() g) => g.hashCode;');
+    var hashCodeReturnType = variables
+        .decoratedElementType(
+            typeProvider.objectType.element.getGetter('hashCode'))
+        .returnType;
+    assertEdge(hashCodeReturnType.node, decoratedTypeAnnotation('int f').node,
+        hard: false);
+  }
+
   Future<void> test_propertyAccess_return_type() async {
     await analyze('''
 class C {
diff --git a/pkg/nnbd_migration/test/migration_visitor_test_base.dart b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
index 06b0451..f853f96 100644
--- a/pkg/nnbd_migration/test/migration_visitor_test_base.dart
+++ b/pkg/nnbd_migration/test/migration_visitor_test_base.dart
@@ -236,7 +236,7 @@
   void assertNoEdge(Object source, Object destination) {
     var edges = getEdges(source, destination);
     if (edges.isNotEmpty) {
-      fail('Expected no edge $source -> $destination, found ${edges.length}');
+      fail('Expected no edge $source -> $destination, found $edges');
     }
   }
 
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index d2b5d94..853cc32 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -42,6 +42,7 @@
 [ $compiler == dartdevc || $compiler == dartdevk ]
 bigint_test/03: SkipSlow # modPow is very slow
 bigint_test/15: SkipSlow # modPow is very slow
+list_concurrent_modify_self_test: SkipSlow # missing check causes list to grow to whole heap
 uri_parse_test: Slow, Pass
 uri_test: Slow, Pass
 
diff --git a/tests/corelib/list_concurrent_modify_self_test.dart b/tests/corelib/list_concurrent_modify_self_test.dart
new file mode 100644
index 0000000..cb481b7
--- /dev/null
+++ b/tests/corelib/list_concurrent_modify_self_test.dart
@@ -0,0 +1,17 @@
+// 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:collection";
+import "dart:typed_data";
+import "package:expect/expect.dart";
+
+void main() {
+  testConcurrentAddSelf([1, 2, 3]);
+}
+
+testConcurrentAddSelf(List list) {
+  Expect.throws(() {
+    list.addAll(list);
+  }, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)");
+}
diff --git a/tests/corelib/list_concurrent_modify_test.dart b/tests/corelib/list_concurrent_modify_test.dart
index 9e8d338..a163524 100644
--- a/tests/corelib/list_concurrent_modify_test.dart
+++ b/tests/corelib/list_concurrent_modify_test.dart
@@ -21,9 +21,6 @@
   testConcurrentModification(new Int16List(0).toList());
   testConcurrentModification(new Uint32List(0).toList());
   testConcurrentModification(new Int32List(0).toList());
-
-  testConcurrentAddSelf([]);
-  testConcurrentAddSelf([1, 2, 3]);
 }
 
 void testConcurrentModification(List<int> list) {
@@ -77,12 +74,6 @@
   }
 }
 
-testConcurrentAddSelf(List list) {
-  Expect.throws(() {
-    list.addAll(list);
-  }, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)");
-}
-
 class MyList<E> extends ListBase<E> {
   // TODO(42496): Use a nullable list because insert() is implemented in terms
   // of length=. Change this back to `E` and remove the `as E` below when that
diff --git a/tests/corelib_2/corelib_2.status b/tests/corelib_2/corelib_2.status
index 316928f..5704e10 100644
--- a/tests/corelib_2/corelib_2.status
+++ b/tests/corelib_2/corelib_2.status
@@ -53,6 +53,7 @@
 [ $compiler == dartdevc || $compiler == dartdevk ]
 bigint_test/03: SkipSlow # modPow is very slow
 bigint_test/15: SkipSlow # modPow is very slow
+list_concurrent_modify_self_test: SkipSlow # missing check causes list to grow to whole heap
 uri_parse_test: Slow, Pass
 uri_test: Slow, Pass
 
diff --git a/tests/corelib_2/list_concurrent_modify_self_test.dart b/tests/corelib_2/list_concurrent_modify_self_test.dart
new file mode 100644
index 0000000..cb481b7
--- /dev/null
+++ b/tests/corelib_2/list_concurrent_modify_self_test.dart
@@ -0,0 +1,17 @@
+// 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:collection";
+import "dart:typed_data";
+import "package:expect/expect.dart";
+
+void main() {
+  testConcurrentAddSelf([1, 2, 3]);
+}
+
+testConcurrentAddSelf(List list) {
+  Expect.throws(() {
+    list.addAll(list);
+  }, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)");
+}
diff --git a/tests/corelib_2/list_concurrent_modify_test.dart b/tests/corelib_2/list_concurrent_modify_test.dart
index 4d5de96..b3fcb17 100644
--- a/tests/corelib_2/list_concurrent_modify_test.dart
+++ b/tests/corelib_2/list_concurrent_modify_test.dart
@@ -23,9 +23,6 @@
   testConcurrentModification(new Int16List(0).toList());
   testConcurrentModification(new Uint32List(0).toList());
   testConcurrentModification(new Int32List(0).toList());
-
-  testConcurrentAddSelf([]);
-  testConcurrentAddSelf([1, 2, 3]);
 }
 
 void testConcurrentModification(List<int> list) {
@@ -79,12 +76,6 @@
   }
 }
 
-testConcurrentAddSelf(List list) {
-  Expect.throws(() {
-    list.addAll(list);
-  }, (e) => e is ConcurrentModificationError, "testConcurrentAddSelf($list)");
-}
-
 class MyList<E> extends ListBase<E> {
   List<E> _source;
   MyList(this._source);
diff --git a/tools/VERSION b/tools/VERSION
index e96dbff..27b1b1d 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 24
+PRERELEASE 25
 PRERELEASE_PATCH 0
\ No newline at end of file