mirror of
https://github.com/openRuyi-Project/gcc.git
synced 2026-09-06 14:01:37 +00:00
D front-end changes: - Import latest fixes from v2.112.0-beta.1. - Associative array operations are now lowered to templates defined in `core.internal.newaa'. D runtime changes: - Import latest fixes from v2.112.0-beta.1. Phobos changes: - Import latest fixes from v2.112.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd e1f6680f50. * Make-lang.in (D_FRONTEND_OBJS): Remove d/gluelayer.o, d/iasm.o, d/iasmgcc.o. Add d/iasm-package.o, d/iasm-gcc.o. (d/iasm-%.o): New recipe. * d-convert.cc (convert_expr): Remove library call to dynamic_cast. * d-lang.cc (d_init_options): Set errorSupplementLimit parameter. * decl.cc (DeclVisitor::visit): Update for new front-end interface. * expr.cc (ExprVisitor::visit (EqualExp *)): Update for front-end lowering expression using templates. (ExprVisitor::visit (InExp *)): Likewise. (ExprVisitor::visit (IndexExp *)): Likewise. (ExprVisitor::visit (CastExp *)): Likewise. (ExprVisitor::visit (RemoveExp *)): Likewise. (ExprVisitor::visit (AddrExp *)): Likewise. (ExprVisitor::visit (NewExp *)): Likewise. (ExprVisitor::visit (ArrayLiteralExp *)): Likewise. (ExprVisitor::visit (AssocArrayLiteralExp *)): Likewise. * imports.cc (ImportVisitor::visit (AliasDeclaration *)): Update for new front-end interface. * runtime.def (DYNAMIC_CAST): Remove. (INTERFACE_CAST): Remove. (ARRAYLITERALTX): Remove. (ADEQ2): Remove. (ASSOCARRAYLITERALTX): Remove. (AANEW): Remove. (AAEQUAL): Remove. (AAINX): Remove. (AAGETY): Remove. (AAGETRVALUEX): Remove. (AADELX): Remove. * typeinfo.cc (TypeInfoVisitor::visit): Layout xopEquals and xtoHash in TypeInfo_AssociativeArray. (create_typeinfo): Add new fields to internal typeinfo. (check_typeinfo_type): Print instantiation trace of error. * types.cc (TypeVisitor::visit (TypeStruct *)): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e1f6680f50. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/cast_.d. Remove rt/aaA.d, rt/adi.d, rt/cast_.d. (DRUNTIME_DSOURCES_POSIX): Add core/sys/posix/endian.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos f87979028. * src/Makefile.am (PHOBOS_DSOURCES): Add std/internal/entropy.d. * src/Makefile.in: Regenerate. * testsuite/libphobos.aa/test_aa.d: Adjust test. * testsuite/libphobos.init_fini/custom_gc.d: Likewise. gcc/testsuite/ChangeLog: * gdc.dg/asm1.d: Adjust test. * gdc.dg/asm5.d: Likewise. * gdc.dg/pr100967.d: Likewise. * gdc.dg/rtti1.d: Likewise. * gdc.dg/rtti2.d: New test.
1244 lines
38 KiB
D
1244 lines
38 KiB
D
/**
|
|
* Contains traits for runtime internal usage.
|
|
*
|
|
* Copyright: Copyright Digital Mars 2014 -.
|
|
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
|
* Authors: Martin Nowak
|
|
* Source: $(DRUNTIMESRC core/internal/_traits.d)
|
|
*/
|
|
module core.internal.traits;
|
|
|
|
alias AliasSeq(TList...) = TList;
|
|
|
|
template Fields(T)
|
|
{
|
|
static if (is(T == struct) || is(T == union))
|
|
alias Fields = typeof(T.tupleof[0 .. $ - __traits(isNested, T)]);
|
|
else static if (is(T == class) || is(T == interface))
|
|
alias Fields = typeof(T.tupleof);
|
|
else
|
|
alias Fields = AliasSeq!T;
|
|
}
|
|
|
|
T trustedCast(T, U)(auto ref U u) @trusted pure nothrow
|
|
{
|
|
return cast(T)u;
|
|
}
|
|
|
|
alias Unconst(T : const U, U) = U;
|
|
|
|
/// taken from std.traits.Unqual
|
|
template Unqual(T : const U, U)
|
|
{
|
|
static if (is(U == shared V, V))
|
|
alias Unqual = V;
|
|
else
|
|
alias Unqual = U;
|
|
}
|
|
|
|
template BaseElemOf(T)
|
|
{
|
|
static if (is(OriginalType!T == E[N], E, size_t N))
|
|
alias BaseElemOf = BaseElemOf!E;
|
|
else
|
|
alias BaseElemOf = T;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static assert(is(BaseElemOf!(int) == int));
|
|
static assert(is(BaseElemOf!(int[1]) == int));
|
|
static assert(is(BaseElemOf!(int[1][2]) == int));
|
|
static assert(is(BaseElemOf!(int[1][]) == int[1][]));
|
|
static assert(is(BaseElemOf!(int[][1]) == int[]));
|
|
enum E : int[2]{ test = [0, 1] }
|
|
static assert(is(BaseElemOf!(E) == int));
|
|
}
|
|
|
|
// [For internal use]
|
|
template ModifyTypePreservingTQ(alias Modifier, T)
|
|
{
|
|
static if (is(T U == immutable U)) alias ModifyTypePreservingTQ = immutable Modifier!U;
|
|
else static if (is(T U == shared inout const U)) alias ModifyTypePreservingTQ = shared inout const Modifier!U;
|
|
else static if (is(T U == shared inout U)) alias ModifyTypePreservingTQ = shared inout Modifier!U;
|
|
else static if (is(T U == shared const U)) alias ModifyTypePreservingTQ = shared const Modifier!U;
|
|
else static if (is(T U == shared U)) alias ModifyTypePreservingTQ = shared Modifier!U;
|
|
else static if (is(T U == inout const U)) alias ModifyTypePreservingTQ = inout const Modifier!U;
|
|
else static if (is(T U == inout U)) alias ModifyTypePreservingTQ = inout Modifier!U;
|
|
else static if (is(T U == const U)) alias ModifyTypePreservingTQ = const Modifier!U;
|
|
else alias ModifyTypePreservingTQ = Modifier!T;
|
|
}
|
|
@safe unittest
|
|
{
|
|
alias Intify(T) = int;
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, real) == int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, const real) == const int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, inout real) == inout int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, inout const real) == inout const int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, shared real) == shared int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, shared const real) == shared const int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, shared inout real) == shared inout int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, shared inout const real) == shared inout const int));
|
|
static assert(is(ModifyTypePreservingTQ!(Intify, immutable real) == immutable int));
|
|
}
|
|
|
|
// Substitute all `inout` qualifiers that appears in T to `const`
|
|
template substInout(T)
|
|
{
|
|
static if (is(T == immutable))
|
|
{
|
|
alias substInout = T;
|
|
}
|
|
else static if (is(T : shared const U, U) || is(T : const U, U))
|
|
{
|
|
// U is top-unqualified
|
|
mixin("alias substInout = "
|
|
~ (is(T == shared) ? "shared " : "")
|
|
~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const
|
|
~ "substInoutForm!U;");
|
|
}
|
|
else
|
|
static assert(0);
|
|
}
|
|
|
|
private template substInoutForm(T)
|
|
{
|
|
static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface))
|
|
{
|
|
alias substInoutForm = T; // prevent matching to the form of alias-this-ed type
|
|
}
|
|
else static if (is(T == V[K], K, V)) alias substInoutForm = substInout!V[substInout!K];
|
|
else static if (is(T == U[n], U, size_t n)) alias substInoutForm = substInout!U[n];
|
|
else static if (is(T == U[], U)) alias substInoutForm = substInout!U[];
|
|
else static if (is(T == U*, U)) alias substInoutForm = substInout!U*;
|
|
else alias substInoutForm = T;
|
|
}
|
|
|
|
unittest
|
|
{
|
|
// https://github.com/dlang/dmd/issues/21452
|
|
struct S { int x; }
|
|
struct T { int x; alias x this; }
|
|
|
|
enum EnumInt { a = 123 }
|
|
enum EnumUInt : uint { a = 123 }
|
|
enum EnumFloat : float { a = 123 }
|
|
enum EnumString : string { a = "123" }
|
|
enum EnumStringW : wstring { a = "123" }
|
|
enum EnumStruct : S { a = S(7) }
|
|
enum EnumAliasThis : T { a = T(7) }
|
|
enum EnumDArray : int[] { a = [1] }
|
|
enum EnumAArray : int[int] { a = [0 : 1] }
|
|
|
|
static assert(substInout!(EnumInt).stringof == "EnumInt");
|
|
static assert(substInout!(inout(EnumUInt)).stringof == "const(EnumUInt)");
|
|
static assert(substInout!(EnumFloat).stringof == "EnumFloat");
|
|
static assert(substInout!(EnumString).stringof == "EnumString");
|
|
static assert(substInout!(inout(EnumStringW)).stringof == "const(EnumStringW)");
|
|
static assert(substInout!(EnumStruct).stringof == "EnumStruct");
|
|
static assert(substInout!(EnumAliasThis).stringof == "EnumAliasThis");
|
|
static assert(substInout!(EnumDArray).stringof == "EnumDArray");
|
|
static assert(substInout!(inout(EnumAArray)[int]).stringof == "const(EnumAArray)[int]");
|
|
}
|
|
|
|
/// used to declare an extern(D) function that is defined in a different module
|
|
template externDFunc(string fqn, T:FT*, FT) if (is(FT == function))
|
|
{
|
|
static if (is(FT RT == return) && is(FT Args == function))
|
|
{
|
|
import core.demangle : mangleFunc;
|
|
enum decl = {
|
|
string s = "extern(D) RT externDFunc(Args)";
|
|
foreach (attr; __traits(getFunctionAttributes, FT))
|
|
s ~= " " ~ attr;
|
|
return s ~ ";";
|
|
}();
|
|
pragma(mangle, mangleFunc!T(fqn)) mixin(decl);
|
|
}
|
|
else
|
|
static assert(0);
|
|
}
|
|
|
|
template staticIota(int beg, int end)
|
|
{
|
|
static if (beg + 1 >= end)
|
|
{
|
|
static if (beg >= end)
|
|
{
|
|
alias staticIota = AliasSeq!();
|
|
}
|
|
else
|
|
{
|
|
alias staticIota = AliasSeq!(+beg);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
enum mid = beg + (end - beg) / 2;
|
|
alias staticIota = AliasSeq!(staticIota!(beg, mid), staticIota!(mid, end));
|
|
}
|
|
}
|
|
|
|
private struct __InoutWorkaroundStruct {}
|
|
@property T rvalueOf(T)(T val) { return val; }
|
|
@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
|
|
@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
|
|
|
|
// taken from std.traits.isAssignable
|
|
template isAssignable(Lhs, Rhs = Lhs)
|
|
{
|
|
enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);
|
|
}
|
|
|
|
// taken from std.traits.isInnerClass
|
|
template isInnerClass(T) if (is(T == class))
|
|
{
|
|
static if (is(typeof(T.outer)))
|
|
{
|
|
template hasOuterMember(T...)
|
|
{
|
|
static if (T.length == 0)
|
|
enum hasOuterMember = false;
|
|
else
|
|
enum hasOuterMember = T[0] == "outer" || hasOuterMember!(T[1 .. $]);
|
|
}
|
|
enum isInnerClass = __traits(isSame, typeof(T.outer), __traits(parent, T)) && !hasOuterMember!(__traits(allMembers, T));
|
|
}
|
|
else
|
|
enum isInnerClass = false;
|
|
}
|
|
|
|
template dtorIsNothrow(T)
|
|
{
|
|
enum dtorIsNothrow = is(typeof(function{T t=void;}) : void function() nothrow);
|
|
}
|
|
|
|
// taken from std.meta.allSatisfy
|
|
template allSatisfy(alias F, T...)
|
|
{
|
|
static foreach (Ti; T)
|
|
{
|
|
static if (!is(typeof(allSatisfy) == bool) && // not yet defined
|
|
!F!(Ti))
|
|
{
|
|
enum allSatisfy = false;
|
|
}
|
|
}
|
|
static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
|
|
{
|
|
enum allSatisfy = true;
|
|
}
|
|
}
|
|
|
|
// taken from std.meta.anySatisfy
|
|
template anySatisfy(alias F, Ts...)
|
|
{
|
|
static foreach (T; Ts)
|
|
{
|
|
static if (!is(typeof(anySatisfy) == bool) && // not yet defined
|
|
F!T)
|
|
{
|
|
enum anySatisfy = true;
|
|
}
|
|
}
|
|
static if (!is(typeof(anySatisfy) == bool)) // if not yet defined
|
|
{
|
|
enum anySatisfy = false;
|
|
}
|
|
}
|
|
|
|
// simplified from std.traits.maxAlignment
|
|
template maxAlignment(Ts...)
|
|
if (Ts.length > 0)
|
|
{
|
|
enum maxAlignment =
|
|
{
|
|
size_t result = 0;
|
|
static foreach (T; Ts)
|
|
if (T.alignof > result) result = T.alignof;
|
|
return result;
|
|
}();
|
|
}
|
|
|
|
template classInstanceAlignment(T)
|
|
if (is(T == class))
|
|
{
|
|
enum classInstanceAlignment = __traits(classInstanceAlignment, T);
|
|
}
|
|
|
|
/// See $(REF hasElaborateMove, std,traits)
|
|
template hasElaborateMove(S)
|
|
{
|
|
static if (__traits(isStaticArray, S))
|
|
{
|
|
enum bool hasElaborateMove = S.sizeof && hasElaborateMove!(BaseElemOf!S);
|
|
}
|
|
else static if (is(S == struct))
|
|
{
|
|
enum hasElaborateMove = (is(typeof(S.init.opPostMove(lvalueOf!S))) &&
|
|
!is(typeof(S.init.opPostMove(rvalueOf!S)))) ||
|
|
anySatisfy!(.hasElaborateMove, Fields!S);
|
|
}
|
|
else
|
|
{
|
|
enum bool hasElaborateMove = false;
|
|
}
|
|
}
|
|
|
|
// std.traits.hasElaborateDestructor
|
|
template hasElaborateDestructor(S)
|
|
{
|
|
static if (__traits(isStaticArray, S))
|
|
{
|
|
enum bool hasElaborateDestructor = S.sizeof && hasElaborateDestructor!(BaseElemOf!S);
|
|
}
|
|
else static if (is(S == struct))
|
|
{
|
|
// Once https://issues.dlang.org/show_bug.cgi?id=24865 is fixed, then
|
|
// this should be the implementation, but until that's fixed, we need the
|
|
// uncommented code.
|
|
// enum hasElaborateDestructor = __traits(hasMember, S, "__xdtor");
|
|
|
|
enum hasElaborateDestructor = hasDtor([__traits(allMembers, S)]);
|
|
}
|
|
else
|
|
{
|
|
enum bool hasElaborateDestructor = false;
|
|
}
|
|
}
|
|
|
|
private bool hasDtor(string[] members)
|
|
{
|
|
foreach (name; members)
|
|
{
|
|
if (name == "__xdtor")
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static struct NoDestructor {}
|
|
static assert(!hasElaborateDestructor!NoDestructor);
|
|
static assert(!hasElaborateDestructor!(NoDestructor[42]));
|
|
static assert(!hasElaborateDestructor!(NoDestructor[0]));
|
|
static assert(!hasElaborateDestructor!(NoDestructor[]));
|
|
|
|
static struct HasDestructor { ~this() {} }
|
|
static assert( hasElaborateDestructor!HasDestructor);
|
|
static assert( hasElaborateDestructor!(HasDestructor[42]));
|
|
static assert(!hasElaborateDestructor!(HasDestructor[0]));
|
|
static assert(!hasElaborateDestructor!(HasDestructor[]));
|
|
|
|
static struct HasDestructor2 { HasDestructor s; }
|
|
static assert( hasElaborateDestructor!HasDestructor2);
|
|
static assert( hasElaborateDestructor!(HasDestructor2[42]));
|
|
static assert(!hasElaborateDestructor!(HasDestructor2[0]));
|
|
static assert(!hasElaborateDestructor!(HasDestructor2[]));
|
|
|
|
static class HasFinalizer { ~this() {} }
|
|
static assert(!hasElaborateDestructor!HasFinalizer);
|
|
|
|
static struct HasUnion { union { HasDestructor s; } }
|
|
static assert(!hasElaborateDestructor!HasUnion);
|
|
static assert(!hasElaborateDestructor!(HasUnion[42]));
|
|
static assert(!hasElaborateDestructor!(HasUnion[0]));
|
|
static assert(!hasElaborateDestructor!(HasUnion[]));
|
|
|
|
static assert(!hasElaborateDestructor!int);
|
|
static assert(!hasElaborateDestructor!(int[0]));
|
|
static assert(!hasElaborateDestructor!(int[42]));
|
|
static assert(!hasElaborateDestructor!(int[]));
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=24865
|
|
@safe unittest
|
|
{
|
|
static struct S2 { ~this() {} }
|
|
static struct S3 { S2 field; }
|
|
static struct S6 { S3[0] field; }
|
|
|
|
static assert( hasElaborateDestructor!S2);
|
|
static assert( hasElaborateDestructor!S3);
|
|
static assert(!hasElaborateDestructor!S6);
|
|
}
|
|
|
|
// std.traits.hasElaborateCopyDestructor
|
|
template hasElaborateCopyConstructor(S)
|
|
{
|
|
static if (__traits(isStaticArray, S))
|
|
{
|
|
enum bool hasElaborateCopyConstructor = S.sizeof && hasElaborateCopyConstructor!(BaseElemOf!S);
|
|
}
|
|
else static if (is(S == struct))
|
|
{
|
|
enum hasElaborateCopyConstructor = __traits(hasCopyConstructor, S) || __traits(hasPostblit, S);
|
|
}
|
|
else
|
|
{
|
|
enum bool hasElaborateCopyConstructor = false;
|
|
}
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static struct S
|
|
{
|
|
int x;
|
|
this(return scope ref typeof(this) rhs) { }
|
|
this(int x, int y) {}
|
|
}
|
|
|
|
static assert( hasElaborateCopyConstructor!S);
|
|
static assert(!hasElaborateCopyConstructor!(S[0][1]));
|
|
|
|
static struct S2
|
|
{
|
|
int x;
|
|
this(int x, int y) {}
|
|
}
|
|
|
|
static assert(!hasElaborateCopyConstructor!S2);
|
|
|
|
static struct S3
|
|
{
|
|
int x;
|
|
this(return scope ref typeof(this) rhs, int x = 42) { }
|
|
this(int x, int y) {}
|
|
}
|
|
|
|
static assert( hasElaborateCopyConstructor!S3);
|
|
|
|
static struct S4 { union { S s; } }
|
|
|
|
static assert(!hasElaborateCopyConstructor!S4);
|
|
}
|
|
|
|
template hasElaborateAssign(S)
|
|
{
|
|
static if (__traits(isStaticArray, S))
|
|
{
|
|
enum bool hasElaborateAssign = S.sizeof && hasElaborateAssign!(BaseElemOf!S);
|
|
}
|
|
else static if (is(S == struct))
|
|
{
|
|
enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) ||
|
|
is(typeof(S.init.opAssign(lvalueOf!S)));
|
|
}
|
|
else
|
|
{
|
|
enum bool hasElaborateAssign = false;
|
|
}
|
|
}
|
|
|
|
unittest
|
|
{
|
|
{
|
|
static struct S {}
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { int i; }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { void opAssign(S) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { void opAssign(ref S) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { void opAssign(int) {} }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { this(this) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
// https://issues.dlang.org/show_bug.cgi?id=24834
|
|
/+
|
|
{
|
|
static struct S { this(ref S) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
+/
|
|
{
|
|
static struct S { ~this() {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct S { @disable void opAssign(S); }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member {}
|
|
static struct S { Member member; }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member { void opAssign(Member) {} }
|
|
static struct S { Member member; }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member {}
|
|
static struct S { Member member; void opAssign(S) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member { @disable void opAssign(Member); }
|
|
static struct S { Member member; }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member { @disable void opAssign(Member); }
|
|
static struct S { Member member; void opAssign(S) {} }
|
|
static assert( hasElaborateAssign!S);
|
|
static assert( hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member { void opAssign(Member) {} }
|
|
static struct S { Member member; @disable void opAssign(S); }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
{
|
|
static struct Member { void opAssign(Member) {} }
|
|
static struct S { union { Member member; } }
|
|
static assert(!hasElaborateAssign!S);
|
|
static assert(!hasElaborateAssign!(S[10]));
|
|
static assert(!hasElaborateAssign!(S[0]));
|
|
static assert(!hasElaborateAssign!(S[]));
|
|
}
|
|
|
|
static assert(!hasElaborateAssign!int);
|
|
static assert(!hasElaborateAssign!(string[]));
|
|
static assert(!hasElaborateAssign!Object);
|
|
}
|
|
|
|
template hasIndirections(T)
|
|
{
|
|
static if (is(T == enum))
|
|
enum hasIndirections = hasIndirections!(OriginalType!T);
|
|
else static if (is(T == struct) || is(T == union))
|
|
enum hasIndirections = anySatisfy!(.hasIndirections, typeof(T.tupleof));
|
|
else static if (__traits(isAssociativeArray, T) || is(T == class) || is(T == interface))
|
|
enum hasIndirections = true;
|
|
else static if (is(T == E[N], E, size_t N))
|
|
enum hasIndirections = T.sizeof && (is(immutable E == immutable void) || hasIndirections!(BaseElemOf!E));
|
|
else static if (isFunctionPointer!T)
|
|
enum hasIndirections = false;
|
|
else
|
|
enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T;
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
static assert(!hasIndirections!int);
|
|
static assert(!hasIndirections!(const int));
|
|
|
|
static assert( hasIndirections!(int*));
|
|
static assert( hasIndirections!(const int*));
|
|
|
|
static assert( hasIndirections!(int[]));
|
|
static assert(!hasIndirections!(int[42]));
|
|
static assert(!hasIndirections!(int[0]));
|
|
|
|
static assert( hasIndirections!(int*));
|
|
static assert( hasIndirections!(int*[]));
|
|
static assert( hasIndirections!(int*[42]));
|
|
static assert(!hasIndirections!(int*[0]));
|
|
|
|
static assert( hasIndirections!string);
|
|
static assert( hasIndirections!(string[]));
|
|
static assert( hasIndirections!(string[42]));
|
|
static assert(!hasIndirections!(string[0]));
|
|
|
|
static assert( hasIndirections!(void[]));
|
|
static assert( hasIndirections!(void[17]));
|
|
static assert(!hasIndirections!(void[0]));
|
|
|
|
static assert( hasIndirections!(string[int]));
|
|
static assert( hasIndirections!(string[int]*));
|
|
static assert( hasIndirections!(string[int][]));
|
|
static assert( hasIndirections!(string[int][12]));
|
|
static assert(!hasIndirections!(string[int][0]));
|
|
|
|
static assert(!hasIndirections!(int function(string)));
|
|
static assert( hasIndirections!(int delegate(string)));
|
|
static assert(!hasIndirections!(const(int function(string))));
|
|
static assert( hasIndirections!(const(int delegate(string))));
|
|
static assert(!hasIndirections!(immutable(int function(string))));
|
|
static assert( hasIndirections!(immutable(int delegate(string))));
|
|
|
|
static class C {}
|
|
static assert( hasIndirections!C);
|
|
|
|
static interface I {}
|
|
static assert( hasIndirections!I);
|
|
|
|
{
|
|
enum E : int { a }
|
|
static assert(!hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : int* { a }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : string { a = "" }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : int[] { a = null }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : int[3] { a = [1, 2, 3] }
|
|
static assert(!hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : int*[3] { a = [null, null, null] }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : int*[0] { a = int*[0].init }
|
|
static assert(!hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : C { a = null }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
{
|
|
enum E : I { a = null }
|
|
static assert( hasIndirections!E);
|
|
}
|
|
|
|
{
|
|
static struct S {}
|
|
static assert(!hasIndirections!S);
|
|
|
|
enum E : S { a = S.init }
|
|
static assert(!hasIndirections!S);
|
|
}
|
|
{
|
|
static struct S { int i; }
|
|
static assert(!hasIndirections!S);
|
|
|
|
enum E : S { a = S.init }
|
|
static assert(!hasIndirections!S);
|
|
}
|
|
{
|
|
static struct S { C c; }
|
|
static assert( hasIndirections!S);
|
|
|
|
enum E : S { a = S.init }
|
|
static assert( hasIndirections!S);
|
|
}
|
|
{
|
|
static struct S { int[] arr; }
|
|
static assert( hasIndirections!S);
|
|
|
|
enum E : S { a = S.init }
|
|
static assert( hasIndirections!S);
|
|
}
|
|
{
|
|
int local;
|
|
struct S { void foo() { ++local; } }
|
|
static assert( hasIndirections!S);
|
|
|
|
enum E : S { a = S.init }
|
|
static assert( hasIndirections!S);
|
|
}
|
|
|
|
{
|
|
static union U {}
|
|
static assert(!hasIndirections!U);
|
|
}
|
|
{
|
|
static union U { int i; }
|
|
static assert(!hasIndirections!U);
|
|
}
|
|
{
|
|
static union U { C c; }
|
|
static assert( hasIndirections!U);
|
|
}
|
|
{
|
|
static union U { int[] arr; }
|
|
static assert( hasIndirections!U);
|
|
}
|
|
}
|
|
|
|
// https://issues.dlang.org/show_bug.cgi?id=12000
|
|
@safe unittest
|
|
{
|
|
static struct S(T)
|
|
{
|
|
static assert(hasIndirections!T);
|
|
}
|
|
|
|
static class A(T)
|
|
{
|
|
S!A a;
|
|
}
|
|
|
|
A!int dummy;
|
|
}
|
|
|
|
// https://github.com/dlang/dmd/issues/20812
|
|
@safe unittest
|
|
{
|
|
static assert(!hasIndirections!void);
|
|
static assert(!hasIndirections!(const void));
|
|
static assert(!hasIndirections!(inout void));
|
|
static assert(!hasIndirections!(immutable void));
|
|
static assert(!hasIndirections!(shared void));
|
|
|
|
static assert( hasIndirections!(void*));
|
|
static assert( hasIndirections!(const void*));
|
|
static assert( hasIndirections!(inout void*));
|
|
static assert( hasIndirections!(immutable void*));
|
|
static assert( hasIndirections!(shared void*));
|
|
|
|
static assert( hasIndirections!(void[]));
|
|
static assert( hasIndirections!(const void[]));
|
|
static assert( hasIndirections!(inout void[]));
|
|
static assert( hasIndirections!(immutable void[]));
|
|
static assert( hasIndirections!(shared void[]));
|
|
|
|
static assert( hasIndirections!(void[42]));
|
|
static assert( hasIndirections!(const void[42]));
|
|
static assert( hasIndirections!(inout void[42]));
|
|
static assert( hasIndirections!(immutable void[42]));
|
|
static assert( hasIndirections!(shared void[42]));
|
|
|
|
static assert(!hasIndirections!(void[0]));
|
|
static assert(!hasIndirections!(const void[0]));
|
|
static assert(!hasIndirections!(inout void[0]));
|
|
static assert(!hasIndirections!(immutable void[0]));
|
|
static assert(!hasIndirections!(shared void[0]));
|
|
}
|
|
|
|
template hasUnsharedIndirections(T)
|
|
{
|
|
static if (is(T == immutable))
|
|
enum hasUnsharedIndirections = false;
|
|
else static if (is(T == struct) || is(T == union))
|
|
enum hasUnsharedIndirections = anySatisfy!(.hasUnsharedIndirections, Fields!T);
|
|
else static if (is(T : E[N], E, size_t N))
|
|
enum hasUnsharedIndirections = is(E == void) ? false : hasUnsharedIndirections!E;
|
|
else static if (isFunctionPointer!T)
|
|
enum hasUnsharedIndirections = false;
|
|
else static if (isPointer!T)
|
|
enum hasUnsharedIndirections = !is(T : shared(U)*, U) && !is(T : immutable(U)*, U);
|
|
else static if (isDynamicArray!T)
|
|
enum hasUnsharedIndirections = !is(T : shared(V)[], V) && !is(T : immutable(V)[], V);
|
|
else static if (is(T == class) || is(T == interface))
|
|
enum hasUnsharedIndirections = !is(T : shared(W), W);
|
|
else
|
|
enum hasUnsharedIndirections = isDelegate!T || __traits(isAssociativeArray, T); // TODO: how to handle these?
|
|
}
|
|
|
|
unittest
|
|
{
|
|
static struct Foo { shared(int)* val; }
|
|
|
|
static assert(!hasUnsharedIndirections!(immutable(char)*));
|
|
static assert(!hasUnsharedIndirections!(string));
|
|
|
|
static assert(!hasUnsharedIndirections!(Foo));
|
|
static assert( hasUnsharedIndirections!(Foo*));
|
|
static assert(!hasUnsharedIndirections!(shared(Foo)*));
|
|
static assert(!hasUnsharedIndirections!(immutable(Foo)*));
|
|
|
|
int local;
|
|
struct HasContextPointer { int opCall() { return ++local; } }
|
|
static assert(hasIndirections!HasContextPointer);
|
|
}
|
|
|
|
enum bool isAggregateType(T) = is(T == struct) || is(T == union) ||
|
|
is(T == class) || is(T == interface);
|
|
|
|
enum bool isPointer(T) = is(T == U*, U) && !isAggregateType!T;
|
|
|
|
enum bool isDynamicArray(T) = is(DynamicArrayTypeOf!T) && !isAggregateType!T;
|
|
|
|
template OriginalType(T)
|
|
{
|
|
template Impl(T)
|
|
{
|
|
static if (is(T U == enum)) alias Impl = OriginalType!U;
|
|
else alias Impl = T;
|
|
}
|
|
|
|
alias OriginalType = ModifyTypePreservingTQ!(Impl, T);
|
|
}
|
|
|
|
template DynamicArrayTypeOf(T)
|
|
{
|
|
static if (is(AliasThisTypeOf!T AT) && !is(AT[] == AT))
|
|
alias X = DynamicArrayTypeOf!AT;
|
|
else
|
|
alias X = OriginalType!T;
|
|
|
|
static if (is(Unqual!X : E[], E) && !is(typeof({ enum n = X.length; })))
|
|
alias DynamicArrayTypeOf = X;
|
|
else
|
|
static assert(0, T.stringof ~ " is not a dynamic array");
|
|
}
|
|
|
|
private template AliasThisTypeOf(T)
|
|
if (isAggregateType!T)
|
|
{
|
|
alias members = __traits(getAliasThis, T);
|
|
|
|
static if (members.length == 1)
|
|
alias AliasThisTypeOf = typeof(__traits(getMember, T.init, members[0]));
|
|
else
|
|
static assert(0, T.stringof~" does not have alias this type");
|
|
}
|
|
|
|
template isFunctionPointer(T...)
|
|
if (T.length == 1)
|
|
{
|
|
static if (is(T[0] U) || is(typeof(T[0]) U))
|
|
{
|
|
static if (is(U F : F*) && is(F == function))
|
|
enum bool isFunctionPointer = true;
|
|
else
|
|
enum bool isFunctionPointer = false;
|
|
}
|
|
else
|
|
enum bool isFunctionPointer = false;
|
|
}
|
|
|
|
template isDelegate(T...)
|
|
if (T.length == 1)
|
|
{
|
|
static if (is(typeof(& T[0]) U : U*) && is(typeof(& T[0]) U == delegate))
|
|
{
|
|
// T is a (nested) function symbol.
|
|
enum bool isDelegate = true;
|
|
}
|
|
else static if (is(T[0] W) || is(typeof(T[0]) W))
|
|
{
|
|
// T is an expression or a type. Take the type of it and examine.
|
|
enum bool isDelegate = is(W == delegate);
|
|
}
|
|
else
|
|
enum bool isDelegate = false;
|
|
}
|
|
|
|
// std.meta.Filter
|
|
template Filter(alias pred, TList...)
|
|
{
|
|
static if (TList.length == 0)
|
|
{
|
|
alias Filter = AliasSeq!();
|
|
}
|
|
else static if (TList.length == 1)
|
|
{
|
|
static if (pred!(TList[0]))
|
|
alias Filter = AliasSeq!(TList[0]);
|
|
else
|
|
alias Filter = AliasSeq!();
|
|
}
|
|
/* The next case speeds up compilation by reducing
|
|
* the number of Filter instantiations
|
|
*/
|
|
else static if (TList.length == 2)
|
|
{
|
|
static if (pred!(TList[0]))
|
|
{
|
|
static if (pred!(TList[1]))
|
|
alias Filter = AliasSeq!(TList[0], TList[1]);
|
|
else
|
|
alias Filter = AliasSeq!(TList[0]);
|
|
}
|
|
else
|
|
{
|
|
static if (pred!(TList[1]))
|
|
alias Filter = AliasSeq!(TList[1]);
|
|
else
|
|
alias Filter = AliasSeq!();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
alias Filter =
|
|
AliasSeq!(
|
|
Filter!(pred, TList[ 0 .. $/2]),
|
|
Filter!(pred, TList[$/2 .. $ ]));
|
|
}
|
|
}
|
|
|
|
// std.meta.staticMap
|
|
template staticMap(alias F, T...)
|
|
{
|
|
static if (T.length == 0)
|
|
{
|
|
alias staticMap = AliasSeq!();
|
|
}
|
|
else static if (T.length == 1)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]));
|
|
}
|
|
/* Cases 2 to 8 improve compile performance by reducing
|
|
* the number of recursive instantiations of staticMap
|
|
*/
|
|
else static if (T.length == 2)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]));
|
|
}
|
|
else static if (T.length == 3)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]));
|
|
}
|
|
else static if (T.length == 4)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]));
|
|
}
|
|
else static if (T.length == 5)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]));
|
|
}
|
|
else static if (T.length == 6)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]));
|
|
}
|
|
else static if (T.length == 7)
|
|
{
|
|
alias staticMap = AliasSeq!(F!(T[0]), F!(T[1]), F!(T[2]), F!(T[3]), F!(T[4]), F!(T[5]), F!(T[6]));
|
|
}
|
|
else static if (T.length == 8)
|
|
{
|
|
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]));
|
|
}
|
|
else
|
|
{
|
|
alias staticMap =
|
|
AliasSeq!(
|
|
staticMap!(F, T[ 0 .. $/2]),
|
|
staticMap!(F, T[$/2 .. $ ]));
|
|
}
|
|
}
|
|
|
|
// std.exception.assertCTFEable
|
|
version (CoreUnittest) package(core)
|
|
void assertCTFEable(alias dg)()
|
|
{
|
|
static assert({ cast(void) dg(); return true; }());
|
|
cast(void) dg();
|
|
}
|
|
|
|
// std.traits.FunctionTypeOf
|
|
/*
|
|
Get the function type from a callable object `func`.
|
|
|
|
Using builtin `typeof` on a property function yields the types of the
|
|
property value, not of the property function itself. Still,
|
|
`FunctionTypeOf` is able to obtain function types of properties.
|
|
|
|
Note:
|
|
Do not confuse function types with function pointer types; function types are
|
|
usually used for compile-time reflection purposes.
|
|
*/
|
|
template FunctionTypeOf(func...)
|
|
if (func.length == 1 /*&& isCallable!func*/)
|
|
{
|
|
static if (is(typeof(& func[0]) Fsym : Fsym*) && is(Fsym == function) || is(typeof(& func[0]) Fsym == delegate))
|
|
{
|
|
alias FunctionTypeOf = Fsym; // HIT: (nested) function symbol
|
|
}
|
|
else static if (is(typeof(& func[0].opCall) Fobj == delegate))
|
|
{
|
|
alias FunctionTypeOf = Fobj; // HIT: callable object
|
|
}
|
|
else static if (is(typeof(& func[0].opCall) Ftyp : Ftyp*) && is(Ftyp == function))
|
|
{
|
|
alias FunctionTypeOf = Ftyp; // HIT: callable type
|
|
}
|
|
else static if (is(func[0] T) || is(typeof(func[0]) T))
|
|
{
|
|
static if (is(T == function))
|
|
alias FunctionTypeOf = T; // HIT: function
|
|
else static if (is(T Fptr : Fptr*) && is(Fptr == function))
|
|
alias FunctionTypeOf = Fptr; // HIT: function pointer
|
|
else static if (is(T Fdlg == delegate))
|
|
alias FunctionTypeOf = Fdlg; // HIT: delegate
|
|
else
|
|
static assert(0);
|
|
}
|
|
else
|
|
static assert(0);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
class C
|
|
{
|
|
int value() @property { return 0; }
|
|
}
|
|
static assert(is( typeof(C.value) == int ));
|
|
static assert(is( FunctionTypeOf!(C.value) == function ));
|
|
}
|
|
|
|
@system unittest
|
|
{
|
|
int test(int a);
|
|
int propGet() @property;
|
|
int propSet(int a) @property;
|
|
int function(int) test_fp;
|
|
int delegate(int) test_dg;
|
|
static assert(is( typeof(test) == FunctionTypeOf!(typeof(test)) ));
|
|
static assert(is( typeof(test) == FunctionTypeOf!test ));
|
|
static assert(is( typeof(test) == FunctionTypeOf!test_fp ));
|
|
static assert(is( typeof(test) == FunctionTypeOf!test_dg ));
|
|
alias int GetterType() @property;
|
|
alias int SetterType(int) @property;
|
|
static assert(is( FunctionTypeOf!propGet == GetterType ));
|
|
static assert(is( FunctionTypeOf!propSet == SetterType ));
|
|
|
|
interface Prop { int prop() @property; }
|
|
Prop prop;
|
|
static assert(is( FunctionTypeOf!(Prop.prop) == GetterType ));
|
|
static assert(is( FunctionTypeOf!(prop.prop) == GetterType ));
|
|
|
|
class Callable { int opCall(int) { return 0; } }
|
|
auto call = new Callable;
|
|
static assert(is( FunctionTypeOf!call == typeof(test) ));
|
|
|
|
struct StaticCallable { static int opCall(int) { return 0; } }
|
|
StaticCallable stcall_val;
|
|
StaticCallable* stcall_ptr;
|
|
static assert(is( FunctionTypeOf!stcall_val == typeof(test) ));
|
|
static assert(is( FunctionTypeOf!stcall_ptr == typeof(test) ));
|
|
|
|
interface Overloads
|
|
{
|
|
void test(string);
|
|
real test(real);
|
|
int test(int);
|
|
int test() @property;
|
|
}
|
|
alias ov = __traits(getVirtualMethods, Overloads, "test");
|
|
alias F_ov0 = FunctionTypeOf!(ov[0]);
|
|
alias F_ov1 = FunctionTypeOf!(ov[1]);
|
|
alias F_ov2 = FunctionTypeOf!(ov[2]);
|
|
alias F_ov3 = FunctionTypeOf!(ov[3]);
|
|
static assert(is(F_ov0* == void function(string)));
|
|
static assert(is(F_ov1* == real function(real)));
|
|
static assert(is(F_ov2* == int function(int)));
|
|
static assert(is(F_ov3* == int function() @property));
|
|
|
|
alias F_dglit = FunctionTypeOf!((int a){ return a; });
|
|
static assert(is(F_dglit* : int function(int)));
|
|
}
|
|
|
|
// std.traits.ReturnType
|
|
/*
|
|
Get the type of the return value from a function,
|
|
a pointer to function, a delegate, a struct
|
|
with an opCall, a pointer to a struct with an opCall,
|
|
or a class with an `opCall`. Please note that $(D_KEYWORD ref)
|
|
is not part of a type, but the attribute of the function
|
|
(see template $(LREF functionAttributes)).
|
|
*/
|
|
template ReturnType(func...)
|
|
if (func.length == 1 /*&& isCallable!func*/)
|
|
{
|
|
static if (is(FunctionTypeOf!func R == return))
|
|
alias ReturnType = R;
|
|
else
|
|
static assert(0, "argument has no return type");
|
|
}
|
|
|
|
//
|
|
@safe unittest
|
|
{
|
|
int foo();
|
|
ReturnType!foo x; // x is declared as int
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
struct G
|
|
{
|
|
int opCall (int i) { return 1;}
|
|
}
|
|
|
|
alias ShouldBeInt = ReturnType!G;
|
|
static assert(is(ShouldBeInt == int));
|
|
|
|
G g;
|
|
static assert(is(ReturnType!g == int));
|
|
|
|
G* p;
|
|
alias pg = ReturnType!p;
|
|
static assert(is(pg == int));
|
|
|
|
class C
|
|
{
|
|
int opCall (int i) { return 1;}
|
|
}
|
|
|
|
static assert(is(ReturnType!C == int));
|
|
|
|
C c;
|
|
static assert(is(ReturnType!c == int));
|
|
|
|
class Test
|
|
{
|
|
int prop() @property { return 0; }
|
|
}
|
|
alias R_Test_prop = ReturnType!(Test.prop);
|
|
static assert(is(R_Test_prop == int));
|
|
|
|
alias R_dglit = ReturnType!((int a) { return a; });
|
|
static assert(is(R_dglit == int));
|
|
}
|
|
|
|
// std.traits.Parameters
|
|
/*
|
|
Get, as a tuple, the types of the parameters to a function, a pointer
|
|
to function, a delegate, a struct with an `opCall`, a pointer to a
|
|
struct with an `opCall`, or a class with an `opCall`.
|
|
*/
|
|
template Parameters(func...)
|
|
if (func.length == 1 /*&& isCallable!func*/)
|
|
{
|
|
static if (is(FunctionTypeOf!func P == function))
|
|
alias Parameters = P;
|
|
else
|
|
static assert(0, "argument has no parameters");
|
|
}
|
|
|
|
//
|
|
@safe unittest
|
|
{
|
|
int foo(int, long);
|
|
void bar(Parameters!foo); // declares void bar(int, long);
|
|
void abc(Parameters!foo[1]); // declares void abc(long);
|
|
}
|
|
|
|
@safe unittest
|
|
{
|
|
int foo(int i, bool b) { return 0; }
|
|
static assert(is(Parameters!foo == AliasSeq!(int, bool)));
|
|
static assert(is(Parameters!(typeof(&foo)) == AliasSeq!(int, bool)));
|
|
|
|
struct S { real opCall(real r, int i) { return 0.0; } }
|
|
S s;
|
|
static assert(is(Parameters!S == AliasSeq!(real, int)));
|
|
static assert(is(Parameters!(S*) == AliasSeq!(real, int)));
|
|
static assert(is(Parameters!s == AliasSeq!(real, int)));
|
|
|
|
class Test
|
|
{
|
|
int prop() @property { return 0; }
|
|
}
|
|
alias P_Test_prop = Parameters!(Test.prop);
|
|
static assert(P_Test_prop.length == 0);
|
|
|
|
alias P_dglit = Parameters!((int a){});
|
|
static assert(P_dglit.length == 1);
|
|
static assert(is(P_dglit[0] == int));
|
|
}
|
|
|
|
// Return `true` if `Type` has `member` that evaluates to `true` in a static if condition
|
|
enum isTrue(Type, string member) = __traits(compiles, { static if (__traits(getMember, Type, member)) {} else static assert(0); });
|
|
|
|
unittest
|
|
{
|
|
static struct T
|
|
{
|
|
enum a = true;
|
|
enum b = false;
|
|
enum c = 1;
|
|
enum d = 45;
|
|
enum e = "true";
|
|
enum f = "";
|
|
enum g = null;
|
|
alias h = bool;
|
|
}
|
|
|
|
static assert( isTrue!(T, "a"));
|
|
static assert(!isTrue!(T, "b"));
|
|
static assert( isTrue!(T, "c"));
|
|
static assert( isTrue!(T, "d"));
|
|
static assert( isTrue!(T, "e"));
|
|
static assert( isTrue!(T, "f"));
|
|
static assert(!isTrue!(T, "g"));
|
|
static assert(!isTrue!(T, "h"));
|
|
}
|
|
|
|
template hasUDA(alias symbol, alias attribute)
|
|
{
|
|
enum isAttr(T) = is(T == attribute);
|
|
|
|
enum hasUDA = anySatisfy!(isAttr, __traits(getAttributes, symbol));
|
|
}
|
|
|
|
unittest
|
|
{
|
|
enum SomeUDA;
|
|
|
|
struct Test
|
|
{
|
|
int woUDA;
|
|
@SomeUDA int oneUDA;
|
|
@SomeUDA @SomeUDA int twoUDAs;
|
|
}
|
|
|
|
static assert(hasUDA!(Test.oneUDA, SomeUDA));
|
|
static assert(hasUDA!(Test.twoUDAs, SomeUDA));
|
|
static assert(!hasUDA!(Test.woUDA, SomeUDA));
|
|
}
|