| 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.
|
|
|