[vm] Fix nullability checks for FutureOr in Class::IsSubtypeOf.
TEST=vm/dart/regress_48522
Fixed: https://github.com/dart-lang/sdk/issues/48522
Change-Id: I228ff30bd6223a01acd7ab8eea45bf5e35c55cc5
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237082
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
diff --git a/runtime/tests/vm/dart/regress_48522_test.dart b/runtime/tests/vm/dart/regress_48522_test.dart
new file mode 100644
index 0000000..d01562b
--- /dev/null
+++ b/runtime/tests/vm/dart/regress_48522_test.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2022, 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.
+
+// Regression test for https://github.com/dart-lang/sdk/issues/48522.
+// Test that FutureOr<T?> = FutureOr<T?>? <: Future<T?>?.
+
+import 'dart:async';
+
+import 'package:expect/expect.dart';
+
+Future<String?>? foo() {
+ return null;
+}
+
+FutureOr<String?>? bar() {
+ return null;
+}
+
+FutureOr<String?> baz() {
+ return null;
+}
+
+typedef F = FutureOr<String?> Function();
+typedef G = FutureOr<String?>? Function();
+
+void main() {
+ // Check Future<T?>? <: FutureOr<T?>?.
+ print(foo.runtimeType);
+ Expect.isTrue(foo is G);
+ (foo as dynamic) as G; // Should not throw.
+
+ final G v1 = foo;
+ print(v1.runtimeType);
+ Expect.isTrue(v1 is G);
+ (v1 as dynamic) as G; // Should not throw.
+
+ // Check Future<T?>? <: FutureOr<T?>.
+ print(foo.runtimeType);
+ Expect.isTrue(foo is F);
+ (foo as dynamic) as F; // Should not throw.
+
+ final F v2 = foo;
+ print(v2.runtimeType);
+ Expect.isTrue(v2 is F);
+ (v2 as dynamic) as F; // Should not throw.
+
+ // Check FutureOr<T?> = FutureOr<T?>?.
+ print(bar.runtimeType);
+ Expect.isTrue(bar is F);
+ (bar as dynamic) as F; // Should not throw.
+ print(baz.runtimeType);
+ Expect.isTrue(baz is G);
+ (baz as dynamic) as G; // Should not throw.
+}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 241097c..2b6b9c2 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -5416,7 +5416,9 @@
AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
// If T0 is Future<S0>, then T0 <: Future<S1>, iff S0 <: S1.
if (type_arg.IsSubtypeOf(other_type_arg, space, trail)) {
- if (verified_nullability) {
+ // verified_nullability doesn't take into account the nullability of
+ // S1, just of the FutureOr type.
+ if (verified_nullability || !other_type_arg.IsNonNullable()) {
return true;
}
}