[dart2js] Support Future/FutureOr in RTI.
Change-Id: Ib0d849947d023a421d682061920faac8e6d7d352
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107220
Reviewed-by: Stephen Adams <sra@google.com>
diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart
index 17cb4d4..1c45247 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -468,6 +468,9 @@
static String _canonicalRecipeOfNever() => '0&';
static String _canonicalRecipeOfAny() => '1&';
+ static String _canonicalRecipeOfFutureOr(Rti baseType) =>
+ '${Rti._getCanonicalRecipe(baseType)}/';
+
static Rti _lookupDynamicRti(universe) {
return _lookupTerminalRti(
universe, Rti.kindDynamic, _canonicalRecipeOfDynamic());
@@ -500,6 +503,23 @@
return _finishRti(universe, rti);
}
+ static Rti _lookupFutureOrRti(universe, Rti baseType) {
+ String canonicalRecipe = _canonicalRecipeOfFutureOr(baseType);
+ var cache = evalCache(universe);
+ var probe = _cacheGet(cache, canonicalRecipe);
+ if (probe != null) return _castToRti(probe);
+ return _createFutureOrRti(universe, baseType, canonicalRecipe);
+ }
+
+ static Rti _createFutureOrRti(
+ universe, Rti baseType, String canonicalRecipe) {
+ var rti = Rti.allocate();
+ Rti._setKind(rti, Rti.kindFutureOr);
+ Rti._setPrimary(rti, baseType);
+ Rti._setCanonicalRecipe(rti, canonicalRecipe);
+ return _finishRti(universe, rti);
+ }
+
static String _canonicalRecipeJoin(Object arguments) {
String s = '', sep = '';
int length = _Utils.arrayLength(arguments);
@@ -771,6 +791,13 @@
handleExtendedOperations(parser, stack);
break;
+ case Recipe.wrapFutureOr:
+ push(
+ stack,
+ _Universe._lookupFutureOrRti(universe(parser),
+ toType(universe(parser), environment(parser), pop(stack))));
+ break;
+
default:
JS('', 'throw "Bad character " + #', ch);
}
@@ -976,7 +1003,14 @@
// `true` because [s] <: T.
return true;
} else {
- // TODO(fishythefish): Check [s] <: Future<T>.
+ // Check [s] <: Future<T>.
+ // TODO(fishythefish): Do this without allocating an RTI for Future<T>
+ // each time.
+ String futureClass = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
+ var argumentsArray = JS('', '[#]', tTypeArgument);
+ var tFuture =
+ _Universe._lookupInterfaceRti(universe, futureClass, argumentsArray);
+ return _isSubtype(universe, s, sEnv, tFuture, tEnv);
}
}
diff --git a/tests/compiler/dart2js_extra/rti/subtype_test.dart b/tests/compiler/dart2js_extra/rti/subtype_test.dart
index 78753f7..ab6f2cf 100644
--- a/tests/compiler/dart2js_extra/rti/subtype_test.dart
+++ b/tests/compiler/dart2js_extra/rti/subtype_test.dart
@@ -8,6 +8,7 @@
import "package:expect/expect.dart";
final String objectName = JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME);
+final String futureName = JS_GET_NAME(JsGetName.FUTURE_CLASS_TYPE_NAME);
final String nullName = JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
const typeRulesJson = r'''
@@ -34,6 +35,12 @@
strictSubtype('CodeUnits', 'Iterable<num>');
strictSubtype('Iterable<int>', 'Iterable<num>');
strictSubtype('List<int>', objectName);
+ strictSubtype('$futureName<int>', '$futureName<num>');
+ strictSubtype('int', 'int/');
+ strictSubtype('$futureName<int>', 'int/');
+ strictSubtype('int/', 'num/');
+ strictSubtype('int', 'num/');
+ strictSubtype('$futureName<int>', 'num/');
strictSubtype(nullName, 'int');
strictSubtype(nullName, 'Iterable<CodeUnits>');
strictSubtype(nullName, objectName);
@@ -57,6 +64,7 @@
equivalent('List<@>', 'List<~>');
equivalent('List<@>', 'List<1&>');
equivalent('List<~>', 'List<1&>');
+ equivalent('@/', '~/');
}
String reason(String s, String t) => "$s <: $t";