diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index 27fa9b1c444..9e731aa5bf1 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart @@ -83,10 +83,8 @@ class FlutterDevice { required Platform platform, TargetModel targetModel = TargetModel.flutter, List? experimentalFlags, - ResidentCompiler? generator, String? userIdentifier, }) async { - ResidentCompiler generator; final TargetPlatform targetPlatform = await device.targetPlatform; if (device.platformType == PlatformType.fuchsia) { targetModel = TargetModel.flutterRunner; @@ -111,6 +109,8 @@ class FlutterDevice { fileSystem: globals.fs, ); + final ResidentCompiler generator; + // For both web and non-web platforms we initialize dill to/from // a shared location for faster bootstrapping. If the compiler fails // due to a kernel target or version mismatch, no error is reported @@ -119,7 +119,7 @@ class FlutterDevice { // used to file a bug, but the compiler will still start up correctly. if (targetPlatform == TargetPlatform.web_javascript) { // TODO(zanderso): consistently provide these flags across platforms. - late String platformDillName; + final String platformDillName; final List extraFrontEndOptions = List.of(buildInfo.extraFrontEndOptions); if (buildInfo.nullSafetyMode == NullSafetyMode.unsound) { platformDillName = 'ddc_outline.dill'; @@ -132,12 +132,12 @@ class FlutterDevice { extraFrontEndOptions.add('--sound-null-safety'); } } else { - assert(false); + throw StateError('Expected buildInfo.nullSafetyMode to be one of unsound or sound, got ${buildInfo.nullSafetyMode}'); } final String platformDillPath = globals.fs.path.join( getWebPlatformBinariesDirectory(globals.artifacts!, buildInfo.webRenderer).path, - platformDillName + platformDillName, ); generator = ResidentCompiler( diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 632baa289ba..d0a963c94f3 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1093,7 +1093,11 @@ abstract class FlutterCommand extends Command { (languageVersion.major == nullSafeVersion.major && languageVersion.minor >= nullSafeVersion.minor)) { nullSafetyMode = NullSafetyMode.sound; } else { - nullSafetyMode = NullSafetyMode.unsound; + throwToolExit( + 'This application does not support sound null-safety (its language version is $languageVersion).\n' + 'To build this application, you must provide the CLI flag --no-sound-null-safety. Dart 3 will only ' + 'support sound null safety, see https://dart.dev/null-safety.', + ); } } else if (!wasNullSafetyFlagParsed) { // This mode is only used for commands which do not build a single target like diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 779a31a9b75..4b3b729cb2c 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -554,6 +554,27 @@ void main() { ProcessManager: () => processManager, }); + testUsingContext('tool exits on non-sound-null-safe code when explicit flag not passed', () async { + final DummyFlutterCommand flutterCommand = DummyFlutterCommand(packagesPath: 'foo'); + flutterCommand.argParser + ..addFlag(FlutterOptions.kNullSafety, defaultsTo: true) + ..addOption('target'); + final File targetFile = fileSystem.file('targetFile.dart') + ..writeAsStringSync('// @dart = 2.11'); + expect( + () async => flutterCommand.getBuildInfo( + forcedBuildMode: BuildMode.debug, + forcedTargetFile: targetFile, + ), + throwsToolExit( + message: 'This application does not support sound null-safety (its language version is 2.11)', + ), + ); + }, overrides: { + FileSystem: () => fileSystem, + ProcessManager: () => processManager, + }); + testUsingContext('use packagesPath to generate BuildInfo', () async { final DummyFlutterCommand flutterCommand = DummyFlutterCommand(packagesPath: 'foo'); final BuildInfo buildInfo = await flutterCommand.getBuildInfo(forcedBuildMode: BuildMode.debug); diff --git a/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart b/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart index ce51fe469f1..902ce7974e7 100644 --- a/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart +++ b/packages/flutter_tools/test/integration.shard/test_data/stepping_project.dart @@ -65,7 +65,7 @@ class WebSteppingProject extends Project { final String pubspec = ''' name: test environment: - sdk: '>=2.10.0 <4.0.0' + sdk: '>=2.12.0 <4.0.0' dependencies: flutter: sdk: flutter