Unverified Commit b1d75fc9 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

[flutter_tools] add flag for sound-null-safety, unify with experiments (#58533)

Also combines experiments into extraGenSnapshot/ExtraFrontEndOptions. Allows providing --no-sound-null-safety to allow out of order migration and running.
parent 95edf281
......@@ -340,8 +340,7 @@ Future<void> _runToolTests() async {
/// target app.
Future<void> _runBuildTests() async {
final List<FileSystemEntity> exampleDirectories = Directory(path.join(flutterRoot, 'examples')).listSync()
// TODO(jonahwilliams): re-enable once https://github.com/flutter/flutter/issues/57234 is done.
// ..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable')))
..add(Directory(path.join(flutterRoot, 'dev', 'integration_tests', 'flutter_gallery')));
final String branch = Platform.environment['CIRRUS_BRANCH'];
......@@ -377,7 +376,7 @@ Future<void> _runExampleProjectBuildTests(FileSystemEntity exampleDirectory) asy
final String examplePath = exampleDirectory.path;
final bool hasNullSafety = File(path.join(examplePath, 'null_safety')).existsSync();
final List<String> additionalArgs = hasNullSafety
? <String>['--enable-experiment', 'non-nullable']
? <String>['--enable-experiment', 'non-nullable', '--no-sound-null-safety']
: <String>[];
if (Directory(path.join(examplePath, 'android')).existsSync()) {
await _flutterBuildApk(examplePath, release: false, additionalArgs: additionalArgs, verifyCaching: verifyCaching);
......@@ -603,10 +602,9 @@ Future<void> _runFrameworkTests() async {
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_localizations'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'flutter_test'), tableData: bigqueryApi?.tabledata);
await _runFlutterTest(path.join(flutterRoot, 'packages', 'fuchsia_remote_debug_protocol'), tableData: bigqueryApi?.tabledata);
// TODO(jonahwilliams): re-enable once https://github.com/flutter/flutter/issues/57234 is done.
// await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'),
// options: <String>['--enable-experiment=non-nullable'],
// );
await _runFlutterTest(path.join(flutterRoot, 'dev', 'integration_tests', 'non_nullable'),
options: <String>['--enable-experiment=non-nullable', '--no-sound-null-safety'],
);
await _runFlutterTest(
path.join(flutterRoot, 'dev', 'tracing_tests'),
options: <String>['--enable-vmservice'],
......@@ -756,8 +754,7 @@ Future<void> _runWebIntegrationTests() async {
await _runWebDebugTest('lib/stack_trace.dart');
await _runWebDebugTest('lib/web_directory_loading.dart');
await _runWebDebugTest('test/test.dart');
// TODO(jonahwilliams): re-enable once https://github.com/flutter/flutter/issues/57234 is done.
// await _runWebDebugTest('lib/null_safe_main.dart', enableNullSafety: true);
await _runWebDebugTest('lib/null_safe_main.dart', enableNullSafety: true);
await _runWebDebugTest('lib/web_define_loading.dart',
additionalArguments: <String>[
'--dart-define=test.valueA=Example',
......@@ -875,6 +872,7 @@ Future<void> _runWebDebugTest(String target, {
...<String>[
'--enable-experiment',
'non-nullable',
'--no-sound-null-safety'
],
'-d',
'chrome',
......
......@@ -155,7 +155,7 @@ Future<void> run(List<String> args) async {
concurrency: math.max(1, globals.platform.numberOfProcessors - 2),
icudtlPath: globals.fs.path.absolute(argResults[_kOptionIcudtl] as String),
coverageDirectory: coverageDirectory,
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
);
if (collector != null) {
......
......@@ -82,7 +82,7 @@ RunCommand "${FLUTTER_ROOT}/bin/flutter" \
-dTrackWidgetCreation="${TRACK_WIDGET_CREATION}" \
--DartDefines="${DART_DEFINES}" \
--ExtraGenSnapshotOptions="${EXTRA_GEN_SNAPSHOT_OPTIONS}" \
-dExtraFrontEndOptions="${EXTRA_FRONT_END_OPTIONS}" \
--ExtraFrontEndOptions="${EXTRA_FRONT_END_OPTIONS}" \
--build-inputs="${build_inputs_path}" \
--build-outputs="${build_outputs_path}" \
--output="${ephemeral_dir}" \
......
......@@ -69,7 +69,7 @@ or
if (extraGenSnapshotOptions != null)
'--ExtraGenSnapshotOptions=$extraGenSnapshotOptions',
if (extraFrontEndOptions != null)
'-dExtraFrontEndOptions=$extraFrontEndOptions',
'--ExtraFrontEndOptions=$extraFrontEndOptions',
target,
],
);
......
......@@ -168,7 +168,7 @@ is set to release or run \"flutter build ios --release\", then re-run Archive fr
-dEnableBitcode="${bitcode_flag}" \
--ExtraGenSnapshotOptions="${EXTRA_GEN_SNAPSHOT_OPTIONS}" \
--DartDefines="${DART_DEFINES}" \
-dExtraFrontEndOptions="${EXTRA_FRONT_END_OPTIONS}" \
--ExtraFrontEndOptions="${EXTRA_FRONT_END_OPTIONS}" \
"${build_mode}_ios_bundle_flutter_assets"
if [[ $? -ne 0 ]]; then
......
......@@ -919,9 +919,6 @@ abstract class BaseFlutterTask extends DefaultTask {
}
args "-dTargetPlatform=android"
args "-dBuildMode=${buildMode}"
if (extraFrontEndOptions != null) {
args "-dExtraFrontEndOptions=${extraFrontEndOptions}"
}
if (trackWidgetCreation != null) {
args "-dTrackWidgetCreation=${trackWidgetCreation}"
}
......@@ -943,6 +940,9 @@ abstract class BaseFlutterTask extends DefaultTask {
if (extraGenSnapshotOptions != null) {
args "--ExtraGenSnapshotOptions=${extraGenSnapshotOptions}"
}
if (extraFrontEndOptions != null) {
args "--ExtraFrontEndOptions=${extraFrontEndOptions}"
}
args ruleNames
}
}
......
......@@ -310,10 +310,10 @@ Future<void> buildGradleApp({
command.add('-Ptrack-widget-creation=${buildInfo.trackWidgetCreation}');
if (buildInfo.extraFrontEndOptions != null) {
command.add('-Pextra-front-end-options=${buildInfo.extraFrontEndOptions.join(',')}');
command.add('-Pextra-front-end-options=${encodeDartDefines(buildInfo.extraFrontEndOptions)}');
}
if (buildInfo.extraGenSnapshotOptions != null) {
command.add('-Pextra-gen-snapshot-options=${buildInfo.extraGenSnapshotOptions.join(',')}');
command.add('-Pextra-gen-snapshot-options=${encodeDartDefines(buildInfo.extraGenSnapshotOptions)}');
}
if (buildInfo.fileSystemRoots != null && buildInfo.fileSystemRoots.isNotEmpty) {
command.add('-Pfilesystem-roots=${buildInfo.fileSystemRoots.join('|')}');
......
......@@ -143,9 +143,9 @@ class BuildInfo {
if (dartObfuscation != null)
'DART_OBFUSCATION': dartObfuscation.toString(),
if (extraFrontEndOptions?.isNotEmpty ?? false)
'EXTRA_FRONT_END_OPTIONS': extraFrontEndOptions.join(','),
'EXTRA_FRONT_END_OPTIONS': encodeDartDefines(extraFrontEndOptions),
if (extraGenSnapshotOptions?.isNotEmpty ?? false)
'EXTRA_GEN_SNAPSHOT_OPTIONS': extraGenSnapshotOptions.join(','),
'EXTRA_GEN_SNAPSHOT_OPTIONS': encodeDartDefines(extraGenSnapshotOptions),
if (splitDebugInfoPath != null)
'SPLIT_DEBUG_INFO': splitDebugInfoPath,
if (trackWidgetCreation != null)
......@@ -667,11 +667,11 @@ String encodeDartDefines(List<String> defines) {
}
/// Dart defines are encoded inside [environmentDefines] as a comma-separated list.
List<String> decodeDartDefines(Map<String, String> environmentDefines) {
if (!environmentDefines.containsKey(kDartDefines) || environmentDefines[kDartDefines].isEmpty) {
List<String> decodeDartDefines(Map<String, String> environmentDefines, String key) {
if (!environmentDefines.containsKey(key) || environmentDefines[key].isEmpty) {
return const <String>[];
}
return environmentDefines[kDartDefines]
return environmentDefines[key]
.split(',')
.map<Object>(Uri.decodeComponent)
.cast<String>()
......
......@@ -441,7 +441,6 @@ class _ResidentWebRunner extends ResidentWebRunner {
debuggingOptions.buildInfo,
debuggingOptions.initializePlatform,
false,
debuggingOptions.buildInfo.dartExperiments,
);
}
await device.device.startApp(
......@@ -504,7 +503,6 @@ class _ResidentWebRunner extends ResidentWebRunner {
debuggingOptions.buildInfo,
debuggingOptions.initializePlatform,
false,
debuggingOptions.buildInfo.dartExperiments,
);
} on ToolExit {
return OperationResult(1, 'Failed to recompile application.');
......
......@@ -246,8 +246,7 @@ class AndroidAot extends AotElfBase {
if (!output.existsSync()) {
output.createSync(recursive: true);
}
final List<String> extraGenSnapshotOptions = environment.defines[kExtraGenSnapshotOptions]?.split(',')
?? const <String>[];
final List<String> extraGenSnapshotOptions = decodeDartDefines(environment.defines, kExtraGenSnapshotOptions);
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final int snapshotExitCode = await snapshotter.build(
......
......@@ -205,10 +205,7 @@ class KernelSnapshot extends Target {
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
// This configuration is all optional.
final String rawFrontEndOption = environment.defines[kExtraFrontEndOptions];
final List<String> extraFrontEndOptions = (rawFrontEndOption?.isNotEmpty ?? false)
? rawFrontEndOption?.split(',')
: null;
final List<String> extraFrontEndOptions = decodeDartDefines(environment.defines, kExtraFrontEndOptions);
final List<String> fileSystemRoots = environment.defines[kFileSystemRoots]?.split(',');
final String fileSystemScheme = environment.defines[kFileSystemScheme];
......@@ -254,7 +251,7 @@ class KernelSnapshot extends Target {
extraFrontEndOptions: extraFrontEndOptions,
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
dartDefines: decodeDartDefines(environment.defines),
dartDefines: decodeDartDefines(environment.defines, kDartDefines),
packageConfig: packageConfig,
);
if (output == null || output.errorCount != 0) {
......@@ -287,8 +284,7 @@ abstract class AotElfBase extends Target {
if (environment.defines[kTargetPlatform] == null) {
throw MissingDefineException(kTargetPlatform, 'aot_elf');
}
final List<String> extraGenSnapshotOptions = environment.defines[kExtraGenSnapshotOptions]?.split(',')
?? const <String>[];
final List<String> extraGenSnapshotOptions = decodeDartDefines(environment.defines, kExtraGenSnapshotOptions);
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
final String splitDebugInfo = environment.defines[kSplitDebugInfo];
......
......@@ -46,7 +46,7 @@ abstract class AotAssemblyBase extends Target {
if (environment.defines[kTargetPlatform] == null) {
throw MissingDefineException(kTargetPlatform, 'aot_assembly');
}
final List<String> extraGenSnapshotOptions = parseExtraGenSnapshotOptions(environment);
final List<String> extraGenSnapshotOptions = decodeDartDefines(environment.defines, kExtraGenSnapshotOptions);
final bool bitcode = environment.defines[kBitcodeFlag] == 'true';
final BuildMode buildMode = getBuildModeForName(environment.defines[kBuildMode]);
final TargetPlatform targetPlatform = getTargetPlatformForName(environment.defines[kTargetPlatform]);
......@@ -447,13 +447,3 @@ Future<RunResult> createStubAppFramework(File outputFile, SdkType sdk, { bool in
}
}
}
/// iOS and macOS build scripts may pass extraGenSnapshotOptions as an empty
/// string.
List<String> parseExtraGenSnapshotOptions(Environment environment) {
final String value = environment.defines[kExtraGenSnapshotOptions];
if (value == null || value.trim().isEmpty) {
return <String>[];
}
return value.split(',');
}
......@@ -15,7 +15,6 @@ import '../exceptions.dart';
import 'assets.dart';
import 'dart.dart';
import 'icon_tree_shaker.dart';
import 'ios.dart';
/// Copy the macOS framework to the correct copy dir by invoking 'cp -R'.
///
......@@ -198,7 +197,7 @@ class CompileMacOSFramework extends Target {
}
final String splitDebugInfo = environment.defines[kSplitDebugInfo];
final bool dartObfuscation = environment.defines[kDartObfuscation] == 'true';
final List<String> extraGenSnapshotOptions = parseExtraGenSnapshotOptions(environment);
final List<String> extraGenSnapshotOptions = decodeDartDefines(environment.defines, kExtraGenSnapshotOptions);
final AOTSnapshotter snapshotter = AOTSnapshotter(
reportTimings: false,
fileSystem: globals.fs,
......
......@@ -28,11 +28,6 @@ const String kHasWebPlugins = 'HasWebPlugins';
/// Valid values are O1 (lowest, profile default) to O4 (highest, release default).
const String kDart2jsOptimization = 'Dart2jsOptimization';
/// Allow specifying experiments for dart2js.
///
/// Multiple values should be encoded as a comma-separated list.
const String kEnableExperiment = 'EnableExperiment';
/// Whether to disable dynamic generation code to satisfy csp policies.
const String kCspMode = 'cspMode';
......@@ -164,8 +159,8 @@ class Dart2JSTarget extends Target {
final String packageFile = globalPackagesPath;
final File outputKernel = environment.buildDir.childFile('app.dill');
final File outputFile = environment.buildDir.childFile('main.dart.js');
final List<String> dartDefines = decodeDartDefines(environment.defines);
final String enabledExperiments = environment.defines[kEnableExperiment];
final List<String> dartDefines = decodeDartDefines(environment.defines, kDartDefines);
final List<String> extraFrontEndOptions = decodeDartDefines(environment.defines, kExtraFrontEndOptions);
// Run the dart2js compilation in two stages, so that icon tree shaking can
// parse the kernel file for web builds.
......@@ -173,8 +168,7 @@ class Dart2JSTarget extends Target {
globals.artifacts.getArtifactPath(Artifact.engineDartBinary),
globals.artifacts.getArtifactPath(Artifact.dart2jsSnapshot),
'--libraries-spec=$specPath',
if (enabledExperiments != null)
'--enable-experiment=$enabledExperiments',
...?extraFrontEndOptions,
'-o',
outputKernel.path,
'--packages=$packageFile',
......@@ -194,8 +188,7 @@ class Dart2JSTarget extends Target {
globals.artifacts.getArtifactPath(Artifact.engineDartBinary),
globals.artifacts.getArtifactPath(Artifact.dart2jsSnapshot),
'--libraries-spec=$specPath',
if (enabledExperiments != null)
'--enable-experiment=$enabledExperiments',
...?extraFrontEndOptions,
if (dart2jsOptimization != null)
'-$dart2jsOptimization'
else
......
......@@ -105,6 +105,7 @@ class AssembleCommand extends FlutterCommand {
'root of the current Flutter project.',
);
argParser.addOption(kExtraGenSnapshotOptions);
argParser.addOption(kExtraFrontEndOptions);
argParser.addOption(kDartDefines);
argParser.addOption(
'resource-pool-size',
......@@ -204,10 +205,12 @@ class AssembleCommand extends FlutterCommand {
if (argResults.wasParsed(kExtraGenSnapshotOptions)) {
results[kExtraGenSnapshotOptions] = argResults[kExtraGenSnapshotOptions] as String;
}
// Workaround for dart-define formatting
if (argResults.wasParsed(kDartDefines)) {
results[kDartDefines] = argResults[kDartDefines] as String;
}
if (argResults.wasParsed(kExtraFrontEndOptions)) {
results[kExtraFrontEndOptions] = argResults[kExtraFrontEndOptions] as String;
}
return results;
}
......
......@@ -41,6 +41,7 @@ class BuildAarCommand extends BuildSubCommand {
addSplitDebugInfoOption();
addDartObfuscationOption();
usesTrackWidgetCreation(verboseHelp: false);
addNullSafetyModeOptions();
argParser
..addMultiOption(
'target-platform',
......
......@@ -33,6 +33,7 @@ class BuildApkCommand extends BuildSubCommand {
addBundleSkSLPathOption(hide: !verboseHelp);
addEnableExperimentation(hide: !verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
addNullSafetyModeOptions();
argParser
..addFlag('split-per-abi',
negatable: false,
......
......@@ -21,6 +21,7 @@ class BuildFuchsiaCommand extends BuildSubCommand {
usesTargetOption();
usesDartDefineOption();
addBuildModeFlags(verboseHelp: verboseHelp);
addNullSafetyModeOptions();
argParser.addOption(
'runner-source',
help: 'The package source to use for the flutter_runner. '
......
......@@ -33,6 +33,7 @@ class BuildIOSCommand extends BuildSubCommand {
usesExtraFrontendOptions();
addEnableExperimentation(hide: !verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
addNullSafetyModeOptions();
argParser
..addFlag('simulator',
help: 'Build for the iOS simulator instead of the device. This changes '
......
......@@ -28,6 +28,7 @@ class BuildLinuxCommand extends BuildSubCommand {
addEnableExperimentation(hide: !verboseHelp);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
addNullSafetyModeOptions();
}
@override
......
......@@ -29,6 +29,7 @@ class BuildMacosCommand extends BuildSubCommand {
usesBuildNameOption();
addEnableExperimentation(hide: !verboseHelp);
addBuildPerformanceFile(hide: !verboseHelp);
addNullSafetyModeOptions();
}
@override
......
......@@ -11,7 +11,7 @@ import '../build_info.dart';
import '../features.dart';
import '../project.dart';
import '../runner/flutter_command.dart'
show DevelopmentArtifact, FlutterCommandResult, FlutterOptions;
show DevelopmentArtifact, FlutterCommandResult;
import '../web/compile.dart';
import 'build.dart';
......@@ -25,6 +25,7 @@ class BuildWebCommand extends BuildSubCommand {
addBuildModeFlags(excludeDebug: true);
usesDartDefineOption();
addEnableExperimentation(hide: !verboseHelp);
addNullSafetyModeOptions();
argParser.addFlag('web-initialize-platform',
defaultsTo: true,
negatable: true,
......@@ -71,7 +72,6 @@ class BuildWebCommand extends BuildSubCommand {
buildInfo,
boolArg('web-initialize-platform'),
boolArg('csp'),
stringsArg(FlutterOptions.kEnableExperiment),
);
return FlutterCommandResult.success();
}
......
......@@ -66,6 +66,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
usesPubOption();
usesTrackWidgetCreation(verboseHelp: verboseHelp);
usesIsolateFilterOption(hide: !verboseHelp);
addNullSafetyModeOptions();
}
bool get traceStartup => boolArg('trace-startup');
......
......@@ -31,6 +31,9 @@ class TestCommand extends FlutterCommand {
}) : assert(testWrapper != null) {
requiresPubspecYaml();
usesPubOption();
addNullSafetyModeOptions();
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addEnableExperimentation(hide: !verboseHelp);
argParser
..addMultiOption('name',
help: 'A regular expression matching substrings of the names of tests to run.',
......@@ -128,8 +131,6 @@ class TestCommand extends FlutterCommand {
'This flag is ignored if --start-paused or coverage are requested. '
'The vmservice will be enabled no matter what in those cases.'
);
usesTrackWidgetCreation(verboseHelp: verboseHelp);
addEnableExperimentation(hide: !verboseHelp);
}
/// The interface for starting and configuring the tester.
......@@ -172,7 +173,6 @@ class TestCommand extends FlutterCommand {
final String tags = stringArg('tags');
final String excludeTags = stringArg('exclude-tags');
final FlutterProject flutterProject = FlutterProject.current();
final List<String> dartExperiments = stringsArg(FlutterOptions.kEnableExperiment);
if (buildTestAssets && flutterProject.manifest.assets.isNotEmpty) {
await _buildTestAsset();
......@@ -278,7 +278,7 @@ class TestCommand extends FlutterCommand {
flutterProject: flutterProject,
web: stringArg('platform') == 'chrome',
randomSeed: stringArg('test-randomize-ordering-seed'),
dartExperiments: dartExperiments,
extraFrontEndOptions: getBuildInfo(forcedBuildMode: BuildMode.debug).extraFrontEndOptions,
);
if (collector != null) {
......
......@@ -269,7 +269,14 @@ class KernelCompiler {
'--platform',
platformDill,
],
...?extraFrontEndOptions,
if (extraFrontEndOptions != null)
for (String arg in extraFrontEndOptions)
if (arg == '--sound-null-safety')
'--null-safety'
else if (arg == '--no-sound-null-safety')
'--no-null-safety'
else
arg,
mainUri?.toString() ?? mainPath,
];
......@@ -398,7 +405,7 @@ abstract class ResidentCompiler {
String initializeFromDill,
TargetModel targetModel,
bool unsafePackageSerialization,
List<String> experimentalFlags,
List<String> extraFrontEndOptions,
String platformDill,
List<String> dartDefines,
String librariesSpec,
......@@ -494,7 +501,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
this.initializeFromDill,
this.targetModel = TargetModel.flutter,
this.unsafePackageSerialization,
this.experimentalFlags,
this.extraFrontEndOptions,
this.platformDill,
List<String> dartDefines,
this.librariesSpec,
......@@ -512,7 +519,7 @@ class DefaultResidentCompiler implements ResidentCompiler {
final String fileSystemScheme;
final String initializeFromDill;
final bool unsafePackageSerialization;
final List<String> experimentalFlags;
final List<String> extraFrontEndOptions;
final List<String> dartDefines;
final String librariesSpec;
......@@ -660,8 +667,14 @@ class DefaultResidentCompiler implements ResidentCompiler {
platformDill,
],
if (unsafePackageSerialization == true) '--unsafe-package-serialization',
if ((experimentalFlags != null) && experimentalFlags.isNotEmpty)
'--enable-experiment=${experimentalFlags.join(',')}',
if (extraFrontEndOptions != null)
for (String arg in extraFrontEndOptions)
if (arg == '--sound-null-safety')
'--null-safety'
else if (arg == '--no-sound-null-safety')
'--no-null-safety'
else
arg,
];
globals.printTrace(command.join(' '));
_server = await globals.processManager.start(command);
......
......@@ -47,7 +47,6 @@ class FlutterDevice {
this.viewFilter,
TargetModel targetModel = TargetModel.flutter,
TargetPlatform targetPlatform,
List<String> experimentalFlags,
ResidentCompiler generator,
}) : assert(buildInfo.trackWidgetCreation != null),
generator = generator ?? ResidentCompiler(
......@@ -61,9 +60,9 @@ class FlutterDevice {
fileSystemRoots: fileSystemRoots ?? <String>[],
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
dartDefines: buildInfo.dartDefines,
packagesPath: globalPackagesPath,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
);
/// Create a [FlutterDevice] with optional code generation enabled.
......@@ -106,7 +105,7 @@ class FlutterDevice {
trackWidgetCreation: buildInfo.trackWidgetCreation,
),
targetModel: TargetModel.dartdevc,
experimentalFlags: experimentalFlags,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
platformDill: globals.fs.file(globals.artifacts
.getArtifactPath(Artifact.webPlatformKernelDill, mode: buildInfo.mode))
.absolute.uri.toString(),
......@@ -127,8 +126,8 @@ class FlutterDevice {
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
targetModel: targetModel,
experimentalFlags: experimentalFlags,
dartDefines: buildInfo.dartDefines,
extraFrontEndOptions: buildInfo.extraFrontEndOptions,
initializeFromDill: getDefaultCachedKernelPath(
trackWidgetCreation: buildInfo.trackWidgetCreation,
),
......@@ -148,7 +147,6 @@ class FlutterDevice {
fileSystemRoots: fileSystemRoots,
fileSystemScheme:fileSystemScheme,
viewFilter: viewFilter,
experimentalFlags: experimentalFlags,
targetModel: targetModel,
targetPlatform: targetPlatform,
generator: generator,
......
......@@ -109,6 +109,7 @@ class FlutterOptions {
static const String kDartDefinesOption = 'dart-define';
static const String kBundleSkSLPathOption = 'bundle-sksl-path';
static const String kPerformanceMeasurementFile = 'performance-measurement-file';
static const String kNullSafety = 'sound-null-safety';
}
abstract class FlutterCommand extends Command<void> {
......@@ -460,6 +461,14 @@ abstract class FlutterCommand extends Command<void> {
);
}
void addNullSafetyModeOptions() {
argParser.addFlag(FlutterOptions.kNullSafety,
help: 'Whether to override the default null safety setting.',
defaultsTo: null,
hide: true,
);
}
void usesExtraFrontendOptions() {
argParser.addMultiOption(FlutterOptions.kExtraFrontEndOptions,
splitCommas: true,
......@@ -572,15 +581,15 @@ abstract class FlutterCommand extends Command<void> {
final List<String> experiments =
argParser.options.containsKey(FlutterOptions.kEnableExperiment)
? stringsArg(FlutterOptions.kEnableExperiment)
? stringsArg(FlutterOptions.kEnableExperiment).toList()
: <String>[];
final List<String> extraGenSnapshotOptions =
argParser.options.containsKey(FlutterOptions.kExtraGenSnapshotOptions)
? stringsArg(FlutterOptions.kExtraGenSnapshotOptions)
? stringsArg(FlutterOptions.kExtraGenSnapshotOptions).toList()
: <String>[];
final List<String> extraFrontEndOptions =
argParser.options.containsKey(FlutterOptions.kExtraFrontEndOptions)
? stringsArg(FlutterOptions.kExtraFrontEndOptions)
? stringsArg(FlutterOptions.kExtraFrontEndOptions).toList()
: <String>[];
if (experiments.isNotEmpty) {
......@@ -591,6 +600,18 @@ abstract class FlutterCommand extends Command<void> {
}
}
if (argParser.options.containsKey(FlutterOptions.kNullSafety)) {
final bool nullSafety = boolArg(FlutterOptions.kNullSafety);
// Explicitly check for `true` and `false` so that `null` results in not
// passing a flag. This will use the automatically detected null-safety
// value based on the entrypoint
if (nullSafety == true) {
extraFrontEndOptions.add('--sound-null-safety');
} else if (nullSafety == false) {
extraFrontEndOptions.add('--no-sound-null-safety');
}
}
final bool dartObfuscation = argParser.options.containsKey(FlutterOptions.kDartObfuscationOption)
&& boolArg(FlutterOptions.kDartObfuscationOption);
......
......@@ -88,7 +88,7 @@ FlutterPlatform installHook({
FlutterProject flutterProject,
String icudtlPath,
PlatformPluginRegistration platformPluginRegistration,
@required List<String> dartExperiments,
@required List<String> extraFrontEndOptions,
}) {
assert(testWrapper != null);
assert(enableObservatory || (!startPaused && observatoryPort == null));
......@@ -121,7 +121,7 @@ FlutterPlatform installHook({
projectRootDirectory: projectRootDirectory,
flutterProject: flutterProject,
icudtlPath: icudtlPath,
dartExperiments: dartExperiments,
extraFrontEndOptions: extraFrontEndOptions,
);
platformPluginRegistration(platform);
return platform;
......@@ -269,7 +269,7 @@ class FlutterPlatform extends PlatformPlugin {
this.projectRootDirectory,
this.flutterProject,
this.icudtlPath,
@required this.dartExperiments,
@required this.extraFrontEndOptions,
}) : assert(shellPath != null);
final String shellPath;
......@@ -290,7 +290,7 @@ class FlutterPlatform extends PlatformPlugin {
final Uri projectRootDirectory;
final FlutterProject flutterProject;
final String icudtlPath;
final List<String> dartExperiments;
final List<String> extraFrontEndOptions;
Directory fontsDirectory;
......@@ -459,7 +459,7 @@ class FlutterPlatform extends PlatformPlugin {
if (precompiledDillPath == null && precompiledDillFiles == null) {
// Lazily instantiate compiler so it is built only if it is actually used.
compiler ??= TestCompiler(buildMode, trackWidgetCreation, flutterProject, dartExperiments);
compiler ??= TestCompiler(buildMode, trackWidgetCreation, flutterProject, extraFrontEndOptions);
mainDart = await compiler.compile(globals.fs.file(mainDart).uri);
if (mainDart == null) {
......@@ -751,7 +751,7 @@ class FlutterPlatform extends PlatformPlugin {
testConfigFile: findTestConfigFile(globals.fs.file(testUrl)),
host: host,
updateGoldens: updateGoldens,
nullSafety: dartExperiments.contains('non-nullable'),
nullSafety: extraFrontEndOptions?.contains('--enable-experiment=non-nullable') ?? false,
);
}
......
......@@ -51,7 +51,7 @@ abstract class FlutterTestRunner {
Directory coverageDirectory,
bool web = false,
String randomSeed,
@required List<String> dartExperiments,
@required List<String> extraFrontEndOptions,
});
}
......@@ -85,7 +85,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
Directory coverageDirectory,
bool web = false,
String randomSeed,
@required List<String> dartExperiments,
@required List<String> extraFrontEndOptions,
}) async {
// Configure package:test to use the Flutter engine for child processes.
final String shellPath = globals.artifacts.getArtifactPath(Artifact.flutterTester);
......@@ -177,7 +177,7 @@ class _FlutterTestRunnerImpl implements FlutterTestRunner {
projectRootDirectory: globals.fs.currentDirectory.uri,
flutterProject: flutterProject,
icudtlPath: icudtlPath,
dartExperiments: dartExperiments,
extraFrontEndOptions: extraFrontEndOptions,
);
// Make the global packages path absolute.
......
......@@ -42,7 +42,7 @@ class TestCompiler {
this.buildMode,
this.trackWidgetCreation,
this.flutterProject,
this.dartExperiments,
this.extraFrontEndOptions,
) : testFilePath = getKernelPathForTransformerOptions(
globals.fs.path.join(flutterProject.directory.path, getBuildDirectory(), 'testfile.dill'),
trackWidgetCreation: trackWidgetCreation,
......@@ -66,7 +66,7 @@ class TestCompiler {
final BuildMode buildMode;
final bool trackWidgetCreation;
final String testFilePath;
final List<String> dartExperiments;
final List<String> extraFrontEndOptions;
ResidentCompiler compiler;
......@@ -106,7 +106,7 @@ class TestCompiler {
unsafePackageSerialization: false,
dartDefines: const <String>[],
packagesPath: globalPackagesPath,
experimentalFlags: dartExperiments,
extraFrontEndOptions: extraFrontEndOptions,
);
if (flutterProject.hasBuilders) {
return CodeGeneratingResidentCompiler.create(
......
......@@ -28,7 +28,6 @@ Future<void> buildWeb(
BuildInfo buildInfo,
bool initializePlatform,
bool csp,
List<String> experiments,
) async {
if (!flutterProject.web.existsSync()) {
throwToolExit('Missing index.html.');
......@@ -53,8 +52,8 @@ Future<void> buildWeb(
kDartDefines: encodeDartDefines(buildInfo.dartDefines),
kCspMode: csp.toString(),
kIconTreeShakerFlag: buildInfo.treeShakeIcons.toString(),
if (experiments.isNotEmpty)
kEnableExperiment: experiments?.join(','),
if (buildInfo.extraFrontEndOptions?.isNotEmpty ?? false)
kExtraFrontEndOptions: buildInfo.extraFrontEndOptions.join(',')
},
artifacts: globals.artifacts,
fileSystem: globals.fs,
......
......@@ -356,8 +356,8 @@ void main() {
'set(PROJECT_DIR "${fileSystem.currentDirectory.path}")',
' "DART_DEFINES=\\"foo.bar%3D2,fizz.far%3D3\\""',
' "DART_OBFUSCATION=\\"true\\""',
' "EXTRA_FRONT_END_OPTIONS=\\"--enable-experiment=non-nullable\\""',
' "EXTRA_GEN_SNAPSHOT_OPTIONS=\\"--enable-experiment=non-nullable\\""',
' "EXTRA_FRONT_END_OPTIONS=\\"--enable-experiment%3Dnon-nullable\\""',
' "EXTRA_GEN_SNAPSHOT_OPTIONS=\\"--enable-experiment%3Dnon-nullable\\""',
' "SPLIT_DEBUG_INFO=\\"foo/\\""',
' "TRACK_WIDGET_CREATION=\\"true\\""',
' "TREE_SHAKE_ICONS=\\"true\\""',
......
......@@ -56,7 +56,6 @@ void main() {
BuildInfo.debug,
false,
false,
<String>[],
), throwsToolExit());
}, overrides: <Type, Generator>{
Platform: () => fakePlatform,
......
......@@ -291,8 +291,8 @@ void main() {
expect(props.findAllElements('FLUTTER_ROOT').first.text, flutterRoot);
expect(props.findAllElements('TRACK_WIDGET_CREATION').first.text, 'true');
expect(props.findAllElements('TREE_SHAKE_ICONS').first.text, 'true');
expect(props.findAllElements('EXTRA_GEN_SNAPSHOT_OPTIONS').first.text, '--enable-experiment=non-nullable');
expect(props.findAllElements('EXTRA_FRONT_END_OPTIONS').first.text, '--enable-experiment=non-nullable');
expect(props.findAllElements('EXTRA_GEN_SNAPSHOT_OPTIONS').first.text, '--enable-experiment%3Dnon-nullable');
expect(props.findAllElements('EXTRA_FRONT_END_OPTIONS').first.text, '--enable-experiment%3Dnon-nullable');
expect(props.findAllElements('DART_DEFINES').first.text, 'foo%3Da,bar%3Db');
expect(props.findAllElements('DART_OBFUSCATION').first.text, 'true');
expect(props.findAllElements('SPLIT_DEBUG_INFO').first.text, r'C:\foo\');
......
......@@ -184,7 +184,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner {
Directory coverageDirectory,
bool web = false,
String randomSeed,
@override List<String> dartExperiments,
@override List<String> extraFrontEndOptions,
}) async {
lastEnableObservatoryValue = enableObservatory;
return exitCode;
......
......@@ -113,8 +113,8 @@ void main() {
'DART_DEFINES': 'foo%3D2,bar%3D2',
'DART_OBFUSCATION': 'true',
'SPLIT_DEBUG_INFO': 'foo/',
'EXTRA_FRONT_END_OPTIONS': '--enable-experiment=non-nullable,bar',
'EXTRA_GEN_SNAPSHOT_OPTIONS': '--enable-experiment=non-nullable,fizz',
'EXTRA_FRONT_END_OPTIONS': '--enable-experiment%3Dnon-nullable,bar',
'EXTRA_GEN_SNAPSHOT_OPTIONS': '--enable-experiment%3Dnon-nullable,fizz',
});
});
......@@ -129,18 +129,18 @@ void main() {
testWithoutContext('decodeDartDefines decodes URI encoded dart defines', () {
expect(decodeDartDefines(<String, String>{
kDartDefines: '%22hello%22'
}), <String>['"hello"']);
}, kDartDefines), <String>['"hello"']);
expect(decodeDartDefines(<String, String>{
kDartDefines: 'https%3A%2F%2Fwww.google.com'
}), <String>['https://www.google.com']);
}, kDartDefines), <String>['https://www.google.com']);
expect(decodeDartDefines(<String, String>{
kDartDefines: '2%2C3%2C4,5'
}), <String>['2,3,4', '5']);
}, kDartDefines), <String>['2,3,4', '5']);
expect(decodeDartDefines(<String, String>{
kDartDefines: 'true,false,flase'
}), <String>['true', 'false', 'flase']);
}, kDartDefines), <String>['true', 'false', 'flase']);
expect(decodeDartDefines(<String, String>{
kDartDefines: '1232%2C456,2'
}), <String>['1232,456', '2']);
}, kDartDefines), <String>['1232,456', '2']);
});
}
......@@ -255,7 +255,7 @@ void main() {
test('Dart2JSTarget calls dart2js with expected args with enabled experiment', () => testbed.run(() async {
environment.defines[kBuildMode] = 'profile';
environment.defines[kEnableExperiment] = 'non-nullable';
environment.defines[kExtraFrontEndOptions] = '--enable-experiment=non-nullable';
processManager.addCommand(FakeCommand(
command: <String>[
...kDart2jsLinuxArgs,
......
......@@ -22,7 +22,7 @@ void main() {
buildMode: BuildMode.debug,
shellPath: '/',
explicitObservatoryPort: 1234,
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
);
flutterPlatform.loadChannel('test1.dart', MockSuitePlatform());
......@@ -35,7 +35,7 @@ void main() {
buildMode: BuildMode.debug,
shellPath: '/',
precompiledDillPath: 'example.dill',
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
);
flutterPlatform.loadChannel('test1.dart', MockSuitePlatform());
......@@ -113,7 +113,7 @@ void main() {
shellPath: 'abc',
enableObservatory: false,
startPaused: true,
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
), throwsAssertionError);
expect(() => installHook(
......@@ -122,7 +122,7 @@ void main() {
enableObservatory: false,
startPaused: false,
observatoryPort: 123,
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
), throwsAssertionError);
FlutterPlatform capturedPlatform;
......@@ -143,7 +143,7 @@ void main() {
observatoryPort: 200,
serverType: InternetAddressType.IPv6,
icudtlPath: 'ghi',
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
platformPluginRegistration: (FlutterPlatform platform) {
capturedPlatform = platform;
});
......@@ -192,7 +192,7 @@ class TestFlutterPlatform extends FlutterPlatform {
startPaused: false,
enableObservatory: false,
buildTestAssets: false,
dartExperiments: <String>[],
extraFrontEndOptions: <String>[],
);
@override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment