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 |