Skip to content

Commit

Permalink
Fix Issue 16744: Add Typeof
Browse files Browse the repository at this point in the history
This an alternative implementation to #4920
  • Loading branch information
MetaLang committed Jul 29, 2017
1 parent a9169d6 commit b26f48c
Showing 1 changed file with 121 additions and 0 deletions.
121 changes: 121 additions & 0 deletions std/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,7 @@
* $(LREF Unsigned)
* $(LREF ValueType)
* $(LREF Promoted)
* $(LREF TypeOf)
* ))
* $(TR $(TD Misc) $(TD
* $(LREF mangledName)
Expand Down Expand Up @@ -7284,6 +7285,126 @@ template Promoted(T)
}
}

/*
A template designed to function in the same manner as the
built-in `typeof` utility. As it is a template, Typeof can be
passed around like any other symbol, unlike `typeof`.
Also, whereas `typeof` will not accept symbols that are already
types (e.g., `typeof(int)` will not compile), Typeof will accept
both values and types.
Params:
T = The symbol to take the type of. Can be either a type
or a value.
Returns:
The type of the given symbol. If the symbol is something that
does not have a valid type (such as a module name or an
expression that evaluates to the special `__error__` type),
an error will be raised at compile time.
Note:
If the given symbol is a template, the result type will be `void`.
*/
template Typeof(T...)
if (T.length == 1)
{
static if (__traits(isTemplate, T[0]))
alias Typeof = void;
else static if (is(T[0] TypeOfT0))
alias Typeof = TypeOfT0;
else static if (is(typeof(T[0]) TypeOfT0))
alias Typeof = TypeOfT0;
else
static assert(false, "Cannot take the type of " ~ T[0].stringof);
}

///
@safe unittest
{
//Types, values and expressions are accepted
assert(is(Typeof!1 == typeof(1)));
assert(is(Typeof!false == typeof(false)));
assert(is(Typeof!"" == string));

assert(is(Typeof!int == int));
assert(is(Typeof!bool == bool));
assert(is(Typeof!string == string));

assert(is(Typeof!(1 + 2 / 3) == typeof(1 + 2 / 3)));

struct S {}
assert(is(Typeof!(S()) == typeof(S())));
assert(is(Typeof!S == S));

class C {}
C c;
assert(is(Typeof!c == typeof(c)));
assert(is(Typeof!C == C));

//The type of a template is `void`
assert(is(Typeof!Typeof == typeof(Typeof)));
assert(is(Typeof!Typeof == void));

//Modules do not have a valid type
assert(!__traits(compiles, { alias _ = Typeof!(std.traits); }));
}

///
@safe unittest
{
import std.meta: AliasSeq, staticMap;

alias typesAndValues = AliasSeq!(int, false, char, "test");

//The built-in typeof cannot be passed to templates.
//The following will not compile
//alias justTypes = staticMap!(typeof, typeAndValues);

//But Typeof can
assert(is(staticMap!(Typeof, typesAndValues) == AliasSeq!(int, bool, char, string)));
}

@safe unittest
{
import std.meta: AliasSeq;

template testMatch(T...)
if (T.length == 1)
{
static if (is(T[0]))
enum testMatch = is(Typeof!(T[0]) == T[0]) && is(Typeof!(T[0].init) == typeof(T[0].init));
else static if (is(typeof(T[0])))
enum testMatch = is(Typeof!(T[0]) == typeof(T[0])) && is(Typeof!(typeof(T[0])) == typeof(T[0]));
else
enum testMatch = false;
}

struct TestS {}
class TestC {}

foreach (T; AliasSeq!(NumericTypeList,
ImaginaryTypeList,
ComplexTypeList,
CharTypeList,
TestS,
TestC))
{
static assert(testMatch!T);
static assert(testMatch!(T function(T)));
static assert(testMatch!(T delegate(T)));
static assert(testMatch!(T[]));
static assert(testMatch!(T[10]));
static assert(testMatch!(T[T]));
}

static assert(testMatch!null);
static assert(is(Typeof!void == void));
static assert(testMatch!Typeof);
}

//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
// Misc.
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::://
Expand Down

0 comments on commit b26f48c

Please sign in to comment.