Add fromEntries on HashMap and LinkedHashMap

Closes #34818

Change-Id: I77b117c16169a5c5bd5655e851256930a2ea5a28
Reviewed-on: https://dart-review.googlesource.com/c/81188
Commit-Queue: Nate Bosch <nbosch@google.com>
Reviewed-by: Lasse R.H. Nielsen <lrn@google.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index da17f5a..b310f71 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -150,6 +150,8 @@
 
 ### Core library changes
 
+*   Add `HashMap.fromEntries` and `LinkedHashmap.fromEntries` constructors.
+
 ### Dart VM
 
 ### Tool Changes
diff --git a/sdk/lib/collection/hash_map.dart b/sdk/lib/collection/hash_map.dart
index 84655dc..dcdb4ee 100644
--- a/sdk/lib/collection/hash_map.dart
+++ b/sdk/lib/collection/hash_map.dart
@@ -153,4 +153,16 @@
     MapBase._fillMapWithIterables(map, keys, values);
     return map;
   }
+
+  /**
+   * Creates a [HashMap] containing the entries of [entries].
+   *
+   * Returns a new `HashMap<K, V>` where all entries of [entries]
+   * have been added in iteration order.
+   *
+   * If multiple [entries] have the same key,
+   * later occurrences overwrite the earlier ones.
+   */
+  factory HashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+      HashMap<K, V>()..addEntries(entries);
 }
diff --git a/sdk/lib/collection/linked_hash_map.dart b/sdk/lib/collection/linked_hash_map.dart
index b4c2bf4..770c6e1 100644
--- a/sdk/lib/collection/linked_hash_map.dart
+++ b/sdk/lib/collection/linked_hash_map.dart
@@ -141,4 +141,16 @@
     MapBase._fillMapWithIterables(map, keys, values);
     return map;
   }
+
+  /**
+   * Creates a [LinkedHashMap] containing the entries of [entries].
+   *
+   * Returns a new `LinkedHashMap<K, V>` where all entries of [entries]
+   * have been added in iteration order.
+   *
+   * If multiple [entries] have the same key,
+   * later occurrences overwrite the earlier ones.
+   */
+  factory LinkedHashMap.fromEntries(Iterable<MapEntry<K, V>> entries) =>
+      <K, V>{}..addEntries(entries);
 }
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index 4e8a878..42b606a 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -175,8 +175,11 @@
   /**
    * Creates a new map and adds all entries.
    *
-   * Creates a new map like `new Map<K, V>()` and then adds the key
-   * and value of eacy entry in [entries] in iteration order.
+   * Returns a new `Map<K, V>` where all entries of [entries]
+   * have been added in iteration order.
+   *
+   * If multiple [entries] have the same key,
+   * later occurrences overwrite the earlier ones.
    */
   factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>
       <K, V>{}..addEntries(entries);
diff --git a/tests/corelib_2/map_from_entries_test.dart b/tests/corelib_2/map_from_entries_test.dart
new file mode 100644
index 0000000..ef114a7
--- /dev/null
+++ b/tests/corelib_2/map_from_entries_test.dart
@@ -0,0 +1,47 @@
+// Copyright (c) 2018, 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 'package:expect/expect.dart';
+
+main() {
+  runTests(<K, V>(entries) => Map<K, V>.fromEntries(entries));
+  runTests(<K, V>(entries) => HashMap<K, V>.fromEntries(entries));
+  runTests(<K, V>(entries) => LinkedHashMap<K, V>.fromEntries(entries));
+}
+
+void runTests(Map<K, V> Function<K, V>(Iterable<MapEntry<K, V>>) ctor) {
+  fromEntriesTest(ctor);
+  emptyIterableTest(ctor);
+  equalElementsTest(ctor);
+}
+
+void fromEntriesTest(Map<K, V> Function<K, V>(Iterable<MapEntry<K, V>>) ctor) {
+  var map = ctor([MapEntry(1, "one"), MapEntry(2, "two")]);
+  Expect.equals(2, map.length);
+  Expect.equals(2, map.keys.length);
+  Expect.equals(2, map.values.length);
+  Expect.equals("one", map[1]);
+  Expect.equals("two", map[2]);
+}
+
+void emptyIterableTest(
+    Map<K, V> Function<K, V>(Iterable<MapEntry<K, V>>) ctor) {
+  var map = ctor([]);
+  Expect.equals(0, map.length);
+  Expect.equals(0, map.keys.length);
+  Expect.equals(0, map.values.length);
+}
+
+void equalElementsTest(
+    Map<K, V> Function<K, V>(Iterable<MapEntry<K, V>>) ctor) {
+  var map =
+      ctor([MapEntry(1, "one"), MapEntry(2, "two"), MapEntry(2, "other")]);
+  Expect.equals(2, map.length);
+  Expect.equals(2, map.keys.length);
+  Expect.equals(2, map.values.length);
+  Expect.equals("one", map[1]);
+  Expect.equals("other", map[2]);
+}