Index: pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
diff --git a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
index 91f541ea3cf5789bb0091a2c03ac2ee745ba91be..48261a20b2ac1d9868af4211470fa266edabfdaa 100644 |
--- a/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
+++ b/pkg/dev_compiler/tool/input_sdk/private/ddc_runtime/operations.dart |
@@ -154,7 +154,7 @@ dputMirror(obj, field, value) { |
var setterType = getSetterType(getType(obj), f); |
if (setterType != null) { |
setterType = _stripGenericArguments(setterType); |
- return JS('', '#[#] = #', obj, f, check(value, setterType)); |
+ return JS('', '#[#] = #._check(#)', obj, f, setterType, value); |
} |
} |
return noSuchMethod( |
@@ -167,7 +167,7 @@ dput(obj, field, value) { |
if (f != null) { |
var setterType = getSetterType(getType(obj), f); |
if (setterType != null) { |
- return JS('', '#[#] = #', obj, f, check(value, setterType)); |
+ return JS('', '#[#] = #._check(#)', obj, f, setterType, value); |
} |
// Always allow for JS interop objects. |
if (isJsInterop(obj)) { |
@@ -189,7 +189,7 @@ _checkApply(type, actuals) => JS('', '''(() => { |
if ($actuals.length < $type.args.length) return false; |
let index = 0; |
for(let i = 0; i < $type.args.length; ++i) { |
- $check($actuals[i], $type.args[i]); |
+ $type.args[i]._check($actuals[i]); |
++index; |
} |
if ($actuals.length == $type.args.length) return true; |
@@ -197,7 +197,7 @@ _checkApply(type, actuals) => JS('', '''(() => { |
if ($type.optionals.length > 0) { |
if (extras > $type.optionals.length) return false; |
for(let i = 0, j=index; i < extras; ++i, ++j) { |
- $check($actuals[j], $type.optionals[i]); |
+ $type.optionals[i]._check($actuals[j]); |
} |
return true; |
} |
@@ -215,7 +215,7 @@ _checkApply(type, actuals) => JS('', '''(() => { |
if (!($hasOwnProperty.call($type.named, name))) { |
return false; |
} |
- $check(opts[name], $type.named[name]); |
+ $type.named[name]._check(opts[name]); |
} |
return true; |
})()'''); |
@@ -482,68 +482,30 @@ final _ignoreTypeFailure = JS('', '''(() => { |
}); |
})()'''); |
-/// Returns true if [obj] is an instance of [type] in strong mode, otherwise |
-/// false. |
-/// |
-/// This also allows arbitrary JS function objects to be subtypes of every Dart |
-/// function types. |
-bool strongInstanceOf(obj, type, ignoreFromWhiteList) => JS('', '''(() => { |
- let actual = $getReifiedType($obj); |
- let result = $isSubtype(actual, $type); |
- if (result || |
- (actual == $int && $isSubtype($double, $type)) || |
- (actual == $jsobject && $_isFunctionType(type) && |
- typeof(obj) === 'function')) { |
- return true; |
- } |
- if (result === null && |
- dart.__ignoreWhitelistedErrors && |
- $ignoreFromWhiteList && |
- $_ignoreTypeFailure(actual, $type)) { |
- return true; |
- } |
- return false; |
-})()'''); |
- |
-/// Returns true if [obj] is null or an instance of [type] |
-/// Returns false if [obj] is non-null and not an instance of [type] |
-/// in strong mode |
-bool instanceOfOrNull(obj, type) { |
- // If strongInstanceOf returns null, convert to false here. |
- return obj == null || JS('bool', '#', strongInstanceOf(obj, type, true)); |
-} |
- |
@JSExportName('is') |
bool instanceOf(obj, type) { |
if (obj == null) { |
return JS('bool', '# == # || #', type, Null, _isTop(type)); |
} |
- return strongInstanceOf(obj, type, false); |
+ return JS('#', '!!#', isSubtype(getReifiedType(obj), type)); |
} |
@JSExportName('as') |
-cast(obj, type) { |
- if (JS('bool', '# == #', type, dynamic) || obj == null) return obj; |
- bool result = strongInstanceOf(obj, type, true); |
- if (JS('bool', '#', result)) return obj; |
- if (JS('bool', '!dart.__ignoreAllErrors')) { |
- _throwCastError(obj, type, result); |
- } |
- JS('', 'console.error(#)', |
- 'Actual: ${typeName(getReifiedType(obj))} Expected: ${typeName(type)}'); |
- return obj; |
-} |
- |
-check(obj, type) { |
- if (JS('bool', '# == #', type, dynamic) || obj == null) return obj; |
- bool result = strongInstanceOf(obj, type, true); |
- if (JS('bool', '#', result)) return obj; |
- if (JS('bool', '!dart.__ignoreAllErrors')) { |
- _throwTypeError(obj, type, result); |
+cast(obj, type, bool typeError) { |
+ if (obj == null) return obj; |
+ var actual = getReifiedType(obj); |
+ var result = isSubtype(actual, type); |
+ if (JS( |
+ 'bool', |
+ '# === true || # === null && dart.__ignoreWhitelistedErrors && #(#, #)', |
+ result, |
+ result, |
+ _ignoreTypeFailure, |
+ actual, |
+ type)) { |
+ return obj; |
} |
- JS('', 'console.error(#)', |
- 'Actual: ${typeName(getReifiedType(obj))} Expected: ${typeName(type)}'); |
- return obj; |
+ return castError(obj, type, typeError); |
} |
bool test(bool obj) { |
@@ -570,64 +532,34 @@ void booleanConversionFailed(obj) { |
"type '${typeName(expected)}' in boolean expression"); |
} |
-void _throwCastError(obj, type, bool result) { |
- var actual = getReifiedType(obj); |
- if (result == false) throwCastError(obj, actual, type); |
+castError(obj, type, bool typeError) { |
+ var objType = getReifiedType(obj); |
+ if (JS('bool', '!dart.__ignoreAllErrors')) { |
+ var errorInStrongMode = isSubtype(objType, type) == null; |
- throwStrongModeCastError(obj, actual, type); |
-} |
+ var actual = typeName(objType); |
+ var expected = typeName(type); |
+ if (JS('bool', 'dart.__trapRuntimeErrors')) JS('', 'debugger'); |
-void _throwTypeError(obj, type, bool result) { |
- var actual = getReifiedType(obj); |
- if (result == false) throwTypeError(obj, actual, type); |
- |
- throwStrongModeTypeError(obj, actual, type); |
+ var error = JS('bool', '#', typeError) |
+ ? new TypeErrorImplementation(obj, actual, expected, errorInStrongMode) |
+ : new CastErrorImplementation(obj, actual, expected, errorInStrongMode); |
+ throw error; |
+ } |
+ JS('', 'console.error(#)', |
+ 'Actual: ${typeName(objType)} Expected: ${typeName(type)}'); |
+ return obj; |
} |
asInt(obj) { |
if (obj == null) return null; |
if (JS('bool', 'Math.floor(#) != #', obj, obj)) { |
- throwCastError(obj, getReifiedType(obj), JS('', '#', int)); |
+ castError(obj, JS('', '#', int), false); |
} |
return obj; |
} |
-/// Adds type type test predicates to a constructor for a non-parameterized |
-/// type. Non-parameterized types can use `instanceof` for subclass checks and |
-/// fall through to a helper for subtype tests. |
-addSimpleTypeTests(ctor) => JS('', '''(() => { |
- $ctor.is = function is_C(object) { |
- // This is incorrect for classes [Null] and [Object], so we do not use |
- // [addSimpleTypeTests] for these classes. |
- if (object instanceof this) return true; |
- return dart.is(object, this); |
- }; |
- $ctor.as = function as_C(object) { |
- if (object instanceof this) return object; |
- return dart.as(object, this); |
- }; |
- $ctor._check = function check_C(object) { |
- if (object instanceof this) return object; |
- return dart.check(object, this); |
- }; |
-})()'''); |
- |
-/// Adds type type test predicates to a constructor. Used for parmeterized |
-/// types. We avoid `instanceof` for, e.g. `x is ListQueue` since there is |
-/// no common class for `ListQueue<int>` and `ListQueue<String>`. |
-addTypeTests(ctor) => JS('', '''(() => { |
- $ctor.as = function as_G(object) { |
- return dart.as(object, this); |
- }; |
- $ctor.is = function is_G(object) { |
- return dart.is(object, this); |
- }; |
- $ctor._check = function check_G(object) { |
- return dart.check(object, this); |
- }; |
-})()'''); |
- |
// TODO(vsm): Consider optimizing this. We may be able to statically |
// determine which == operation to invoke given the static types. |
equals(x, y) => JS('', '''(() => { |
@@ -933,21 +865,29 @@ noSuchMethod(obj, Invocation invocation) { |
constFn(x) => JS('', '() => x'); |
runtimeType(obj) { |
- // Handle primitives where the method isn't on the object. |
- var result = _checkPrimitiveType(obj); |
- if (result != null) return wrapType(result); |
- |
- // Delegate to the (possibly user-defined) method on the object. |
- var extension = getExtensionType(obj); |
- if (extension != null) { |
- result = JS('', '#[dartx.runtimeType]', obj); |
- // If extension doesn't override runtimeType, return the extension type. |
- return result ?? wrapType(extension); |
- } |
- if (JS('bool', 'typeof # == "function" && # instanceof Function', obj, obj)) { |
- return wrapType(getReifiedType(obj)); |
+ if (obj == null) return Null; |
+ if (JS('bool', '# instanceof #', obj, Object)) { |
+ // A normal Dart object: get `obj.runtimeType` |
+ // (callable Dart classes are also handled here) |
+ return JS('', '#.runtimeType', obj); |
+ } |
+ if (JS('bool', 'typeof obj == "object"')) { |
+ // Some other kind of JS object. |
+ var extensionType = JS('', '#[#]', obj, _extensionType); |
+ if (extensionType != null) { |
+ // An extension type: get `obj[dartx.runtimeType]` |
+ var result = JS('', '#[dartx.runtimeType]', obj); |
+ // If the extension doesn't override runtimeType, handle that. |
+ // TODO(jmesserly): is this still possible? Object members should always |
+ // be defined on extension types. |
+ if (result != null) return result; |
+ } else { |
+ extensionType = jsobject; |
+ } |
+ return wrapType(extensionType); |
} |
- return JS('', '#.runtimeType', obj); |
+ // All other types: fall back to `getReifiedType` |
+ return wrapType(getReifiedType(obj)); |
} |
/// Implements Dart's interpolated strings as ES2015 tagged template literals. |