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

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

Issue 3003613002: improve DDC's type checks (Closed)
Patch Set: format Created 3 years, 4 months 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
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.

Powered by Google App Engine
This is Rietveld 408576698