Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Unified Diff: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart

Issue 2515353003: Support lazy JS types. (Closed)
Patch Set: Support lazy JS types. Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
index 1c1acb27bc294a45f533d0e58369833632fa0ffb..91a4ea82f883c5754c3557c915f098774700802a 100644
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/types.dart
@@ -56,7 +56,9 @@ final _typeObject = JS('', 'Symbol("typeObject")');
// TODO(jmesserly): we shouldn't implement Type here. It should be moved down
// to AbstractFunctionType.
class TypeRep implements Type {
- TypeRep() { _initialize; }
+ TypeRep() {
+ _initialize;
+ }
String get name => this.toString();
}
@@ -64,12 +66,46 @@ class Dynamic extends TypeRep {
toString() => 'dynamic';
}
+class LazyJSType implements Type {
+ final _jsTypeCallback;
+ final _dartName;
+
+ LazyJSType(this._jsTypeCallback, this._dartName);
+
+ get _rawJSType => JS('', '#()', _jsTypeCallback);
+
+ toString() => _jsTypeCallback != null ? typeName(_rawJSType) : _dartName;
+}
+
+_isInstanceOfLazyJSType(o, LazyJSType t) {
+ if (t._jsTypeCallback != null) {
+ return JS('bool', 'dart.is(#, #)', o, t._rawJSType);
+ }
+ if (o == null) return false;
+ // Anonymous case: match any JS type.
+ return _isJSObject(o);
+}
+
+_asInstanceOfLazyJSType(o, LazyJSType t) {
+ if (t._jsTypeCallback != null) {
+ return JS('bool', 'dart.as(#, #)', o, t._rawJSType);
+ }
+ // Anonymous case: allow any JS type.
+ if (o == null) return null;
+ if (!_isJSObject(o)) _throwCastError(o, t, true);
+ return o;
+}
+
+bool _isJSObject(o) => JS('bool', '!dart.getReifiedType(o)[dart._runtimeType]');
+
@JSExportName('dynamic')
final _dynamic = new Dynamic();
final _initialize = _initialize2();
-_initialize2() => JS('', '''(() => {
+_initialize2() => JS(
+ '',
+ '''(() => {
// JavaScript API forwards to runtime library.
$TypeRep.prototype.is = function is_T(object) {
return dart.is(object, this);
@@ -91,6 +127,13 @@ _initialize2() => JS('', '''(() => {
$Dynamic.prototype._check = function check_Dynamic(object) {
return object;
};
+
+ $LazyJSType.prototype.is = function is_T(object) {
+ return $_isInstanceOfLazyJSType(object, this);
+ };
+ $LazyJSType.prototype.as = function as_T(object) {
+ return $_asInstanceOfLazyJSType(object, this);
+ };
})()''');
class Void extends TypeRep {
@@ -103,6 +146,7 @@ final _void = new Void();
class Bottom extends TypeRep {
toString() => 'bottom';
}
+
final bottom = new Bottom();
class JSObject extends TypeRep {
@@ -117,7 +161,9 @@ class WrappedType extends Type {
toString() => typeName(_wrappedType);
}
-final AbstractFunctionType = JS('', '''
+final AbstractFunctionType = JS(
+ '',
+ '''
class AbstractFunctionType extends $TypeRep {
constructor() {
super();
@@ -172,6 +218,7 @@ final AbstractFunctionType = JS('', '''
/// reached via this path (if any) is the canonical representative
/// for this packet.
final _fnTypeNamedArgMap = JS('', 'new Map()');
+
/// Memo table for positional argument groups. A positional argument
/// packet [type1, ..., typen] (required or optional) corresponds to
/// the path n, type1, ...., typen. The element reached via
@@ -179,11 +226,13 @@ final _fnTypeNamedArgMap = JS('', 'new Map()');
/// packet. Note that required and optional parameters packages
/// may have the same canonical representation.
final _fnTypeArrayArgMap = JS('', 'new Map()');
+
/// Memo table for function types. The index path consists of the
/// path length - 1, the returnType, the canonical positional argument
/// packet, and if present, the canonical optional or named argument
/// packet. A level of indirection could be avoided here if desired.
final _fnTypeTypeMap = JS('', 'new Map()');
+
/// Memo table for small function types with no optional or named
/// arguments and less than a fixed n (currently 3) number of
/// required arguments. Indexing into this table by the number
@@ -192,7 +241,9 @@ final _fnTypeTypeMap = JS('', 'new Map()');
/// index path (if present) is the canonical function type.
final _fnTypeSmallMap = JS('', '[new Map(), new Map(), new Map()]');
-final FunctionType = JS('', '''
+final FunctionType = JS(
+ '',
+ '''
class FunctionType extends $AbstractFunctionType {
static _memoizeArray(map, arr, create) {
let len = arr.length;
@@ -346,8 +397,9 @@ final FunctionType = JS('', '''
}
''');
-
-final Typedef = JS('', '''
+final Typedef = JS(
+ '',
+ '''
class Typedef extends $AbstractFunctionType {
constructor(name, closure) {
super();
@@ -391,7 +443,9 @@ final Typedef = JS('', '''
final _typeFormalCount = JS('', 'Symbol("_typeFormalCount")');
-_functionType(definite, returnType, args, extra) => JS('', '''(() => {
+_functionType(definite, returnType, args, extra) => JS(
+ '',
+ '''(() => {
// TODO(jmesserly): this is a bit of a retrofit, to easily fit
// generic functions into all of the existing ways we generate function
// signatures. Given `(T) => [T, [T]]` we'll return a function that does
@@ -427,7 +481,9 @@ definiteFunctionType(returnType, args, extra) =>
typedef(name, closure) => JS('', 'new #(#, #)', Typedef, name, closure);
-typeName(type) => JS('', '''(() => {
+typeName(type) => JS(
+ '',
+ '''(() => {
if ($type === void 0) return "undefined type";
if ($type === null) return "null type";
// Non-instance types
@@ -480,9 +536,16 @@ getImplicitFunctionType(type) {
return getMethodTypeFromType(type, 'call');
}
-bool isFunctionType(type) =>
- JS('bool', '# instanceof # || # === #',
- type, AbstractFunctionType, type, Function);
+bool isFunctionType(type) => JS('bool', '# instanceof # || # === #', type,
+ AbstractFunctionType, type, Function);
+
+isLazyJSSubtype(LazyJSType t1, LazyJSType t2, covariant) {
+ if (t1 == t2) return true;
+
+ // All anonymous JS types are subtypes of each other.
+ if (t1._jsTypeCallback == null || t2._jsTypeCallback == null) return true;
+ return isClassSubType(t1._rawJSType, t2._rawJSType, covariant);
+}
/// Returns true if [ft1] <: [ft2].
/// Returns false if [ft1] </: [ft2] in both spec and strong mode
@@ -491,7 +554,9 @@ bool isFunctionType(type) =>
/// If [covariant] is true, then we are checking subtyping in a covariant
/// position, and hence the direction of the check for function types
/// corresponds to the direction of the check according to the Dart spec.
-isFunctionSubtype(ft1, ft2, covariant) => JS('', '''(() => {
+isFunctionSubtype(ft1, ft2, covariant) => JS(
+ '',
+ '''(() => {
if ($ft2 === $Function) {
return true;
}
@@ -571,7 +636,9 @@ isFunctionSubtype(ft1, ft2, covariant) => JS('', '''(() => {
/// TODO(leafp): This duplicates code in operations.dart.
/// I haven't found a way to factor it out that makes the
/// code generator happy though.
-_subtypeMemo(f) => JS('', '''(() => {
+_subtypeMemo(f) => JS(
+ '',
+ '''(() => {
let memo = new Map();
return (t1, t2) => {
let map = memo.get(t1);
@@ -592,14 +659,16 @@ _subtypeMemo(f) => JS('', '''(() => {
/// Returns false if [t1] </: [t2] in both spec and strong mode
/// Returns undefined if [t1] </: [t2] in strong mode, but spec
/// mode may differ
-final isSubtype =
- JS('', '$_subtypeMemo((t1, t2) => (t1 === t2) || $_isSubtype(t1, t2, true))');
+final isSubtype = JS(
+ '', '$_subtypeMemo((t1, t2) => (t1 === t2) || $_isSubtype(t1, t2, true))');
_isBottom(type) => JS('bool', '# == #', type, bottom);
_isTop(type) => JS('bool', '# == # || # == #', type, Object, type, dynamic);
-_isSubtype(t1, t2, covariant) => JS('', '''(() => {
+_isSubtype(t1, t2, covariant) => JS(
+ '',
+ '''(() => {
if ($t1 === $t2) return true;
// Trivially true.
@@ -633,10 +702,17 @@ _isSubtype(t1, t2, covariant) => JS('', '''(() => {
if ($isFunctionType($t1) && $isFunctionType($t2)) {
return $isFunctionSubtype($t1, $t2, $covariant);
}
+
+ if ($t1 instanceof $LazyJSType && $t2 instanceof $LazyJSType) {
+ return $isLazyJSSubtype($t1, $t2, $covariant);
+ }
+
return false;
})()''');
-isClassSubType(t1, t2, covariant) => JS('', '''(() => {
+isClassSubType(t1, t2, covariant) => JS(
+ '',
+ '''(() => {
// We support Dart's covariant generics with the caveat that we do not
// substitute bottom for dynamic in subtyping rules.
// I.e., given T1, ..., Tn where at least one Ti != dynamic we disallow:
@@ -717,7 +793,9 @@ isClassSubType(t1, t2, covariant) => JS('', '''(() => {
// TODO(jmesserly): this isn't currently used, but it could be if we want
// `obj is NonGroundType<T,S>` to be rejected at runtime instead of compile
// time.
-isGroundType(type) => JS('', '''(() => {
+isGroundType(type) => JS(
+ '',
+ '''(() => {
// TODO(vsm): Cache this if we start using it at runtime.
if ($type instanceof $AbstractFunctionType) {
« no previous file with comments | « pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/rtti.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698