Version 2.12.0-254.0.dev

Merge commit '2c2cff3a5a20071cb3d5e7f0048ca4167108952b' into 'dev'
diff --git a/DEPS b/DEPS
index 711f1b5..2ec4a05 100644
--- a/DEPS
+++ b/DEPS
@@ -133,7 +133,7 @@
   "ply_rev": "604b32590ffad5cbb82e4afef1d305512d06ae93",
   "pool_rev": "7abe634002a1ba8a0928eded086062f1307ccfae",
   "protobuf_rev": "0d03fd588df69e9863e2a2efc0059dee8f18d5b2",
-  "pub_rev": "7cff05f2522d5468648f854695ca8671aae2104d",
+  "pub_rev": "267fb68add3b85a0f6698bf5ae2648f1a1df515b",
   "pub_semver_rev": "10569a1e867e909cf5db201f73118020453e5db8",
   "resource_rev": "6b79867d0becf5395e5819a75720963b8298e9a7",
   "root_certificates_rev": "7e5ec82c99677a2e5b95ce296c4d68b0d3378ed8",
diff --git a/pkg/front_end/test/crashing_test_case_minimizer.dart b/pkg/front_end/test/crashing_test_case_minimizer.dart
index 46ce8f7..57c27f6 100644
--- a/pkg/front_end/test/crashing_test_case_minimizer.dart
+++ b/pkg/front_end/test/crashing_test_case_minimizer.dart
@@ -58,6 +58,12 @@
           settings.targetString = "flutter";
         } else if (arg.startsWith("--target=ddc")) {
           settings.targetString = "ddc";
+        } else if (arg == "--noTryToDeleteEmptyFilesUpFront") {
+          settings.noTryToDeleteEmptyFilesUpFront = true;
+        } else if (arg.startsWith("--wantErrorOnReload=")) {
+          String wantErrorOnReload =
+              arg.substring("--wantErrorOnReload=".length);
+          settings.lookForErrorErrorOnReload = wantErrorOnReload;
         } else if (arg == "--oldBlockDelete") {
           settings.oldBlockDelete = true;
         } else if (arg == "--lineDelete") {
diff --git a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
index abc52b9..0749061 100644
--- a/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
+++ b/pkg/front_end/test/crashing_test_case_minimizer_impl.dart
@@ -87,12 +87,14 @@
   bool widgetTransformation = false;
   final List<Uri> invalidate = [];
   String targetString = "VM";
+  bool noTryToDeleteEmptyFilesUpFront = false;
   bool oldBlockDelete = false;
   bool lineDelete = false;
   bool byteDelete = false;
   bool askAboutRedirectCrashTarget = false;
   bool autoUncoverAllCrashes = false;
   int stackTraceMatches = 1;
+  String lookForErrorErrorOnReload;
   final Set<String> askedAboutRedirect = {};
   final List<Map<String, dynamic>> fileSystems = [];
   final Set<String> allAutoRedirects = {};
@@ -116,6 +118,7 @@
       'widgetTransformation': widgetTransformation,
       'invalidate': invalidate.map((uri) => uri.toString()).toList(),
       'targetString': targetString,
+      'noTryToDeleteEmptyFilesUpFront': noTryToDeleteEmptyFilesUpFront,
       'oldBlockDelete': oldBlockDelete,
       'lineDelete': lineDelete,
       'byteDelete': byteDelete,
@@ -125,6 +128,7 @@
       'askedAboutRedirect': askedAboutRedirect.toList(),
       'fileSystems': fileSystems,
       'allAutoRedirects': allAutoRedirects.toList(),
+      'lookForErrorErrorOnReload': lookForErrorErrorOnReload,
     };
   }
 
@@ -139,6 +143,7 @@
     invalidate.addAll(
         (json["invalidate"] as List).map((uriString) => Uri.parse(uriString)));
     targetString = json["targetString"];
+    noTryToDeleteEmptyFilesUpFront = json["noTryToDeleteEmptyFilesUpFront"];
     oldBlockDelete = json["oldBlockDelete"];
     lineDelete = json["lineDelete"];
     byteDelete = json["byteDelete"];
@@ -151,6 +156,7 @@
     fileSystems.addAll((json["fileSystems"] as List).cast());
     allAutoRedirects.clear();
     allAutoRedirects.addAll((json["allAutoRedirects"] as List).cast());
+    lookForErrorErrorOnReload = json["lookForErrorErrorOnReload"];
 
     _fsNotInitial.initializeFromJson(fileSystems.removeLast());
   }
@@ -172,6 +178,7 @@
   bool _skip = false;
   bool _check = false;
   int _currentFsNum = -1;
+  bool _gotWantedError = false;
 
   Component _latestComponent;
   IncrementalCompiler _latestCrashingIncrementalCompiler;
@@ -332,20 +339,22 @@
       }
 
       // Try to delete empty files.
-      bool changedSome2 = true;
-      while (changedSome2) {
-        if (await _shouldQuit()) break;
-        changedSome2 = false;
-        for (int i = 0; i < uris.length; i++) {
+      if (!_settings.noTryToDeleteEmptyFilesUpFront) {
+        bool changedSome2 = true;
+        while (changedSome2) {
           if (await _shouldQuit()) break;
-          Uri uri = uris[i];
-          if (_fs.data[uri] == null || _fs.data[uri].isNotEmpty) continue;
-          print("About to work on file $i of ${uris.length}");
-          await _deleteContent(uris, i, false, initialComponent,
-              deleteFile: true);
-          if (_fs.data[uri] == null) {
-            changedSome = true;
-            changedSome2 = true;
+          changedSome2 = false;
+          for (int i = 0; i < uris.length; i++) {
+            if (await _shouldQuit()) break;
+            Uri uri = uris[i];
+            if (_fs.data[uri] == null || _fs.data[uri].isNotEmpty) continue;
+            print("About to work on file $i of ${uris.length}");
+            await _deleteContent(uris, i, false, initialComponent,
+                deleteFile: true);
+            if (_fs.data[uri] == null) {
+              changedSome = true;
+              changedSome2 = true;
+            }
           }
         }
       }
@@ -435,6 +444,15 @@
           }
         }
       }
+
+      // Partially a sanity-check, and partially to make sure there's a latest
+      // component for [_tryToRemoveUnreferencedFileContent] to work with (if
+      // crashing after an invalidation).
+      if (!await _crashesOnCompile(initialComponent)) {
+        throw "At a state where we should crash, we didn't!";
+      }
+      await _tryToRemoveUnreferencedFileContent(initialComponent,
+          deleteFile: true);
     }
 
     if (await _shouldQuit()) {
@@ -890,9 +908,11 @@
     bool removedSome = false;
     if (await _shouldQuit()) return;
     for (MapEntry<Uri, Uint8List> entry in _fs.data.entries) {
-      if (entry.value == null || entry.value.isEmpty) continue;
+      if (entry.value == null) continue;
+      if (!deleteFile && entry.value.isEmpty) continue;
       if (!entry.key.toString().endsWith(".dart")) continue;
-      if (!neededUris.contains(entry.key) && _fs.data[entry.key].length != 0) {
+      if (!neededUris.contains(entry.key) &&
+          (deleteFile || _fs.data[entry.key].length != 0)) {
         if (deleteFile) {
           _fs.data[entry.key] = null;
         } else {
@@ -1773,6 +1793,8 @@
 
   Future<bool> _crashesOnCompile(Component initialComponent) async {
     IncrementalCompiler incrementalCompiler;
+    _gotWantedError = false;
+    bool didNotGetWantedErrorAfterFirstCompile = true;
     if (_settings.noPlatform) {
       incrementalCompiler = new IncrementalCompiler(_setupCompilerContext());
     } else {
@@ -1788,8 +1810,10 @@
         ByteSink sink = new ByteSink();
         BinaryPrinter printer = new BinaryPrinter(sink);
         printer.writeComponentFile(_latestComponent);
-        sink.builder.takeBytes();
       }
+
+      if (_gotWantedError) didNotGetWantedErrorAfterFirstCompile = false;
+
       for (Uri uri in _settings.invalidate) {
         incrementalCompiler.invalidate(uri);
         Component delta = await incrementalCompiler.computeDelta();
@@ -1802,6 +1826,13 @@
           sink.builder.takeBytes();
         }
       }
+      if (_settings.lookForErrorErrorOnReload != null &&
+          _gotWantedError &&
+          didNotGetWantedErrorAfterFirstCompile) {
+        // We throw here so the "compile crashes"... This is looking for
+        // crashes after-all :)
+        throw "Got the wanted error!";
+      }
       _latestComponent = null; // if it didn't crash this isn't relevant.
       return false;
     } catch (e, st) {
@@ -1908,6 +1939,12 @@
     options.omitPlatform = false;
     options.onDiagnostic = (DiagnosticMessage message) {
       // don't care.
+      // Except if we're looking to trigger a specific error on reload.
+      if (_settings.lookForErrorErrorOnReload != null &&
+          message.ansiFormatted.first
+              .contains(_settings.lookForErrorErrorOnReload)) {
+        _gotWantedError = true;
+      }
     };
     if (_settings.noPlatform) {
       options.librariesSpecificationUri = null;
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index 086e491..de68c1d 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -375,8 +375,6 @@
       return const NeverType(Nullability.nonNullable);
     }
 
-    // The effect of the following rules is accounted for in the code below via
-    // the invocations of intersectNullabilities.
     // DOWN(T1*, T2*) = S* where S is DOWN(T1, T2)
     // DOWN(T1*, T2?) = S* where S is DOWN(T1, T2)
     // DOWN(T1?, T2*) = S* where S is DOWN(T1, T2)
@@ -385,6 +383,49 @@
     // DOWN(T1?, T2?) = S? where S is DOWN(T1, T2)
     // DOWN(T1?, T2) = S where S is DOWN(T1, T2)
     // DOWN(T1, T2?) = S where S is DOWN(T1, T2)
+    {
+      bool type1HasNullabilityMarker = !isTypeWithoutNullabilityMarker(type1,
+          isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
+      bool type2HasNullabilityMarker = !isTypeWithoutNullabilityMarker(type2,
+          isNonNullableByDefault: clientLibrary.isNonNullableByDefault);
+      if (type1HasNullabilityMarker && !type2HasNullabilityMarker) {
+        return _getNullabilityAwareStandardLowerBound(
+            computeTypeWithoutNullabilityMarker(type1,
+                isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+            type2,
+            clientLibrary);
+      } else if (!type1HasNullabilityMarker && type2HasNullabilityMarker) {
+        return _getNullabilityAwareStandardLowerBound(
+            type1,
+            computeTypeWithoutNullabilityMarker(type2,
+                isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+            clientLibrary);
+      } else if (isLegacyTypeConstructorApplication(type1,
+              isNonNullableByDefault: clientLibrary.isNonNullableByDefault) ||
+          isLegacyTypeConstructorApplication(type2,
+              isNonNullableByDefault: clientLibrary.isNonNullableByDefault)) {
+        return _getNullabilityAwareStandardLowerBound(
+                computeTypeWithoutNullabilityMarker(type1,
+                    isNonNullableByDefault:
+                        clientLibrary.isNonNullableByDefault),
+                computeTypeWithoutNullabilityMarker(type2,
+                    isNonNullableByDefault:
+                        clientLibrary.isNonNullableByDefault),
+                clientLibrary)
+            .withDeclaredNullability(Nullability.legacy);
+      } else if (isNullableTypeConstructorApplication(type1) &&
+          isNullableTypeConstructorApplication(type2)) {
+        return _getNullabilityAwareStandardLowerBound(
+                computeTypeWithoutNullabilityMarker(type1,
+                    isNonNullableByDefault:
+                        clientLibrary.isNonNullableByDefault),
+                computeTypeWithoutNullabilityMarker(type2,
+                    isNonNullableByDefault:
+                        clientLibrary.isNonNullableByDefault),
+                clientLibrary)
+            .withDeclaredNullability(Nullability.nullable);
+      }
+    }
 
     if (type1 is FunctionType && type2 is FunctionType) {
       return _getNullabilityAwareFunctionStandardLowerBound(
@@ -678,8 +719,6 @@
       return type2.withDeclaredNullability(Nullability.nullable);
     }
 
-    // The effect of the following rules is accounted for in the code below via
-    // the invocations of uniteNullabilities.
     // UP(T1*, T2*) = S* where S is UP(T1, T2)
     // UP(T1*, T2?) = S? where S is UP(T1, T2)
     // UP(T1?, T2*) = S? where S is UP(T1, T2)
@@ -688,6 +727,28 @@
     // UP(T1?, T2?) = S? where S is UP(T1, T2)
     // UP(T1?, T2) = S? where S is UP(T1, T2)
     // UP(T1, T2?) = S? where S is UP(T1, T2)
+    if (isNullableTypeConstructorApplication(type1) ||
+        isNullableTypeConstructorApplication(type2)) {
+      return _getNullabilityAwareStandardUpperBound(
+              computeTypeWithoutNullabilityMarker(type1,
+                  isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+              computeTypeWithoutNullabilityMarker(type2,
+                  isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+              clientLibrary)
+          .withDeclaredNullability(Nullability.nullable);
+    }
+    if (isLegacyTypeConstructorApplication(type1,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault) ||
+        isLegacyTypeConstructorApplication(type2,
+            isNonNullableByDefault: clientLibrary.isNonNullableByDefault)) {
+      return _getNullabilityAwareStandardUpperBound(
+              computeTypeWithoutNullabilityMarker(type1,
+                  isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+              computeTypeWithoutNullabilityMarker(type2,
+                  isNonNullableByDefault: clientLibrary.isNonNullableByDefault),
+              clientLibrary)
+          .withDeclaredNullability(Nullability.legacy);
+    }
 
     if (type1 is TypeParameterType) {
       return _getNullabilityAwareTypeParameterStandardUpperBound(
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 93b9795..03707fb 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -1071,9 +1071,7 @@
   @override
   DartType visitTypeParameterType(TypeParameterType node) {
     if (eliminationTargets.contains(node.parameter)) {
-      return typeParameterReplacement.withDeclaredNullability(
-          uniteNullabilities(
-              typeParameterReplacement.nullability, node.nullability));
+      return typeParameterReplacement;
     }
     return super.visitTypeParameterType(node);
   }
diff --git a/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart b/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
index 11f7da9..a787415 100644
--- a/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/resources/resources.g.dart
@@ -7708,7 +7708,7 @@
 ''';
 
 String _migration_js;
-// migration_dart md5 is 'ed25ca8e4192ae0a3fd5a19afb8efe5f'
+// migration_dart md5 is 'f0f101e4851eb5288f5fa4074c4246a6'
 String _migration_js_base64 = '''
 KGZ1bmN0aW9uIGRhcnRQcm9ncmFtKCl7ZnVuY3Rpb24gY29weVByb3BlcnRpZXMoYSxiKXt2YXIgcz1P
 YmplY3Qua2V5cyhhKQpmb3IodmFyIHI9MDtyPHMubGVuZ3RoO3IrKyl7dmFyIHE9c1tyXQpiW3FdPWFb
diff --git a/pkg/nnbd_migration/lib/src/front_end/web/migration.dart b/pkg/nnbd_migration/lib/src/front_end/web/migration.dart
index 0c2ddb8..7a5de1c 100644
--- a/pkg/nnbd_migration/lib/src/front_end/web/migration.dart
+++ b/pkg/nnbd_migration/lib/src/front_end/web/migration.dart
@@ -2,6 +2,10 @@
 // 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.
 
+// Explicitly opt out this file from null safety, for build reasons, inside
+// Google.
+// @dart=2.9
+
 import 'dart:async';
 import 'dart:convert';
 import 'dart:html';
diff --git a/tools/VERSION b/tools/VERSION
index bb1be73..927bbe8 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 12
 PATCH 0
-PRERELEASE 253
+PRERELEASE 254
 PRERELEASE_PATCH 0
\ No newline at end of file