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