]> git.ipfire.org Git - thirdparty/gcc.git/blob - libphobos/libdruntime/core/internal/traits.d
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
[thirdparty/gcc.git] / libphobos / libdruntime / core / internal / traits.d
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 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 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)
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
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
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;
283 this(return scope ref typeof(this) rhs) { }
284 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;
293 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) { }
302 this(int x, int y) {}
303 }
304
305 static assert(hasElaborateCopyConstructor!S3);
306 }
307
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
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
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
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
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
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
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
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 {
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
620 class Callable { int opCall(int) { return 0; } }
621 auto call = new Callable;
622 static assert(is( FunctionTypeOf!call == typeof(test) ));
623
624 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 {
680 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 {
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 {
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 {
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
743 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 {
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
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 }