| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 // The following methods are used to handle type information | 5 // The following methods are used to handle type information |
| 6 // | 6 // |
| 7 | 7 |
| 8 /** | 8 /** |
| 9 * @constructor | 9 * @constructor |
| 10 * @param {string} classkey | 10 * @param {string} classkey |
| 11 * @param {string=} typekey | 11 * @param {string=} typekey |
| 12 * @param {Array.<RTT>=} typeargs | 12 * @param {Array.<RTT>=} typeargs |
| 13 * @param {RTT} returnType | 13 * @param {RTT} returnType |
| 14 * @param {bool} functionType | 14 * @param {bool} functionType |
| 15 * @param {string=} named optional |
| 15 */ | 16 */ |
| 16 function RTT(classkey, typekey, typeargs, returnType, functionType) { | 17 function RTT(classkey, typekey, typeargs, returnType, functionType, named) { |
| 17 this.classKey = classkey; | 18 this.classKey = classkey; |
| 18 this.typeKey = typekey ? typekey : classkey; | 19 this.typeKey = typekey ? typekey : classkey; |
| 19 this.typeArgs = typeargs; | 20 this.typeArgs = typeargs; |
| 20 this.returnType = returnType; // key for the return type | 21 this.returnType = returnType; // key for the return type |
| 22 this.named = named; |
| 21 this.implementedTypes = {}; | 23 this.implementedTypes = {}; |
| 22 this.functionType = functionType; | 24 this.functionType = functionType; |
| 23 // Add self | 25 // Add self |
| 24 this.implementedTypes[classkey] = this; | 26 this.implementedTypes[classkey] = this; |
| 25 // Add Object | 27 // Add Object |
| 26 if (!functionType && classkey != $cls('Object')) { | 28 if (!functionType && classkey != $cls('Object')) { |
| 27 this.implementedTypes[$cls('Object')] = RTT.objectType; | 29 this.implementedTypes[$cls('Object')] = RTT.objectType; |
| 28 } | 30 } |
| 29 } | 31 } |
| 30 | 32 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 61 RTT.prototype.implementedByTypeSwitch = function(value){ | 63 RTT.prototype.implementedByTypeSwitch = function(value){ |
| 62 return this.functionType ? this.implementedByTypeFunc(value) : | 64 return this.functionType ? this.implementedByTypeFunc(value) : |
| 63 this.implementedByType(value); | 65 this.implementedByType(value); |
| 64 }; | 66 }; |
| 65 | 67 |
| 66 /** | 68 /** |
| 67 * @param {!RTT} other | 69 * @param {!RTT} other |
| 68 * @return {boolean} Whether this type is implement by other | 70 * @return {boolean} Whether this type is implement by other |
| 69 */ | 71 */ |
| 70 RTT.prototype.implementedByType = function(otherType) { | 72 RTT.prototype.implementedByType = function(otherType) { |
| 71 if (otherType === this || otherType === RTT.dynamicType) { | 73 if (otherType === this || otherType === RTT.dynamicType.$lookupRTT(null,otherT
ype.named)) { |
| 72 return true; | 74 return true; |
| 73 } | 75 } |
| 74 var targetTypeInfo = $mapLookup(otherType.implementedTypes, this.classKey); | 76 var targetTypeInfo = $mapLookup(otherType.implementedTypes, this.classKey); |
| 75 if (targetTypeInfo == null) { | 77 if (targetTypeInfo == null) { |
| 76 return false; | 78 return false; |
| 77 } | 79 } |
| 78 if (targetTypeInfo.typeArgs && this.typeArgs) { | 80 if (targetTypeInfo.typeArgs && this.typeArgs) { |
| 79 for(var i = this.typeArgs.length - 1; i >= 0; i--) { | 81 for(var i = this.typeArgs.length - 1; i >= 0; i--) { |
| 80 if (!this.typeArgs[i].implementedByTypeSwitch(targetTypeInfo.typeArgs[i]))
{ | 82 if (!this.typeArgs[i].implementedByTypeSwitch(targetTypeInfo.typeArgs[i]))
{ |
| 81 return false; | 83 return false; |
| 82 } | 84 } |
| 83 } | 85 } |
| 84 } | 86 } |
| 85 return true; | 87 return true; |
| 86 }; | 88 }; |
| 87 | 89 |
| 88 /** | 90 /** |
| 89 * @param {!RTT} other | 91 * @param {!RTT} other |
| 90 * @return {boolean} Whether this type is assignable by other | 92 * @return {boolean} Whether this type is assignable by other |
| 91 */ | 93 */ |
| 92 RTT.prototype.assignableByType = function(otherType) { | 94 RTT.prototype.assignableByType = function(otherType) { |
| 93 if (otherType === this || otherType === RTT.dynamicType || this === RTT.dynami
cType) { | 95 if (otherType === this || otherType === RTT.dynamicType.$lookupRTT(null,otherT
ype.named) |
| 96 || this === RTT.dynamicType.$lookupRTT(null,this.named)) { |
| 94 return true; | 97 return true; |
| 95 } | 98 } |
| 96 var targetTypeInfo = $mapLookup(otherType.implementedTypes, this.classKey); | 99 var targetTypeInfo = $mapLookup(otherType.implementedTypes, this.classKey); |
| 97 if (targetTypeInfo == null) { | 100 if (targetTypeInfo == null) { |
| 98 targetTypeInfo = $mapLookup(this.implementedTypes, otherType.classKey); | 101 targetTypeInfo = $mapLookup(this.implementedTypes, otherType.classKey); |
| 99 if (targetTypeInfo == null) { | 102 if (targetTypeInfo == null) { |
| 100 return false; | 103 return false; |
| 101 } | 104 } |
| 102 } | 105 } |
| 103 if (targetTypeInfo.typeArgs && this.typeArgs) { | 106 if (targetTypeInfo.typeArgs && this.typeArgs) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 114 /** | 117 /** |
| 115 * @param {!RTT} other | 118 * @param {!RTT} other |
| 116 * @return {boolean} Whether this type is implemented by other | 119 * @return {boolean} Whether this type is implemented by other |
| 117 */ | 120 */ |
| 118 RTT.prototype.implementedByTypeFunc = function(otherType) { | 121 RTT.prototype.implementedByTypeFunc = function(otherType) { |
| 119 if (otherType.$lookupRTT) { | 122 if (otherType.$lookupRTT) { |
| 120 otherType = otherType.$lookupRTT(); | 123 otherType = otherType.$lookupRTT(); |
| 121 } else if (!(otherType instanceof RTT)) { | 124 } else if (!(otherType instanceof RTT)) { |
| 122 return false; | 125 return false; |
| 123 } | 126 } |
| 124 if (otherType === this || otherType === RTT.dynamicType) { | 127 if (otherType === this || otherType === RTT.dynamicType.$lookupRTT(null,otherT
ype.named)) { |
| 125 return true; | 128 return true; |
| 126 } | 129 } |
| 127 var props = Object.getOwnPropertyNames(otherType.implementedTypes); | 130 var props = Object.getOwnPropertyNames(otherType.implementedTypes); |
| 128 NEXT_PROPERTY: for (var i = 0 ; i < props.length; i++) { | 131 NEXT_PROPERTY: for (var i = 0 ; i < props.length; i++) { |
| 129 var mapped = otherType.implementedTypes[props[i]]; | 132 var mapped = otherType.implementedTypes[props[i]]; |
| 130 if (mapped.returnType && this.returnType && | 133 if (mapped.returnType && this.returnType && |
| 131 !this.returnType.assignableByType(mapped.returnType)) { | 134 !this.returnType.assignableByType(mapped.returnType)) { |
| 132 continue; | 135 continue; |
| 133 } | 136 } |
| 134 if (mapped.typeArgs && this.typeArgs) { | 137 if (mapped.typeArgs && this.typeArgs) { |
| 135 if (this.typeArgs.length != mapped.typeArgs.length) { | 138 if (mapped.typeArgs.length < this.typeArgs.length) { |
| 136 continue; | 139 continue; |
| 137 } | 140 } |
| 138 for (var x = this.typeArgs.length - 1; x >= 0; x--) { | 141 var named = false; |
| 142 var x; |
| 143 for (x = 0; x < this.typeArgs.length; x++) { |
| 144 if (this.typeArgs[x].named || mapped.typeArgs[x].named) { |
| 145 named = true; |
| 146 break; |
| 147 } |
| 139 if (!this.typeArgs[x].assignableByType(mapped.typeArgs[x])) { | 148 if (!this.typeArgs[x].assignableByType(mapped.typeArgs[x])) { |
| 140 continue NEXT_PROPERTY; | 149 continue NEXT_PROPERTY; |
| 141 } | 150 } |
| 142 } | 151 } |
| 152 if (!named && x < this.typeArgs.length) { |
| 153 continue NEXT_PROPERTY; |
| 154 } |
| 155 for (; x < this.typeArgs.length; x++) { |
| 156 if (!this.typeArgs[x].assignableByType(mapped.typeArgs[x]) |
| 157 || !(this.typeArgs[x].named === mapped.typeArgs[x].named)) { |
| 158 continue NEXT_PROPERTY; |
| 159 } |
| 160 } |
| 143 } else if (mapped.typeArgs || this.typeArgs) { | 161 } else if (mapped.typeArgs || this.typeArgs) { |
| 144 return false; | 162 continue NEXT_PROPERTY; |
| 145 } | 163 } |
| 146 return true; | 164 return true; |
| 147 } | 165 } |
| 148 return false; | 166 return false; |
| 149 }; | 167 }; |
| 150 | 168 |
| 151 /** | 169 /** |
| 152 * @return {string} the class name associated with this type | 170 * @return {string} the class name associated with this type |
| 153 */ | 171 */ |
| 154 RTT.prototype.getClassName = function() { | 172 RTT.prototype.getClassName = function() { |
| 155 var name = this.classKey; | 173 var name = this.classKey; |
| 156 if (name.substr(0, 4) == "cls:") { | 174 if (name.substr(0, 4) == "cls:") { |
| 157 name = name.substr(4); | 175 name = name.substr(4); |
| 158 } | 176 } |
| 159 if (name.substr(-5) == "$Dart") { | 177 if (name.substr(-5) == "$Dart") { |
| 160 name = name.substr(0, name.length - 5); | 178 name = name.substr(0, name.length - 5); |
| 161 } | 179 } |
| 162 return name; | 180 return name; |
| 163 } | 181 } |
| 164 | 182 |
| 165 /** | 183 /** |
| 166 * @param {RTT} | 184 * @param {RTT} |
| 167 * @return {boolean} | 185 * @return {boolean} |
| 168 */ | 186 */ |
| 169 RTT.nullInstanceOf = function(type) { | 187 RTT.nullInstanceOf = function(type) { |
| 170 return type === RTT.objectType || type === RTT.dynamicType; | 188 return type === RTT.objectType || type === RTT.dynamicType.$lookupRTT(null,typ
e.named); |
| 171 }; | 189 }; |
| 172 | 190 |
| 173 /** | 191 /** |
| 174 * @param {*} value The value to retrieve type information for | 192 * @param {*} value The value to retrieve type information for |
| 175 * @return {RTT} | 193 * @return {RTT} |
| 176 */ | 194 */ |
| 177 RTT.getNativeTypeInfo = function(value) { | 195 RTT.getNativeTypeInfo = function(value) { |
| 178 if (value instanceof Array) return Array.$lookupRTT(); | 196 if (value instanceof Array) return Array.$lookupRTT(); |
| 179 switch (typeof value) { | 197 switch (typeof value) { |
| 180 case 'string': return String.$lookupRTT(); | 198 case 'string': return String.$lookupRTT(); |
| 181 case 'number': return Number.$lookupRTT(); | 199 case 'number': return Number.$lookupRTT(); |
| 182 case 'boolean': return Boolean.$lookupRTT(); | 200 case 'boolean': return Boolean.$lookupRTT(); |
| 183 } | 201 } |
| 184 return RTT.placeholderType; | 202 return RTT.placeholderType; |
| 185 }; | 203 }; |
| 186 | 204 |
| 187 /** | 205 /** |
| 188 * @param {string} name | 206 * @param {string} name |
| 189 * @param {function(RTT,Array.<RTT>)=} implementsSupplier | 207 * @param {function(RTT,Array.<RTT>)=} implementsSupplier |
| 190 * @param {Array.<RTT>=} typeArgs | 208 * @param {Array.<RTT>=} typeArgs |
| 209 * @param {string} named optional value |
| 191 * @return {RTT} The RTT information object | 210 * @return {RTT} The RTT information object |
| 192 */ | 211 */ |
| 193 RTT.create = function(name, implementsSupplier, typeArgs) { | 212 RTT.create = function(name, implementsSupplier, typeArgs, named) { |
| 194 if (name == $cls("Object")) return RTT.objectType; | 213 if (name == $cls("Object") && !named) return RTT.objectType; |
| 195 var typekey = RTT.getTypeKey(name, typeArgs); | 214 var typekey = RTT.getTypeKey(name, typeArgs, null, named); |
| 196 var rtt = $mapLookup(RTT.types, typekey); | 215 var rtt = $mapLookup(RTT.types, typekey); |
| 197 if (rtt) { | 216 if (rtt) { |
| 198 return rtt; | 217 return rtt; |
| 199 } | 218 } |
| 200 var classkey = RTT.getTypeKey(name); | 219 var classkey = RTT.getTypeKey(name); |
| 201 rtt = new RTT(classkey, typekey, typeArgs); | 220 rtt = new RTT(classkey, typekey, typeArgs, null, false, named); |
| 202 RTT.types[typekey] = rtt; | 221 RTT.types[typekey] = rtt; |
| 203 if (implementsSupplier) { | 222 if (implementsSupplier) { |
| 204 implementsSupplier(rtt, typeArgs); | 223 implementsSupplier(rtt, typeArgs); |
| 205 } | 224 } |
| 206 return rtt; | 225 return rtt; |
| 207 }; | 226 }; |
| 208 | 227 |
| 209 /** | 228 /** |
| 210 * @param {Array.<RTT>=} typeArgs | 229 * @param {Array.<RTT>=} typeArgs |
| 211 * @param {<RTT>=} returnType (if defined) | 230 * @param {<RTT>=} returnType (if defined) |
| 231 * @param {string} named optional value |
| 212 * @return {RTT} The RTT information object | 232 * @return {RTT} The RTT information object |
| 213 */ | 233 */ |
| 214 RTT.createFunction = function(typeArgs, returnType) { | 234 RTT.createFunction = function(typeArgs, returnType, named) { |
| 215 var name = $cls("Function"); | 235 var name = $cls("Function$Dart"); |
| 216 var typekey = RTT.getTypeKey(name, typeArgs, returnType); | 236 var typekey = RTT.getTypeKey(name, typeArgs, returnType, named); |
| 217 var rtt = $mapLookup(RTT.types, typekey); | 237 var rtt = $mapLookup(RTT.types, typekey); |
| 218 if (rtt) { | 238 if (rtt) { |
| 219 return rtt; | 239 return rtt; |
| 220 } | 240 } |
| 221 var classkey = RTT.getTypeKey(name); | 241 var classkey = RTT.getTypeKey(name); |
| 222 rtt = new RTT(classkey, typekey, typeArgs, returnType, true); | 242 rtt = new RTT(classkey, typekey, typeArgs, returnType, true, named); |
| 223 RTT.types[typekey] = rtt; | 243 RTT.types[typekey] = rtt; |
| 224 return rtt; | 244 return rtt; |
| 225 }; | 245 }; |
| 226 | 246 |
| 247 /** |
| 248 * @param {RTT} old |
| 249 * @param {string} named optional |
| 250 * @return {RTT} The RTT information object with named |
| 251 */ |
| 252 RTT.clone = function(old, named) { |
| 253 var name = old.getClassName(); |
| 254 var typekey = RTT.getTypeKey(name, old.typeArgs, old.returnType, named); |
| 255 var rtt = $mapLookup(RTT.types, typekey); |
| 256 if (rtt) { |
| 257 return rtt; |
| 258 } |
| 259 var classkey = RTT.getTypeKey(name); |
| 260 rtt = new RTT(classkey, typekey, old.typeArgs, old.returnType, old.functionTyp
e, named); |
| 261 RTT.types[typekey] = rtt; |
| 262 rtt.implementedTypes = old.implementedTypes |
| 263 return rtt; |
| 264 }; |
| 265 |
| 227 /** | 266 /** |
| 228 * @param {string} classkey | 267 * @param {string} classkey |
| 229 * @param {Array.<(RTT|string)>=} typeargs | 268 * @param {Array.<(RTT|string)>=} typeargs |
| 230 * @param {string} returntype | 269 * @param {string} returntype |
| 270 * @param {string=} named optional |
| 231 * @return {string} | 271 * @return {string} |
| 232 */ | 272 */ |
| 233 RTT.getTypeKey = function(classkey, typeargs, returntype) { | 273 RTT.getTypeKey = function(classkey, typeargs, returntype, named) { |
| 234 var key = classkey; | 274 var key = classkey; |
| 275 if (named) { |
| 276 key += ":" + named; |
| 277 } |
| 235 if (typeargs) { | 278 if (typeargs) { |
| 236 key += "<" + typeargs.join(",") + ">"; | 279 key += "<" + typeargs.join(",") + ">"; |
| 237 } | 280 } |
| 238 if (returntype) { | 281 if (returntype) { |
| 239 key += "-><" + returntype + ">"; | 282 key += "-><" + returntype + ">"; |
| 240 } | 283 } |
| 241 return key; | 284 return key; |
| 242 }; | 285 }; |
| 243 | 286 |
| 244 /** | 287 /** |
| (...skipping 20 matching lines...) Expand all Loading... |
| 265 */ | 308 */ |
| 266 RTT.removeTypeInfo = function(o) { | 309 RTT.removeTypeInfo = function(o) { |
| 267 o.$typeInfo = null; | 310 o.$typeInfo = null; |
| 268 return o; | 311 return o; |
| 269 }; | 312 }; |
| 270 | 313 |
| 271 /** | 314 /** |
| 272 * The typeArg array is optional | 315 * The typeArg array is optional |
| 273 * @param {Array.<RTT>=} typeArgs | 316 * @param {Array.<RTT>=} typeArgs |
| 274 * @param {number} i | 317 * @param {number} i |
| 318 * @param {string=} named optional |
| 275 * @return {RTT} | 319 * @return {RTT} |
| 276 */ | 320 */ |
| 277 RTT.getTypeArg = function(typeArgs, i) { | 321 RTT.getTypeArg = function(typeArgs, i, named) { |
| 278 if (typeArgs) { | 322 if (typeArgs) { |
| 279 if (typeArgs.length > i) { | 323 if (typeArgs.length > i) { |
| 324 if (named && named != typeArgs[i].named) { |
| 325 return RTT.clone(typeArgs[i], named); |
| 326 } |
| 280 return typeArgs[i]; | 327 return typeArgs[i]; |
| 281 } else { | 328 } else { |
| 282 throw new Error("Missing type arg"); | 329 throw new Error("Missing type arg"); |
| 283 } | 330 } |
| 284 } | 331 } |
| 285 return RTT.dynamicType; | 332 return RTT.dynamicType.$lookupRTT(null,named); |
| 286 }; | 333 }; |
| 287 | 334 |
| 288 /** | 335 /** |
| 289 * The typeArg array is optional | 336 * The typeArg array is optional |
| 290 * @param {*} o | 337 * @param {*} o |
| 291 * @param {string} classkey | 338 * @param {string} classkey |
| 292 * @return {Array.<RTT>} | 339 * @return {Array.<RTT>} |
| 293 */ | 340 */ |
| 294 RTT.getTypeArgsFor = function(o, classkey) { | 341 RTT.getTypeArgsFor = function(o, classkey) { |
| 295 var rtt = $mapLookup(RTT.getTypeInfo(o).implementedTypes, classkey); | 342 var rtt = $mapLookup(RTT.getTypeInfo(o).implementedTypes, classkey); |
| 296 if (!rtt) { | 343 if (!rtt) { |
| 297 throw new Error("internal error: can not find " + | 344 throw new Error("internal error: can not find " + |
| 298 classkey + " in " + JSON.stringify(o)); | 345 classkey + " in " + JSON.stringify(o)); |
| 299 } | 346 } |
| 300 return rtt.typeArgs; | 347 return rtt.typeArgs; |
| 301 }; | 348 }; |
| 302 | 349 |
| 303 // Base types for runtime type information | 350 // Base types for runtime type information |
| 304 | 351 |
| 305 /** @type {!RTT} */ | 352 /** @type {!RTT} */ |
| 306 function ImplementsAll(name) { | 353 function ImplementsAll(name,named) { |
| 307 RTT.call(this,name); | 354 var typeKey = RTT.getTypeKey(name, null, null, named); |
| 355 RTT.call(this,name,typeKey,null,null,null,named); |
| 308 } | 356 } |
| 309 $inherits(ImplementsAll,RTT); | 357 $inherits(ImplementsAll,RTT); |
| 310 ImplementsAll.prototype.implementedBy = function(o) {return true}; | 358 ImplementsAll.prototype.implementedBy = function(o) {return true}; |
| 311 ImplementsAll.prototype.implementedByType = function(o) {return true}; | 359 ImplementsAll.prototype.implementedByType = function(o) {return true}; |
| 312 | 360 |
| 313 RTT.objectType = new ImplementsAll($cls('Object')); | 361 RTT.objectType = new ImplementsAll($cls('Object')); |
| 314 RTT.dynamicType = new ImplementsAll($cls('Dynamic')); | |
| 315 RTT.placeholderType = new ImplementsAll($cls('::')); | 362 RTT.placeholderType = new ImplementsAll($cls('::')); |
| 316 | 363 |
| 364 function ImplementsDynamic(named) { |
| 365 ImplementsAll.call(this,$cls('Dynamic'),named); |
| 366 } |
| 367 $inherits(ImplementsDynamic,ImplementsAll); |
| 368 ImplementsDynamic.prototype.$lookupRTT = function(typeArgs, named) { |
| 369 var typekey = RTT.getTypeKey($cls('Dynamic'), null, null, named); |
| 370 var rtt = $mapLookup(RTT.types, typekey); |
| 371 if (rtt) { |
| 372 return rtt; |
| 373 } |
| 374 rtt = new ImplementsDynamic(named); |
| 375 RTT.types[typekey] = rtt; |
| 376 return rtt; |
| 377 } |
| 378 RTT.dynamicType = ImplementsDynamic.prototype.$lookupRTT(); |
| 379 |
| 317 /** | 380 /** |
| 318 * Checks that a value is assignable to an expected type, and either returns tha
t | 381 * Checks that a value is assignable to an expected type, and either returns tha
t |
| 319 * value if it is, or else throws a TypeMismatchException. | 382 * value if it is, or else throws a TypeMismatchException. |
| 320 * | 383 * |
| 321 * @param {!RTT} the expected type | 384 * @param {!RTT} the expected type |
| 322 * @param {*} the value to check | 385 * @param {*} the value to check |
| 323 * @return {*} the value | 386 * @return {*} the value |
| 324 */ | 387 */ |
| 325 function $chk(rtt, value) { | 388 function $chk(rtt, value) { |
| 326 // null can be assigned to any type | 389 // null can be assigned to any type |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 372 return typeof o == 'number'; | 435 return typeof o == 'number'; |
| 373 } | 436 } |
| 374 | 437 |
| 375 /** | 438 /** |
| 376 * @param {*} o | 439 * @param {*} o |
| 377 * @return {boolean} | 440 * @return {boolean} |
| 378 */ | 441 */ |
| 379 function $isString(o) { | 442 function $isString(o) { |
| 380 return typeof o == 'string'; | 443 return typeof o == 'string'; |
| 381 } | 444 } |
| OLD | NEW |