| 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);
|
| +}
|
|
|