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) || is(T == interface))
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
allSatisfy(alias F,T...)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
anySatisfy(alias F,Ts...)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 alias classInstanceAlignment = maxAlignment!(void*, typeof(T.tupleof));
238 }
239
240 /// See $(REF hasElaborateMove, std,traits)
hasElaborateMove(S)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
hasElaborateDestructor(S)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
hasElaborateCopyConstructor(S)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;
thisS299 this(return scope ref typeof(this) rhs) { }
thisS300 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;
thisS2309 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) { }
thisS3318 this(int x, int y) {}
319 }
320
321 static assert(hasElaborateCopyConstructor!S3);
322 }
323
hasElaborateAssign(S)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
hasIndirections(T)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
hasUnsharedIndirections(T)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;
opCallHasContextPointer388 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
OriginalType(T)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
DynamicArrayTypeOf(T)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
Filter(alias pred,TList...)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
staticMap(alias F,T...)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
package(core)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 {
value()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
opCall(int)640 class Callable { int opCall(int) { return 0; } }
641 auto call = new Callable;
642 static assert(is( FunctionTypeOf!call == typeof(test) ));
643
opCallStaticCallable644 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(getVirtualFunctions, 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 {
opCallG700 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 {
opCall(int i)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 {
prop()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 {
foo(int i,bool b)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
opCallS763 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 {
prop()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
hasUDA(alias symbol,alias attribute)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 }
837