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 
Fields(T)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 
trustedCast(T,U)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 
BaseElemOf(T)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]
ModifyTypePreservingTQ(alias Modifier,T)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`
substInout(T)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 
substInoutForm(T)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 
staticIota(int beg,int end)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 {}
rvalueOf(T)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     {
hasOuterMember(T...)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 
dtorIsNothrow(T)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 enum allSatisfy(alias pred, items...) =
189 {
190     static foreach (item; items)
191         static if (!pred!item)
192             if (__ctfe) return false;
193     return true;
194 }();
195 
196 // taken from std.meta.anySatisfy
197 enum anySatisfy(alias pred, items...) =
198 {
199     static foreach (item; items)
200         static if (pred!item)
201             if (__ctfe) return true;
202     return false;
203 }();
204 
205 // simplified from std.traits.maxAlignment
206 template maxAlignment(Ts...)
207 if (Ts.length > 0)
208 {
209     enum maxAlignment =
210     {
211         size_t result = 0;
212         static foreach (T; Ts)
213             if (T.alignof > result) result = T.alignof;
214         return result;
215     }();
216 }
217 
218 template classInstanceAlignment(T)
219 if (is(T == class))
220 {
221     alias classInstanceAlignment = maxAlignment!(void*, typeof(T.tupleof));
222 }
223 
224 /// See $(REF hasElaborateMove, std,traits)
hasElaborateMove(S)225 template hasElaborateMove(S)
226 {
227     static if (__traits(isStaticArray, S))
228     {
229         enum bool hasElaborateMove = S.sizeof && hasElaborateMove!(BaseElemOf!S);
230     }
231     else static if (is(S == struct))
232     {
233         enum hasElaborateMove = (is(typeof(S.init.opPostMove(lvalueOf!S))) &&
234                                     !is(typeof(S.init.opPostMove(rvalueOf!S)))) ||
235                                 anySatisfy!(.hasElaborateMove, Fields!S);
236     }
237     else
238     {
239         enum bool hasElaborateMove = false;
240     }
241 }
242 
243 // std.traits.hasElaborateDestructor
hasElaborateDestructor(S)244 template hasElaborateDestructor(S)
245 {
246     static if (__traits(isStaticArray, S))
247     {
248         enum bool hasElaborateDestructor = S.sizeof && hasElaborateDestructor!(BaseElemOf!S);
249     }
250     else static if (is(S == struct))
251     {
252         enum hasElaborateDestructor = __traits(hasMember, S, "__dtor")
253             || anySatisfy!(.hasElaborateDestructor, Fields!S);
254     }
255     else
256     {
257         enum bool hasElaborateDestructor = false;
258     }
259 }
260 
261 // std.traits.hasElaborateCopyDestructor
hasElaborateCopyConstructor(S)262 template hasElaborateCopyConstructor(S)
263 {
264     static if (__traits(isStaticArray, S))
265     {
266         enum bool hasElaborateCopyConstructor = S.sizeof && hasElaborateCopyConstructor!(BaseElemOf!S);
267     }
268     else static if (is(S == struct))
269     {
270         enum hasElaborateCopyConstructor = __traits(hasCopyConstructor, S) || __traits(hasPostblit, S);
271     }
272     else
273     {
274         enum bool hasElaborateCopyConstructor = false;
275     }
276 }
277 
278 @safe unittest
279 {
280     static struct S
281     {
282         int x;
thisS283         this(return scope ref typeof(this) rhs) { }
thisS284         this(int x, int y) {}
285     }
286 
287     static assert(hasElaborateCopyConstructor!S);
288     static assert(!hasElaborateCopyConstructor!(S[0][1]));
289 
290     static struct S2
291     {
292         int x;
thisS2293         this(int x, int y) {}
294     }
295 
296     static assert(!hasElaborateCopyConstructor!S2);
297 
298     static struct S3
299     {
300         int x;
301         this(return scope ref typeof(this) rhs, int x = 42) { }
thisS3302         this(int x, int y) {}
303     }
304 
305     static assert(hasElaborateCopyConstructor!S3);
306 }
307 
hasElaborateAssign(S)308 template hasElaborateAssign(S)
309 {
310     static if (__traits(isStaticArray, S))
311     {
312         enum bool hasElaborateAssign = S.sizeof && hasElaborateAssign!(BaseElemOf!S);
313     }
314     else static if (is(S == struct))
315     {
316         enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) ||
317                                   is(typeof(S.init.opAssign(lvalueOf!S))) ||
318                                   anySatisfy!(.hasElaborateAssign, Fields!S);
319     }
320     else
321     {
322         enum bool hasElaborateAssign = false;
323     }
324 }
325 
hasIndirections(T)326 template hasIndirections(T)
327 {
328     static if (is(T == struct) || is(T == union))
329         enum hasIndirections = anySatisfy!(.hasIndirections, Fields!T);
330     else static if (is(T == E[N], E, size_t N))
331         enum hasIndirections = T.sizeof && is(E == void) ? true : hasIndirections!(BaseElemOf!E);
332     else static if (isFunctionPointer!T)
333         enum hasIndirections = false;
334     else
335         enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T ||
336             __traits(isAssociativeArray, T) || is (T == class) || is(T == interface);
337 }
338 
hasUnsharedIndirections(T)339 template hasUnsharedIndirections(T)
340 {
341     static if (is(T == immutable))
342         enum hasUnsharedIndirections = false;
343     else static if (is(T == struct) || is(T == union))
344         enum hasUnsharedIndirections = anySatisfy!(.hasUnsharedIndirections, Fields!T);
345     else static if (is(T : E[N], E, size_t N))
346         enum hasUnsharedIndirections = is(E == void) ? false : hasUnsharedIndirections!E;
347     else static if (isFunctionPointer!T)
348         enum hasUnsharedIndirections = false;
349     else static if (isPointer!T)
350         enum hasUnsharedIndirections = !is(T : shared(U)*, U) && !is(T : immutable(U)*, U);
351     else static if (isDynamicArray!T)
352         enum hasUnsharedIndirections = !is(T : shared(V)[], V) && !is(T : immutable(V)[], V);
353     else static if (is(T == class) || is(T == interface))
354         enum hasUnsharedIndirections = !is(T : shared(W), W);
355     else
356         enum hasUnsharedIndirections = isDelegate!T || __traits(isAssociativeArray, T); // TODO: how to handle these?
357 }
358 
359 unittest
360 {
361     static struct Foo { shared(int)* val; }
362 
363     static assert(!hasUnsharedIndirections!(immutable(char)*));
364     static assert(!hasUnsharedIndirections!(string));
365 
366     static assert(!hasUnsharedIndirections!(Foo));
367     static assert( hasUnsharedIndirections!(Foo*));
368     static assert(!hasUnsharedIndirections!(shared(Foo)*));
369     static assert(!hasUnsharedIndirections!(immutable(Foo)*));
370 }
371 
372 enum bool isAggregateType(T) = is(T == struct) || is(T == union) ||
373                                is(T == class) || is(T == interface);
374 
375 enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T;
376 
377 enum bool isDynamicArray(T) = is(DynamicArrayTypeOf!T) && !isAggregateType!T;
378 
OriginalType(T)379 template OriginalType(T)
380 {
381     template Impl(T)
382     {
383         static if (is(T U == enum)) alias Impl = OriginalType!U;
384         else                        alias Impl =              T;
385     }
386 
387     alias OriginalType = ModifyTypePreservingTQ!(Impl, T);
388 }
389 
DynamicArrayTypeOf(T)390 template DynamicArrayTypeOf(T)
391 {
392     static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
393         alias X = DynamicArrayTypeOf!AT;
394     else
395         alias X = OriginalType!T;
396 
397     static if (is(Unqual!X : E[], E) && !is(typeof({ enum n = X.length; })))
398         alias DynamicArrayTypeOf = X;
399     else
400         static assert(0, T.stringof ~ " is not a dynamic array");
401 }
402 
403 private template AliasThisTypeOf(T)
404     if (isAggregateType!T)
405 {
406     alias members = __traits(getAliasThis, T);
407 
408     static if (members.length == 1)
409         alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0]));
410     else
411         static assert(0, T.stringof~" does not have alias this type");
412 }
413 
414 template isFunctionPointer(T...)
415     if (T.length == 1)
416 {
417     static if (is(T[0] U) || is(typeof(T[0]) U))
418     {
419         static if (is(U F : F*) && is(F == function))
420             enum bool isFunctionPointer = true;
421         else
422             enum bool isFunctionPointer = false;
423     }
424     else
425         enum bool isFunctionPointer = false;
426 }
427 
428 template isDelegate(T...)
429     if (T.length == 1)
430 {
431     static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate))
432     {
433         // T is a (nested) function symbol.
434         enum bool isDelegate = true;
435     }
436     else static if (is(T[0] W) || is(typeof(T[0]) W))
437     {
438         // T is an expression or a type.  Take the type of it and examine.
439         enum bool isDelegate = is(W == delegate);
440     }
441     else
442         enum bool isDelegate = false;
443 }
444 
445 // std.meta.Filter
Filter(alias pred,TList...)446 template Filter(alias pred, TList...)
447 {
448     static if (TList.length == 0)
449     {
450         alias Filter = AliasSeq!();
451     }
452     else static if (TList.length == 1)
453     {
454         static if (pred!(TList[0]))
455             alias Filter = AliasSeq!(TList[0]);
456         else
457             alias Filter = AliasSeq!();
458     }
459     /* The next case speeds up compilation by reducing
460      * the number of Filter instantiations
461      */
462     else static if (TList.length == 2)
463     {
464         static if (pred!(TList[0]))
465         {
466             static if (pred!(TList[1]))
467                 alias Filter = AliasSeq!(TList[0], TList[1]);
468             else
469                 alias Filter = AliasSeq!(TList[0]);
470         }
471         else
472         {
473             static if (pred!(TList[1]))
474                 alias Filter = AliasSeq!(TList[1]);
475             else
476                 alias Filter = AliasSeq!();
477         }
478     }
479     else
480     {
481         alias Filter =
482             AliasSeq!(
483                 Filter!(pred, TList[ 0  .. $/2]),
484                 Filter!(pred, TList[$/2 ..  $ ]));
485     }
486 }
487 
488 // std.meta.staticMap
staticMap(alias F,T...)489 template staticMap(alias F, T...)
490 {
491     static if (T.length == 0)
492     {
493         alias staticMap = AliasSeq!();
494     }
495     else static if (T.length == 1)
496     {
497         alias staticMap = AliasSeq!(F!(T[0]));
498     }
499     /* Cases 2 to 8 improve compile performance by reducing
500      * the number of recursive instantiations of staticMap
501      */
502     else static if (T.length == 2)
503     {
504         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]));
505     }
506     else static if (T.length == 3)
507     {
508         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]));
509     }
510     else static if (T.length == 4)
511     {
512         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]));
513     }
514     else static if (T.length == 5)
515     {
516         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]));
517     }
518     else static if (T.length == 6)
519     {
520         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]));
521     }
522     else static if (T.length == 7)
523     {
524         alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]), F!(T[6]));
525     }
526     else static if (T.length == 8)
527     {
528         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]));
529     }
530     else
531     {
532         alias staticMap =
533             AliasSeq!(
534                 staticMap!(F, T[ 0  .. $/2]),
535                 staticMap!(F, T[$/2 ..  $ ]));
536     }
537 }
538 
539 // std.exception.assertCTFEable
package(core)540 version (CoreUnittest) package(core)
541 void assertCTFEable(alias dg)()
542 {
543     static assert({ cast(void) dg(); return true; }());
544     cast(void) dg();
545 }
546 
547 // std.traits.FunctionTypeOf
548 /*
549 Get the function type from a callable object `func`.
550 
551 Using builtin `typeof` on a property function yields the types of the
552 property value, not of the property function itself.  Still,
553 `FunctionTypeOf` is able to obtain function types of properties.
554 
555 Note:
556 Do not confuse function types with function pointer types; function types are
557 usually used for compile-time reflection purposes.
558  */
559 template FunctionTypeOf(func...)
560 if (func.length == 1 /*&& isCallable!func*/)
561 {
562     static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate))
563     {
564         alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol
565     }
566     else static if (is(typeof(& func[0].opCall) Fobj == delegate))
567     {
568         alias FunctionTypeOf = Fobj; // HIT: callable object
569     }
570     else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function))
571     {
572         alias FunctionTypeOf = Ftyp; // HIT: callable type
573     }
574     else static if (is(func[0] T) || is(typeof(func[0]) T))
575     {
576         static if (is(T == function))
577             alias FunctionTypeOf = T;    // HIT: function
578         else static if (is(T Fptr : Fptr*) && is(Fptr == function))
579             alias FunctionTypeOf = Fptr; // HIT: function pointer
580         else static if (is(T Fdlg == delegate))
581             alias FunctionTypeOf = Fdlg; // HIT: delegate
582         else
583             static assert(0);
584     }
585     else
586         static assert(0);
587 }
588 
589 @safe unittest
590 {
591     class C
592     {
value()593         int value() @property { return 0; }
594     }
595     static assert(is( typeof(C.value) == int ));
596     static assert(is( FunctionTypeOf!(C.value) == function ));
597 }
598 
599 @system unittest
600 {
601     int test(int a);
602     int propGet() @property;
603     int propSet(int a) @property;
604     int function(int) test_fp;
605     int delegate(int) test_dg;
606     static assert(is( typeof(test) == FunctionTypeOf!(typeof(test)) ));
607     static assert(is( typeof(test) == FunctionTypeOf!test ));
608     static assert(is( typeof(test) == FunctionTypeOf!test_fp ));
609     static assert(is( typeof(test) == FunctionTypeOf!test_dg ));
610     alias int GetterType() @property;
611     alias int SetterType(int) @property;
612     static assert(is( FunctionTypeOf!propGet == GetterType ));
613     static assert(is( FunctionTypeOf!propSet == SetterType ));
614 
615     interface Prop { int prop() @property; }
616     Prop prop;
617     static assert(is( FunctionTypeOf!(Prop.prop) == GetterType ));
618     static assert(is( FunctionTypeOf!(prop.prop) == GetterType ));
619 
opCall(int)620     class Callable { int opCall(int) { return 0; } }
621     auto call = new Callable;
622     static assert(is( FunctionTypeOf!call == typeof(test) ));
623 
opCallStaticCallable624     struct StaticCallable { static int opCall(int) { return 0; } }
625     StaticCallable stcall_val;
626     StaticCallable* stcall_ptr;
627     static assert(is( FunctionTypeOf!stcall_val == typeof(test) ));
628     static assert(is( FunctionTypeOf!stcall_ptr == typeof(test) ));
629 
630     interface Overloads
631     {
632         void test(string);
633         real test(real);
634         int  test(int);
635         int  test() @property;
636     }
637     alias ov = __traits(getVirtualFunctions, Overloads, "test");
638     alias F_ov0 = FunctionTypeOf!(ov[0]);
639     alias F_ov1 = FunctionTypeOf!(ov[1]);
640     alias F_ov2 = FunctionTypeOf!(ov[2]);
641     alias F_ov3 = FunctionTypeOf!(ov[3]);
642     static assert(is(F_ov0* == void function(string)));
643     static assert(is(F_ov1* == real function(real)));
644     static assert(is(F_ov2* == int function(int)));
645     static assert(is(F_ov3* == int function() @property));
646 
647     alias F_dglit = FunctionTypeOf!((int a){ return a; });
648     static assert(is(F_dglit* : int function(int)));
649 }
650 
651 // std.traits.ReturnType
652 /*
653 Get the type of the return value from a function,
654 a pointer to function, a delegate, a struct
655 with an opCall, a pointer to a struct with an opCall,
656 or a class with an `opCall`. Please note that $(D_KEYWORD ref)
657 is not part of a type, but the attribute of the function
658 (see template $(LREF functionAttributes)).
659 */
660 template ReturnType(func...)
661 if (func.length == 1 /*&& isCallable!func*/)
662 {
663     static if (is(FunctionTypeOf!func R == return))
664         alias ReturnType = R;
665     else
666         static assert(0, "argument has no return type");
667 }
668 
669 //
670 @safe unittest
671 {
672     int foo();
673     ReturnType!foo x;   // x is declared as int
674 }
675 
676 @safe unittest
677 {
678     struct G
679     {
opCallG680         int opCall (int i) { return 1;}
681     }
682 
683     alias ShouldBeInt = ReturnType!G;
684     static assert(is(ShouldBeInt == int));
685 
686     G g;
687     static assert(is(ReturnType!g == int));
688 
689     G* p;
690     alias pg = ReturnType!p;
691     static assert(is(pg == int));
692 
693     class C
694     {
opCall(int i)695         int opCall (int i) { return 1;}
696     }
697 
698     static assert(is(ReturnType!C == int));
699 
700     C c;
701     static assert(is(ReturnType!c == int));
702 
703     class Test
704     {
prop()705         int prop() @property { return 0; }
706     }
707     alias R_Test_prop = ReturnType!(Test.prop);
708     static assert(is(R_Test_prop == int));
709 
710     alias R_dglit = ReturnType!((int a) { return a; });
711     static assert(is(R_dglit == int));
712 }
713 
714 // std.traits.Parameters
715 /*
716 Get, as a tuple, the types of the parameters to a function, a pointer
717 to function, a delegate, a struct with an `opCall`, a pointer to a
718 struct with an `opCall`, or a class with an `opCall`.
719 */
720 template Parameters(func...)
721 if (func.length == 1 /*&& isCallable!func*/)
722 {
723     static if (is(FunctionTypeOf!func P == function))
724         alias Parameters = P;
725     else
726         static assert(0, "argument has no parameters");
727 }
728 
729 //
730 @safe unittest
731 {
732     int foo(int, long);
733     void bar(Parameters!foo);      // declares void bar(int, long);
734     void abc(Parameters!foo[1]);   // declares void abc(long);
735 }
736 
737 @safe unittest
738 {
foo(int i,bool b)739     int foo(int i, bool b) { return 0; }
740     static assert(is(Parameters!foo == AliasSeq!(int, bool)));
741     static assert(is(Parameters!(typeof(&foo)) == AliasSeq!(int, bool)));
742 
opCallS743     struct S { real opCall(real r, int i) { return 0.0; } }
744     S s;
745     static assert(is(Parameters!S == AliasSeq!(real, int)));
746     static assert(is(Parameters!(S*) == AliasSeq!(real, int)));
747     static assert(is(Parameters!s == AliasSeq!(real, int)));
748 
749     class Test
750     {
prop()751         int prop() @property { return 0; }
752     }
753     alias P_Test_prop = Parameters!(Test.prop);
754     static assert(P_Test_prop.length == 0);
755 
756     alias P_dglit = Parameters!((int a){});
757     static assert(P_dglit.length == 1);
758     static assert(is(P_dglit[0] == int));
759 }
760 
761 // Return `true` if `Type` has `member` that evaluates to `true` in a static if condition
762 enum isTrue(Type, string member) = __traits(compiles, { static if (__traits(getMember, Type, member)) {} else static assert(0); });
763 
764 unittest
765 {
766     static struct T
767     {
768         enum a = true;
769         enum b = false;
770         enum c = 1;
771         enum d = 45;
772         enum e = "true";
773         enum f = "";
774         enum g = null;
775         alias h = bool;
776     }
777 
778     static assert( isTrue!(T, "a"));
779     static assert(!isTrue!(T, "b"));
780     static assert( isTrue!(T, "c"));
781     static assert( isTrue!(T, "d"));
782     static assert( isTrue!(T, "e"));
783     static assert( isTrue!(T, "f"));
784     static assert(!isTrue!(T, "g"));
785     static assert(!isTrue!(T, "h"));
786 }
787 
hasUDA(alias symbol,alias attribute)788 template hasUDA(alias symbol, alias attribute)
789 {
790     alias attrs = __traits(getAttributes, symbol);
791 
792     static foreach (a; attrs)
793     {
794         static if (is(a == attribute))
795         {
796             enum hasUDA = true;
797         }
798     }
799 
800     static if (!__traits(compiles, (hasUDA == true)))
801         enum hasUDA = false;
802 }
803 
804 unittest
805 {
806     struct SomeUDA{}
807 
808     struct Test
809     {
810         int woUDA;
811         @SomeUDA int withUDA;
812     }
813 
814     static assert(hasUDA!(Test.withUDA, SomeUDA));
815     static assert(!hasUDA!(Test.woUDA, SomeUDA));
816 }
817