"Fossies" - the Fresh Open Source Software Archive

Member "dmd2/src/druntime/src/core/internal/traits.d" (20 Nov 2020, 26033 Bytes) of package /linux/misc/dmd.2.094.2.linux.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) D source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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