Reduce reliance on typeof(U.field) to prepare for supporting U==enum.

This commit is contained in:
Sönke Ludwig 2019-02-22 00:40:04 +01:00
parent 95c2919d2b
commit 78ca6e0cb5

View file

@ -39,6 +39,7 @@ struct TaggedUnion(U) if (is(U == union) || is(U == struct))
hasElaborateCopyConstructor, hasElaborateDestructor, isCopyable;
import std.ascii : toUpper;
alias FieldDefinitionType = U;
alias FieldTypes = FieldTypeTuple!U;
alias fieldNames = FieldNameTuple!U;
@ -48,6 +49,8 @@ struct TaggedUnion(U) if (is(U == union) || is(U == struct))
/// A type enum that identifies the type of value currently stored.
alias Kind = TypeEnum!U;
private alias FieldTypeByName(string name) = FieldTypes[__traits(getMember, Kind, name)];
private {
static if (isUnionType!(FieldTypes[0]) || __VERSION__ < 2072) {
void[Largest!FieldTypes.sizeof] m_data;
@ -341,12 +344,15 @@ struct TaggedAlgebraic(U) if (is(U == union) || is(U == struct))
import std.string : format;
/// Alias of the type used for defining the possible storage types/kinds.
alias Union = U;
deprecated alias Union = U;
/// The underlying tagged union type
alias UnionType = TaggedUnion!U;
private TaggedUnion!U m_union;
/// A type enum that identifies the type of value currently stored.
alias Kind = TaggedUnion!U.Kind;
alias Kind = UnionType.Kind;
/// Compatibility alias
deprecated("Use 'Kind' instead.") alias Type = Kind;
@ -1149,7 +1155,7 @@ private static auto implementOp(OpKind kind, string name, T, ARGS...)(ref T self
enum assert_msg = "Operator "~name~" ("~kind.stringof~") can only be used on values of the following types: "~[info.fields].join(", ");
default: assert(false, assert_msg);
foreach (i, f; info.fields) {
alias FT = typeof(__traits(getMember, T.Union, f));
alias FT = T.UnionType.FieldTypeByName!f;
case __traits(getMember, T.Kind, f):
static if (NoDuplicates!(info.ReturnTypes).length == 1)
return info.perform(self.m_union.trustedGet!FT, args);
@ -1361,17 +1367,17 @@ private string generateConstructors(U)()
// normal type constructors
foreach (tname; UniqueTypeFields!U)
ret ~= q{
this(typeof(U.%1$s) value)
this(UnionType.FieldTypeByName!"%1$s" value)
{
static if (isUnionType!(typeof(U.%1$s)))
static if (isUnionType!(UnionType.FieldTypeByName!"%1$s"))
m_union.set!(Kind.%1$s)();
else
m_union.set!(Kind.%1$s)(value);
}
void opAssign(typeof(U.%1$s) value)
void opAssign(UnionType.FieldTypeByName!"%1$s" value)
{
static if (isUnionType!(typeof(U.%1$s)))
static if (isUnionType!(UnionType.FieldTypeByName!"%1$s"))
m_union.set!(Kind.%1$s)();
else
m_union.set!(Kind.%1$s)(value);
@ -1381,14 +1387,14 @@ private string generateConstructors(U)()
// type constructors with explicit type tag
foreach (tname; TypeTuple!(UniqueTypeFields!U, AmbiguousTypeFields!U))
ret ~= q{
this(typeof(U.%1$s) value, Kind type)
this(UnionType.FieldTypeByName!"%1$s" value, Kind type)
{
switch (type) {
default: assert(false, format("Invalid type ID for type %%s: %%s", typeof(U.%1$s).stringof, type));
default: assert(false, format("Invalid type ID for type %%s: %%s", UnionType.FieldTypeByName!"%1$s".stringof, type));
foreach (i, n; TaggedUnion!U.fieldNames) {
static if (is(typeof(U.%1$s) == typeof(__traits(getMember, U, n)))) {
static if (is(UnionType.FieldTypeByName!"%1$s" == UnionType.FieldTypes[i])) {
case __traits(getMember, Kind, n):
static if (isUnionType!(m_union.FieldTypes[i]))
static if (isUnionType!(UnionType.FieldTypes[i]))
m_union.set!(__traits(getMember, Kind, n))();
else m_union.set!(__traits(getMember, Kind, n))(value);
return;