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 }