1 /** 
2  * Provides runtime traits, which provide much of the functionality of tango.core.Traits and
3  * is-expressions, as well as some functionality that is only available at runtime, using 
4  * runtime type information. 
5  * 
6  * Authors: Chris Wright (dhasenan) $(EMAIL dhasenan@gmail.com)
7  * License: Tango License, Apache 2.0
8  * Copyright: Copyright (c) 2009, CHRISTOPHER WRIGHT
9  */
10 module tango.core.RuntimeTraits;
11 
12 import tango.core.Compiler;
13 
14 /** If the given type represents a typedef, return the actual type.
15   * Typedefs have been removed from the language and are no longer supported.
16   */
17 const(TypeInfo) realType (const(TypeInfo) type)
18 {
19     // TypeInfo_Invariant inherits from TypeInfo_Const.
20     if (auto ct = cast(const(TypeInfo_Const))type)
21     {
22         return ct.base;
23     }
24     return type;
25 }
26 
27 /// If the given type represents a class, return its ClassInfo; else return null;
28 const(ClassInfo) asClass (const(TypeInfo) type)
29 {
30     if (isInterface (type))
31     {
32         auto klass = cast(TypeInfo_Interface) type;
33         return klass.info;
34     }
35     if (isClass (type))
36     {
37         auto klass = cast(TypeInfo_Class) type;
38         return klass.info;
39     }
40     return null;
41 }
42 
43 /** Returns true iff one type is an ancestor of the other, or if the types are the same.
44  * If either is null, returns false. */
45 bool isDerived (const(ClassInfo) derived, const(ClassInfo) base)
46 {
47     auto derived_nc = cast(ClassInfo)derived;
48     auto base_nc = cast(ClassInfo)base;
49     if (derived is null || base is null)
50         return false;
51     do
52         if (derived_nc is base_nc)
53             return true;
54     while ((derived_nc = cast(ClassInfo)derived_nc.base) !is null);
55     return false;
56 }
57 
58 /** Returns true iff implementor implements the interface described
59  * by iface. This is an expensive operation (linear in the number of
60  * interfaces and base classes).
61  */
62 bool implements (const(ClassInfo) implementor, const(ClassInfo) iface)
63 {
64     foreach (info; applyInterfaces (implementor))
65     {
66         if (iface is info)
67             return true;
68     }
69     return false;
70 }
71 
72 /** Returns true iff an instance of class test is implicitly castable to target. 
73  * This is an expensive operation (isDerived + implements). */
74 bool isImplicitly (const(ClassInfo) test, const(ClassInfo) target)
75 {
76     // Keep isDerived first.
77     // isDerived will be much faster than implements.
78     return (isDerived (test, target) || implements (test, target));
79 }
80 
81 /** Returns true iff an instance of type test is implicitly castable to target. 
82  * If the types describe classes or interfaces, this is an expensive operation. */
83 bool isImplicitly (const(TypeInfo) test, const(TypeInfo) target)
84 {
85     // A lot of special cases. This is ugly.
86     if (test is target)
87         return true;
88     if (isStaticArray (test) && isDynamicArray (target) && valueType (test) is valueType (target))
89     {
90         // you can implicitly cast static to dynamic (currently) if they 
91         // have the same value type. Other casts should be forbidden.
92         return true;
93     }
94     auto klass1 = asClass (test);
95     auto klass2 = asClass (target);
96     if (isClass (test) && isClass (target))
97     {
98         return isDerived (klass1, klass2);
99     }
100     if (isInterface (test) && isInterface (target))
101     {
102         return isDerived (klass1, klass2);
103     }
104     if (klass1 && klass2)
105     {
106         return isImplicitly (klass1, klass2);
107     }
108     if (klass1 || klass2)
109     {
110         // no casts from class to non-class
111         return false;
112     }
113     if ((isSignedInteger (test) && isSignedInteger (target)) || (isUnsignedInteger (test) && isUnsignedInteger (target)) || (isFloat (
114             test) && isFloat (target)) || (isCharacter (test) && isCharacter (target)))
115     {
116         return test.tsize () <= target.tsize ();
117     }
118     if (isSignedInteger (test) && isUnsignedInteger (target))
119     {
120         // potential loss of data
121         return false;
122     }
123     if (isUnsignedInteger (test) && isSignedInteger (target))
124     {
125         // if the sizes are the same, you could be losing data
126         // the upper half of the range wraps around to negatives
127         // if the target type is larger, you can safely hold it
128         return test.tsize () < target.tsize ();
129     }
130     // delegates and functions: no can do
131     // pointers: no
132     // structs: no
133     return false;
134 }
135 
136 ///
137 const(ClassInfo)[] baseClasses (const(ClassInfo) type)
138 {
139     if (type is null)
140         return null;
141     auto type_nc = cast()type;
142     const(ClassInfo)[] types;
143     while ((type_nc = type_nc.base) !is null)
144         types ~= type_nc;
145     return types;
146 }
147 
148 /** Returns a list of all interfaces that this type implements, directly
149  * or indirectly. This includes base interfaces of types the class implements,
150  * and interfaces that base classes implement, and base interfaces of interfaces
151  * that base classes implement. This is an expensive operation. */
152 const(ClassInfo)[] baseInterfaces (const(ClassInfo) type)
153 {
154     if (type is null)
155         return null;
156     auto type_nc = cast()type;
157     const(ClassInfo)[] types = directInterfaces (type);
158     while ((type_nc = type_nc.base) !is null)
159     {
160         types ~= interfaceGraph (type_nc);
161     }
162     return types;
163 }
164 
165 /** Returns all the interfaces that this type directly implements, including
166  * inherited interfaces. This is an expensive operation.
167  * 
168  * Examples:
169  * ---
170  * interface I1 {}
171  * interface I2 : I1 {}
172  * class A : I2 {}
173  * 
174  * auto interfaces = interfaceGraph (A.classinfo);
175  * // interfaces = [I1.classinfo, I2.classinfo]
176  * --- 
177  * 
178  * ---
179  * interface I1 {}
180  * interface I2 {}
181  * class A : I1 {}
182  * class B : A, I2 {}
183  * 
184  * auto interfaces = interfaceGraph (B.classinfo);
185  * // interfaces = [I2.classinfo]
186  * ---
187  */
188 const(ClassInfo)[] interfaceGraph (const(ClassInfo) type)
189 {
190     const(ClassInfo)[] info;
191     foreach (iface; type.interfaces)
192     {
193         info ~= iface.classinfo;
194         info ~= interfaceGraph (iface.classinfo);
195     }
196     return info;
197 }
198 
199 /** Iterate through all interfaces that type implements, directly or indirectly, including base interfaces. */
200 struct applyInterfaces
201 {
202     ///
203     this(const(ClassInfo) type)
204     {
205         this.type = cast()type;
206     }
207 
208     ///
209     int opApply (scope int delegate (ref ClassInfo) dg)
210     {
211         int result = 0;
212         for (; type; type = type.base)
213         {
214             foreach (iface; type.interfaces)
215             {
216                 result = dg (iface.classinfo);
217                 if (result)
218                     return result;
219                 result = applyInterfaces (iface.classinfo).opApply (dg);
220                 if (result)
221                     return result;
222             }
223         }
224         return result;
225     }
226 
227     ClassInfo type;
228 }
229 
230 ///
231 const(ClassInfo)[] baseTypes (const(ClassInfo) type)
232 {
233     if (type is null)
234         return null;
235     return baseClasses (type) ~ baseInterfaces (type);
236 }
237 
238 ///
239 ModuleInfo* moduleOf (const(ClassInfo) type)
240 {
241     foreach (modula; ModuleInfo)
242         foreach (klass; modula.localClasses)
243             if (klass is type)
244                 return modula;
245     return null;
246 }
247 
248 /// Returns a list of interfaces that this class directly implements.
249 const(ClassInfo)[] directInterfaces (const(ClassInfo) type)
250 {
251     const(ClassInfo)[] types;
252     foreach (iface; type.interfaces)
253         types ~= iface.classinfo;
254     return types;
255 }
256 
257 /** Returns a list of all types that are derived from the given type. This does not 
258  * count interfaces; that is, if type is an interface, you will only get derived 
259  * interfaces back. It is an expensive operations. */
260 const(ClassInfo)[] derivedTypes (const(ClassInfo) type)
261 {
262     const(ClassInfo)[] types;
263     foreach (modula; ModuleInfo)
264         foreach (klass; modula.localClasses)
265             if (isDerived (klass, type) && (klass !is type))
266                 types ~= klass;
267     return types;
268 }
269 
270 ///
271 bool isDynamicArray (const(TypeInfo) type)
272 {
273     // This implementation is evil.
274     // Array typeinfos are named TypeInfo_A?, and defined individually for each
275     // possible type aside from structs. For example, typeinfo for int[] is
276     // TypeInfo_Ai; for uint[], TypeInfo_Ak.
277     // So any TypeInfo with length 11 and starting with TypeInfo_A is an array
278     // type.
279     // Also, TypeInfo_Array is an array type.
280     auto type2 = realType (type);
281     return ((type2.classinfo.name[9] == 'A') && (type2.classinfo.name.length == 11)) || ((type2.classinfo.name.length == 12) && (type2.classinfo.name[9..12] == "Aya")) || 
282         ((cast(TypeInfo_Array) type2) !is null);
283 }
284 
285 ///
286 bool isStaticArray (const(TypeInfo) type)
287 {
288     auto type2 = realType (type);
289     return (cast(TypeInfo_StaticArray) type2) !is null;
290 }
291 
292 /** Returns true iff the given type is a dynamic or static array (false for associative
293  * arrays and non-arrays). */
294 bool isArray (const(TypeInfo) type)
295 {
296     auto type2 = realType (type);
297     return isDynamicArray (type2) || isStaticArray (type2);
298 }
299 
300 ///
301 bool isAssociativeArray (const(TypeInfo) type)
302 {
303     auto type2 = realType (type);
304     return (cast(TypeInfo_AssociativeArray) type2) !is null;
305 }
306 
307 ///
308 bool isCharacter (const(TypeInfo) type)
309 {
310     auto type2 = realType (type);
311     return (type2 is typeid(char) || type2 is typeid(wchar) || type2 is typeid(dchar));
312 }
313 
314 ///
315 bool isString (const(TypeInfo) type)
316 {
317     auto type2 = realType (type);
318     return isArray (type2) && isCharacter (valueType (type2));
319 }
320 
321 ///
322 bool isUnsignedInteger (const(TypeInfo) type)
323 {
324     auto type2 = realType (type);
325     return (type2 is typeid(uint) || type2 is typeid(ulong) || type2 is typeid(ushort) || type2 is typeid(ubyte));
326 }
327 
328 ///
329 bool isSignedInteger (const(TypeInfo) type)
330 {
331     auto type2 = realType (type);
332     return (type2 is typeid(int) || type2 is typeid(long) || type2 is typeid(short) || type2 is typeid(byte));
333 }
334 
335 ///
336 bool isInteger (const(TypeInfo) type)
337 {
338     auto type2 = realType (type);
339     return isSignedInteger (type2) || isUnsignedInteger (type2);
340 }
341 
342 ///
343 bool isBool (const(TypeInfo) type)
344 {
345     auto type2 = realType (type);
346     return (type2 is typeid(bool));
347 }
348 
349 ///
350 bool isFloat (const(TypeInfo) type)
351 {
352     auto type2 = realType (type);
353     return (type2 is typeid(float) || type2 is typeid(double) || type2 is typeid(real));
354 }
355 
356 ///
357 bool isPrimitive (const(TypeInfo) type)
358 {
359     auto type2 = realType (type);
360     return (isArray (type2) || isAssociativeArray (type2) || isCharacter (type2) || isFloat (type2) || isInteger (type2));
361 }
362 
363 /// Returns true iff the given type represents an interface.
364 bool isInterface (const(TypeInfo) type)
365 {
366     return (cast(TypeInfo_Interface) type) !is null;
367 }
368 
369 ///
370 bool isPointer (const(TypeInfo) type)
371 {
372     auto type2 = realType (type);
373     return (cast(TypeInfo_Pointer) type2) !is null;
374 }
375 
376 /// Returns true iff the type represents a class (false for interfaces).
377 bool isClass (const(TypeInfo) type)
378 {
379     auto type2 = realType (type);
380     return (cast(TypeInfo_Class) type2) !is null;
381 }
382 
383 ///
384 bool isStruct (const(TypeInfo) type)
385 {
386     auto type2 = realType (type);
387     return (cast(TypeInfo_Struct) type2) !is null;
388 }
389 
390 ///
391 bool isFunction (const(TypeInfo) type)
392 {
393     auto type2 = realType (type);
394     return ((cast(TypeInfo_Function) type2) !is null) || ((cast(TypeInfo_Delegate) type2) !is null);
395 }
396 
397 /** Returns true iff the given type is a reference type. */
398 bool isReferenceType (const(TypeInfo) type)
399 {
400     return isClass (type) || isPointer (type) || isDynamicArray (type);
401 }
402 
403 /** Returns true iff the given type represents a user-defined type. 
404  * This does not include functions, delegates, aliases, or typedefs. */
405 bool isUserDefined (const(TypeInfo) type)
406 {
407     return isClass (type) || isStruct (type);
408 }
409 
410 /** Returns true for all value types, false for all reference types.
411  * For functions and delegates, returns false (is this the way it should be?). */
412 bool isValueType (const(TypeInfo) type)
413 {
414     return !(isDynamicArray (type) || isAssociativeArray (type) || isPointer (type) || isClass (type) || isFunction (
415             type));
416 }
417 
418 /** The key type of the given type. For an array, size_t; for an associative
419  * array T[U], U. */
420 const(TypeInfo) keyType (const(TypeInfo) type)
421 {
422     auto type2 = realType (type);
423     auto assocArray = cast(TypeInfo_AssociativeArray) type2;
424     if (assocArray)
425         return assocArray.key;
426     if (isArray (type2))
427         return typeid(size_t);
428     return null;
429 }
430 
431 /** The value type of the given type -- given T[] or T[n], T; given T[U],
432  * T; given T*, T; anything else, null. */
433 const(TypeInfo) valueType (const(TypeInfo) type)
434 {
435     auto type2 = realType (type);
436     if (isArray (type2))
437         return type2.next;
438     auto assocArray = cast(TypeInfo_AssociativeArray) type2;
439     if (assocArray)
440         return assocArray.value;
441     auto pointer = cast(TypeInfo_Pointer) type2;
442     if (pointer)
443         return pointer.m_next;
444     return null;
445 }
446 
447 /** If the given type represents a delegate or function, the return type
448  * of that function. Otherwise, null. */
449 const(TypeInfo) returnType (const(TypeInfo) type)
450 {
451     auto type2 = realType (type);
452     auto delegat = cast(TypeInfo_Delegate) type2;
453     if (delegat)
454         return delegat.next;
455     auto func = cast(TypeInfo_Function) type2;
456     if (func)
457         return func.next;
458     return null;
459 }
460 
461 debug (UnitTest)
462 {
463 
464     interface I1
465     {
466     }
467 
468     interface I2
469     {
470     }
471 
472     interface I3
473     {
474     }
475 
476     interface I4
477     {
478     }
479 
480     class A
481     {
482     }
483 
484     class B : A, I1
485     {
486     }
487 
488     class C : B, I2, I3
489     {
490     }
491 
492     class D : A, I1
493     {
494         int foo (int i)
495         {
496             return i;
497         }
498     }
499 
500     struct S1
501     {
502     }
503 
504     unittest {
505         // Struct-related stuff.
506         auto type = typeid(S1);
507         assert (isStruct (type));
508         assert (isValueType (type));
509         assert (isUserDefined (type));
510         assert (!isClass (type));
511         assert (!isPointer (type));
512         assert (null is returnType (type));
513         assert (!isPrimitive (type));
514         assert (valueType (type) is null);
515     }
516 
517     unittest {
518         auto type = A.classinfo;
519         assert (baseTypes (type) == [Object.classinfo]);
520         assert (baseClasses (type) == [Object.classinfo]);
521         assert (baseInterfaces (type).length == 0);
522         type = C.classinfo;
523         assert (baseClasses (type) == [B.classinfo, A.classinfo, Object.classinfo]);
524         assert (baseInterfaces (type) == [I2.classinfo, I3.classinfo, I1.classinfo]);
525         assert (baseTypes (type) == [B.classinfo, A.classinfo, Object.classinfo, I2.classinfo, I3.classinfo,
526                 I1.classinfo]);
527     }
528 
529     unittest {
530         assert (isPointer (typeid(S1*)));
531         assert (isArray (typeid(S1[])));
532         assert (valueType (typeid(S1*)) is typeid(S1));
533         auto d = new D;
534         assert (returnType (typeid(typeof(&d.foo))) is typeid(int));
535         assert (isFloat (typeid(real)));
536         assert (isFloat (typeid(double)));
537         assert (isFloat (typeid(float)));
538         assert (!isFloat (typeid(creal)));
539         assert (!isFloat (typeid(cdouble)));
540         assert (!isInteger (typeid(float)));
541         assert (!isInteger (typeid(creal)));
542         assert (isInteger (typeid(ulong)));
543         assert (isInteger (typeid(ubyte)));
544         assert (isCharacter (typeid(char)));
545         assert (isCharacter (typeid(wchar)));
546         assert (isCharacter (typeid(dchar)));
547         assert (!isCharacter (typeid(ubyte)));
548         assert (isArray (typeid(typeof("hello"))));
549         assert (isCharacter (typeid(typeof("hello"[0]))));
550         assert (valueType (typeid(typeof("hello"))) is typeid(typeof(cast(immutable(char))'h')));
551         assert (isString (typeid(typeof("hello"))), typeof("hello").stringof);
552         immutable(dchar)[5] staticString_s = "hello"d;
553         auto staticString = typeid(typeof(staticString_s));
554         auto dynamicString = typeid(typeof("hello"d[0 .. $]));
555         assert (isString (staticString));
556         assert (isStaticArray (staticString));
557         assert (isDynamicArray (dynamicString), dynamicString.toString () ~ dynamicString.classinfo.name);
558         assert (isString (dynamicString));
559 
560         auto type = typeid(int[immutable(char)[]]);
561         assert (valueType (type) is typeid(int), (cast()valueType (type)).toString ());
562         assert (keyType (type) is typeid(immutable(char)[]), (cast()keyType (type)).toString ());
563         void delegate (int) dg = (int i)
564         {
565         };
566         assert (returnType (typeid(typeof(dg))) is typeid(void));
567         assert (returnType (typeid(int delegate (int))) is typeid(int));
568 
569         assert (!isDynamicArray (typeid(int[4])));
570         assert (isStaticArray (typeid(int[4])));
571     }
572 
573 }