[dart2js] Add negatable flag for native null assertions

Allows build systems to turn off native null assertions if the
default value ever changes.

Change-Id: I7265b2328e4e8834d8bbe19159fcac7ea916b451
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/168763
Commit-Queue: Srujan Gaddam <srujzs@google.com>
Reviewed-by: Sigmund Cherem <sigmund@google.com>
diff --git a/pkg/compiler/lib/src/commandline_options.dart b/pkg/compiler/lib/src/commandline_options.dart
index 1c52968..b042613 100644
--- a/pkg/compiler/lib/src/commandline_options.dart
+++ b/pkg/compiler/lib/src/commandline_options.dart
@@ -23,7 +23,6 @@
   static const String enableCheckedMode = '--enable-checked-mode';
   static const String enableAsserts = '--enable-asserts';
   static const String enableNullAssertions = '--null-assertions';
-  static const String enableNativeNullAssertions = '--native-null-assertions';
   static const String enableDiagnosticColors = '--enable-diagnostic-colors';
   static const String experimentalTrackAllocations =
       '--experimental-track-allocations';
@@ -76,6 +75,10 @@
       '--no-frequency-based-minification';
   // Disables minification even if enabled by other options, e.g. '-O2'.
   static const String noMinify = '--no-minify';
+
+  static const String nativeNullAssertions = '--native-null-assertions';
+  static const String noNativeNullAssertions = '--no-native-null-assertions';
+
   static const String noSourceMaps = '--no-source-maps';
   static const String preserveUris = '--preserve-uris';
   static const String printLegacyStars = '--debug-print-legacy-stars';
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 3bd43ed..7142b49 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -444,7 +444,8 @@
         (_) => setCheckedMode(Flags.enableCheckedMode)),
     new OptionHandler(Flags.enableAsserts, passThrough),
     new OptionHandler(Flags.enableNullAssertions, passThrough),
-    new OptionHandler(Flags.enableNativeNullAssertions, passThrough),
+    new OptionHandler(Flags.nativeNullAssertions, passThrough),
+    new OptionHandler(Flags.noNativeNullAssertions, passThrough),
     new OptionHandler(Flags.trustTypeAnnotations, setTrustTypeAnnotations),
     new OptionHandler(Flags.trustPrimitives, passThrough),
     new OptionHandler(Flags.trustJSInteropTypeAnnotations, ignoreOption),
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index c0638c2..e999cd9 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -240,7 +240,8 @@
 
   /// Whether to generate code asserting that non-nullable return values of
   /// `@Native` methods or `JS()` invocations are checked for being non-null.
-  bool enableNativeNullAssertions = false;
+  bool nativeNullAssertions = false;
+  bool _noNativeNullAssertions = false;
 
   /// Whether to generate a source-map file together with the output program.
   bool generateSourceMap = true;
@@ -454,8 +455,9 @@
           _hasOption(options, Flags.enableAsserts)
       ..enableNullAssertions = _hasOption(options, Flags.enableCheckedMode) ||
           _hasOption(options, Flags.enableNullAssertions)
-      ..enableNativeNullAssertions =
-          _hasOption(options, Flags.enableNativeNullAssertions)
+      ..nativeNullAssertions = _hasOption(options, Flags.nativeNullAssertions)
+      .._noNativeNullAssertions =
+          _hasOption(options, Flags.noNativeNullAssertions)
       ..experimentalTrackAllocations =
           _hasOption(options, Flags.experimentalTrackAllocations)
       ..experimentalAllocationsPath = _extractStringOption(
@@ -534,6 +536,10 @@
       throw ArgumentError("'${Flags.soundNullSafety}' requires the "
           "'non-nullable' experiment to be enabled");
     }
+    if (nativeNullAssertions && _noNativeNullAssertions) {
+      throw ArgumentError("'${Flags.nativeNullAssertions}' incompatible with "
+          "'${Flags.noNativeNullAssertions}'");
+    }
   }
 
   void deriveOptions() {
@@ -592,6 +598,8 @@
     if (_disableMinification) {
       enableMinification = false;
     }
+
+    if (_noNativeNullAssertions) nativeNullAssertions = false;
   }
 
   /// Returns `true` if warnings and hints are shown for all packages.
diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart
index aa1ea95..3e327fb 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1545,7 +1545,7 @@
           sourceInformation: null));
       HInstruction value = pop();
       // TODO(johnniwinther): Provide source information.
-      if (options.enableNativeNullAssertions) {
+      if (options.nativeNullAssertions) {
         if (_isNonNullableByDefault(functionNode)) {
           DartType type = _getDartTypeIfValid(functionNode.returnType);
           if (dartTypes.isNonNullableIfSound(type) &&
@@ -4800,7 +4800,7 @@
   /// If [invocation] is a `JS()` invocation in a web library and the static
   /// type is non-nullable, add a check to make sure it isn't null.
   void _maybeAddNullCheckOnJS(ir.StaticInvocation invocation) {
-    if (options.enableNativeNullAssertions &&
+    if (options.nativeNullAssertions &&
         nodeIsInWebLibrary(invocation) &&
         closedWorld.dartTypes
             .isNonNullableIfSound(_getStaticType(invocation).type)) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 6011731..aff9860 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -926,7 +926,7 @@
 
   HInstruction maybeAddNativeReturnNullCheck(
       HInstruction node, HInstruction replacement, FunctionEntity method) {
-    if (_options.enableNativeNullAssertions) {
+    if (_options.nativeNullAssertions) {
       if (method.library.isNonNullableByDefault) {
         FunctionType type =
             _closedWorld.elementEnvironment.getFunctionType(method);
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
index 85521eb..7ed8c58 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// dart2jsOptions=--no-native-null-assertions
+
 import 'non_web_library_interfaces.dart';
 import 'null_assertions_test_lib.dart';
 
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
index 7bfe293..ee0d648 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
@@ -2,6 +2,8 @@
 // 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.
 
+// dart2jsOptions=--no-native-null-assertions
+
 import 'null_assertions_test_lib.dart';
 import 'web_library_interfaces.dart';