diff --git a/pkg/dev_compiler/tool/ddb b/pkg/dev_compiler/tool/ddb index 14bd9de9f250..824db4832692 100755 --- a/pkg/dev_compiler/tool/ddb +++ b/pkg/dev_compiler/tool/ddb @@ -47,6 +47,11 @@ void main(List args) async { 'DDC binary. Defaults to false.', defaultsTo: false, negatable: true) + ..addFlag('null-assertions', + help: 'Run with assertions that values passed to non-nullable method ' + 'parameters are not null.', + defaultsTo: false, + negatable: true) ..addFlag('observe', help: 'Run the compiler in the Dart VM with --observe. Implies --debug.', @@ -101,6 +106,7 @@ void main(List args) async { var compile = mode == 'compile' || mode == 'all'; var run = mode == 'run' || mode == 'all'; var verbose = options['verbose'] as bool; + var nonNullAsserts = options['null-assertions'] as bool; var soundNullSafety = options['sound-null-safety'] as bool; // Enable null safety either by passing the `non-nullable` experiment flag or @@ -272,6 +278,7 @@ void main(List args) async { if ($nnbd) { sdk.dart.nullSafety($soundNullSafety); sdk.dart.weakNullSafetyWarnings(!$soundNullSafety); + sdk.dart.nonNullAsserts($nonNullAsserts); } sdk._debugger.registerDevtoolsFormatter(); app.$libname.main(); @@ -305,6 +312,7 @@ try { if ($nnbd) { sdk.dart.nullSafety($soundNullSafety); sdk.dart.weakNullSafetyWarnings(!$soundNullSafety); + sdk.dart.nonNullAsserts($nonNullAsserts); } sdk._isolate_helper.startRootIsolate(main, []); } catch(e) { @@ -339,6 +347,7 @@ try { if ($nnbd) { dart.nullSafety($soundNullSafety); dart.weakNullSafetyWarnings(!$soundNullSafety); + sdk.dart.nonNullAsserts($nonNullAsserts); } _isolate_helper.startRootIsolate(() => {}, []); main(); diff --git a/pkg/test_runner/lib/src/browser.dart b/pkg/test_runner/lib/src/browser.dart index 9c8a16a8b263..e9d957a07b56 100644 --- a/pkg/test_runner/lib/src/browser.dart +++ b/pkg/test_runner/lib/src/browser.dart @@ -145,9 +145,11 @@ bool _invalidVariableName(String keyword, {bool strictMode = true}) { /// or extension, like "math_test". [testNameAlias] is the alias of the /// test variable used for import/export (usually relative to its module root). /// [testJSDir] is the relative path to the build directory where the -/// dartdevc-generated JS file is stored. +/// dartdevc-generated JS file is stored. [nonNullAsserts] enables non-null +/// assertions for non-nullable method parameters when running with weak null +/// safety. String dartdevcHtml(String testName, String testNameAlias, String testJSDir, - Compiler compiler, NnbdMode mode) { + Compiler compiler, NnbdMode mode, bool nonNullAsserts) { var testId = pathToJSIdentifier(testName); var testIdAlias = pathToJSIdentifier(testNameAlias); var isKernel = compiler == Compiler.dartdevk; @@ -234,6 +236,7 @@ requirejs(["$testName", "dart_sdk", "async_helper"], if ($isNnbd) { sdk.dart.nullSafety($isNnbdStrong); sdk.dart.weakNullSafetyWarnings(!$isNnbdStrong); + sdk.dart.nonNullAsserts($nonNullAsserts); } dartMainRunner(function testMainWrapper() { diff --git a/pkg/test_runner/lib/src/compiler_configuration.dart b/pkg/test_runner/lib/src/compiler_configuration.dart index 03ff44642844..02d7b2a056e6 100644 --- a/pkg/test_runner/lib/src/compiler_configuration.dart +++ b/pkg/test_runner/lib/src/compiler_configuration.dart @@ -419,8 +419,12 @@ class Dart2jsCompilerConfiguration extends Dart2xCompilerConfiguration { List computeCompilerArguments( TestFile testFile, List vmOptions, List args) { + // TODO(#42403) Handle this option if dart2js supports non-nullable asserts + // on non-nullable method arguments. + var options = testFile.sharedOptions.toList(); + options.remove('--null-assertions'); return [ - ...testFile.sharedOptions, + ...options, ..._configuration.sharedOptions, ..._experimentsArgument(_configuration, testFile), ...testFile.dart2jsOptions, @@ -510,6 +514,11 @@ class DevCompilerConfiguration extends CompilerConfiguration { Command _createCommand(String inputFile, String outputFile, List sharedOptions, Map environment) { var args = []; + // Remove option for generating non-null assertions for non-nullable + // method parameters in weak mode. DDC treats this as a runtime flag for + // the bootstrapping code, instead of a compiler option. + var options = sharedOptions.toList(); + options.remove('--null-assertions'); if (!_useSdk) { // If we're testing a built SDK, DDC will find its own summary. // @@ -524,7 +533,7 @@ class DevCompilerConfiguration extends CompilerConfiguration { .toNativePath(); args.addAll(["--dart-sdk-summary", sdkSummary]); } - args.addAll(sharedOptions); + args.addAll(options); args.addAll(_configuration.sharedOptions); args.addAll([ @@ -1179,8 +1188,12 @@ class FastaCompilerConfiguration extends CompilerConfiguration { @override List computeCompilerArguments( TestFile testFile, List vmOptions, List args) { + // Remove shared option for generating non-null assertions for non-nullable + // method parameters in weak mode. It's currently unused by the front end. + var options = testFile.sharedOptions.toList(); + options.remove('--null-assertions'); var arguments = [ - ...testFile.sharedOptions, + ...options, ..._configuration.sharedOptions, ..._experimentsArgument(_configuration, testFile), if (_configuration.configuration.nnbdMode == NnbdMode.strong) ...[ diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart index f1aa7b715d46..fe5f5d2a080f 100644 --- a/pkg/test_runner/lib/src/test_suite.dart +++ b/pkg/test_runner/lib/src/test_suite.dart @@ -810,8 +810,10 @@ class StandardTestSuite extends TestSuite { "${nameFromModuleRoot.directoryPath}/$nameNoExt"; var jsDir = Path(compilationTempDir).relativeTo(Repository.dir).toString(); + var nullAssertions = + testFile.sharedOptions.contains('--null-assertions'); content = dartdevcHtml(nameNoExt, nameFromModuleRootNoExt, jsDir, - configuration.compiler, configuration.nnbdMode); + configuration.compiler, configuration.nnbdMode, nullAssertions); } } diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart index ba418a468056..0a3c9a25350a 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart @@ -28,20 +28,19 @@ final _nullFailedSet = JS('!', 'new Set()'); // Run-time null safety assertion per: // https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#automatic-debug-assertion-insertion nullFailed(String? fileUri, int? line, int? column, String? variable) { - if (strictNullSafety) { + if (_nonNullAsserts) { throw AssertionErrorImpl( 'A null value was passed into a non-nullable parameter $variable', fileUri, line, column, '$variable != null'); - } else { - var key = '$fileUri:$line:$column'; - if (!JS('!', '#.has(#)', _nullFailedSet, key)) { - JS('', '#.add(#)', _nullFailedSet, key); - _nullWarn( - 'A null value was passed into a non-nullable parameter $variable'); - } + } + var key = '$fileUri:$line:$column'; + if (!JS('!', '#.has(#)', _nullFailedSet, key)) { + JS('', '#.add(#)', _nullFailedSet, key); + _nullWarn( + 'A null value was passed into a non-nullable parameter $variable'); } } diff --git a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart index a4bcaf833278..9a2b72f24680 100644 --- a/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart +++ b/sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/types.dart @@ -45,6 +45,18 @@ void weakNullSafetyWarnings(bool showWarnings) { _weakNullSafetyWarnings = showWarnings; } +@notNull +bool _nonNullAsserts = false; + +/// Sets the runtime mode to insert non-null assertions on non-nullable method +/// parameters. +/// +/// When [weakNullSafetyWarnings] is also `true` the assertions will fail +/// instead of printing a warning for the non-null parameters. +void nonNullAsserts(bool enable) { + _nonNullAsserts = enable; +} + final metadata = JS('', 'Symbol("metadata")'); /// Types in dart are represented internally at runtime as follows. diff --git a/tests/language/nnbd/null_assertions/parameter_checks_test.dart b/tests/language/nnbd/null_assertions/parameter_checks_test.dart index c6f9cc64aec8..d841cd44ff14 100644 --- a/tests/language/nnbd/null_assertions/parameter_checks_test.dart +++ b/tests/language/nnbd/null_assertions/parameter_checks_test.dart @@ -5,7 +5,8 @@ // Test for null assertions for parameters in NNBD weak mode. // Requirements=nnbd-weak -// VMOptions=--enable-asserts --null-assertions +// VMOptions=--enable-asserts +// SharedOptions=--null-assertions // Opt out of Null Safety: // @dart = 2.6