Version 2.17.0-18.0.dev

Merge commit '9bea02b9763e01f8871b7652096be9e10985197d' into 'dev'
diff --git a/pkg/analysis_server/lib/src/lsp/mapping.dart b/pkg/analysis_server/lib/src/lsp/mapping.dart
index 8a26c20..305bc67 100644
--- a/pkg/analysis_server/lib/src/lsp/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/mapping.dart
@@ -683,6 +683,36 @@
 bool isDartDocument(lsp.TextDocumentIdentifier? doc) =>
     doc?.uri.endsWith('.dart') ?? false;
 
+/// Converts a [server.Location] to an [lsp.Range] by translating the
+/// offset/length using a `LineInfo`.
+///
+/// This function ignores any line/column info on the
+/// [server.Location] assuming it is either not available not unreliable.
+lsp.Range locationOffsetLenToRange(
+        server.LineInfo lineInfo, server.Location location) =>
+    toRange(lineInfo, location.offset, location.length);
+
+/// Converts a [server.Location] to an [lsp.Range] if all line and column
+/// values are available.
+///
+/// Returns null if any values are -1 or null.
+lsp.Range? locationToRange(server.Location location) {
+  final startLine = location.startLine;
+  final startColumn = location.startColumn;
+  final endLine = location.endLine ?? -1;
+  final endColumn = location.endColumn ?? -1;
+  if (startLine == -1 ||
+      startColumn == -1 ||
+      endLine == -1 ||
+      endColumn == -1) {
+    return null;
+  }
+  // LSP positions are 0-based but Location is 1-based.
+  return Range(
+      start: Position(line: startLine - 1, character: startColumn - 1),
+      end: Position(line: endLine - 1, character: endColumn - 1));
+}
+
 /// Merges two [WorkspaceEdit]s into a single one.
 ///
 /// Will throw if given [WorkspaceEdit]s that do not use documentChanges.
@@ -800,10 +830,12 @@
     message = '$message\n${error.correction}';
   }
 
-  var lineInfo = getLineInfo(error.location.file);
+  final range = locationToRange(error.location) ??
+      locationOffsetLenToRange(
+          getLineInfo(error.location.file), error.location);
   var documentationUrl = error.url;
   return lsp.Diagnostic(
-    range: toRange(lineInfo, error.location.offset, error.location.length),
+    range: range,
     severity: pluginToDiagnosticSeverity(error.severity),
     code: error.code,
     source: languageSourceName,
@@ -831,6 +863,9 @@
   return lsp.DiagnosticRelatedInformation(
       location: lsp.Location(
         uri: Uri.file(file).toString(),
+        // TODO(dantup): Switch to using line/col information from the context
+        // message once confirmed that AnalyzerConverter is not using the wrong
+        // LineInfo.
         range: toRange(
           lineInfo,
           message.location.offset,
diff --git a/pkg/analysis_server/test/lsp/diagnostic_test.dart b/pkg/analysis_server/test/lsp/diagnostic_test.dart
index 3b7fc18..2d009c7 100644
--- a/pkg/analysis_server/test/lsp/diagnostic_test.dart
+++ b/pkg/analysis_server/test/lsp/diagnostic_test.dart
@@ -30,15 +30,15 @@
     final pluginError = plugin.AnalysisError(
       plugin.AnalysisErrorSeverity.ERROR,
       plugin.AnalysisErrorType.STATIC_TYPE_WARNING,
-      plugin.Location(pluginAnalyzedFilePath, 0, 6, 0, 0,
-          endLine: 0, endColumn: 6),
+      plugin.Location(pluginAnalyzedFilePath, 0, 6, 1, 1,
+          endLine: 1, endColumn: 7),
       'Test error from plugin',
       'ERR1',
       contextMessages: [
         plugin.DiagnosticMessage(
             'Related error',
-            plugin.Location(pluginAnalyzedFilePath, 31, 4, 1, 12,
-                endLine: 1, endColumn: 16))
+            plugin.Location(pluginAnalyzedFilePath, 31, 4, 2, 13,
+                endLine: 2, endColumn: 17))
       ],
     );
     final pluginResult =
diff --git a/pkg/analyzer/lib/src/summary2/top_level_inference.dart b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
index 9f2b66c..004c65b 100644
--- a/pkg/analyzer/lib/src/summary2/top_level_inference.dart
+++ b/pkg/analyzer/lib/src/summary2/top_level_inference.dart
@@ -290,7 +290,7 @@
 
   @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
-    var element = node.staticElement;
+    var element = node.staticElement?.declaration;
     if (element is PropertyAccessorElement && element.isGetter) {
       _set.add(element.variable);
     }
diff --git a/pkg/analyzer/test/src/summary/resynthesize_common.dart b/pkg/analyzer/test/src/summary/resynthesize_common.dart
index 4232bfc..5c069d3 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_common.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_common.dart
@@ -31540,6 +31540,32 @@
 ''');
   }
 
+  test_type_inference_classField_fromNullSafe_toLegacy() async {
+    testFile = convertPath('/home/test/lib/test.dart');
+    addLibrarySource('/home/test/lib/a.dart', '''
+class E {
+  static final a = 0;
+}
+''');
+    var library = await checkLibrary('''
+// @dart = 2.9
+import 'a.dart';
+final v = E.a;
+''');
+    checkElementText(library, r'''
+library
+  imports
+    package:test/a.dart
+  definingUnit
+    topLevelVariables
+      static final v @38
+        type: int*
+    accessors
+      synthetic static get v @-1
+        returnType: int*
+''');
+  }
+
   test_type_inference_closure_with_function_typed_parameter() async {
     var library = await checkLibrary('''
 var x = (int f(String x)) => 0;
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
index aca8022..1443d95 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/enum_from_lib_used_as_type.dart.expect
@@ -22,6 +22,6 @@
   synthetic constructor •() → self::Class
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3380,getterSelectorId:3381]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3384,getterSelectorId:3385]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::Enum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
index 446a1e7..c16c8ac 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tree_shake_enum_from_lib.dart.expect
@@ -51,6 +51,6 @@
   synthetic constructor •() → self::ConstClass
     : super core::Object::•()
     ;
-[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3384,getterSelectorId:3385]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
+[@vm.procedure-attributes.metadata=methodOrSetterCalledDynamically:false,getterCalledDynamically:false,hasThisUses:false,hasTearOffUses:false,methodOrSetterSelectorId:3388,getterSelectorId:3389]  method method([@vm.inferred-type.metadata=dart.core::Null? (value: null)] self::ConstEnum e) → core::int
     return [@vm.inferred-type.metadata=!] e.{core::_Enum::index}{core::int};
 }
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index a39e324..f2b6fc0 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -185,6 +185,27 @@
       !identical(_data, oldData) || (_checkSum != oldCheckSum);
 
   int get length;
+
+  // If this collection has never had an insertion, and [other] is the same
+  // representation and has had no deletions, then adding the entries of [other]
+  // will end up building the same [_data] and [_index]. We can do this more
+  // efficiently by copying the Lists directly.
+  //
+  // Precondition: [this] and [other] must use the same hashcode and equality.
+  bool _quickCopy(_HashBase other) {
+    if (!identical(_index, _uninitializedIndex)) return false;
+    if (other._usedData == 0) return true; // [other] is empty, nothing to copy.
+    if (other._deletedKeys != 0) return false;
+
+    assert(!identical(other._index, _uninitializedIndex));
+    assert(!identical(other._data, _uninitializedData));
+    _index = Uint32List.fromList(other._index);
+    _hashMask = other._hashMask;
+    _data = List.of(other._data, growable: false);
+    _usedData = other._usedData;
+    _deletedKeys = other._deletedKeys;
+    return true;
+  }
 }
 
 class _OperatorEqualsAndHashCode {
@@ -233,6 +254,16 @@
     _usedData = 0;
     _deletedKeys = 0;
   }
+
+  void addAll(Map<K, V> other) {
+    if (other is _InternalLinkedHashMap) {
+      final otherBase = other as _InternalLinkedHashMap; // manual promotion.
+      // If this map is empty we might be able to block-copy from [other].
+      if (isEmpty && _quickCopy(otherBase)) return;
+      // TODO(48143): Pre-grow capacity if it will reduce rehashing.
+    }
+    super.addAll(other);
+  }
 }
 
 // This is essentially the same class as _InternalLinkedHashMap, but it does
@@ -531,7 +562,7 @@
     return false;
   }
 
-  void forEach(void f(K key, V value)) {
+  void forEach(void action(K key, V value)) {
     final data = _data;
     final checkSum = _checkSum;
     final len = _usedData;
@@ -540,7 +571,7 @@
       if (_HashBase._isDeleted(data, current)) continue;
       final key = internal.unsafeCast<K>(current);
       final value = internal.unsafeCast<V>(data[offset + 1]);
-      f(key, value);
+      action(key, value);
       if (_isModifiedSince(data, checkSum)) {
         throw ConcurrentModificationError(this);
       }
@@ -561,6 +592,16 @@
         _IdenticalAndIdentityHashCode
     implements LinkedHashMap<K, V> {
   _CompactLinkedIdentityHashMap() : super(_HashBase._INITIAL_INDEX_SIZE);
+
+  void addAll(Map<K, V> other) {
+    if (other is _CompactLinkedIdentityHashMap) {
+      final otherBase = other as _CompactLinkedIdentityHashMap;
+      // If this map is empty we might be able to block-copy from [other].
+      if (isEmpty && _quickCopy(otherBase)) return;
+      // TODO(48143): Pre-grow capacity if it will reduce rehashing.
+    }
+    super.addAll(other);
+  }
 }
 
 class _CompactLinkedCustomHashMap<K, V> extends _HashFieldBase
@@ -832,6 +873,16 @@
   // is not required by the spec. (For instance, always using an identity set
   // would be technically correct, albeit surprising.)
   Set<E> toSet() => new _CompactLinkedHashSet<E>()..addAll(this);
+
+  void addAll(Iterable<E> other) {
+    if (other is _CompactLinkedHashSet) {
+      final otherBase = other as _CompactLinkedHashSet;
+      // If this set is empty we might be able to block-copy from [other].
+      if (isEmpty && _quickCopy(otherBase)) return;
+      // TODO(48143): Pre-grow capacity if it will reduce rehashing.
+    }
+    super.addAll(other);
+  }
 }
 
 @pragma("vm:entry-point")
@@ -924,6 +975,16 @@
   static Set<R> _newEmpty<R>() => new _CompactLinkedIdentityHashSet<R>();
 
   Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newEmpty);
+
+  void addAll(Iterable<E> other) {
+    if (other is _CompactLinkedIdentityHashSet) {
+      final otherBase = other as _CompactLinkedIdentityHashSet;
+      // If this set is empty we might be able to block-copy from [other].
+      if (isEmpty && _quickCopy(otherBase)) return;
+      // TODO(48143): Pre-grow capacity if it will reduce rehashing.
+    }
+    super.addAll(other);
+  }
 }
 
 class _CompactLinkedCustomHashSet<E> extends _HashFieldBase
diff --git a/tools/VERSION b/tools/VERSION
index cb01692..1a53903 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 17
 PATCH 0
-PRERELEASE 17
+PRERELEASE 18
 PRERELEASE_PATCH 0
\ No newline at end of file