| 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) {
|
| + 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
|
|
|