diff --git a/src/sumtype.d b/src/sumtype.d index 54effd9..35338f0 100644 --- a/src/sumtype.d +++ b/src/sumtype.d @@ -256,6 +256,8 @@ private enum hasPostblit(T) = __traits(hasPostblit, T); private enum isInout(T) = is(T == inout); +private enum memberName(size_t tid) = "values_" ~ toCtString!tid; + // Workaround for dlang issue 19669 private enum haveDip1000 = __traits(compiles, () @safe { int x; @@ -300,16 +302,12 @@ private: union Storage { - // Workaround for dlang issue 20068 - template memberName(T) - if (IndexOf!(T, Types) >= 0) - { - enum tid = IndexOf!(T, Types); - mixin("enum memberName = `values_", toCtString!tid, "`;"); - } - - static foreach (T; Types) { - mixin("T ", memberName!T, ";"); + static foreach (tid, T; Types) { + /+ + Giving these fields individual names makes it possible to use brace + initialization for Storage. + +/ + mixin("T ", memberName!tid, ";"); } } @@ -317,28 +315,28 @@ private: Tag tag; /** - * Accesses the value stored in a SumType. + * Accesses the value stored in a SumType by its index. * * This method is memory-safe, provided that: * * 1. A SumType's tag is always accurate. - * 2. A SumType cannot be assigned to in @safe code if that assignment - * could cause unsafe aliasing. + * 2. A SumType's value cannot be unsafely aliased in @safe code. * * All code that accesses a SumType's tag or storage directly, including * @safe code in this module, must be manually checked to ensure that it * does not violate either of the above requirements. */ @trusted - ref inout(T) get(T)() inout - if (IndexOf!(T, Types) >= 0) + // Explicit return type omitted + // Workaround for https://github.com/dlang/dmd/issues/20549 + ref get(size_t tid)() inout + if (tid < Types.length) { - enum tid = IndexOf!(T, Types); assert(tag == tid, - "This `" ~ SumType.stringof ~ - "` does not contain a(n) `" ~ T.stringof ~ "`" + "This `" ~ SumType.stringof ~ "`" ~ + "does not contain a(n) `" ~ Types[tid].stringof ~ "`" ); - return __traits(getMember, storage, Storage.memberName!T); + return storage.tupleof[tid]; } public: @@ -351,9 +349,9 @@ public: static if (isCopyable!T) { // Workaround for dlang issue 21542 - __traits(getMember, storage, Storage.memberName!T) = __ctfe ? value : forward!value; + storage.tupleof[tid] = __ctfe ? value : forward!value; } else { - __traits(getMember, storage, Storage.memberName!T) = forward!value; + storage.tupleof[tid] = forward!value; } tag = tid; @@ -365,7 +363,7 @@ public: /// ditto this(const(T) value) const { - __traits(getMember, storage, Storage.memberName!T) = value; + storage.tupleof[tid] = value; tag = tid; } } @@ -378,7 +376,7 @@ public: /// ditto this(immutable(T) value) immutable { - __traits(getMember, storage, Storage.memberName!T) = value; + storage.tupleof[tid] = value; tag = tid; } } @@ -392,7 +390,7 @@ public: this(Value)(Value value) inout if (is(Value == DeducedParameterType!(inout(T)))) { - __traits(getMember, storage, Storage.memberName!T) = value; + storage.tupleof[tid] = value; tag = tid; } } @@ -414,10 +412,9 @@ public: storage = other.match!((ref value) { alias OtherTypes = Map!(InoutOf, Types); enum tid = IndexOf!(typeof(value), OtherTypes); - alias T = Types[tid]; mixin("inout(Storage) newStorage = { ", - Storage.memberName!T, ": value", + memberName!tid, ": value", " };"); return newStorage; @@ -431,10 +428,10 @@ public: this(ref SumType other) { storage = other.match!((ref value) { - alias T = typeof(value); + enum tid = IndexOf!(typeof(value), Types); mixin("Storage newStorage = { ", - Storage.memberName!T, ": value", + memberName!tid, ": value", " };"); return newStorage; @@ -453,10 +450,9 @@ public: storage = other.match!((ref value) { alias OtherTypes = Map!(ConstOf, Types); enum tid = IndexOf!(typeof(value), OtherTypes); - alias T = Types[tid]; mixin("const(Storage) newStorage = { ", - Storage.memberName!T, ": value", + memberName!tid, ": value", " };"); return newStorage; @@ -475,10 +471,9 @@ public: storage = other.match!((ref value) { alias OtherTypes = Map!(ImmutableOf, Types); enum tid = IndexOf!(typeof(value), OtherTypes); - alias T = Types[tid]; mixin("immutable(Storage) newStorage = { ", - Storage.memberName!T, ": value", + memberName!tid, ": value", " };"); return newStorage; @@ -549,12 +544,13 @@ public: this.match!destroyIfOwner; static if (isCopyable!T) { + // Workaround for dlang issue 21542 mixin("Storage newStorage = { ", - Storage.memberName!T, ": __ctfe ? rhs : forward!rhs", + memberName!tid, ": __ctfe ? rhs : forward!rhs", " };"); } else { mixin("Storage newStorage = { ", - Storage.memberName!T, ": forward!rhs", + memberName!tid, ": forward!rhs", " };"); } @@ -1005,7 +1001,7 @@ version (D_BetterC) {} else alias MySum = SumType!(ubyte, void*[2]); MySum x = [null, cast(void*) 0x12345678]; - void** p = &x.get!(void*[2])[1]; + void** p = &x.get!1[1]; x = ubyte(123); assert(*p != cast(void*) 0x12345678); @@ -1034,8 +1030,8 @@ version (D_BetterC) {} else } catch (Exception e) {} assert( - (x.tag == 0 && x.get!A.value == 123) || - (x.tag == 1 && x.get!B.value == 456) + (x.tag == 0 && x.get!0.value == 123) || + (x.tag == 1 && x.get!1.value == 456) ); } @@ -1093,8 +1089,8 @@ version (D_BetterC) {} else SumType!(S[1]) x = [S(0)]; SumType!(S[1]) y = x; - auto xval = x.get!(S[1])[0].n; - auto yval = y.get!(S[1])[0].n; + auto xval = x.get!0[0].n; + auto yval = y.get!0[0].n; assert(xval != yval); } @@ -1169,8 +1165,8 @@ version (D_BetterC) {} else SumType!S y; y = x; - auto xval = x.get!S.n; - auto yval = y.get!S.n; + auto xval = x.get!0.n; + auto yval = y.get!0.n; assert(xval != yval); } @@ -1241,8 +1237,8 @@ version (D_BetterC) {} else SumType!S x = S(); SumType!S y = x; - auto xval = x.get!S.n; - auto yval = y.get!S.n; + auto xval = x.get!0.n; + auto yval = y.get!0.n; assert(xval != yval); } @@ -1783,10 +1779,10 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) * argument's tag, so there's no need to use TagTuple. */ enum handlerArgs(size_t caseId) = - "args[0].get!(SumTypes[0].Types[" ~ toCtString!caseId ~ "])()"; + "args[0].get!(" ~ toCtString!caseId ~ ")()"; alias valueTypes(size_t caseId) = - typeof(args[0].get!(SumTypes[0].Types[caseId])()); + typeof(args[0].get!(caseId)()); enum numCases = SumTypes[0].Types.length; // Multiple dispatch (slow path) @@ -1810,9 +1806,7 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...) template getType(size_t i) { - enum tid = tags[i]; - alias T = SumTypes[i].Types[tid]; - alias getType = typeof(args[i].get!T()); + alias getType = typeof(args[i].get!(tags[i])()); } alias valueTypes = Map!(getType, Iota!(tags.length)); @@ -2015,8 +2009,7 @@ template handlerArgs(size_t caseId, typeCounts...) static foreach (i; 0 .. tags.length) { handlerArgs = AliasSeq!( handlerArgs, - "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~ - ".Types[" ~ toCtString!(tags[i]) ~ "])(), " + "args[" ~ toCtString!i ~ "].get!(" ~ toCtString!(tags[i]) ~ ")(), " ); } } @@ -2264,7 +2257,7 @@ version (D_Exceptions) (ref double d) { d *= 2; } ); - assert(value.get!double.isClose(6.28)); + assert(value.get!1.isClose(6.28)); } // Handlers that return by ref