Version 2.12.0-114.0.dev

Merge commit '3e7b5b2e7b2a19bd01042647a4be0e1dd81236d5' into 'dev'
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index d466c551..54435dc 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -2057,9 +2057,37 @@
       // If the variable isn't initialized, call the initializer and set it.
       Fragment initialize(is_uninitialized);
       initialize += BuildExpression();
-      initialize += StoreLocal(position, variable);
-      initialize += Drop();
-      initialize += Goto(join);
+      if (variable->is_final()) {
+        // Late final variable, so check whether it has been assigned
+        // during initialization.
+        initialize += LoadLocal(variable);
+        TargetEntryInstr *is_uninitialized_after_init,
+            *is_initialized_after_init;
+        initialize += Constant(Object::sentinel());
+        initialize += flow_graph_builder_->BranchIfStrictEqual(
+            &is_uninitialized_after_init, &is_initialized_after_init);
+        {
+          // The variable is uninitialized, so store the initializer result.
+          Fragment store_result(is_uninitialized_after_init);
+          store_result += StoreLocal(position, variable);
+          store_result += Drop();
+          store_result += Goto(join);
+        }
+
+        {
+          // Already initialized, so throw a LateInitializationError.
+          Fragment already_assigned(is_initialized_after_init);
+          already_assigned += flow_graph_builder_->ThrowLateInitializationError(
+              position, "_throwLocalAssignedDuringInitialization",
+              variable->name());
+          already_assigned += Goto(join);
+        }
+      } else {
+        // Late non-final variable. Store the initializer result.
+        initialize += StoreLocal(position, variable);
+        initialize += Drop();
+        initialize += Goto(join);
+      }
     } else {
       // The variable has no initializer, so throw a LateInitializationError.
       Fragment initialize(is_uninitialized);
diff --git a/sdk/lib/_internal/vm/lib/array.dart b/sdk/lib/_internal/vm/lib/array.dart
index 643faf4..99e04aa 100644
--- a/sdk/lib/_internal/vm/lib/array.dart
+++ b/sdk/lib/_internal/vm/lib/array.dart
@@ -35,6 +35,72 @@
     return result;
   }
 
+  // Specialization of List.of constructor for growable == false.
+  factory _List.of(Iterable<E> elements) {
+    if (elements is _GrowableList) {
+      return _List._ofGrowableList(unsafeCast(elements));
+    }
+    if (elements is _List) {
+      return _List._ofList(unsafeCast(elements));
+    }
+    if (elements is _ImmutableList) {
+      return _List._ofImmutableList(unsafeCast(elements));
+    }
+    if (elements is EfficientLengthIterable) {
+      return _List._ofEfficientLengthIterable(unsafeCast(elements));
+    }
+    return _List._ofOther(elements);
+  }
+
+  factory _List._ofGrowableList(_GrowableList<E> elements) {
+    final int length = elements.length;
+    final list = _List<E>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _List._ofList(_List<E> elements) {
+    final int length = elements.length;
+    final list = _List<E>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _List._ofImmutableList(_ImmutableList<E> elements) {
+    final int length = elements.length;
+    final list = _List<E>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _List._ofEfficientLengthIterable(
+      EfficientLengthIterable<E> elements) {
+    final int length = elements.length;
+    final list = _List<E>(length);
+    if (length > 0) {
+      int i = 0;
+      for (var element in elements) {
+        list[i++] = element;
+      }
+      if (i != length) throw ConcurrentModificationError(elements);
+    }
+    return list;
+  }
+
+  factory _List._ofOther(Iterable<E> elements) {
+    // The static type of `makeListFixedLength` is `List<E>`, not `_List<E>`,
+    // but we know that is what it does.  `makeListFixedLength` is too generally
+    // typed since it is available on the web platform which has different
+    // system List types.
+    return unsafeCast(makeListFixedLength(_GrowableList<E>._ofOther(elements)));
+  }
+
   @pragma("vm:recognized", "graph-intrinsic")
   E operator [](int index) native "List_getIndexed";
 
diff --git a/sdk/lib/_internal/vm/lib/array_patch.dart b/sdk/lib/_internal/vm/lib/array_patch.dart
index df03cf6..e935025 100644
--- a/sdk/lib/_internal/vm/lib/array_patch.dart
+++ b/sdk/lib/_internal/vm/lib/array_patch.dart
@@ -46,44 +46,11 @@
 
   @patch
   factory List.of(Iterable<E> elements, {bool growable: true}) {
-    final cid = ClassID.getID(elements);
-    final isVMList = (cid == ClassID.cidArray) ||
-        (cid == ClassID.cidGrowableObjectArray) ||
-        (cid == ClassID.cidImmutableArray);
-
-    if (isVMList) {
-      final ListBase<E> elementsAsList = elements as ListBase<E>;
-      final int length = elementsAsList.length;
-      final list =
-          growable ? new _GrowableList<E>(length) : new _List<E>(length);
-      if (length > 0) {
-        for (int i = 0; i < length; i++) {
-          list[i] = elementsAsList[i];
-        }
-      }
-      return list;
+    if (growable) {
+      return _GrowableList.of(elements);
+    } else {
+      return _List.of(elements);
     }
-
-    if (elements is EfficientLengthIterable) {
-      final int length = elements.length;
-      final list =
-          growable ? new _GrowableList<E>(length) : new _List<E>(length);
-      if (length > 0) {
-        int i = 0;
-        for (var element in elements) {
-          list[i++] = element;
-        }
-        if (i != length) throw ConcurrentModificationError(elements);
-      }
-      return list;
-    }
-
-    final list = <E>[];
-    for (var elements in elements) {
-      list.add(elements);
-    }
-    if (growable) return list;
-    return makeListFixedLength(list);
   }
 
   @patch
diff --git a/sdk/lib/_internal/vm/lib/growable_array.dart b/sdk/lib/_internal/vm/lib/growable_array.dart
index 416e7bd..537fb34 100644
--- a/sdk/lib/_internal/vm/lib/growable_array.dart
+++ b/sdk/lib/_internal/vm/lib/growable_array.dart
@@ -130,6 +130,72 @@
     return result;
   }
 
+  // Specialization of List.of constructor for growable == true.
+  factory _GrowableList.of(Iterable<T> elements) {
+    if (elements is _GrowableList) {
+      return _GrowableList._ofGrowableList(unsafeCast(elements));
+    }
+    if (elements is _List) {
+      return _GrowableList._ofList(unsafeCast(elements));
+    }
+    if (elements is _ImmutableList) {
+      return _GrowableList._ofImmutableList(unsafeCast(elements));
+    }
+    if (elements is EfficientLengthIterable) {
+      return _GrowableList._ofEfficientLengthIterable(unsafeCast(elements));
+    }
+    return _GrowableList._ofOther(elements);
+  }
+
+  factory _GrowableList._ofList(_List<T> elements) {
+    final int length = elements.length;
+    final list = _GrowableList<T>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _GrowableList._ofGrowableList(_GrowableList<T> elements) {
+    final int length = elements.length;
+    final list = _GrowableList<T>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _GrowableList._ofImmutableList(_ImmutableList<T> elements) {
+    final int length = elements.length;
+    final list = _GrowableList<T>(length);
+    for (int i = 0; i < length; i++) {
+      list[i] = elements[i];
+    }
+    return list;
+  }
+
+  factory _GrowableList._ofEfficientLengthIterable(
+      EfficientLengthIterable<T> elements) {
+    final int length = elements.length;
+    final list = _GrowableList<T>(length);
+    if (length > 0) {
+      int i = 0;
+      for (var element in elements) {
+        list[i++] = element;
+      }
+      if (i != length) throw ConcurrentModificationError(elements);
+    }
+    return list;
+  }
+
+  factory _GrowableList._ofOther(Iterable<T> elements) {
+    final list = _GrowableList<T>(0);
+    for (var elements in elements) {
+      list.add(elements);
+    }
+    return list;
+  }
+
   @pragma("vm:recognized", "asm-intrinsic")
   @pragma("vm:exact-result-type",
       <dynamic>[_GrowableList, "result-type-uses-passed-type-arguments"])
diff --git a/sdk/lib/_internal/vm/lib/internal_patch.dart b/sdk/lib/_internal/vm/lib/internal_patch.dart
index 24f9461..f1d22c9 100644
--- a/sdk/lib/_internal/vm/lib/internal_patch.dart
+++ b/sdk/lib/_internal/vm/lib/internal_patch.dart
@@ -212,4 +212,9 @@
   static _throwLocalAlreadyInitialized(String localName) {
     throw new LateError.localAI(localName);
   }
+
+  @pragma("vm:entry-point")
+  static _throwLocalAssignedDuringInitialization(String localName) {
+    throw new LateError.localADI(localName);
+  }
 }
diff --git a/tests/dart2js/native/fake_thing_test.dart b/tests/dart2js/native/fake_thing_test.dart
index 0131821..542a5ca 100644
--- a/tests/dart2js/native/fake_thing_test.dart
+++ b/tests/dart2js/native/fake_thing_test.dart
@@ -26,13 +26,9 @@
 })()""");
 }
 
-inscrutable(x) {
-  if (new DateTime.now().millisecondsSinceEpoch == 0) {
-    return x;
-  } else {
-    return 42;
-  }
-}
+@pragma('dart2js:noInline')
+@pragma('dart2js:assumeDynamic')
+inscrutable(x) => x;
 
 main() {
   setup();
diff --git a/tests/dart2js_2/native/fake_thing_test.dart b/tests/dart2js_2/native/fake_thing_test.dart
index 8e1ca18..63fda12 100644
--- a/tests/dart2js_2/native/fake_thing_test.dart
+++ b/tests/dart2js_2/native/fake_thing_test.dart
@@ -28,13 +28,9 @@
 })()""");
 }
 
-inscrutable(x) {
-  if (new DateTime.now().millisecondsSinceEpoch == 0) {
-    return x;
-  } else {
-    return 42;
-  }
-}
+@pragma('dart2js:noInline')
+@pragma('dart2js:assumeDynamic')
+inscrutable(x) => x;
 
 main() {
   setup();
diff --git a/tests/language/nnbd/syntax/late_modifier_runtime_error_test.dart b/tests/language/nnbd/syntax/late_modifier_runtime_error_test.dart
index 851d225..c410775 100644
--- a/tests/language/nnbd/syntax/late_modifier_runtime_error_test.dart
+++ b/tests/language/nnbd/syntax/late_modifier_runtime_error_test.dart
@@ -106,7 +106,8 @@
   Expect.throws(() {
     local2 = 2;
   }, (e) => isValidError(e, "Local 'local2' has already been initialized."));
-  // Uncomment after https://github.com/dart-lang/sdk/issues/44372 is fixed.
-  // Expect.throws(() => local3,
-  //     (e) => isValidError(e, "Local 'local3' has already been initialized."));
+  Expect.throws(
+      () => local3,
+      (e) => isValidError(
+          e, "Local 'local3' has been assigned during initialization."));
 }
diff --git a/tools/VERSION b/tools/VERSION
index 5397bdc..41ab758 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 113
+PRERELEASE 114
 PRERELEASE_PATCH 0
\ No newline at end of file