1 /** 2 * Contains traits for runtime internal usage. 3 * 4 * Copyright: Copyright Digital Mars 2014 -. 5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 6 * Authors: Martin Nowak 7 * Source: $(DRUNTIMESRC core/internal/_traits.d) 8 */ 9 module core.internal.traits; 10 11 alias AliasSeq(TList...) = TList; 12 13 template Fields(T) 14 { 15 static if (is(T == struct) || is(T == union)) 16 alias Fields = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]); 17 else static if (is(T == class) || is(T == interface)) 18 alias Fields = typeof(T.tupleof); 19 else 20 alias Fields = AliasSeq!T; 21 } 22 23 T trustedCast(T, U)(auto ref U u) @trusted pure nothrow 24 { 25 return cast(T)u; 26 } 27 28 alias Unconst(T : const U, U) = U; 29 30 /// taken from std.traits.Unqual 31 template Unqual(T : const U, U) 32 { 33 static if (is(U == shared V, V)) 34 alias Unqual = V; 35 else 36 alias Unqual = U; 37 } 38 39 template BaseElemOf(T) 40 { 41 static if (is(T == E[N], E, size_t N)) 42 alias BaseElemOf = BaseElemOf!E; 43 else 44 alias BaseElemOf = T; 45 } 46 47 unittest 48 { 49 static assert(is(BaseElemOf!(int) == int)); 50 static assert(is(BaseElemOf!(int[1]) == int)); 51 static assert(is(BaseElemOf!(int[1][2]) == int)); 52 static assert(is(BaseElemOf!(int[1][]) == int[1][])); 53 static assert(is(BaseElemOf!(int[][1]) == int[])); 54 } 55 56 // [For internal use] 57 template ModifyTypePreservingTQ(alias Modifier, T) 58 { 59 static if (is(T U == immutable U)) alias ModifyTypePreservingTQ = immutable Modifier!U; 60 else static if (is(T U == shared inout const U)) alias ModifyTypePreservingTQ = shared inout const Modifier!U; 61 else static if (is(T U == shared inout U)) alias ModifyTypePreservingTQ = shared inout Modifier!U; 62 else static if (is(T U == shared const U)) alias ModifyTypePreservingTQ = shared const Modifier!U; 63 else static if (is(T U == shared U)) alias ModifyTypePreservingTQ = shared Modifier!U; 64 else static if (is(T U == inout const U)) alias ModifyTypePreservingTQ = inout const Modifier!U; 65 else static if (is(T U == inout U)) alias ModifyTypePreservingTQ = inout Modifier!U; 66 else static if (is(T U == const U)) alias ModifyTypePreservingTQ = const Modifier!U; 67 else alias ModifyTypePreservingTQ = Modifier!T; 68 } 69 @safe unittest 70 { 71 alias Intify(T) = int; 72 static assert(is(ModifyTypePreservingTQ!(Intify, real) == int)); 73 static assert(is(ModifyTypePreservingTQ!(Intify, const real) == const int)); 74 static assert(is(ModifyTypePreservingTQ!(Intify, inout real) == inout int)); 75 static assert(is(ModifyTypePreservingTQ!(Intify, inout const real) == inout const int)); 76 static assert(is(ModifyTypePreservingTQ!(Intify, shared real) == shared int)); 77 static assert(is(ModifyTypePreservingTQ!(Intify, shared const real) == shared const int)); 78 static assert(is(ModifyTypePreservingTQ!(Intify, shared inout real) == shared inout int)); 79 static assert(is(ModifyTypePreservingTQ!(Intify, shared inout const real) == shared inout const int)); 80 static assert(is(ModifyTypePreservingTQ!(Intify, immutable real) == immutable int)); 81 } 82 83 // Substitute all `inout` qualifiers that appears in T to `const` 84 template substInout(T) 85 { 86 static if (is(T == immutable)) 87 { 88 alias substInout = T; 89 } 90 else static if (is(T : shared const U, U) || is(T : const U, U)) 91 { 92 // U is top-unqualified 93 mixin("alias substInout = " 94 ~ (is(T == shared) ? "shared " : "") 95 ~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const 96 ~ "substInoutForm!U;"); 97 } 98 else 99 static assert(0); 100 } 101 102 private template substInoutForm(T) 103 { 104 static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface)) 105 { 106 alias substInoutForm = T; // prevent matching to the form of alias-this-ed type 107 } 108 else static if (is(T : V[K], K, V)) alias substInoutForm = substInout!V[substInout!K]; 109 else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n]; 110 else static if (is(T : U[], U)) alias substInoutForm = substInout!U[]; 111 else static if (is(T : U*, U)) alias substInoutForm = substInout!U*; 112 else alias substInoutForm = T; 113 } 114 115 /// used to declare an extern(D) function that is defined in a different module 116 template externDFunc(string fqn, T:FT*, FT) if (is(FT == function)) 117 { 118 static if (is(FT RT == return) && is(FT Args == function)) 119 { 120 import core.demangle : mangleFunc; 121 enum decl = { 122 string s = "extern(D) RT externDFunc(Args)"; 123 foreach (attr; __traits(getFunctionAttributes, FT)) 124 s ~= " " ~ attr; 125 return s ~ ";"; 126 }(); 127 pragma(mangle, mangleFunc!T(fqn)) mixin(decl); 128 } 129 else 130 static assert(0); 131 } 132 133 template staticIota(int beg, int end) 134 { 135 static if (beg + 1 >= end) 136 { 137 static if (beg >= end) 138 { 139 alias staticIota = AliasSeq!(); 140 } 141 else 142 { 143 alias staticIota = AliasSeq!(+beg); 144 } 145 } 146 else 147 { 148 enum mid = beg + (end - beg) / 2; 149 alias staticIota = AliasSeq!(staticIota!(beg, mid), staticIota!(mid, end)); 150 } 151 } 152 153 private struct __InoutWorkaroundStruct {} 154 @property T rvalueOf(T)(T val) { return val; } 155 @property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); 156 @property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init); 157 158 // taken from std.traits.isAssignable 159 template isAssignable(Lhs, Rhs = Lhs) 160 { 161 enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs); 162 } 163 164 // taken from std.traits.isInnerClass 165 template isInnerClass(T) if (is(T == class)) 166 { 167 static if (is(typeof(T.outer))) 168 { 169 template hasOuterMember(T...) 170 { 171 static if (T.length == 0) 172 enum hasOuterMember = false; 173 else 174 enum hasOuterMember = T[0] == "outer" || hasOuterMember!(T[1 .. $]); 175 } 176 enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T)) && !hasOuterMember!(__traits(allMembers, T)); 177 } 178 else 179 enum isInnerClass = false; 180 } 181 182 template dtorIsNothrow(T) 183 { 184 enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow); 185 } 186 187 // taken from std.meta.allSatisfy 188 template allSatisfy(alias F, T...) 189 { 190 static foreach (Ti; T) 191 { 192 static if (!is(typeof(allSatisfy) == bool) && // not yet defined 193 !F!(Ti)) 194 { 195 enum allSatisfy = false; 196 } 197 } 198 static if (!is(typeof(allSatisfy) == bool)) // if not yet defined 199 { 200 enum allSatisfy = true; 201 } 202 } 203 204 // taken from std.meta.anySatisfy 205 template anySatisfy(alias F, Ts...) 206 { 207 static foreach (T; Ts) 208 { 209 static if (!is(typeof(anySatisfy) == bool) && // not yet defined 210 F!T) 211 { 212 enum anySatisfy = true; 213 } 214 } 215 static if (!is(typeof(anySatisfy) == bool)) // if not yet defined 216 { 217 enum anySatisfy = false; 218 } 219 } 220 221 // simplified from std.traits.maxAlignment 222 template maxAlignment(Ts...) 223 if (Ts.length > 0) 224 { 225 enum maxAlignment = 226 { 227 size_t result = 0; 228 static foreach (T; Ts) 229 if (T.alignof > result) result = T.alignof; 230 return result; 231 }(); 232 } 233 234 template classInstanceAlignment(T) 235 if (is(T == class)) 236 { 237 enum classInstanceAlignment = __traits(classInstanceAlignment, T); 238 } 239 240 /// See $(REF hasElaborateMove, std,traits) 241 template hasElaborateMove(S) 242 { 243 static if (__traits(isStaticArray, S)) 244 { 245 enum bool hasElaborateMove = S.sizeof && hasElaborateMove!(BaseElemOf!S); 246 } 247 else static if (is(S == struct)) 248 { 249 enum hasElaborateMove = (is(typeof(S.init.opPostMove(lvalueOf!S))) && 250 !is(typeof(S.init.opPostMove(rvalueOf!S)))) || 251 anySatisfy!(.hasElaborateMove, Fields!S); 252 } 253 else 254 { 255 enum bool hasElaborateMove = false; 256 } 257 } 258 259 // std.traits.hasElaborateDestructor 260 template hasElaborateDestructor(S) 261 { 262 static if (__traits(isStaticArray, S)) 263 { 264 enum bool hasElaborateDestructor = S.sizeof && hasElaborateDestructor!(BaseElemOf!S); 265 } 266 else static if (is(S == struct)) 267 { 268 enum hasElaborateDestructor = __traits(hasMember, S, "__dtor") 269 || anySatisfy!(.hasElaborateDestructor, Fields!S); 270 } 271 else 272 { 273 enum bool hasElaborateDestructor = false; 274 } 275 } 276 277 // std.traits.hasElaborateCopyDestructor 278 template hasElaborateCopyConstructor(S) 279 { 280 static if (__traits(isStaticArray, S)) 281 { 282 enum bool hasElaborateCopyConstructor = S.sizeof && hasElaborateCopyConstructor!(BaseElemOf!S); 283 } 284 else static if (is(S == struct)) 285 { 286 enum hasElaborateCopyConstructor = __traits(hasCopyConstructor, S) || __traits(hasPostblit, S); 287 } 288 else 289 { 290 enum bool hasElaborateCopyConstructor = false; 291 } 292 } 293 294 @safe unittest 295 { 296 static struct S 297 { 298 int x; 299 this(return scope ref typeof(this) rhs) { } 300 this(int x, int y) {} 301 } 302 303 static assert(hasElaborateCopyConstructor!S); 304 static assert(!hasElaborateCopyConstructor!(S[0][1])); 305 306 static struct S2 307 { 308 int x; 309 this(int x, int y) {} 310 } 311 312 static assert(!hasElaborateCopyConstructor!S2); 313 314 static struct S3 315 { 316 int x; 317 this(return scope ref typeof(this) rhs, int x = 42) { } 318 this(int x, int y) {} 319 } 320 321 static assert(hasElaborateCopyConstructor!S3); 322 } 323 324 template hasElaborateAssign(S) 325 { 326 static if (__traits(isStaticArray, S)) 327 { 328 enum bool hasElaborateAssign = S.sizeof && hasElaborateAssign!(BaseElemOf!S); 329 } 330 else static if (is(S == struct)) 331 { 332 enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) || 333 is(typeof(S.init.opAssign(lvalueOf!S))) || 334 anySatisfy!(.hasElaborateAssign, Fields!S); 335 } 336 else 337 { 338 enum bool hasElaborateAssign = false; 339 } 340 } 341 342 template hasIndirections(T) 343 { 344 static if (is(T == struct) || is(T == union)) 345 enum hasIndirections = anySatisfy!(.hasIndirections, typeof(T.tupleof)); 346 else static if (is(T == E[N], E, size_t N)) 347 enum hasIndirections = T.sizeof && is(E == void) ? true : hasIndirections!(BaseElemOf!E); 348 else static if (isFunctionPointer!T) 349 enum hasIndirections = false; 350 else 351 enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T || 352 __traits(isAssociativeArray, T) || is (T == class) || is(T == interface); 353 } 354 355 template hasUnsharedIndirections(T) 356 { 357 static if (is(T == immutable)) 358 enum hasUnsharedIndirections = false; 359 else static if (is(T == struct) || is(T == union)) 360 enum hasUnsharedIndirections = anySatisfy!(.hasUnsharedIndirections, Fields!T); 361 else static if (is(T : E[N], E, size_t N)) 362 enum hasUnsharedIndirections = is(E == void) ? false : hasUnsharedIndirections!E; 363 else static if (isFunctionPointer!T) 364 enum hasUnsharedIndirections = false; 365 else static if (isPointer!T) 366 enum hasUnsharedIndirections = !is(T : shared(U)*, U) && !is(T : immutable(U)*, U); 367 else static if (isDynamicArray!T) 368 enum hasUnsharedIndirections = !is(T : shared(V)[], V) && !is(T : immutable(V)[], V); 369 else static if (is(T == class) || is(T == interface)) 370 enum hasUnsharedIndirections = !is(T : shared(W), W); 371 else 372 enum hasUnsharedIndirections = isDelegate!T || __traits(isAssociativeArray, T); // TODO: how to handle these? 373 } 374 375 unittest 376 { 377 static struct Foo { shared(int)* val; } 378 379 static assert(!hasUnsharedIndirections!(immutable(char)*)); 380 static assert(!hasUnsharedIndirections!(string)); 381 382 static assert(!hasUnsharedIndirections!(Foo)); 383 static assert( hasUnsharedIndirections!(Foo*)); 384 static assert(!hasUnsharedIndirections!(shared(Foo)*)); 385 static assert(!hasUnsharedIndirections!(immutable(Foo)*)); 386 387 int local; 388 struct HasContextPointer { int opCall() { return ++local; } } 389 static assert(hasIndirections!HasContextPointer); 390 } 391 392 enum bool isAggregateType(T) = is(T == struct) || is(T == union) || 393 is(T == class) || is(T == interface); 394 395 enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T; 396 397 enum bool isDynamicArray(T) = is(DynamicArrayTypeOf!T) && !isAggregateType!T; 398 399 template OriginalType(T) 400 { 401 template Impl(T) 402 { 403 static if (is(T U == enum)) alias Impl = OriginalType!U; 404 else alias Impl = T; 405 } 406 407 alias OriginalType = ModifyTypePreservingTQ!(Impl, T); 408 } 409 410 template DynamicArrayTypeOf(T) 411 { 412 static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT)) 413 alias X = DynamicArrayTypeOf!AT; 414 else 415 alias X = OriginalType!T; 416 417 static if (is(Unqual!X : E[], E) && !is(typeof({ enum n = X.length; }))) 418 alias DynamicArrayTypeOf = X; 419 else 420 static assert(0, T.stringof ~ " is not a dynamic array"); 421 } 422 423 private template AliasThisTypeOf(T) 424 if (isAggregateType!T) 425 { 426 alias members = __traits(getAliasThis, T); 427 428 static if (members.length == 1) 429 alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0])); 430 else 431 static assert(0, T.stringof~" does not have alias this type"); 432 } 433 434 template isFunctionPointer(T...) 435 if (T.length == 1) 436 { 437 static if (is(T[0] U) || is(typeof(T[0]) U)) 438 { 439 static if (is(U F : F*) && is(F == function)) 440 enum bool isFunctionPointer = true; 441 else 442 enum bool isFunctionPointer = false; 443 } 444 else 445 enum bool isFunctionPointer = false; 446 } 447 448 template isDelegate(T...) 449 if (T.length == 1) 450 { 451 static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate)) 452 { 453 // T is a (nested) function symbol. 454 enum bool isDelegate = true; 455 } 456 else static if (is(T[0] W) || is(typeof(T[0]) W)) 457 { 458 // T is an expression or a type. Take the type of it and examine. 459 enum bool isDelegate = is(W == delegate); 460 } 461 else 462 enum bool isDelegate = false; 463 } 464 465 // std.meta.Filter 466 template Filter(alias pred, TList...) 467 { 468 static if (TList.length == 0) 469 { 470 alias Filter = AliasSeq!(); 471 } 472 else static if (TList.length == 1) 473 { 474 static if (pred!(TList[0])) 475 alias Filter = AliasSeq!(TList[0]); 476 else 477 alias Filter = AliasSeq!(); 478 } 479 /* The next case speeds up compilation by reducing 480 * the number of Filter instantiations 481 */ 482 else static if (TList.length == 2) 483 { 484 static if (pred!(TList[0])) 485 { 486 static if (pred!(TList[1])) 487 alias Filter = AliasSeq!(TList[0], TList[1]); 488 else 489 alias Filter = AliasSeq!(TList[0]); 490 } 491 else 492 { 493 static if (pred!(TList[1])) 494 alias Filter = AliasSeq!(TList[1]); 495 else 496 alias Filter = AliasSeq!(); 497 } 498 } 499 else 500 { 501 alias Filter = 502 AliasSeq!( 503 Filter!(pred, TList[ 0 .. $/2]), 504 Filter!(pred, TList[$/2 .. $ ])); 505 } 506 } 507 508 // std.meta.staticMap 509 template staticMap(alias F, T...) 510 { 511 static if (T.length == 0) 512 { 513 alias staticMap = AliasSeq!(); 514 } 515 else static if (T.length == 1) 516 { 517 alias staticMap = AliasSeq!(F!(T[0])); 518 } 519 /* Cases 2 to 8 improve compile performance by reducing 520 * the number of recursive instantiations of staticMap 521 */ 522 else static if (T.length == 2) 523 { 524 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1])); 525 } 526 else static if (T.length == 3) 527 { 528 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2])); 529 } 530 else static if (T.length == 4) 531 { 532 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3])); 533 } 534 else static if (T.length == 5) 535 { 536 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4])); 537 } 538 else static if (T.length == 6) 539 { 540 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5])); 541 } 542 else static if (T.length == 7) 543 { 544 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]), F!(T[6])); 545 } 546 else static if (T.length == 8) 547 { 548 alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]), F!(T[6]), F!(T[7])); 549 } 550 else 551 { 552 alias staticMap = 553 AliasSeq!( 554 staticMap!(F, T[ 0 .. $/2]), 555 staticMap!(F, T[$/2 .. $ ])); 556 } 557 } 558 559 // std.exception.assertCTFEable 560 version (CoreUnittest) package(core) 561 void assertCTFEable(alias dg)() 562 { 563 static assert({ cast(void) dg(); return true; }()); 564 cast(void) dg(); 565 } 566 567 // std.traits.FunctionTypeOf 568 /* 569 Get the function type from a callable object `func`. 570 571 Using builtin `typeof` on a property function yields the types of the 572 property value, not of the property function itself. Still, 573 `FunctionTypeOf` is able to obtain function types of properties. 574 575 Note: 576 Do not confuse function types with function pointer types; function types are 577 usually used for compile-time reflection purposes. 578 */ 579 template FunctionTypeOf(func...) 580 if (func.length == 1 /*&& isCallable!func*/) 581 { 582 static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate)) 583 { 584 alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol 585 } 586 else static if (is(typeof(& func[0].opCall) Fobj == delegate)) 587 { 588 alias FunctionTypeOf = Fobj; // HIT: callable object 589 } 590 else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function)) 591 { 592 alias FunctionTypeOf = Ftyp; // HIT: callable type 593 } 594 else static if (is(func[0] T) || is(typeof(func[0]) T)) 595 { 596 static if (is(T == function)) 597 alias FunctionTypeOf = T; // HIT: function 598 else static if (is(T Fptr : Fptr*) && is(Fptr == function)) 599 alias FunctionTypeOf = Fptr; // HIT: function pointer 600 else static if (is(T Fdlg == delegate)) 601 alias FunctionTypeOf = Fdlg; // HIT: delegate 602 else 603 static assert(0); 604 } 605 else 606 static assert(0); 607 } 608 609 @safe unittest 610 { 611 class C 612 { 613 int value() @property { return 0; } 614 } 615 static assert(is( typeof(C.value) == int )); 616 static assert(is( FunctionTypeOf!(C.value) == function )); 617 } 618 619 @system unittest 620 { 621 int test(int a); 622 int propGet() @property; 623 int propSet(int a) @property; 624 int function(int) test_fp; 625 int delegate(int) test_dg; 626 static assert(is( typeof(test) == FunctionTypeOf!(typeof(test)) )); 627 static assert(is( typeof(test) == FunctionTypeOf!test )); 628 static assert(is( typeof(test) == FunctionTypeOf!test_fp )); 629 static assert(is( typeof(test) == FunctionTypeOf!test_dg )); 630 alias int GetterType() @property; 631 alias int SetterType(int) @property; 632 static assert(is( FunctionTypeOf!propGet == GetterType )); 633 static assert(is( FunctionTypeOf!propSet == SetterType )); 634 635 interface Prop { int prop() @property; } 636 Prop prop; 637 static assert(is( FunctionTypeOf!(Prop.prop) == GetterType )); 638 static assert(is( FunctionTypeOf!(prop.prop) == GetterType )); 639 640 class Callable { int opCall(int) { return 0; } } 641 auto call = new Callable; 642 static assert(is( FunctionTypeOf!call == typeof(test) )); 643 644 struct StaticCallable { static int opCall(int) { return 0; } } 645 StaticCallable stcall_val; 646 StaticCallable* stcall_ptr; 647 static assert(is( FunctionTypeOf!stcall_val == typeof(test) )); 648 static assert(is( FunctionTypeOf!stcall_ptr == typeof(test) )); 649 650 interface Overloads 651 { 652 void test(string); 653 real test(real); 654 int test(int); 655 int test() @property; 656 } 657 alias ov = __traits(getVirtualMethods, Overloads, "test"); 658 alias F_ov0 = FunctionTypeOf!(ov[0]); 659 alias F_ov1 = FunctionTypeOf!(ov[1]); 660 alias F_ov2 = FunctionTypeOf!(ov[2]); 661 alias F_ov3 = FunctionTypeOf!(ov[3]); 662 static assert(is(F_ov0* == void function(string))); 663 static assert(is(F_ov1* == real function(real))); 664 static assert(is(F_ov2* == int function(int))); 665 static assert(is(F_ov3* == int function() @property)); 666 667 alias F_dglit = FunctionTypeOf!((int a){ return a; }); 668 static assert(is(F_dglit* : int function(int))); 669 } 670 671 // std.traits.ReturnType 672 /* 673 Get the type of the return value from a function, 674 a pointer to function, a delegate, a struct 675 with an opCall, a pointer to a struct with an opCall, 676 or a class with an `opCall`. Please note that $(D_KEYWORD ref) 677 is not part of a type, but the attribute of the function 678 (see template $(LREF functionAttributes)). 679 */ 680 template ReturnType(func...) 681 if (func.length == 1 /*&& isCallable!func*/) 682 { 683 static if (is(FunctionTypeOf!func R == return)) 684 alias ReturnType = R; 685 else 686 static assert(0, "argument has no return type"); 687 } 688 689 // 690 @safe unittest 691 { 692 int foo(); 693 ReturnType!foo x; // x is declared as int 694 } 695 696 @safe unittest 697 { 698 struct G 699 { 700 int opCall (int i) { return 1;} 701 } 702 703 alias ShouldBeInt = ReturnType!G; 704 static assert(is(ShouldBeInt == int)); 705 706 G g; 707 static assert(is(ReturnType!g == int)); 708 709 G* p; 710 alias pg = ReturnType!p; 711 static assert(is(pg == int)); 712 713 class C 714 { 715 int opCall (int i) { return 1;} 716 } 717 718 static assert(is(ReturnType!C == int)); 719 720 C c; 721 static assert(is(ReturnType!c == int)); 722 723 class Test 724 { 725 int prop() @property { return 0; } 726 } 727 alias R_Test_prop = ReturnType!(Test.prop); 728 static assert(is(R_Test_prop == int)); 729 730 alias R_dglit = ReturnType!((int a) { return a; }); 731 static assert(is(R_dglit == int)); 732 } 733 734 // std.traits.Parameters 735 /* 736 Get, as a tuple, the types of the parameters to a function, a pointer 737 to function, a delegate, a struct with an `opCall`, a pointer to a 738 struct with an `opCall`, or a class with an `opCall`. 739 */ 740 template Parameters(func...) 741 if (func.length == 1 /*&& isCallable!func*/) 742 { 743 static if (is(FunctionTypeOf!func P == function)) 744 alias Parameters = P; 745 else 746 static assert(0, "argument has no parameters"); 747 } 748 749 // 750 @safe unittest 751 { 752 int foo(int, long); 753 void bar(Parameters!foo); // declares void bar(int, long); 754 void abc(Parameters!foo[1]); // declares void abc(long); 755 } 756 757 @safe unittest 758 { 759 int foo(int i, bool b) { return 0; } 760 static assert(is(Parameters!foo == AliasSeq!(int, bool))); 761 static assert(is(Parameters!(typeof(&foo)) == AliasSeq!(int, bool))); 762 763 struct S { real opCall(real r, int i) { return 0.0; } } 764 S s; 765 static assert(is(Parameters!S == AliasSeq!(real, int))); 766 static assert(is(Parameters!(S*) == AliasSeq!(real, int))); 767 static assert(is(Parameters!s == AliasSeq!(real, int))); 768 769 class Test 770 { 771 int prop() @property { return 0; } 772 } 773 alias P_Test_prop = Parameters!(Test.prop); 774 static assert(P_Test_prop.length == 0); 775 776 alias P_dglit = Parameters!((int a){}); 777 static assert(P_dglit.length == 1); 778 static assert(is(P_dglit[0] == int)); 779 } 780 781 // Return `true` if `Type` has `member` that evaluates to `true` in a static if condition 782 enum isTrue(Type, string member) = __traits(compiles, { static if (__traits(getMember, Type, member)) {} else static assert(0); }); 783 784 unittest 785 { 786 static struct T 787 { 788 enum a = true; 789 enum b = false; 790 enum c = 1; 791 enum d = 45; 792 enum e = "true"; 793 enum f = ""; 794 enum g = null; 795 alias h = bool; 796 } 797 798 static assert( isTrue!(T, "a")); 799 static assert(!isTrue!(T, "b")); 800 static assert( isTrue!(T, "c")); 801 static assert( isTrue!(T, "d")); 802 static assert( isTrue!(T, "e")); 803 static assert( isTrue!(T, "f")); 804 static assert(!isTrue!(T, "g")); 805 static assert(!isTrue!(T, "h")); 806 } 807 808 template hasUDA(alias symbol, alias attribute) 809 { 810 alias attrs = __traits(getAttributes, symbol); 811 812 static foreach (a; attrs) 813 { 814 static if (is(a == attribute)) 815 { 816 enum hasUDA = true; 817 } 818 } 819 820 static if (!__traits(compiles, (hasUDA == true))) 821 enum hasUDA = false; 822 } 823 824 unittest 825 { 826 struct SomeUDA{} 827 828 struct Test 829 { 830 int woUDA; 831 @SomeUDA int withUDA; 832 } 833 834 static assert(hasUDA!(Test.withUDA, SomeUDA)); 835 static assert(!hasUDA!(Test.woUDA, SomeUDA)); 836 }