Skip to content

Commit ec28580

Browse files
sstricklCommit Bot
authored and
Commit Bot
committed
[vm] Fix nullability checks for FutureOr in Class::IsSubtypeOf.
TEST=vm/dart/regress_48522 Fixed: #48522 Change-Id: I228ff30bd6223a01acd7ab8eea45bf5e35c55cc5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/237082 Reviewed-by: Alexander Markov <[email protected]> Commit-Queue: Tess Strickland <[email protected]>
1 parent b9a7f00 commit ec28580

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
// Regression test for https://github.com/dart-lang/sdk/issues/48522.
6+
// Test that FutureOr<T?> = FutureOr<T?>? <: Future<T?>?.
7+
8+
import 'dart:async';
9+
10+
import 'package:expect/expect.dart';
11+
12+
Future<String?>? foo() {
13+
return null;
14+
}
15+
16+
FutureOr<String?>? bar() {
17+
return null;
18+
}
19+
20+
FutureOr<String?> baz() {
21+
return null;
22+
}
23+
24+
typedef F = FutureOr<String?> Function();
25+
typedef G = FutureOr<String?>? Function();
26+
27+
void main() {
28+
// Check Future<T?>? <: FutureOr<T?>?.
29+
print(foo.runtimeType);
30+
Expect.isTrue(foo is G);
31+
(foo as dynamic) as G; // Should not throw.
32+
33+
final G v1 = foo;
34+
print(v1.runtimeType);
35+
Expect.isTrue(v1 is G);
36+
(v1 as dynamic) as G; // Should not throw.
37+
38+
// Check Future<T?>? <: FutureOr<T?>.
39+
print(foo.runtimeType);
40+
Expect.isTrue(foo is F);
41+
(foo as dynamic) as F; // Should not throw.
42+
43+
final F v2 = foo;
44+
print(v2.runtimeType);
45+
Expect.isTrue(v2 is F);
46+
(v2 as dynamic) as F; // Should not throw.
47+
48+
// Check FutureOr<T?> = FutureOr<T?>?.
49+
print(bar.runtimeType);
50+
Expect.isTrue(bar is F);
51+
(bar as dynamic) as F; // Should not throw.
52+
print(baz.runtimeType);
53+
Expect.isTrue(baz is G);
54+
(baz as dynamic) as G; // Should not throw.
55+
}

runtime/vm/object.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -5416,7 +5416,9 @@ bool Class::IsSubtypeOf(const Class& cls,
54165416
AbstractType::Handle(zone, type_arguments.TypeAtNullSafe(0));
54175417
// If T0 is Future<S0>, then T0 <: Future<S1>, iff S0 <: S1.
54185418
if (type_arg.IsSubtypeOf(other_type_arg, space, trail)) {
5419-
if (verified_nullability) {
5419+
// verified_nullability doesn't take into account the nullability of
5420+
// S1, just of the FutureOr type.
5421+
if (verified_nullability || !other_type_arg.IsNonNullable()) {
54205422
return true;
54215423
}
54225424
}

0 commit comments

Comments
 (0)