[VM compiler] Take FutureOr into account when checking for Number type.
A field typed 'FutureOr<T>' may contain an instance of a Number type at runtime.
This fixes issue #35542 and adds a regression test.
Change-Id: Idd19dff3edc5e061da28ab2906c34b3133ea8bd8
Reviewed-on: https://dart-review.googlesource.com/c/88280
Commit-Queue: Régis Crelier <regis@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 82f52f3e..65d80af 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -3058,12 +3058,22 @@
return (cid == kDynamicCid) || (cid == kMintCid) || (cid == kDoubleCid);
}
-static bool MaybeNumber(CompileType* type) {
+static bool MayBeNumber(CompileType* type) {
+ if (type->IsNone()) {
+ return false;
+ }
+ auto& compile_type = AbstractType::Handle(type->ToAbstractType()->raw());
+ if (compile_type.IsType() &&
+ Class::Handle(compile_type.type_class()).IsFutureOrClass()) {
+ const auto& type_args = TypeArguments::Handle(compile_type.arguments());
+ if (type_args.IsNull()) {
+ return true;
+ }
+ compile_type = type_args.TypeAt(0);
+ }
// Note that type 'Number' is a subtype of itself.
- return type->ToAbstractType()->IsDynamicType() ||
- type->ToAbstractType()->IsObjectType() ||
- type->ToAbstractType()->IsTypeParameter() ||
- type->IsSubtypeOf(Type::Handle(Type::Number()));
+ return compile_type.IsTopType() || compile_type.IsTypeParameter() ||
+ compile_type.IsSubtypeOf(Type::Handle(Type::Number()), Heap::kOld);
}
// Returns a replacement for a strict comparison and signals if the result has
@@ -3078,8 +3088,8 @@
if (!MayBeBoxableNumber(compare->left()->Type()->ToCid()) ||
!MayBeBoxableNumber(compare->right()->Type()->ToCid())) {
compare->set_needs_number_check(false);
- } else if (!MaybeNumber(compare->left()->Type()) ||
- !MaybeNumber(compare->right()->Type())) {
+ } else if (!MayBeNumber(compare->left()->Type()) ||
+ !MayBeNumber(compare->right()->Type())) {
compare->set_needs_number_check(false);
}
}
diff --git a/tests/language_2/regress_35542_test.dart b/tests/language_2/regress_35542_test.dart
new file mode 100644
index 0000000..9b4a217
--- /dev/null
+++ b/tests/language_2/regress_35542_test.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2019, 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 'dart:async';
+import 'package:expect/expect.dart';
+
+FutureOr<dynamic> x = 'abc';
+dynamic y = 'abc';
+
+void smi() {
+ x = 42;
+ y = 42;
+}
+
+void mint() {
+ x = 0x7fffffff00000000;
+ y = 0x7fffffff00000000;
+}
+
+void dbl() {
+ x = 1.0;
+ y = 1.0;
+}
+
+void main() {
+ smi();
+ Expect.isTrue(identical(x, y));
+ mint();
+ Expect.isTrue(identical(x, y));
+ dbl();
+ Expect.isTrue(identical(x, y));
+}