Version 2.11.0-248.0.dev
Merge commit '1c1fef8d682e59e4e92eba0c01cf75fe3b15af5a' into 'dev'
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/ir/util.dart b/pkg/compiler/lib/src/ir/util.dart
index 15d7550..437a842 100644
--- a/pkg/compiler/lib/src/ir/util.dart
+++ b/pkg/compiler/lib/src/ir/util.dart
@@ -242,3 +242,29 @@
/// and function type variables) are considered.
bool containsFreeVariables(ir.DartType type) =>
type.accept(const _FreeVariableVisitor());
+
+/// Returns true if [importUri] corresponds to dart:html and related libraries.
+bool _isWebLibrary(Uri importUri) =>
+ importUri.scheme == 'dart' &&
+ (importUri.path == 'html' ||
+ importUri.path == 'svg' ||
+ importUri.path == 'indexed_db' ||
+ importUri.path == 'web_audio' ||
+ importUri.path == 'web_gl' ||
+ importUri.path == 'web_sql' ||
+ importUri.path == 'html_common') ||
+ // Mock web library path for testing.
+ importUri.path
+ .contains('native_null_assertions/web_library_interfaces.dart');
+
+bool nodeIsInWebLibrary(ir.TreeNode node) {
+ if (node == null) return false;
+ if (node is ir.Library) return _isWebLibrary(node.importUri);
+ return nodeIsInWebLibrary(node.parent);
+}
+
+bool memberEntityIsInWebLibrary(MemberEntity entity) {
+ var importUri = entity?.library?.canonicalUri;
+ if (importUri == null) return false;
+ return _isWebLibrary(importUri);
+}
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 619683d..3e327fb 100644
--- a/pkg/compiler/lib/src/ssa/builder_kernel.dart
+++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart
@@ -1545,10 +1545,11 @@
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)) {
+ if (dartTypes.isNonNullableIfSound(type) &&
+ nodeIsInWebLibrary(functionNode)) {
push(HNullCheck(value, _abstractValueDomain.excludeNull(returnType),
sticky: true));
value = pop();
@@ -4799,8 +4800,8 @@
/// 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 &&
- _isInWebLibrary(invocation) &&
+ if (options.nativeNullAssertions &&
+ nodeIsInWebLibrary(invocation) &&
closedWorld.dartTypes
.isNonNullableIfSound(_getStaticType(invocation).type)) {
HInstruction code = pop();
@@ -4810,25 +4811,6 @@
}
}
- /// Returns true if [node] belongs to dart:html and related libraries.
- bool _isInWebLibrary(ir.TreeNode node) {
- if (node == null) return false;
- bool isWebLibrary(Uri importUri) =>
- importUri.scheme == 'dart' &&
- (importUri.path == 'html' ||
- importUri.path == 'svg' ||
- importUri.path == 'indexed_db' ||
- importUri.path == 'web_audio' ||
- importUri.path == 'web_gl' ||
- importUri.path == 'web_sql' ||
- importUri.path == 'html_common') ||
- // Mock web library path for testing.
- importUri.path
- .contains('native_null_assertions/js_invocations_in_web_library');
- if (node is ir.Library) return isWebLibrary(node.importUri);
- return _isInWebLibrary(node.parent);
- }
-
void _handleJsStringConcat(ir.StaticInvocation invocation) {
if (_unexpectedForeignArguments(invocation,
minPositional: 2, maxPositional: 2)) {
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index 3386187..aff9860 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -13,6 +13,7 @@
import '../elements/types.dart';
import '../inferrer/abstract_value_domain.dart';
import '../inferrer/types.dart';
+import '../ir/util.dart';
import '../js_backend/field_analysis.dart'
show FieldAnalysisData, JFieldAnalysis;
import '../js_backend/backend.dart' show CodegenInputs;
@@ -925,11 +926,12 @@
HInstruction maybeAddNativeReturnNullCheck(
HInstruction node, HInstruction replacement, FunctionEntity method) {
- if (_options.enableNativeNullAssertions) {
+ if (_options.nativeNullAssertions) {
if (method.library.isNonNullableByDefault) {
FunctionType type =
_closedWorld.elementEnvironment.getFunctionType(method);
- if (_closedWorld.dartTypes.isNonNullableIfSound(type.returnType)) {
+ if (_closedWorld.dartTypes.isNonNullableIfSound(type.returnType) &&
+ memberEntityIsInWebLibrary(method)) {
node.block.addBefore(node, replacement);
replacement = HNullCheck(replacement,
_abstractValueDomain.excludeNull(replacement.instructionType),
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 31eb2d6..464ff44 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -4283,7 +4283,8 @@
_extensionTypes.isNativeClass(member.enclosingClass) &&
member is Procedure &&
member.function != null &&
- member.function.returnType.isPotentiallyNonNullable;
+ member.function.returnType.isPotentiallyNonNullable &&
+ _isWebLibrary(member.enclosingLibrary?.importUri);
// TODO(jmesserly): can we encapsulate REPL name lookups and remove this?
// _emitMemberName would be a nice place to handle it, but we don't have
@@ -5105,6 +5106,7 @@
}
bool _isWebLibrary(Uri importUri) =>
+ importUri != null &&
importUri.scheme == 'dart' &&
(importUri.path == 'html' ||
importUri.path == 'svg' ||
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
similarity index 81%
copy from tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
copy to tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
index e307833..7ed8c58 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_non_web_test.dart
@@ -2,6 +2,9 @@
// 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';
void main() {
diff --git a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
similarity index 81%
rename from tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
rename to tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
index e307833..ee0d648 100644
--- a/tests/dart2js/native/native_null_assertions/flag_disabled_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_disabled_web_test.dart
@@ -2,7 +2,10 @@
// 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';
void main() {
var flagEnabled = false;
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
similarity index 90%
copy from tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
copy to tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
index 0eb3965..61c018b 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_non_web_test.dart
@@ -4,6 +4,7 @@
// dart2jsOptions=--native-null-assertions
+import 'non_web_library_interfaces.dart';
import 'null_assertions_test_lib.dart';
void main() {
diff --git a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
similarity index 91%
rename from tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
rename to tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
index 0eb3965..71baddf 100644
--- a/tests/dart2js/native/native_null_assertions/flag_enabled_test.dart
+++ b/tests/dart2js/native/native_null_assertions/flag_enabled_web_test.dart
@@ -5,6 +5,7 @@
// dart2jsOptions=--native-null-assertions
import 'null_assertions_test_lib.dart';
+import 'web_library_interfaces.dart';
void main() {
var flagEnabled = true;
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
deleted file mode 100644
index 9dd2be1..0000000
--- a/tests/dart2js/native/native_null_assertions/js_invocations_in_non_web_library.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-import '../native_testing.dart';
-import 'null_assertions_lib.dart';
-
-// Implementation of `JSInterface` except in a folder that is not part of the
-// allowlist for the `--native-null-assertions` flag. This file is not treated
-// as a web library, and therefore the `JS()` invocations should not be checked.
-
-@Native('CCCInNonWebLibrary')
-class CCCInNonWebLibrary implements JSInterface {
- String get name => JS('String', '#.name', this);
- String? get optName => JS('String|Null', '#.optName', this);
-}
diff --git a/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart b/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
deleted file mode 100644
index 0554ab4..0000000
--- a/tests/dart2js/native/native_null_assertions/js_invocations_in_web_library.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-import '../native_testing.dart';
-import 'null_assertions_lib.dart';
-
-// Implementation of `JSInterface` in a folder that is explicitly part of the
-// allowlist for the `--native-null-assertions` flag. This file is treated as a
-// web library, and therefore the `JS()` invocations should be checked.
-
-@Native('CCCInWebLibrary')
-class CCCInWebLibrary implements JSInterface {
- String get name => JS('String', '#.name', this);
- String? get optName => JS('String|Null', '#.optName', this);
-}
diff --git a/tests/dart2js/native/native_null_assertions/non_web_library_interfaces.dart b/tests/dart2js/native/native_null_assertions/non_web_library_interfaces.dart
new file mode 100644
index 0000000..f0b6f95
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/non_web_library_interfaces.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import '../native_testing.dart';
+import 'null_assertions_test_lib.dart';
+
+// Implementations of `NativeInterface` and `JSInterface` in a folder that is
+// not part of the allowlist for the `--native-null-assertions` flag. This file
+// is not treated as a web library, and therefore native members and `JS()`
+// invocations should not be checked.
+
+@Native("AAA")
+class AAA implements NativeInterface {
+ int get size native;
+ String get name native;
+ String? get optName native;
+ int method1() native;
+ String method2() native;
+ String? optMethod() native;
+}
+
+@Native('CCC')
+class CCC implements JSInterface {
+ String get name => JS('String', '#.name', this);
+ String? get optName => JS('String|Null', '#.optName', this);
+}
+
+/// Returns an 'AAA' object that satisfies the interface.
+AAA makeA() native;
+
+/// Returns an 'AAA' object where each method breaks the interface's contract.
+AAA makeAX() native;
+
+/// Returns a 'CCC' object that satisfies the interface using `JS()`
+/// invocations.
+CCC makeC() native;
+
+/// Returns a 'CCC' object where each method breaks the interface's contract.
+CCC makeCX() native;
+
+// The 'AAA' version of the code is passed only objects of a single native
+// class, so the native method can be inlined (which happens in the optimizer).
+// This tests that the null-check exists in the 'inlined' code.
+
+@pragma('dart2js:noInline')
+String describeAAA(AAA o) {
+ return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptAAA(AAA o) {
+ return '${o.optName} ${o.optMethod()}';
+}
+
+void testNativeNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+ AAA a = makeA();
+ BBB b = BBB();
+
+ Expect.equals(expectedA, describeNativeInterface(a));
+ Expect.equals(expectedB, describeNativeInterface(b));
+
+ Expect.equals(expectedA, describeAAA(a));
+
+ AAA x = makeAX(); // This object returns `null`!
+ // Since native members are not in a web library, there should be no checks,
+ // regardless of if the flag is enabled.
+ var checkExpectation = (f) => f();
+ checkExpectation(() => describeNativeInterface(x));
+ checkExpectation(() => describeAAA(x));
+
+ checkExpectation(() => x.name);
+ checkExpectation(() => x.size);
+ checkExpectation(() => x.method1());
+ checkExpectation(() => x.method2());
+
+ // Now test that a nullable return type does not have a check.
+ Expect.equals(expectedOptA, describeOptNativeInterface(a));
+ Expect.equals(expectedOptB, describeOptNativeInterface(b));
+ Expect.equals(expectedOptX, describeOptNativeInterface(x));
+
+ Expect.equals(expectedOptA, describeOptAAA(a));
+ Expect.equals(expectedOptX, describeOptAAA(x));
+}
+
+void testJSInvocationNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+
+ CCC c = makeC();
+ CCC cx = makeCX();
+
+ Expect.equals(expectedC, describeJSInterface(c));
+
+ // Since invocations are not in a web library, there should be no checks,
+ // regardless of if the flag is enabled.
+ var checkExpectation = (f) => f();
+ checkExpectation(() => describeJSInterface(cx));
+
+ // Test that invocations with a nullable static type do not have checks.
+ Expect.equals(expectedOptC, describeOptJSInterface(c));
+ Expect.equals(expectedOptCX, describeOptJSInterface(cx));
+}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
deleted file mode 100644
index 894fdf0..0000000
--- a/tests/dart2js/native/native_null_assertions/null_assertions_lib.dart
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
-// 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.
-
-import '../native_testing.dart';
-
-abstract class NativeInterface {
- int get size;
- String get name;
- String? get optName;
- int method1();
- String method2();
- String? optMethod();
-}
-
-@Native("AAA")
-class AAA implements NativeInterface {
- int get size native;
- String get name native;
- String? get optName native;
- int method1() native;
- String method2() native;
- String? optMethod() native;
-}
-
-abstract class JSInterface {
- String get name;
- String? get optName;
-}
-
-class BBB implements NativeInterface {
- int get size => 300;
- String get name => 'Brenda';
- String? get optName => name;
- int method1() => 400;
- String method2() => 'brilliant!';
- String? optMethod() => method2();
-}
diff --git a/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
index 3f1f540..049cd36 100644
--- a/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
+++ b/tests/dart2js/native/native_null_assertions/null_assertions_test_lib.dart
@@ -3,31 +3,29 @@
// BSD-style license that can be found in the LICENSE file.
import '../native_testing.dart';
-import 'js_invocations_in_non_web_library.dart';
-import 'js_invocations_in_web_library.dart';
-import 'null_assertions_lib.dart';
-/// Returns an 'AAA' object that satisfies the interface.
-AAA makeA() native;
+abstract class NativeInterface {
+ int get size;
+ String get name;
+ String? get optName;
+ int method1();
+ String method2();
+ String? optMethod();
+}
-/// Returns an 'AAA' object where each method breaks the interface's contract.
-AAA makeAX() native;
+abstract class JSInterface {
+ String get name;
+ String? get optName;
+}
-/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
-/// that is part of the allowlist.
-CCCInWebLibrary makeWebC() native;
-
-/// Returns the same as above but where each method breaks the interface's
-/// contract.
-CCCInWebLibrary makeWebCX() native;
-
-/// Returns a 'JSInterface' object whose `JS()` invocations exist in a library
-/// that is not part of the allowlist.
-CCCInNonWebLibrary makeNonWebC() native;
-
-/// Returns the same as above but where each method breaks the interface's
-/// contract.
-CCCInNonWebLibrary makeNonWebCX() native;
+class BBB implements NativeInterface {
+ int get size => 300;
+ String get name => 'Brenda';
+ String? get optName => name;
+ int method1() => 400;
+ String method2() => 'brilliant!';
+ String? optMethod() => method2();
+}
void setup() {
JS('', r"""
@@ -52,40 +50,25 @@
self.nativeConstructor(AAA);
- function CCCInWebLibrary(n) {
- this.name = n;
- this.optName = n;
- }
- function CCCInNonWebLibrary(n) {
+ function CCC(n) {
this.name = n;
this.optName = n;
}
- makeWebC = function() {
- return new CCCInWebLibrary('Carol');
+ makeC = function() {
+ return new CCC('Carol');
};
- makeWebCX = function() {
- return new CCCInWebLibrary(void 0);
- };
- makeNonWebC = function() {
- return new CCCInNonWebLibrary('Carol');
- };
- makeNonWebCX = function() {
- return new CCCInNonWebLibrary(void 0);
+ makeCX = function() {
+ return new CCC(void 0);
};
- self.nativeConstructor(CCCInWebLibrary);
- self.nativeConstructor(CCCInNonWebLibrary);
+ self.nativeConstructor(CCC);
})()""");
}
// The 'NativeInterface' version of the code is passed both native and Dart
// objects, so there will be an interceptor dispatch to the method. This tests
// that the null-check exists in the forwarding method.
-//
-// The 'AAA' version of the code is passed only objects of a single native
-// class, so the native method can be inlined (which happens in the optimizer).
-// This tests that the null-check exists in the 'inlined' code.
@pragma('dart2js:noInline')
String describeNativeInterface(NativeInterface o) {
@@ -93,21 +76,11 @@
}
@pragma('dart2js:noInline')
-String describeAAA(AAA o) {
- return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
-}
-
-@pragma('dart2js:noInline')
String describeOptNativeInterface(NativeInterface o) {
return '${o.optName} ${o.optMethod()}';
}
@pragma('dart2js:noInline')
-String describeOptAAA(AAA o) {
- return '${o.optName} ${o.optMethod()}';
-}
-
-@pragma('dart2js:noInline')
String describeJSInterface(JSInterface o) {
return '${o.name}';
}
@@ -126,68 +99,3 @@
const expectedC = 'Carol';
const expectedOptC = 'Carol';
const expectedOptCX = 'null';
-
-// Test that `--native-null-assertions` injects null-checks on the returned
-// value of native methods with a non-nullable return type in an opt-in library.
-void testNativeNullAssertions(bool flagEnabled) {
- nativeTesting();
- setup();
- AAA a = makeA();
- BBB b = BBB();
-
- Expect.equals(expectedA, describeNativeInterface(a));
- Expect.equals(expectedB, describeNativeInterface(b));
-
- Expect.equals(expectedA, describeAAA(a));
-
- AAA x = makeAX(); // This object returns `null`!
- var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
- checkExpectation(() => describeNativeInterface(x));
- checkExpectation(() => describeAAA(x));
-
- checkExpectation(() => x.name);
- checkExpectation(() => x.size);
- checkExpectation(() => x.method1());
- checkExpectation(() => x.method2());
-
- // Now test that a nullable return type does not have a check.
- Expect.equals(expectedOptA, describeOptNativeInterface(a));
- Expect.equals(expectedOptB, describeOptNativeInterface(b));
- Expect.equals(expectedOptX, describeOptNativeInterface(x));
-
- Expect.equals(expectedOptA, describeOptAAA(a));
- Expect.equals(expectedOptX, describeOptAAA(x));
-}
-
-// Test that `--native-null-assertions` injects null-checks on the returned
-// value of `JS()` invocations with a non-nullable static type in an opt-in
-// library.
-void testJSInvocationNullAssertions(bool flagEnabled) {
- nativeTesting();
- setup();
-
- CCCInWebLibrary webC = makeWebC();
- CCCInWebLibrary webCX = makeWebCX();
-
- CCCInNonWebLibrary nonWebC = makeNonWebC();
- CCCInNonWebLibrary nonWebCX = makeNonWebCX();
-
- Expect.equals(expectedC, describeJSInterface(webC));
- Expect.equals(expectedC, describeJSInterface(nonWebC));
-
- // If invocations are in a web library, this should throw if null checks are
- // enabled.
- var checkExpectationWeb = flagEnabled ? Expect.throws : (f) => f();
- checkExpectationWeb(() => describeJSInterface(webCX));
-
- // If invocations are not in a web library, there should not be a null check
- // regardless if the flag is enabled or not.
- var checkExpectationNonWeb = (f) => f();
- checkExpectationNonWeb(() => describeJSInterface(nonWebCX));
-
- // Test that invocations with a nullable static type do not have checks.
- Expect.equals(expectedOptC, describeOptJSInterface(webC));
- Expect.equals(expectedOptC, describeOptJSInterface(nonWebC));
- Expect.equals(expectedOptCX, describeOptJSInterface(webCX));
- Expect.equals(expectedOptCX, describeOptJSInterface(nonWebCX));
-}
diff --git a/tests/dart2js/native/native_null_assertions/web_library_interfaces.dart b/tests/dart2js/native/native_null_assertions/web_library_interfaces.dart
new file mode 100644
index 0000000..48bb86b
--- /dev/null
+++ b/tests/dart2js/native/native_null_assertions/web_library_interfaces.dart
@@ -0,0 +1,105 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// 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.
+
+import '../native_testing.dart';
+import 'null_assertions_test_lib.dart';
+
+// Implementations of `NativeInterface` and `JSInterface` in a folder that is
+// part of the allowlist for the `--native-null-assertions` flag. This file is
+// treated as a web library, and therefore native members and `JS()` invocations
+// should be checked.
+
+@Native("AAA")
+class AAA implements NativeInterface {
+ int get size native;
+ String get name native;
+ String? get optName native;
+ int method1() native;
+ String method2() native;
+ String? optMethod() native;
+}
+
+@Native('CCC')
+class CCC implements JSInterface {
+ String get name => JS('String', '#.name', this);
+ String? get optName => JS('String|Null', '#.optName', this);
+}
+
+/// Returns an 'AAA' object that satisfies the interface.
+AAA makeA() native;
+
+/// Returns an 'AAA' object where each method breaks the interface's contract.
+AAA makeAX() native;
+
+/// Returns a 'CCC' object that satisfies the interface using `JS()`
+/// invocations.
+CCC makeC() native;
+
+/// Returns a 'CCC' object where each method breaks the interface's contract.
+CCC makeCX() native;
+
+// The 'AAA' version of the code is passed only objects of a single native
+// class, so the native method can be inlined (which happens in the optimizer).
+// This tests that the null-check exists in the 'inlined' code.
+
+@pragma('dart2js:noInline')
+String describeAAA(AAA o) {
+ return '${o.name} ${o.method2()} ${o.size} ${o.method1()}';
+}
+
+@pragma('dart2js:noInline')
+String describeOptAAA(AAA o) {
+ return '${o.optName} ${o.optMethod()}';
+}
+
+void testNativeNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+ AAA a = makeA();
+ BBB b = BBB();
+
+ Expect.equals(expectedA, describeNativeInterface(a));
+ Expect.equals(expectedB, describeNativeInterface(b));
+
+ Expect.equals(expectedA, describeAAA(a));
+
+ AAA x = makeAX(); // This object returns `null`!
+ // Since native members are in a web library, this should throw if null checks
+ // are enabled.
+ var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
+ checkExpectation(() => describeNativeInterface(x));
+ checkExpectation(() => describeAAA(x));
+
+ checkExpectation(() => x.name);
+ checkExpectation(() => x.size);
+ checkExpectation(() => x.method1());
+ checkExpectation(() => x.method2());
+
+ // Now test that a nullable return type does not have a check.
+ Expect.equals(expectedOptA, describeOptNativeInterface(a));
+ Expect.equals(expectedOptB, describeOptNativeInterface(b));
+ Expect.equals(expectedOptX, describeOptNativeInterface(x));
+
+ Expect.equals(expectedOptA, describeOptAAA(a));
+ Expect.equals(expectedOptX, describeOptAAA(x));
+}
+
+void testJSInvocationNullAssertions(bool flagEnabled) {
+ nativeTesting();
+ setup();
+
+ CCC c = makeC();
+ CCC cx = makeCX();
+
+ Expect.equals(expectedC, describeJSInterface(c));
+
+ // Since invocations are in a web library, this should throw if null checks
+ // are enabled.
+ var checkExpectation = flagEnabled ? Expect.throws : (f) => f();
+ checkExpectation(() => describeJSInterface(cx));
+
+ // Test that invocations with a nullable static type do not have checks.
+ Expect.equals(expectedOptC, describeOptJSInterface(c));
+ Expect.equals(expectedOptCX, describeOptJSInterface(cx));
+}
diff --git a/tools/VERSION b/tools/VERSION
index dcbe123..0e82789a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 11
PATCH 0
-PRERELEASE 247
+PRERELEASE 248
PRERELEASE_PATCH 0
\ No newline at end of file