Version 3.0.0-3.0.dev

Merge e8906e65e72522e5e574cc772ff0c159dafb5f60 into dev
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index c0abb97..36e3def 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -10,7 +10,6 @@
 import 'util/util.dart';
 
 enum NullSafetyMode {
-  unspecified,
   unsound,
   sound,
 }
@@ -552,24 +551,20 @@
   /// called.
   bool experimentCallInstrumentation = false;
 
-  /// When null-safety is enabled, whether the compiler should emit code with
-  /// unsound or sound semantics.
-  ///
-  /// If unspecified, the mode must be inferred from the entrypoint.
+  /// Whether the compiler should emit code with unsound or sound semantics.
+  /// Since Dart 3.0 this is no longer inferred from sources, but defaults to
+  /// sound semantics.
   ///
   /// This option should rarely need to be accessed directly. Consider using
   /// [useLegacySubtyping] instead.
-  NullSafetyMode nullSafetyMode = NullSafetyMode.unspecified;
+  NullSafetyMode nullSafetyMode = NullSafetyMode.sound;
   bool _soundNullSafety = false;
   bool _noSoundNullSafety = false;
 
   /// Whether to use legacy subtype semantics rather than null-safe semantics.
-  /// This is `true` if null-safety is disabled, i.e. all code is legacy code,
-  /// or if unsound null-safety semantics are being used, since we do not emit
-  /// warnings.
+  /// This is `true` if unsound null-safety semantics are being used, since
+  /// dart2js does not emit warnings for unsound null-safety.
   bool get useLegacySubtyping {
-    assert(nullSafetyMode != NullSafetyMode.unspecified,
-        "Null safety mode unspecified");
     return nullSafetyMode == NullSafetyMode.unsound;
   }
 
diff --git a/pkg/compiler/lib/src/phase/load_kernel.dart b/pkg/compiler/lib/src/phase/load_kernel.dart
index d33642f..b8787a8 100644
--- a/pkg/compiler/lib/src/phase/load_kernel.dart
+++ b/pkg/compiler/lib/src/phase/load_kernel.dart
@@ -111,17 +111,6 @@
   return "${targetName}_platform$unsoundMarker.dill";
 }
 
-void _inferNullSafetyMode(CompilerOptions options, bool isSound) {
-  if (options.nullSafetyMode == NullSafetyMode.unspecified) {
-    options.nullSafetyMode =
-        isSound ? NullSafetyMode.sound : NullSafetyMode.unsound;
-  }
-}
-
-void _validateNullSafetyMode(CompilerOptions options) {
-  assert(options.nullSafetyMode != NullSafetyMode.unspecified);
-}
-
 class _LoadFromKernelResult {
   final ir.Component? component;
   final Library? entryLibrary;
@@ -177,8 +166,6 @@
     throw ArgumentError("$resolvedUri was compiled with $dillMode null "
         "safety and is incompatible with the '$option' option");
   }
-  _inferNullSafetyMode(options, isStrongDill);
-  _validateNullSafetyMode(options);
 
   // When compiling modularly, a dill for the SDK will be provided. In those
   // cases we ignore the implicit platform binary.
@@ -269,7 +256,17 @@
     Uri resolvedUri = options.compilationTarget!;
     bool isLegacy =
         await fe.uriUsesLegacyLanguageVersion(resolvedUri, feOptions);
-    _inferNullSafetyMode(options, !isLegacy);
+    if (isLegacy && options.nullSafetyMode == NullSafetyMode.sound) {
+      reporter.reportError(
+          reporter.createMessage(NO_LOCATION_SPANNABLE, MessageKind.GENERIC, {
+        'text': "Starting with Dart 3.0, `dart compile js` expects programs to be "
+            "null safe by default. Some libraries reached from "
+            "$resolvedUri opted-out of null safety. "
+            "You can temporarily compile this application using the deprecated "
+            "'${Flags.noSoundNullSafety}' option (which will be removed before "
+            "the Dart 3.0 stable release)."
+      }));
+    }
     sources.add(options.compilationTarget!);
   }
 
@@ -298,8 +295,6 @@
       verbosity: verbosity);
   ir.Component? component = await fe.compile(initializedCompilerState, verbose,
       fileSystem, onDiagnostic, sources, isModularCompile);
-  _validateNullSafetyMode(options);
-
   _doTransformsOnKernelLoad(component);
 
   // We have to compute canonical names on the component here to avoid missing
diff --git a/pkg/compiler/lib/src/util/memory_compiler.dart b/pkg/compiler/lib/src/util/memory_compiler.dart
index 2a27c4b..d2d9ae5 100644
--- a/pkg/compiler/lib/src/util/memory_compiler.dart
+++ b/pkg/compiler/lib/src/util/memory_compiler.dart
@@ -143,18 +143,37 @@
 
   // If soundNullSafety is not requested, then we prepend the opt out string to
   // the memory files.
-  if (!options.contains(Flags.soundNullSafety) && !unsafeToTouchSourceFiles) {
-    // Map may be immutable so copy.
-    sources = {};
-    memorySourceFiles.forEach((k, v) => sources[k] = v);
-    RegExp optOutStr = RegExp(r"\/\/\s*@dart\s*=\s*2\.\d+");
+  // TODO(48820): After migrating all tests we should no longer have to infer
+  // a mode in the memory compiler. The logic to update options and to update
+  // sources to opt-out should be removed.
+  if (!options.contains(Flags.soundNullSafety)) {
+    bool addUnsoundFlag = false;
+    if (!unsafeToTouchSourceFiles) {
+      // Map may be immutable so copy.
+      sources = {};
+      memorySourceFiles.forEach((k, v) => sources[k] = v);
+      addUnsoundFlag = true;
+    }
+
     for (var key in sources.keys) {
       if (sources[key] is String && key.endsWith('.dart')) {
-        if (!optOutStr.hasMatch(sources[key])) {
-          sources[key] = '// @dart=2.7\n' + sources[key];
+        RegExp optOutStr = RegExp(r"\/\/\s*@dart\s*=\s*2\.(\d+)");
+        final match = optOutStr.firstMatch(sources[key]);
+        if (match == null) {
+          if (!unsafeToTouchSourceFiles) {
+            sources[key] = '// @dart=2.7\n' + sources[key];
+          }
+        } else {
+          // If the file version is prior to 2.12, we treat it as unsound
+          if (int.parse(match.group(1)) < 12) {
+            addUnsoundFlag = true;
+          }
         }
       }
     }
+    if (addUnsoundFlag && !options.contains(Flags.noSoundNullSafety)) {
+      options = [Flags.noSoundNullSafety, ...options];
+    }
   }
 
   MemorySourceFileProvider provider;
diff --git a/pkg/compiler/test/end_to_end/dart2js_batch_test.dart b/pkg/compiler/test/end_to_end/dart2js_batch_test.dart
index 5d32912..03c68ed 100644
--- a/pkg/compiler/test/end_to_end/dart2js_batch_test.dart
+++ b/pkg/compiler/test/end_to_end/dart2js_batch_test.dart
@@ -67,8 +67,9 @@
   String outFile = path.join(tmpDir.path, 'out.js');
   String outFile2 = path.join(tmpDir.path, 'out2.js');
 
-  process.stdin.writeln('--out="$outFile" "$inFile"');
-  process.stdin.writeln('--out="$outFile2" "$inFile"');
+  // TODO(48820): remove null safety flag.
+  process.stdin.writeln('--no-sound-null-safety --out="$outFile" "$inFile"');
+  process.stdin.writeln('--no-sound-null-safety --out="$outFile2" "$inFile"');
   process.stdin.writeln('too many arguments');
   process.stdin.writeln(r'"non existing file.dart"');
   process.stdin.close();
diff --git a/pkg/compiler/test/end_to_end/modular_loader_test.dart b/pkg/compiler/test/end_to_end/modular_loader_test.dart
index 33bd45b..4ab2e11 100644
--- a/pkg/compiler/test/end_to_end/modular_loader_test.dart
+++ b/pkg/compiler/test/end_to_end/modular_loader_test.dart
@@ -40,7 +40,8 @@
         entryPoint: entryPoint,
         options: [
           '--input-dill=memory:c.dill',
-          '--dill-dependencies=memory:a.dill,memory:b.dill'
+          '--dill-dependencies=memory:a.dill,memory:b.dill',
+          '--sound-null-safety',
         ],
         memorySourceFiles: {'a.dill': aDill, 'b.dill': bDill, 'c.dill': cDill},
         diagnosticHandler: diagnostics,
diff --git a/pkg/compiler/test/end_to_end/output_type_test.dart b/pkg/compiler/test/end_to_end/output_type_test.dart
index 76ee848..bf53338 100644
--- a/pkg/compiler/test/end_to_end/output_type_test.dart
+++ b/pkg/compiler/test/end_to_end/output_type_test.dart
@@ -88,6 +88,7 @@
       'pkg/compiler/test/deferred/data/deferred_helper.dart',
       '--out=custom.js',
       '--deferred-map=def/deferred.json',
+      '--no-sound-null-safety',
       '--no-csp',
       Flags.dumpInfo,
     ], [
@@ -112,6 +113,7 @@
 
     await test([
       'pkg/compiler/test/deferred/data/deferred_helper.dart',
+      '--no-sound-null-safety',
       '--csp',
       ...additionOptionals,
     ], expectedOutput);
diff --git a/pkg/compiler/test/end_to_end/user_crash_test.dart b/pkg/compiler/test/end_to_end/user_crash_test.dart
index e2d353e..51010b06 100644
--- a/pkg/compiler/test/end_to_end/user_crash_test.dart
+++ b/pkg/compiler/test/end_to_end/user_crash_test.dart
@@ -10,6 +10,7 @@
 import 'package:front_end/src/fasta/messages.dart'
     show templateCantReadFile, messageMissingMain;
 import 'package:compiler/compiler_api.dart' as api;
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/util/memory_compiler.dart';
 
 final EXCEPTION = 'Crash-marker';
@@ -75,7 +76,7 @@
           entryPoint: entryPoint,
           memorySourceFiles: memorySourceFiles,
           diagnosticHandler: diagnostics,
-          unsafeToTouchSourceFiles: true);
+          options: [Flags.soundNullSafety]);
     } catch (e) {
       result.exceptions.add(e);
     }
diff --git a/pkg/compiler/test/inference/inference_test_helper.dart b/pkg/compiler/test/inference/inference_test_helper.dart
index 3d5d09b..92a849e 100644
--- a/pkg/compiler/test/inference/inference_test_helper.dart
+++ b/pkg/compiler/test/inference/inference_test_helper.dart
@@ -9,6 +9,7 @@
 import 'package:compiler/src/closure.dart';
 import 'package:compiler/src/common.dart';
 import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/commandline_options.dart';
 import 'package:compiler/src/elements/entities.dart';
 import 'package:compiler/src/inferrer/typemasks/masks.dart';
 import 'package:compiler/src/inferrer/types.dart';
@@ -33,6 +34,9 @@
         args: args,
         options: [stopAfterTypeInference],
         testedConfigs: allInternalConfigs,
+        perTestOptions: {
+          "issue48304.dart": [Flags.soundNullSafety],
+        },
         skip: skip,
         shardIndex: shardIndex ?? 0,
         shards: shardIndex != null ? 4 : 1);
diff --git a/pkg/compiler/test/serialization/on_disk_split_test.dart b/pkg/compiler/test/serialization/on_disk_split_test.dart
index fdd4032..2dda673 100644
--- a/pkg/compiler/test/serialization/on_disk_split_test.dart
+++ b/pkg/compiler/test/serialization/on_disk_split_test.dart
@@ -23,6 +23,7 @@
     await internalMain([
           'pkg/compiler/test/codesize/swarm/swarm.dart',
           Flags.writeClosedWorld,
+          '--no-sound-null-safety',
           '--out=${dillUri}',
         ] +
         commonArgs);
@@ -30,6 +31,7 @@
           '${dillUri}',
           Flags.readClosedWorld,
           Flags.writeData,
+          '--no-sound-null-safety',
           '--out=${outUri}',
         ] +
         commonArgs);
diff --git a/pkg/compiler/test/sourcemaps/minified_names_test.dart b/pkg/compiler/test/sourcemaps/minified_names_test.dart
index 91000fd..47c0f97 100644
--- a/pkg/compiler/test/sourcemaps/minified_names_test.dart
+++ b/pkg/compiler/test/sourcemaps/minified_names_test.dart
@@ -97,6 +97,7 @@
   print('-- ${minified ? 'minified' : 'not-minified'}:');
   var options = [
     Flags.testMode,
+    Flags.noSoundNullSafety,
     '--libraries-spec=$sdkLibrariesSpecificationUri',
     if (minified) Flags.minify,
   ];
diff --git a/pkg/compiler/test/sourcemaps/stacktrace_test.dart b/pkg/compiler/test/sourcemaps/stacktrace_test.dart
index 262c8b2..8adf30a 100644
--- a/pkg/compiler/test/sourcemaps/stacktrace_test.dart
+++ b/pkg/compiler/test/sourcemaps/stacktrace_test.dart
@@ -89,6 +89,7 @@
       '--libraries-spec=$sdkLibrariesSpecificationPath',
       '--packages=${Platform.packageConfig}',
       Flags.testMode,
+      Flags.noSoundNullSafety,
       input,
     ]..addAll(options);
     print("Compiling dart2js ${arguments.join(' ')}");
diff --git a/pkg/compiler/test/sourcemaps/stepping_test.dart b/pkg/compiler/test/sourcemaps/stepping_test.dart
index 8b362b2..df36836 100644
--- a/pkg/compiler/test/sourcemaps/stepping_test.dart
+++ b/pkg/compiler/test/sourcemaps/stepping_test.dart
@@ -75,6 +75,7 @@
     '--out=$outputFile',
     inputFile,
     Flags.disableInlining,
+    Flags.noSoundNullSafety,
     '--libraries-spec=$sdkLibrariesSpecificationUri',
   ];
   CompilationResult compilationResult = await entry.internalMain(arguments);
diff --git a/pkg/compiler/tool/modular_test_suite_helper.dart b/pkg/compiler/tool/modular_test_suite_helper.dart
index a1e36ac..467e3ca 100644
--- a/pkg/compiler/tool/modular_test_suite_helper.dart
+++ b/pkg/compiler/tool/modular_test_suite_helper.dart
@@ -127,6 +127,7 @@
     List<String> args = [
       '--no-sound-null-safety',
       _kernelWorkerScript,
+      '--no-sound-null-safety',
       ...stepArguments,
       '--exclude-non-sources',
       '--multi-root',
@@ -350,6 +351,7 @@
       _dart2jsScript,
       // TODO(sigmund): remove this dependency on libraries.json
       if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+      Flags.noSoundNullSafety,
       '${Flags.entryUri}=$fakeRoot${module.mainSource}',
       '${Flags.inputDill}=${toUri(module, dillId)}',
       for (String flag in flags) '--enable-experiment=$flag',
@@ -411,6 +413,7 @@
       _dart2jsScript,
       // TODO(sigmund): remove this dependency on libraries.json
       if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+      Flags.noSoundNullSafety,
       '${Flags.entryUri}=$fakeRoot${module.mainSource}',
       '${Flags.inputDill}=${toUri(module, fullDillId)}',
       for (String flag in flags) '--enable-experiment=$flag',
@@ -461,6 +464,7 @@
       _dart2jsScript,
       // TODO(sigmund): remove this dependency on libraries.json
       if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+      Flags.noSoundNullSafety,
       '${Flags.entryUri}=$fakeRoot${module.mainSource}',
       '${Flags.inputDill}=${toUri(module, globalUpdatedDillId)}',
       for (String flag in flags) '--enable-experiment=$flag',
@@ -515,6 +519,7 @@
       '--packages=${sdkRoot.toFilePath()}/$packageConfigJsonPath',
       _dart2jsScript,
       if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+      Flags.noSoundNullSafety,
       '${Flags.entryUri}=$fakeRoot${module.mainSource}',
       '${Flags.inputDill}=${toUri(module, globalUpdatedDillId)}',
       for (String flag in flags) '--enable-experiment=$flag',
@@ -569,6 +574,7 @@
       '--packages=${sdkRoot.toFilePath()}/$packageConfigJsonPath',
       _dart2jsScript,
       if (_options.useSdk) '--libraries-spec=$_librarySpecForSnapshot',
+      Flags.noSoundNullSafety,
       '${Flags.entryUri}=$fakeRoot${module.mainSource}',
       '${Flags.inputDill}=${toUri(module, globalUpdatedDillId)}',
       for (String flag in flags) '${Flags.enableLanguageExperiments}=$flag',
diff --git a/pkg/dartdev/test/commands/compile_test.dart b/pkg/dartdev/test/commands/compile_test.dart
index 49f532c..866178c9 100644
--- a/pkg/dartdev/test/commands/compile_test.dart
+++ b/pkg/dartdev/test/commands/compile_test.dart
@@ -698,6 +698,7 @@
       [
         'compile',
         'js',
+        '--no-sound-null-safety',
         '-o',
         outFile,
         inFile,
diff --git a/tools/VERSION b/tools/VERSION
index 838416a..4848c71 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 3
 MINOR 0
 PATCH 0
-PRERELEASE 2
+PRERELEASE 3
 PRERELEASE_PATCH 0
diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json
index f77cd99..e6ffd66 100644
--- a/tools/bots/test_matrix.json
+++ b/tools/bots/test_matrix.json
@@ -535,11 +535,6 @@
     },
     "dart2js-(linux|mac|win)-chrome": {
       "options": {
-        "use-sdk": true
-      }
-    },
-    "dart2js-(linux|mac|win)-chrome-unsound": {
-      "options": {
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -554,11 +549,6 @@
     },
     "dart2js-(linux|win)-firefox": {
       "options": {
-        "use-sdk": true
-      }
-    },
-    "dart2js-(linux|win)-firefox-unsound": {
-      "options": {
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -568,25 +558,14 @@
     "dart2js-win-ie11": {
       "options": {
         "babel": "{\"presets\":[\"es2015\"]}",
-        "use-sdk": true
-      }
-    },
-    "dart2js-win-ie11-unsound": {
-      "options": {
-        "babel": "{\"presets\":[\"es2015\"]}",
+        "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
-        ],
-        "use-sdk": true
+        ]
       }
     },
     "dart2js-win-edge": {
       "options": {
-        "use-sdk": true
-      }
-    },
-    "dart2js-win-edge-unsound": {
-      "options": {
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -595,11 +574,6 @@
     },
     "dart2js-mac-safari": {
       "options": {
-        "use-sdk": true
-      }
-    },
-    "dart2js-mac-safari-unsound": {
-      "options": {
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -610,13 +584,6 @@
       "options": {
         "minified": true,
         "csp": true,
-        "use-sdk": true
-      }
-    },
-    "dart2js-minified-csp-(linux|mac|win)-chrome-unsound": {
-      "options": {
-        "minified": true,
-        "csp": true,
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -630,19 +597,14 @@
         "timeout": 240,
         "dart2js-options": [
           "--merge-fragments-threshold=3",
-          "--simple-load-ids"
+          "--simple-load-ids",
+          "--no-sound-null-safety"
         ]
       }
     },
     "dart2js-minified-(linux|mac|win)-d8": {
       "options": {
         "minified": true,
-        "use-sdk": true
-      }
-    },
-    "dart2js-minified-(linux|mac|win)-d8-unsound": {
-      "options": {
-        "minified": true,
         "use-sdk": true,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -657,7 +619,8 @@
         "builder-tag": "dart2js-weak",
         "dart2js-options": [
           "--merge-fragments-threshold=3",
-          "--simple-load-ids"
+          "--simple-load-ids",
+          "--no-sound-null-safety"
         ]
       }
     },
@@ -666,7 +629,8 @@
         "builder-tag": "dart2js_production",
         "use-sdk": true,
         "dart2js-options": [
-          "-O3"
+          "-O3",
+          "--no-sound-null-safety"
         ]
       }
     },
@@ -675,7 +639,8 @@
         "builder-tag": "dart2js_o0",
         "use-sdk": true,
         "dart2js-options": [
-          "-O0"
+          "-O0",
+          "--no-sound-null-safety"
         ]
       }
     },
@@ -701,12 +666,6 @@
     "dart2js-hostasserts-(linux|mac|win)-(ia32|x64)-d8": {
       "options": {
         "host-checked": true,
-        "timeout": 240
-      }
-    },
-    "dart2js-hostasserts-(linux|mac|win)-(ia32|x64)-d8-unsound": {
-      "options": {
-        "host-checked": true,
         "timeout": 240,
         "dart2js-options": [
           "--no-sound-null-safety"
@@ -2963,13 +2922,6 @@
           ]
         },
         {
-          "name": "dart2js observatory-ui tests",
-          "arguments": [
-            "-ndart2js-hostasserts-linux-ia32-d8-unsound",
-            "observatory_ui"
-          ]
-        },
-        {
           "name": "dart2js extra tests",
           "arguments": [
             "-ndart2js-hostasserts-linux-ia32-d8",
@@ -3029,14 +2981,6 @@
           ]
         },
         {
-          "name": "dart2js observatory-ui tests",
-          "arguments": [
-            "-ndart2js-${system}-${runtime}-unsound",
-            "--reset-browser-configuration",
-            "observatory_ui"
-          ]
-        },
-        {
           "name": "dart2js extra tests",
           "arguments": [
             "-ndart2js-${system}-${runtime}",
@@ -3078,13 +3022,6 @@
           ]
         },
         {
-          "name": "dart2js observatory-ui tests",
-          "arguments": [
-            "-ndart2js-minified-linux-d8-unsound",
-            "observatory_ui"
-          ]
-        },
-        {
           "name": "dart2js extra tests",
           "arguments": [
             "-ndart2js-minified-linux-d8",
@@ -3161,7 +3098,7 @@
         {
           "name": "dart2js observatory-ui tests",
           "arguments": [
-            "-ndart2js-minified-csp-linux-chrome-unsound",
+            "-ndart2js-minified-csp-linux-chrome",
             "--reset-browser-configuration",
             "observatory_ui"
           ]
diff --git a/utils/compiler/BUILD.gn b/utils/compiler/BUILD.gn
index a9e7449..5d93b26 100644
--- a/utils/compiler/BUILD.gn
+++ b/utils/compiler/BUILD.gn
@@ -70,6 +70,9 @@
     # Specifying the platform explicitly elides running the CFE on the sdk
     # sources.
     "--platform-binaries=" + rebase_path("$root_out_dir/"),
+
+    # TODO(48820): remove once dart2js is migrated.
+    "--no-sound-null-safety",
     rebase_path("../../pkg/compiler/lib/src/util/memory_compiler.dart"),
   ]
 }