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 }