Version 2.18.0-136.0.dev

Merge commit '95360796c29d04575ccced5fe6105083c181fdb6' into 'dev'
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 3b66316..4cda143 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,6 @@
+## 4.2.0-dev
+* Update SDK constraints to `>=2.17.0 <3.0.0`.
+
 ## 4.1.0
 * Deprecated `ParameterElement.isNotOptional`, use `isRequired` instead.
 * Deprecated `ResourceProviderMixin.newFile2`, use `newFile` instead.
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 7c4342a..25c8cda 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,10 +1,10 @@
 name: analyzer
-version: 4.1.0
+version: 4.2.0-dev
 description: This package provides a library that performs static analysis of Dart code.
 repository: https://github.com/dart-lang/sdk/tree/main/pkg/analyzer
 
 environment:
-  sdk: '>=2.15.0 <3.0.0'
+  sdk: '>=2.17.0 <3.0.0'
 
 dependencies:
   _fe_analyzer_shared: ^40.0.0
diff --git a/pkg/compiler/lib/src/dump_info.dart b/pkg/compiler/lib/src/dump_info.dart
index 184e44e..e84fc46 100644
--- a/pkg/compiler/lib/src/dump_info.dart
+++ b/pkg/compiler/lib/src/dump_info.dart
@@ -499,6 +499,9 @@
       info.coverageId = '${field.hashCode}';
     }
 
+    _addClosureInfo(info, field,
+        libraryEntity: fieldEntity.library, memberEntity: fieldEntity);
+
     state.info.fields.add(info);
     return info;
   }
@@ -549,9 +552,10 @@
   }
 
   FunctionInfo visitFunction(ir.FunctionNode function,
-      {FunctionEntity functionEntity}) {
-    var parent = function.parent;
-    String name = parent.toStringInternal();
+      {FunctionEntity functionEntity, LocalFunctionInfo localFunctionInfo}) {
+    final parent = function.parent;
+    String name =
+        parent is ir.LocalFunction ? 'call' : parent.toStringInternal();
     bool isConstructor = parent is ir.Constructor;
     bool isFactory = parent is ir.Procedure && parent.isFactory;
     // Kernel `isStatic` refers to static members, constructors, and top-level
@@ -632,6 +636,15 @@
         outputUnit: null);
     state.entityToInfo[functionEntity] = info;
 
+    if (function.parent is ir.Member)
+      _addClosureInfo(info, function.parent,
+          libraryEntity: functionEntity.library, memberEntity: functionEntity);
+    else {
+      // This branch is only reached when function is a 'call' method.
+      // TODO(markzipan): Ensure call methods never have children.
+      info.closures = [];
+    }
+
     if (compiler.options.experimentCallInstrumentation) {
       // We use function.hashCode because it is globally unique and it is
       // available while we are doing codegen.
@@ -641,6 +654,41 @@
     state.info.functions.add(info);
     return info;
   }
+
+  /// Adds closure information to [info], using all nested closures in [member].
+  void _addClosureInfo(Info info, ir.Member member,
+      {LibraryEntity libraryEntity, MemberEntity memberEntity}) {
+    final localFunctionInfoCollector = LocalFunctionInfoCollector();
+    member.accept(localFunctionInfoCollector);
+    List<ClosureInfo> nestedClosures = <ClosureInfo>[];
+    localFunctionInfoCollector.localFunctions.forEach((key, value) {
+      FunctionEntity closureEntity;
+      environment.forEachNestedClosure(memberEntity, (closure) {
+        if (closure.enclosingClass.name == value.name) {
+          closureEntity = closure;
+        }
+      });
+      final closureClassEntity = closureEntity.enclosingClass;
+      final closureInfo =
+          ClosureInfo(name: value.name, outputUnit: null, size: null);
+      state.entityToInfo[closureClassEntity] = closureInfo;
+
+      FunctionEntity callMethod = closedWorld.elementEnvironment
+          .lookupClassMember(closureClassEntity, Identifiers.call);
+      final functionInfo = visitFunction(key.function,
+          functionEntity: callMethod, localFunctionInfo: value);
+      state.entityToInfo[closureEntity] = functionInfo;
+
+      closureInfo.function = functionInfo;
+      functionInfo.parent = closureInfo;
+      state.info.closures.add(closureInfo);
+
+      closureInfo.parent = info;
+      nestedClosures.add(closureInfo);
+    });
+    if (info is FunctionInfo) info.closures = nestedClosures;
+    if (info is FieldInfo) info.closures = nestedClosures;
+  }
 }
 
 /// Annotates [KernelInfoCollector] with info extracted from closed-world
@@ -853,24 +901,25 @@
   }
 
   ClosureInfo visitClosureClass(ClassEntity element) {
-    ClosureInfo closureInfo = ClosureInfo(
-        name: element.name,
-        outputUnit: _unitInfoForClass(element),
-        size: dumpInfoTask.sizeOf(element));
-    kernelInfo.state.entityToInfo[element] = closureInfo;
+    final kClosureInfos = kernelInfo.state.info.closures
+        .where((info) => info.name == element.name)
+        .toList();
+    assert(
+        kClosureInfos.length == 1,
+        'Ambiguous closure resolution. '
+        'Expected singleton, found $kClosureInfos');
+    final kClosureInfo = kClosureInfos.first;
+
+    kClosureInfo.outputUnit = _unitInfoForClass(element);
+    kClosureInfo.size = dumpInfoTask.sizeOf(element);
 
     FunctionEntity callMethod = closedWorld.elementEnvironment
         .lookupClassMember(element, Identifiers.call);
 
-    FunctionInfo functionInfo = visitFunction(callMethod, element.name);
-    if (functionInfo == null) return null;
+    visitFunction(callMethod, element.name);
 
-    closureInfo.function = functionInfo;
-    functionInfo.parent = closureInfo;
-    closureInfo.treeShakenStatus = TreeShakenStatus.Live;
-
-    kernelInfo.state.info.closures.add(closureInfo);
-    return closureInfo;
+    kClosureInfo.treeShakenStatus = TreeShakenStatus.Live;
+    return kClosureInfo;
   }
 
   // TODO(markzipan): [parentName] is used for disambiguation, but this might
@@ -879,8 +928,6 @@
     int size = dumpInfoTask.sizeOf(function);
     // TODO(sigmund): consider adding a small info to represent unreachable
     // code here.
-    if (size == 0 && !shouldKeep(function)) return null;
-
     var compareName = function.name;
     if (function.isConstructor) {
       compareName = compareName == ""
@@ -898,9 +945,10 @@
             !(function.isSetter ^ i.modifiers.isSetter))
         .toList();
     assert(
-        kFunctionInfos.length == 1,
+        kFunctionInfos.length <= 1,
         'Ambiguous function resolution. '
-        'Expected singleton, found $kFunctionInfos');
+        'Expected single or none, found $kFunctionInfos');
+    if (kFunctionInfos.length == 0) return null;
     final kFunctionInfo = kFunctionInfos.first;
 
     List<CodeSpan> code = dumpInfoTask.codeOf(function);
@@ -943,19 +991,13 @@
   int _addClosureInfo(BasicInfo info, MemberEntity member) {
     assert(info is FunctionInfo || info is FieldInfo);
     int size = 0;
-    List<ClosureInfo> nestedClosures = <ClosureInfo>[];
     environment.forEachNestedClosure(member, (closure) {
       ClosureInfo closureInfo = visitClosureClass(closure.enclosingClass);
       if (closureInfo != null) {
-        closureInfo.parent = info;
-        closureInfo.treeShakenStatus = info.treeShakenStatus;
-        nestedClosures.add(closureInfo);
+        closureInfo.treeShakenStatus = TreeShakenStatus.Live;
         size += closureInfo.size;
       }
     });
-    if (info is FunctionInfo) info.closures = nestedClosures;
-    if (info is FieldInfo) info.closures = nestedClosures;
-
     return size;
   }
 
@@ -1432,3 +1474,73 @@
 
   DumpInfoStateData();
 }
+
+class LocalFunctionInfo {
+  final ir.LocalFunction localFunction;
+  final List<ir.TreeNode> hierarchy;
+  final String name;
+  bool isInvoked = false;
+
+  LocalFunctionInfo._(this.localFunction, this.hierarchy, this.name);
+
+  factory LocalFunctionInfo(ir.LocalFunction localFunction) {
+    String name = '';
+    ir.TreeNode node = localFunction;
+    final hierarchy = <ir.TreeNode>[];
+    bool inClosure = false;
+    while (node != null) {
+      // Only consider nodes used for resolving a closure's full name.
+      if (node is ir.FunctionDeclaration) {
+        hierarchy.add(node);
+        name = '_${node.variable.name}' + name;
+        inClosure = false;
+      } else if (node is ir.FunctionExpression) {
+        hierarchy.add(node);
+        name = (inClosure ? '_' : '_closure') + name;
+        inClosure = true;
+      } else if (node is ir.Member) {
+        hierarchy.add(node);
+        var cleanName = node.toStringInternal();
+        if (cleanName.endsWith('.'))
+          cleanName = cleanName.substring(0, cleanName.length - 1);
+        final isFactory = node is ir.Procedure && node.isFactory;
+        if (isFactory) {
+          cleanName = cleanName.replaceAll('.', '\$');
+          cleanName = '${node.enclosingClass.toStringInternal()}_' + cleanName;
+        } else {
+          cleanName = cleanName.replaceAll('.', '_');
+        }
+        name = cleanName + name;
+        inClosure = false;
+      }
+      node = node.parent;
+    }
+
+    return LocalFunctionInfo._(localFunction, hierarchy, name);
+  }
+}
+
+class LocalFunctionInfoCollector extends ir.RecursiveVisitor<void> {
+  final localFunctions = <ir.LocalFunction, LocalFunctionInfo>{};
+
+  @override
+  void visitFunctionExpression(ir.FunctionExpression node) {
+    assert(localFunctions[node] == null);
+    localFunctions[node] = LocalFunctionInfo(node);
+    defaultExpression(node);
+  }
+
+  @override
+  void visitFunctionDeclaration(ir.FunctionDeclaration node) {
+    assert(localFunctions[node] == null);
+    localFunctions[node] = LocalFunctionInfo(node);
+    defaultStatement(node);
+  }
+
+  @override
+  void visitLocalFunctionInvocation(ir.LocalFunctionInvocation node) {
+    if (localFunctions[node.localFunction] == null)
+      visitFunctionDeclaration(node.localFunction);
+    localFunctions[node.localFunction].isInvoked = true;
+  }
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 7db7cad..2496daf 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -260,14 +260,14 @@
 dart/appjit*: SkipSlow # DFE too slow
 dart/b162922506_test: SkipSlow # Generates large input file
 dart/data_uri_spawn_test: Skip # Please triage.
-dart/isolates/fast_object_copy_test*: Slow # issue 46740
+dart/isolates/fast_object_copy_test*: SkipSlow
 dart/minimal_kernel_test: SkipSlow # gen_kernel is too slow on simulated architectures
 dart/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow on simulated architectures
 dart/snapshot_version_test: RuntimeError # Please triage.
 dart_2/appjit*: SkipSlow # DFE too slow
 dart_2/b162922506_test: SkipSlow # Generates large input file
 dart_2/data_uri_spawn_test: Skip # Please triage.
-dart_2/isolates/fast_object_copy_test*: Slow # issue 46740
+dart_2/isolates/fast_object_copy_test*: SkipSlow
 dart_2/minimal_kernel_test: SkipSlow # gen_kernel is too slow on simulated architectures
 dart_2/null_safety_autodetection_in_kernel_compiler_test: SkipSlow # gen_kernel is too slow on simulated architectures
 dart_2/snapshot_version_test: RuntimeError # Please triage.
diff --git a/tools/VERSION b/tools/VERSION
index 6d4108b..16a594e 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 18
 PATCH 0
-PRERELEASE 135
+PRERELEASE 136
 PRERELEASE_PATCH 0
\ No newline at end of file