[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>
This commit is contained in:
Mayank Patke 2019-06-24 20:36:59 +00:00 committed by commit-bot@chromium.org
parent eb387e86e6
commit 637cae2486
2 changed files with 45 additions and 30 deletions

View file

@ -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 @@ bool _isSubtype(universe, Rti s, var sEnv, Rti t, var tEnv) {
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 isDynamicType(Rti t) => Rti._getKind(t) == Rti.kindDynamic;
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);

View file

@ -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 @@ void runTests() {
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));
}