Index: lib/compiler/implementation/lib/js_helper.dart |
diff --git a/lib/compiler/implementation/lib/js_helper.dart b/lib/compiler/implementation/lib/js_helper.dart |
index 55f0bbabd8a21b56b65c26a32c6b70e68f74b8cd..298d58a45c2971ba0166f35db3bca28f7febe746 100644 |
--- a/lib/compiler/implementation/lib/js_helper.dart |
+++ b/lib/compiler/implementation/lib/js_helper.dart |
@@ -951,10 +951,15 @@ getRuntimeTypeInfo(target) { |
return JS('var', @'#.builtin$typeInfo', target); |
} |
+ |
+class CastException extends TypeError { |
+ CastException(String message): super(message); |
+} |
+ |
/** |
* The following methods are called by the runtime to implement |
- * checked mode. We specialize each primitive type (eg int, bool), and |
- * use the compiler's convention to do is checks on regular objects. |
+ * checked mode and casts. We specialize each primitive type (eg int, bool), and |
+ * use the compiler's convention to do is-checks on regular objects. |
*/ |
stringTypeCheck(value) { |
if (value === null) return value; |
@@ -962,42 +967,84 @@ stringTypeCheck(value) { |
throw new TypeError('$value does not implement String'); |
} |
+stringTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is String) return value; |
+ throw new CastException('$value does not implement String'); |
+} |
+ |
doubleTypeCheck(value) { |
if (value === null) return value; |
if (value is double) return value; |
throw new TypeError('$value does not implement double'); |
} |
+doubleTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is double) return value; |
+ throw new CastException('$value does not implement double'); |
+} |
+ |
numTypeCheck(value) { |
if (value === null) return value; |
if (value is num) return value; |
throw new TypeError('$value does not implement num'); |
} |
+numTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is num) return value; |
+ throw new CastException('$value does not implement num'); |
+} |
+ |
boolTypeCheck(value) { |
if (value === null) return value; |
if (value is bool) return value; |
throw new TypeError('$value does not implement bool'); |
} |
+boolTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is bool) return value; |
+ throw new CastException('$value does not implement bool'); |
+} |
+ |
functionTypeCheck(value) { |
if (value === null) return value; |
if (value is Function) return value; |
throw new TypeError('$value does not implement Function'); |
} |
+functionTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is Function) return value; |
+ throw new CastException('$value does not implement Function'); |
+} |
+ |
intTypeCheck(value) { |
if (value === null) return value; |
if (value is int) return value; |
throw new TypeError('$value does not implement int'); |
} |
+intTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is int) return value; |
+ throw new CastException('$value does not implement int'); |
+} |
+ |
void propertyTypeError(value, property) { |
// Cuts the property name to the class name. |
String name = property.substring(3, property.length); |
throw new TypeError('$value does not implement $name'); |
} |
+void propertyTypeCastError(value, property) { |
+ // Cuts the property name to the class name. |
+ String name = property.substring(3, property.length); |
+ throw new CastException('$value does not implement $name'); |
+} |
+ |
/** |
* For types that are not supertypes of native (eg DOM) types, |
* we emit a simple property check to check that an object implements |
@@ -1009,6 +1056,12 @@ propertyTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+propertyTypeCast(Object value, Object property) { |
+ if (value === null) throw new NullPointerException(); |
+ if (JS('bool', '!!#[#]', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |
+ |
/** |
* For types that are supertypes of native (eg DOM) types, we emit a |
* call because we cannot add a JS property to their prototype at load |
@@ -1023,6 +1076,15 @@ callTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+callTypeCast(value, property) { |
+ if (value === null) throw new NullPointerException(); |
+ if ((JS('String', 'typeof #', value) === 'object') |
+ && JS('bool', '#[#]()', value, property)) { |
+ return value; |
+ } |
+ propertyTypeCastError(value, property); |
+} |
+ |
/** |
* Specialization of the type check for String and its supertype |
* since [value] can be a JS primitive. |
@@ -1034,6 +1096,13 @@ stringSuperTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+stringSuperTypeCast(value, property) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is String) return value; |
+ if (JS('bool', '!!#[#]', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |
+ |
stringSuperNativeTypeCheck(value, property) { |
if (value === null) return value; |
if (value is String) return value; |
@@ -1041,6 +1110,13 @@ stringSuperNativeTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+stringSuperNativeTypeCast(value, property) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is String) return value; |
+ if (JS('bool', '#[#]()', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |
+ |
/** |
* Specialization of the type check for List and its supertypes, |
* since [value] can be a JS array. |
@@ -1051,6 +1127,12 @@ listTypeCheck(value) { |
throw new TypeError('$value does not implement List'); |
} |
+listTypeCast(value) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is List) return value; |
+ throw new CastException('$value does not implement List'); |
+} |
+ |
listSuperTypeCheck(value, property) { |
if (value === null) return value; |
if (value is List) return value; |
@@ -1058,9 +1140,23 @@ listSuperTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+listSuperTypeCast(value, property) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is List) return value; |
+ if (JS('bool', '!!#[#]', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |
+ |
listSuperNativeTypeCheck(value, property) { |
if (value === null) return value; |
if (value is List) return value; |
if (JS('bool', '#[#]()', value, property)) return value; |
propertyTypeError(value, property); |
} |
+ |
+listSuperNativeTypeCast(value, property) { |
+ if (value === null) throw new NullPointerException(); |
+ if (value is List) return value; |
+ if (JS('bool', '#[#]()', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |