[dart2js] Add ability to check if RTIs are Object, Function, or Null.
Change-Id: Ia893c688fa619a87fd9ab97cf881f35763a48bdf
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/107080
Commit-Queue: Mayank Patke <fishythefish@google.com>
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 5396d8a..17cb4d4 100644
--- a/sdk/lib/_internal/js_runtime/lib/rti.dart
+++ b/sdk/lib/_internal/js_runtime/lib/rti.dart
@@ -6,10 +6,11 @@
library rti;
import 'dart:_foreign_helper'
- show JS, JS_EMBEDDED_GLOBAL, RAW_DART_FUNCTION_REF;
+ show JS, JS_EMBEDDED_GLOBAL, JS_GET_NAME, RAW_DART_FUNCTION_REF;
import 'dart:_interceptors' show JSArray, JSUnmodifiableArray;
-import 'dart:_js_embedded_names' show RtiUniverseFieldNames, RTI_UNIVERSE;
+import 'dart:_js_embedded_names'
+ show JsGetName, RtiUniverseFieldNames, RTI_UNIVERSE;
import 'dart:_recipe_syntax';
@@ -955,14 +956,13 @@
if (isNullType(s)) return true;
- if (isFunctionType(t)) {
+ if (isFunctionKind(t)) {
// TODO(fishythefish): Check if s is a function subtype of t.
- throw UnimplementedError("isFunctionType(t)");
+ throw UnimplementedError("isFunctionKind(t)");
}
- if (isFunctionType(s)) {
- // TODO(fishythefish): Check if t is Function.
- throw UnimplementedError("isFunctionType(s)");
+ if (isFunctionKind(s)) {
+ return isFunctionType(t);
}
if (isFutureOrType(t)) {
@@ -1023,19 +1023,23 @@
bool isVoidType(Rti t) => Rti._getKind(t) == Rti.kindVoid;
bool isJsInteropType(Rti t) => Rti._getKind(t) == Rti.kindAny;
bool isFutureOrType(Rti t) => Rti._getKind(t) == Rti.kindFutureOr;
-bool isFunctionType(Rti t) => Rti._getKind(t) == Rti.kindFunction;
+bool isFunctionKind(Rti t) => Rti._getKind(t) == Rti.kindFunction;
bool isGenericFunctionTypeParameter(Rti t) =>
Rti._getKind(t) == Rti.kindGenericFunctionParameter;
-bool isObjectType(Rti t) {
- // TODO(fishythefish): Look up Object in universe and compare.
- return false;
-}
+bool isObjectType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME);
-bool isNullType(Rti t) {
- // TODO(fishythefish): Look up Null in universe and compare.
- return false;
-}
+// TODO(fishythefish): Which representation should we use for NNBD?
+// Do we also need to check for `Never?`, etc.?
+bool isNullType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
+
+bool isFunctionType(Rti t) =>
+ Rti._getKind(t) == Rti.kindInterface &&
+ Rti._getInterfaceName(t) == JS_GET_NAME(JsGetName.FUNCTION_CLASS_TYPE_NAME);
/// Unchecked cast to Rti.
Rti _castToRti(s) => JS('Rti', '#', s);
diff --git a/tests/compiler/dart2js_extra/rti/subtype_test.dart b/tests/compiler/dart2js_extra/rti/subtype_test.dart
index 0bf71dd..78753f7 100644
--- a/tests/compiler/dart2js_extra/rti/subtype_test.dart
+++ b/tests/compiler/dart2js_extra/rti/subtype_test.dart
@@ -2,10 +2,14 @@
// 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:_foreign_helper' show JS;
+import 'dart:_foreign_helper' show JS, JS_GET_NAME;
+import 'dart:_js_embedded_names' show JsGetName;
import 'dart:_rti' as rti;
import "package:expect/expect.dart";
+final String objectName = JS_GET_NAME(JsGetName.OBJECT_CLASS_TYPE_NAME);
+final String nullName = JS_GET_NAME(JsGetName.NULL_CLASS_TYPE_NAME);
+
const typeRulesJson = r'''
{
"int": {"num": []},
@@ -29,44 +33,51 @@
strictSubtype('List<CodeUnits>', 'Iterable<List<int>>');
strictSubtype('CodeUnits', 'Iterable<num>');
strictSubtype('Iterable<int>', 'Iterable<num>');
+ strictSubtype('List<int>', objectName);
+ strictSubtype(nullName, 'int');
+ strictSubtype(nullName, 'Iterable<CodeUnits>');
+ strictSubtype(nullName, objectName);
unrelated('int', 'CodeUnits');
+ equivalent(nullName, nullName);
equivalent('double', 'double');
- equivalent('Object', 'Object');
+ equivalent(objectName, objectName);
equivalent('@', '@');
equivalent('~', '~');
equivalent('1&', '1&');
equivalent('List<int>', 'List<int>');
- //equivalent('Object', '@');
- //equivalent('Object', '~');
- //equivalent('Object', '1&');
+ equivalent(objectName, '@');
+ equivalent(objectName, '~');
+ equivalent(objectName, '1&');
equivalent('@', '~');
equivalent('@', '1&');
equivalent('~', '1&');
- //equivalent('List<Object>', 'List<@>');
- //equivalent('List<Object>', 'List<~>');
- //equivalent('List<Object>', 'List<1&>');
+ equivalent('List<$objectName>', 'List<@>');
+ equivalent('List<$objectName>', 'List<~>');
+ equivalent('List<$objectName>', 'List<1&>');
equivalent('List<@>', 'List<~>');
equivalent('List<@>', 'List<1&>');
equivalent('List<~>', 'List<1&>');
}
+String reason(String s, String t) => "$s <: $t";
+
void strictSubtype(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti));
- Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti));
+ Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
}
void unrelated(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isFalse(rti.testingIsSubtype(universe, sRti, tRti));
- Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti));
+ Expect.isFalse(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isFalse(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
}
void equivalent(String s, String t) {
var sRti = rti.testingUniverseEval(universe, s);
var tRti = rti.testingUniverseEval(universe, t);
- Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti));
- Expect.isTrue(rti.testingIsSubtype(universe, tRti, sRti));
+ Expect.isTrue(rti.testingIsSubtype(universe, sRti, tRti), reason(s, t));
+ Expect.isTrue(rti.testingIsSubtype(universe, tRti, sRti), reason(t, s));
}