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 6308359f9e1654c5f92a86cc00c1a68227182be6..1102b1d7a9364fac8edefa142f540e9be756f71f 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,110 +56,104 @@ 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; |
- } |
String get name => this.toString(); |
+ |
+ @JSExportName('is') |
+ bool is_T(object) => instanceOf(object, this); |
+ |
+ @JSExportName('as') |
+ as_T(object) => cast(object, this); |
+ |
+ @JSExportName('_check') |
+ check_T(object) => check(object, this); |
} |
class Dynamic extends TypeRep { |
toString() => 'dynamic'; |
+ |
+ @JSExportName('is') |
+ bool is_T(object) => true; |
+ |
+ @JSExportName('as') |
+ as_T(object) => object; |
+ |
+ @JSExportName('_check') |
+ check_T(object) => object; |
} |
class LazyJSType extends TypeRep { |
- final _jsTypeCallback; |
- final _dartName; |
+ final Function() _rawJSType; |
+ final String _dartName; |
+ |
+ LazyJSType(this._rawJSType, this._dartName); |
+ |
+ toString() => typeName(_rawJSType()); |
- LazyJSType(this._jsTypeCallback, this._dartName); |
+ rawJSTypeForCheck() { |
+ var raw = _rawJSType(); |
+ if (raw != null) return raw; |
+ _warn('Cannot find native JavaScript type ($_dartName) for type check'); |
+ return _dynamic; |
+ } |
+ |
+ @JSExportName('is') |
+ bool is_T(obj) => instanceOf(obj, rawJSTypeForCheck()); |
- get _rawJSType => JS('', '#()', _jsTypeCallback); |
+ @JSExportName('as') |
+ as_T(obj) => cast(obj, rawJSTypeForCheck()); |
- toString() => _jsTypeCallback != null ? typeName(_rawJSType) : _dartName; |
+ @JSExportName('_check') |
+ check_T(obj) => check(obj, rawJSTypeForCheck()); |
+} |
+ |
+/// An anonymous JS type |
+/// |
+/// For the purposes of subtype checks, these match any JS type. |
+class AnonymousJSType extends TypeRep { |
+ final String _dartName; |
+ AnonymousJSType(this._dartName); |
+ toString() => _dartName; |
+ |
+ @JSExportName('is') |
+ bool is_T(obj) => _isJSType(getReifiedType(obj)); |
+ |
+ @JSExportName('as') |
+ as_T(obj) => is_T(obj) ? obj : cast(obj, this); |
+ |
+ @JSExportName('_check') |
+ check_T(obj) => is_T(obj) ? obj : check(obj, this); |
} |
void _warn(arg) { |
JS('void', 'console.warn(#)', arg); |
} |
-_isInstanceOfLazyJSType(o, LazyJSType t) { |
- if (t._jsTypeCallback != null) { |
- if (t._rawJSType == null) { |
- var expected = t._dartName; |
- var actual = typeName(getReifiedType(o)); |
- _warn('Cannot find native JavaScript type ($expected) ' |
- 'to type check $actual'); |
- return true; |
- } |
- return JS('bool', 'dart.is(#, #)', o, t._rawJSType); |
+bool _isJSType(t) => JS('bool', '!#[dart._runtimeType]', t); |
+ |
+var _lazyJSTypes = JS('', 'new Map()'); |
+var _anonymousJSTypes = JS('', 'new Map()'); |
+ |
+lazyJSType(Function() getJSTypeCallback, String name) { |
+ var ret = JS('', '#.get(#)', _lazyJSTypes, name); |
+ if (ret == null) { |
+ ret = new LazyJSType(getJSTypeCallback, name); |
+ JS('', '#.set(#, #)', _lazyJSTypes, name, ret); |
} |
- if (o == null) return false; |
- // Anonymous case: match any JS type. |
- return _isJSObject(o); |
+ return ret; |
} |
-_asInstanceOfLazyJSType(o, LazyJSType t) { |
- if (t._jsTypeCallback != null) { |
- if (t._rawJSType == null) { |
- var expected = t._dartName; |
- var actual = typeName(getReifiedType(o)); |
- _warn('Cannot find native JavaScript type ($expected) ' |
- 'to type check $actual'); |
- return o; |
- } |
- return JS('bool', 'dart.as(#, #)', o, t._rawJSType); |
+anonymousJSType(String name) { |
+ var ret = JS('', '#.get(#)', _anonymousJSTypes, name); |
+ if (ret == null) { |
+ ret = new AnonymousJSType(name); |
+ JS('', '#.set(#, #)', _anonymousJSTypes, name, ret); |
} |
- // Anonymous case: allow any JS type. |
- if (o == null) return null; |
- if (!_isJSObject(o)) _throwCastError(o, t, true); |
- return o; |
+ return ret; |
} |
-bool _isJSObject(o) => |
- JS('bool', '!dart.getReifiedType(#)[dart._runtimeType]', o); |
- |
-bool _isJSType(t) => JS('bool', '!#[dart._runtimeType]', t); |
- |
@JSExportName('dynamic') |
final _dynamic = new Dynamic(); |
-final _initialize = _initialize2(); |
- |
-_initialize2() => JS( |
- '', |
- '''(() => { |
- // JavaScript API forwards to runtime library. |
- $TypeRep.prototype.is = function is_T(object) { |
- return dart.is(object, this); |
- }; |
- $TypeRep.prototype.as = function as_T(object) { |
- return dart.as(object, this); |
- }; |
- $TypeRep.prototype._check = function check_T(object) { |
- return dart.check(object, this); |
- }; |
- |
- // Fast path for type `dynamic`. |
- $Dynamic.prototype.is = function is_Dynamic(object) { |
- return true; |
- }; |
- $Dynamic.prototype.as = function as_Dynamic(object) { |
- return object; |
- }; |
- $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); |
- }; |
- $LazyJSType.prototype._check = function check_T(object) { |
- return $_asInstanceOfLazyJSType(object, this); |
- }; |
-})()'''); |
- |
class Void extends TypeRep { |
toString() => 'void'; |
} |
@@ -709,14 +703,6 @@ String typeName(type) => JS( |
bool _isFunctionType(type) => JS('bool', '# instanceof # || # === #', type, |
AbstractFunctionType, type, Function); |
-isLazyJSSubtype(t1, LazyJSType t2, isCovariant) { |
- // All JS types are subtypes of anonymous JS types. |
- if (t2._jsTypeCallback == null) { |
- return _isJSType(t1); |
- } |
- return _isSubtype(t1, t2._rawJSType, isCovariant); |
-} |
- |
/// Returns true if [ft1] <: [ft2]. |
/// Returns false if [ft1] </: [ft2] in both spec and strong mode |
/// Returns null if [ft1] </: [ft2] in strong mode, but spec mode |
@@ -891,8 +877,12 @@ bool _isSubtype(t1, t2, isCovariant) => JS( |
if (result === true || result === null) return result; |
} |
+ if ($t2 instanceof $AnonymousJSType) { |
+ // All JS types are subtypes of anonymous JS types. |
+ return $_isJSType($t1); |
+ } |
if ($t2 instanceof $LazyJSType) { |
- return $isLazyJSSubtype($t1, $t2, $isCovariant); |
+ return $_isSubtype($t1, $t2.rawJSTypeForCheck(), isCovariant); |
} |
// Function subtyping. |