Chromium Code Reviews| 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 f3c907e8ee937792a8265dc45fae038e7024b957..e6194108efb87fc8fdff0a544e7347d671937f06 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); |
|
vsm
2017/06/30 18:08:48
nice :-)
|
| + |
| + @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. |