| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * This part contains helpers for supporting runtime type information. | 6 * This part contains helpers for supporting runtime type information. |
| 7 * | 7 * |
| 8 * The helper use a mixture of Dart and JavaScript objects. To indicate which is | 8 * The helper use a mixture of Dart and JavaScript objects. To indicate which is |
| 9 * used where we adopt the scheme of using explicit type annotation for Dart | 9 * used where we adopt the scheme of using explicit type annotation for Dart |
| 10 * objects and 'var' or omitted return type for JavaScript objects. | 10 * objects and 'var' or omitted return type for JavaScript objects. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 Type createRuntimeType(String name) => new TypeImpl(name); | 44 Type createRuntimeType(String name) => new TypeImpl(name); |
| 45 | 45 |
| 46 class TypeImpl implements Type { | 46 class TypeImpl implements Type { |
| 47 final String _typeName; | 47 final String _typeName; |
| 48 String _unmangledName; | 48 String _unmangledName; |
| 49 | 49 |
| 50 TypeImpl(this._typeName); | 50 TypeImpl(this._typeName); |
| 51 | 51 |
| 52 String toString() { | 52 String toString() { |
| 53 if (_unmangledName != null) return _unmangledName; | 53 if (_unmangledName != null) return _unmangledName; |
| 54 String unmangledName = unmangleAllIdentifiersIfPreservedAnyways(_typeName); | 54 String unmangledName = |
| 55 unmangleAllIdentifiersIfPreservedAnyways(_typeName); |
| 55 return _unmangledName = unmangledName; | 56 return _unmangledName = unmangledName; |
| 56 } | 57 } |
| 57 | 58 |
| 58 // TODO(ahe): This is a poor hashCode as it collides with its name. | 59 // TODO(ahe): This is a poor hashCode as it collides with its name. |
| 59 int get hashCode => _typeName.hashCode; | 60 int get hashCode => _typeName.hashCode; |
| 60 | 61 |
| 61 bool operator ==(other) { | 62 bool operator ==(other) { |
| 62 return (other is TypeImpl) && _typeName == other._typeName; | 63 return (other is TypeImpl) && _typeName == other._typeName; |
| 63 } | 64 } |
| 64 } | 65 } |
| 65 | 66 |
| 66 /** | 67 /** |
| 67 * Represents a type variable. | 68 * Represents a type variable. |
| 68 * | 69 * |
| 69 * This class holds the information needed when reflecting on generic classes | 70 * This class holds the information needed when reflecting on generic classes |
| 70 * and their members. | 71 * and their members. |
| 71 */ | 72 */ |
| 72 class TypeVariable { | 73 class TypeVariable { |
| 73 final Type owner; | 74 final Type owner; |
| 74 final String name; | 75 final String name; |
| 75 final int bound; | 76 final int bound; |
| 76 | 77 |
| 77 const TypeVariable(this.owner, this.name, this.bound); | 78 const TypeVariable(this.owner, this.name, this.bound); |
| 78 } | 79 } |
| 79 | 80 |
| 80 getMangledTypeName(TypeImpl type) => type._typeName; | 81 getMangledTypeName(TypeImpl type) => type._typeName; |
| 81 | 82 |
| 82 /** | 83 /** |
| 83 * Sets the runtime type information on [target]. [typeInfo] is a type | 84 * Sets the runtime type information on [target]. [rti] is a type |
| 84 * representation of type 4 or 5, that is, either a JavaScript array or | 85 * representation of type 4 or 5, that is, either a JavaScript array or |
| 85 * `null`. | 86 * `null`. |
| 86 */ | 87 */ |
| 87 Object setRuntimeTypeInfo(Object target, var typeInfo) { | 88 Object setRuntimeTypeInfo(Object target, var rti) { |
| 88 assert(typeInfo == null || isJsArray(typeInfo)); | 89 assert(rti == null || isJsArray(rti)); |
| 89 // We have to check for null because factories may return null. | 90 // We have to check for null because factories may return null. |
| 90 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, typeInfo); | 91 if (target != null) JS('var', r'#.$builtinTypeInfo = #', target, rti); |
| 91 return target; | 92 return target; |
| 92 } | 93 } |
| 93 | 94 |
| 94 /** | 95 /** |
| 95 * Returns the runtime type information of [target]. The returned value is a | 96 * Returns the runtime type information of [target]. The returned value is a |
| 96 * list of type representations for the type arguments. | 97 * list of type representations for the type arguments. |
| 97 */ | 98 */ |
| 98 getRuntimeTypeInfo(Object target) { | 99 getRuntimeTypeInfo(Object target) { |
| 99 if (target == null) return null; | 100 if (target == null) return null; |
| 100 return JS('var', r'#.$builtinTypeInfo', target); | 101 return JS('var', r'#.$builtinTypeInfo', target); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 127 | 128 |
| 128 void copyTypeArguments(Object source, Object target) { | 129 void copyTypeArguments(Object source, Object target) { |
| 129 JS('var', r'#.$builtinTypeInfo = #.$builtinTypeInfo', target, source); | 130 JS('var', r'#.$builtinTypeInfo = #.$builtinTypeInfo', target, source); |
| 130 } | 131 } |
| 131 | 132 |
| 132 /** | 133 /** |
| 133 * Retrieves the class name from type information stored on the constructor | 134 * Retrieves the class name from type information stored on the constructor |
| 134 * of [object]. | 135 * of [object]. |
| 135 */ | 136 */ |
| 136 String getClassName(var object) { | 137 String getClassName(var object) { |
| 137 return getDartTypeName(getRawRuntimeType(getInterceptor(object))); | 138 return rawRtiToJsConstructorName(getRawRuntimeType(getInterceptor(object))); |
| 138 } | 139 } |
| 139 | 140 |
| 140 /** | 141 /** |
| 141 * Creates the string representation for the type representation [runtimeType] | 142 * Creates the string representation for the type representation [rti] |
| 142 * of type 4, the JavaScript array, where the first element represents the class | 143 * of type 4, the JavaScript array, where the first element represents the class |
| 143 * and the remaining elements represent the type arguments. | 144 * and the remaining elements represent the type arguments. |
| 144 */ | 145 */ |
| 145 String getRuntimeTypeAsString(var runtimeType, {String onTypeVariable(int i)}) { | 146 String getRuntimeTypeAsString(var rti, {String onTypeVariable(int i)}) { |
| 146 assert(isJsArray(runtimeType)); | 147 assert(isJsArray(rti)); |
| 147 String className = getDartTypeName(getIndex(runtimeType, 0)); | 148 String className = rawRtiToJsConstructorName(getIndex(rti, 0)); |
| 148 return '$className' | 149 return '$className${joinArguments(rti, 1, onTypeVariable: onTypeVariable)}'; |
| 149 '${joinArguments(runtimeType, 1, onTypeVariable: onTypeVariable)}'; | |
| 150 } | 150 } |
| 151 | 151 |
| 152 /** | 152 /** |
| 153 * Returns a human-readable representation of the type representation [type]. | 153 * Returns a human-readable representation of the type representation [rti]. |
| 154 */ | 154 */ |
| 155 String runtimeTypeToString(var type, {String onTypeVariable(int i)}) { | 155 String runtimeTypeToString(var rti, {String onTypeVariable(int i)}) { |
| 156 if (type == null) { | 156 if (rti == null) { |
| 157 return 'dynamic'; | 157 return 'dynamic'; |
| 158 } else if (isJsArray(type)) { | 158 } else if (isJsArray(rti)) { |
| 159 // A list representing a type with arguments. | 159 // A list representing a type with arguments. |
| 160 return getRuntimeTypeAsString(type, onTypeVariable: onTypeVariable); | 160 return getRuntimeTypeAsString(rti, onTypeVariable: onTypeVariable); |
| 161 } else if (isJsFunction(type)) { | 161 } else if (isJsFunction(rti)) { |
| 162 // A reference to the constructor. | 162 // A reference to the constructor. |
| 163 return getDartTypeName(type); | 163 return rawRtiToJsConstructorName(rti); |
| 164 } else if (type is int) { | 164 } else if (rti is int) { |
| 165 if (onTypeVariable == null) { | 165 if (onTypeVariable == null) { |
| 166 return type.toString(); | 166 return rti.toString(); |
| 167 } else { | 167 } else { |
| 168 return onTypeVariable(type); | 168 return onTypeVariable(rti); |
| 169 } | 169 } |
| 170 } else { | 170 } else { |
| 171 // TODO(ahe): Handle function types, and be sure to always return a string. | 171 // TODO(ahe): Handle function types, and be sure to always return a string. |
| 172 return null; | 172 return null; |
| 173 } | 173 } |
| 174 } | 174 } |
| 175 | 175 |
| 176 /** | 176 /** |
| 177 * Creates a comma-separated string of human-readable representations of the | 177 * Creates a comma-separated string of human-readable representations of the |
| 178 * type representations in the JavaScript array [types] starting at index | 178 * type representations in the JavaScript array [types] starting at index |
| (...skipping 22 matching lines...) Expand all Loading... |
| 201 } | 201 } |
| 202 | 202 |
| 203 /** | 203 /** |
| 204 * Returns a human-readable representation of the type of [object]. | 204 * Returns a human-readable representation of the type of [object]. |
| 205 * | 205 * |
| 206 * In minified mode does *not* use unminified identifiers (even when present). | 206 * In minified mode does *not* use unminified identifiers (even when present). |
| 207 */ | 207 */ |
| 208 String getRuntimeTypeString(var object) { | 208 String getRuntimeTypeString(var object) { |
| 209 String className = getClassName(object); | 209 String className = getClassName(object); |
| 210 if (object == null) return className; | 210 if (object == null) return className; |
| 211 var typeInfo = JS('var', r'#.$builtinTypeInfo', object); | 211 var rti = JS('var', r'#.$builtinTypeInfo', object); |
| 212 return "$className${joinArguments(typeInfo, 0)}"; | 212 return "$className${joinArguments(rti, 0)}"; |
| 213 } | 213 } |
| 214 | 214 |
| 215 Type getRuntimeType(var object) { | 215 Type getRuntimeType(var object) { |
| 216 String type = getRuntimeTypeString(object); | 216 String type = getRuntimeTypeString(object); |
| 217 return new TypeImpl(type); | 217 return new TypeImpl(type); |
| 218 } | 218 } |
| 219 | 219 |
| 220 /** | 220 /** |
| 221 * Applies the [substitution] on the [arguments]. | 221 * Applies the [substitution] on the [arguments]. |
| 222 * | 222 * |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 var substitution = getField(interceptor, asField); | 266 var substitution = getField(interceptor, asField); |
| 267 return checkArguments(substitution, arguments, checks); | 267 return checkArguments(substitution, arguments, checks); |
| 268 } | 268 } |
| 269 | 269 |
| 270 /// Returns the field's type name. | 270 /// Returns the field's type name. |
| 271 /// | 271 /// |
| 272 /// In minified mode, uses the unminified names if available. | 272 /// In minified mode, uses the unminified names if available. |
| 273 String computeTypeName(String isField, List arguments) { | 273 String computeTypeName(String isField, List arguments) { |
| 274 // Extract the class name from the is field and append the textual | 274 // Extract the class name from the is field and append the textual |
| 275 // representation of the type arguments. | 275 // representation of the type arguments. |
| 276 return Primitives.formatType(classNameFromIsCheckProperty(isField), | 276 return Primitives.formatType(isCheckPropertyToJsConstructorName(isField), |
| 277 arguments); | 277 arguments); |
| 278 } | 278 } |
| 279 | 279 |
| 280 Object subtypeCast(Object object, String isField, List checks, String asField) { | 280 Object subtypeCast(Object object, String isField, List checks, String asField) { |
| 281 if (object != null && !checkSubtype(object, isField, checks, asField)) { | 281 if (object != null && !checkSubtype(object, isField, checks, asField)) { |
| 282 String actualType = Primitives.objectTypeName(object); | 282 String actualType = Primitives.objectTypeName(object); |
| 283 String typeName = computeTypeName(isField, checks); | 283 String typeName = computeTypeName(isField, checks); |
| 284 // TODO(johnniwinther): Move type lookup to [CastErrorImplementation] to | 284 // TODO(johnniwinther): Move type lookup to [CastErrorImplementation] to |
| 285 // align with [TypeErrorImplementation]. | 285 // align with [TypeErrorImplementation]. |
| 286 throw new CastErrorImplementation(actualType, typeName); | 286 throw new CastErrorImplementation(actualType, typeName); |
| (...skipping 381 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 668 * `null` and `undefined` (which we can avoid). | 668 * `null` and `undefined` (which we can avoid). |
| 669 */ | 669 */ |
| 670 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); | 670 bool isIdentical(var s, var t) => JS('bool', '# === #', s, t); |
| 671 | 671 |
| 672 /** | 672 /** |
| 673 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use | 673 * Returns `true` if the JavaScript values [s] and [t] are not identical. We use |
| 674 * this helper instead of [identical] because `identical` needs to merge | 674 * this helper instead of [identical] because `identical` needs to merge |
| 675 * `null` and `undefined` (which we can avoid). | 675 * `null` and `undefined` (which we can avoid). |
| 676 */ | 676 */ |
| 677 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); | 677 bool isNotIdentical(var s, var t) => JS('bool', '# !== #', s, t); |
| OLD | NEW |