| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 /// This library defines the representation of runtime types. | 5 /// This library defines the representation of runtime types. |
| 6 part of dart._runtime; | 6 part of dart._runtime; |
| 7 | 7 |
| 8 /// The Symbol for storing type arguments on a specialized generic type. | 8 /// The Symbol for storing type arguments on a specialized generic type. |
| 9 final _mixins = JS('', 'Symbol("mixins")'); | 9 final _mixins = JS('', 'Symbol("mixins")'); |
| 10 @JSExportName('implements') | 10 @JSExportName('implements') |
| 11 final implements_ = JS('', 'Symbol("implements")'); | 11 final implements_ = JS('', 'Symbol("implements")'); |
| 12 final metadata = JS('', 'Symbol("metadata")'); | 12 final metadata = JS('', 'Symbol("metadata")'); |
| 13 | 13 |
| 14 /// The symbol used to store the cached `Type` object associated with a class. |
| 15 final _typeObject = JS('', 'Symbol("typeObject")'); |
| 14 | 16 |
| 17 /// Types in dart are represented internally at runtime as follows. |
| 15 /// | 18 /// |
| 16 /// Types in dart are represented at runtime as follows. | |
| 17 /// - Normal nominal types, produced from classes, are represented | 19 /// - Normal nominal types, produced from classes, are represented |
| 18 /// at runtime by the JS class of which they are an instance. | 20 /// at runtime by the JS class of which they are an instance. |
| 19 /// If the type is the result of instantiating a generic class, | 21 /// If the type is the result of instantiating a generic class, |
| 20 /// then the "classes" module manages the association between the | 22 /// then the "classes" module manages the association between the |
| 21 /// instantiated class and the original class declaration | 23 /// instantiated class and the original class declaration |
| 22 /// and the type arguments with which it was instantiated. This | 24 /// and the type arguments with which it was instantiated. This |
| 23 /// assocation can be queried via the "classes" module". | 25 /// assocation can be queried via the "classes" module". |
| 24 /// | 26 /// |
| 25 /// - All other types are represented as instances of class TypeRep, | 27 /// - All other types are represented as instances of class TypeRep, |
| 26 /// defined in this module. | 28 /// defined in this module. |
| 27 /// - Dynamic, Void, and Bottom are singleton instances of sentinal | 29 /// - Dynamic, Void, and Bottom are singleton instances of sentinal |
| 28 /// classes. | 30 /// classes. |
| 29 /// - Function types are instances of subclasses of AbstractFunctionType. | 31 /// - Function types are instances of subclasses of AbstractFunctionType. |
| 30 /// | 32 /// |
| 31 /// Function types are represented in one of two ways: | 33 /// Function types are represented in one of two ways: |
| 32 /// - As an instance of FunctionType. These are eagerly computed. | 34 /// - As an instance of FunctionType. These are eagerly computed. |
| 33 /// - As an instance of TypeDef. The TypeDef representation lazily | 35 /// - As an instance of TypeDef. The TypeDef representation lazily |
| 34 /// computes an instance of FunctionType, and delegates to that instance. | 36 /// computes an instance of FunctionType, and delegates to that instance. |
| 35 /// | 37 /// |
| 36 /// All types satisfy the following interface: | 38 /// These above "runtime types" are what is used for implementing DDC's |
| 37 /// get String name; | 39 /// internal type checks. These objects are distinct from the objects exposed |
| 38 /// String toString(); | 40 /// to user code by class literals and calling `Object.runtimeType`. In DDC, |
| 41 /// the latter are represented by instances of WrappedType which contain a |
| 42 /// real runtime type internally. This ensures that the returned object only |
| 43 /// exposes the API that Type defines: |
| 39 /// | 44 /// |
| 40 /// | 45 /// get String name; |
| 46 /// String toString(); |
| 41 final TypeRep = JS('', ''' | 47 final TypeRep = JS('', ''' |
| 42 class TypeRep { | 48 class TypeRep { |
| 43 get name() { return this.toString(); } | 49 get name() { return this.toString(); } |
| 44 get [$_runtimeType]() { return $Type; } | 50 get [$_runtimeType]() { return $Type; } |
| 45 } | 51 } |
| 46 '''); | 52 '''); |
| 47 | 53 |
| 48 final Dynamic = JS('', ''' | 54 final Dynamic = JS('', ''' |
| 49 class Dynamic extends $TypeRep { | 55 class Dynamic extends $TypeRep { |
| 50 toString() { return "dynamic"; } | 56 toString() { return "dynamic"; } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 68 '''); | 74 '''); |
| 69 final bottom = JS('', 'new $Bottom()'); | 75 final bottom = JS('', 'new $Bottom()'); |
| 70 | 76 |
| 71 final JSObject = JS('', ''' | 77 final JSObject = JS('', ''' |
| 72 class JSObject extends $TypeRep { | 78 class JSObject extends $TypeRep { |
| 73 toString() { return "NativeJavaScriptObject"; } | 79 toString() { return "NativeJavaScriptObject"; } |
| 74 } | 80 } |
| 75 '''); | 81 '''); |
| 76 final jsobject = JS('', 'new $JSObject()'); | 82 final jsobject = JS('', 'new $JSObject()'); |
| 77 | 83 |
| 84 final WrappedType = JS('', ''' |
| 85 class WrappedType extends $TypeRep { |
| 86 constructor(type) { |
| 87 super(); |
| 88 this._runtimeType = type; |
| 89 } |
| 90 toString() { return $typeName(this._runtimeType); } |
| 91 } |
| 92 '''); |
| 93 |
| 78 final AbstractFunctionType = JS('', ''' | 94 final AbstractFunctionType = JS('', ''' |
| 79 class AbstractFunctionType extends $TypeRep { | 95 class AbstractFunctionType extends $TypeRep { |
| 80 constructor() { | 96 constructor() { |
| 81 super(); | 97 super(); |
| 82 this._stringValue = null; | 98 this._stringValue = null; |
| 83 } | 99 } |
| 84 | 100 |
| 85 toString() { return this.name; } | 101 toString() { return this.name; } |
| 86 | 102 |
| 87 get name() { | 103 get name() { |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 bool isDartType(type) => JS('bool', '#(#) === #', _getRuntimeType, type, Type); | 312 bool isDartType(type) => JS('bool', '#(#) === #', _getRuntimeType, type, Type); |
| 297 | 313 |
| 298 typeName(type) => JS('', '''(() => { | 314 typeName(type) => JS('', '''(() => { |
| 299 // Non-instance types | 315 // Non-instance types |
| 300 if ($type instanceof $TypeRep) return $type.toString(); | 316 if ($type instanceof $TypeRep) return $type.toString(); |
| 301 // Instance types | 317 // Instance types |
| 302 let tag = $_getRuntimeType($type); | 318 let tag = $_getRuntimeType($type); |
| 303 if (tag === $Type) { | 319 if (tag === $Type) { |
| 304 let name = $type.name; | 320 let name = $type.name; |
| 305 let args = $getGenericArgs($type); | 321 let args = $getGenericArgs($type); |
| 306 if (args) { | 322 if (!args) return name; |
| 307 name += '<'; | 323 |
| 308 for (let i = 0; i < args.length; ++i) { | 324 let result = name; |
| 309 if (i > 0) name += ', '; | 325 let allDynamic = true; |
| 310 name += $typeName(args[i]); | 326 |
| 311 } | 327 result += '<'; |
| 312 name += '>'; | 328 for (let i = 0; i < args.length; ++i) { |
| 329 if (i > 0) name += ', '; |
| 330 |
| 331 let argName = $typeName(args[i]); |
| 332 if (argName != 'dynamic') allDynamic = false; |
| 333 |
| 334 result += argName; |
| 313 } | 335 } |
| 314 return name; | 336 result += '>'; |
| 337 |
| 338 // Don't print the type arguments if they are all dynamic. Show "raw" |
| 339 // types as just the bare type name. |
| 340 if (allDynamic) return name; |
| 341 return result; |
| 315 } | 342 } |
| 316 if (tag) return "Not a type: " + tag.name; | 343 if (tag) return "Not a type: " + tag.name; |
| 317 return "JSObject<" + $type.name + ">"; | 344 return "JSObject<" + $type.name + ">"; |
| 318 })()'''); | 345 })()'''); |
| 319 | 346 |
| 320 /// Get the underlying function type, potentially from the call method | 347 /// Get the underlying function type, potentially from the call method |
| 321 /// for a class type. | 348 /// for a class type. |
| 322 getImplicitFunctionType(type) => JS('', '''(() => { | 349 getImplicitFunctionType(type) => JS('', '''(() => { |
| 323 if ($isFunctionType($type)) return $type; | 350 if ($isFunctionType($type)) return $type; |
| 324 return $getMethodTypeFromType(type, 'call'); | 351 return $getMethodTypeFromType(type, 'call'); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 398 } | 425 } |
| 399 | 426 |
| 400 return true; | 427 return true; |
| 401 })()'''); | 428 })()'''); |
| 402 | 429 |
| 403 /// | 430 /// |
| 404 /// Computes the canonical type. | 431 /// Computes the canonical type. |
| 405 /// This maps JS types onto their corresponding Dart Type. | 432 /// This maps JS types onto their corresponding Dart Type. |
| 406 /// | 433 /// |
| 407 // TODO(jmesserly): lots more needs to be done here. | 434 // TODO(jmesserly): lots more needs to be done here. |
| 408 canonicalType(t) { | 435 canonicalType(t) => JS('', '''(() => { |
| 409 if (JS('bool', '# === Object', t)) return Object; | 436 if (t === Object) return Object; |
| 410 if (JS('bool', '# === Function', t)) return Function; | 437 if (t === Function) return Function; |
| 411 if (JS('bool', '# === Array', t)) return List; | 438 if (t === Array) return List; |
| 412 | 439 |
| 413 // We shouldn't normally get here with these types, unless something strange | 440 // We shouldn't normally get here with these types, unless something strange |
| 414 // happens like subclassing Number in JS and passing it to Dart. | 441 // happens like subclassing Number in JS and passing it to Dart. |
| 415 if (JS('bool', '# === String', t)) return String; | 442 if (t === String) return String; |
| 416 if (JS('bool', '# === Number', t)) return double; | 443 if (t === Number) return double; |
| 417 if (JS('bool', '# === Boolean', t)) return bool; | 444 if (t === Boolean) return bool; |
| 418 return t; | 445 return t; |
| 419 } | 446 })()'''); |
| 420 | 447 |
| 421 final subtypeMap = JS('', 'new Map()'); | 448 final subtypeMap = JS('', 'new Map()'); |
| 422 isSubtype(t1, t2) => JS('', '''(() => { | 449 isSubtype(t1, t2) => JS('', '''(() => { |
| 423 // See if we already know the answer | 450 // See if we already know the answer |
| 424 // TODO(jmesserly): general purpose memoize function? | 451 // TODO(jmesserly): general purpose memoize function? |
| 425 let map = $subtypeMap.get($t1); | 452 let map = $subtypeMap.get($t1); |
| 426 let result; | 453 let result; |
| 427 if (map) { | 454 if (map) { |
| 428 result = map.get($t2); | 455 result = map.get($t2); |
| 429 if (result !== void 0) return result; | 456 if (result !== void 0) return result; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 557 return true; | 584 return true; |
| 558 } | 585 } |
| 559 | 586 |
| 560 let typeArgs = $getGenericArgs($type); | 587 let typeArgs = $getGenericArgs($type); |
| 561 if (!typeArgs) return true; | 588 if (!typeArgs) return true; |
| 562 for (let t of typeArgs) { | 589 for (let t of typeArgs) { |
| 563 if (t != $Object && t != $dynamicR) return false; | 590 if (t != $Object && t != $dynamicR) return false; |
| 564 } | 591 } |
| 565 return true; | 592 return true; |
| 566 })()'''); | 593 })()'''); |
| OLD | NEW |