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 a7b2f06a280802240ec6c0f0e40707368b3c3077..99a5ac7ca85946a11a3ee89dfdbb79c5771fbfc0 100644 |
--- a/lib/compiler/implementation/lib/js_helper.dart |
+++ b/lib/compiler/implementation/lib/js_helper.dart |
@@ -409,7 +409,7 @@ class Primitives { |
/** [: @"$".charCodeAt(0) :] */ |
static final int DOLLAR_CHAR_VALUE = 36; |
- static String objectToString(Object object) { |
+ static String objectTypeName(Object object) { |
String name = constructorNameFallback(object); |
if (name == 'Object') { |
// Try to decompile the constructor by turning it into a string |
@@ -422,6 +422,11 @@ class Primitives { |
// TODO(kasperl): If the namer gave us a fresh global name, we may |
// want to remove the numeric suffix that makes it unique too. |
if (name.charCodeAt(0) === DOLLAR_CHAR_VALUE) name = name.substring(1); |
+ return name; |
+ } |
+ |
+ static String objectToString(Object object) { |
+ String name = objectTypeName(object); |
return "Instance of '$name'"; |
} |
@@ -978,8 +983,8 @@ getRuntimeTypeInfo(target) { |
/** |
* 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; |
@@ -987,42 +992,80 @@ stringTypeCheck(value) { |
throw new TypeError('$value does not implement String'); |
} |
+stringTypeCast(value) { |
ngeoffray
2012/08/27 14:24:00
These helpers share sooo much with their checked m
|
+ if (value is String || value === null) return value; |
+ // TODO(lrn): When reified types are available, pass value.class and String. |
+ throw new CastException(Primitives.objectTypeName(value), '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 is double || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), '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 is num || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), '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 is bool || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), '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 is Function || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), '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 is int || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), '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 actualType = Primitives.objectTypeName(value); |
+ String expectedType = property.substring(3, property.length); |
+ throw new CastException(actualType, expectedType); |
+} |
+ |
/** |
* For types that are not supertypes of native (eg DOM) types, |
* we emit a simple property check to check that an object implements |
@@ -1035,6 +1078,16 @@ propertyTypeCheck(value, property) { |
} |
/** |
+ * For types that are not supertypes of native (eg DOM) types, |
+ * we emit a simple property check to check that an object implements |
+ * that type. |
+ */ |
+propertyTypeCast(value, property) { |
+ if (value === null || 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 |
* time. |
@@ -1049,6 +1102,20 @@ callTypeCheck(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 |
+ * time. |
+ */ |
+callTypeCast(value, property) { |
+ if (value === null |
+ || ((JS('bool', 'typeof # === "object"', value)) |
+ && 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. |
*/ |
@@ -1059,6 +1126,11 @@ stringSuperTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+stringSuperTypeCast(value, property) { |
+ if (value is String) return value; |
+ return propertyTypeCast(value, property); |
+} |
+ |
stringSuperNativeTypeCheck(value, property) { |
if (value === null) return value; |
if (value is String) return value; |
@@ -1066,6 +1138,12 @@ stringSuperNativeTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+stringSuperNativeTypeCast(value, property) { |
+ if (value is String || value === null) 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. |
@@ -1076,6 +1154,11 @@ listTypeCheck(value) { |
throw new TypeError('$value does not implement List'); |
} |
+listTypeCast(value) { |
+ if (value is List || value === null) return value; |
+ throw new CastException(Primitives.objectTypeName(value), 'List'); |
+} |
+ |
listSuperTypeCheck(value, property) { |
if (value === null) return value; |
if (value is List) return value; |
@@ -1083,6 +1166,11 @@ listSuperTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+listSuperTypeCast(value, property) { |
+ if (value is List) return value; |
+ return propertyTypeCast(value, property); |
+} |
+ |
listSuperNativeTypeCheck(value, property) { |
if (value === null) return value; |
if (value is List) return value; |
@@ -1090,6 +1178,12 @@ listSuperNativeTypeCheck(value, property) { |
propertyTypeError(value, property); |
} |
+listSuperNativeTypeCast(value, property) { |
+ if (value is List || value === null) return value; |
+ if (JS('bool', '#[#]()', value, property)) return value; |
+ propertyTypeCastError(value, property); |
+} |
+ |
/** |
* Special interface recognized by the compiler and implemented by DOM |
* objects that support integer indexing. This interface is not |