Skip to content

Commit

Permalink
Merge pull request #68 from s-ludwig/fix_const_issue
Browse files Browse the repository at this point in the history
Fix type system (const/inout) breach.
  • Loading branch information
Leonid Kramer authored May 20, 2021
2 parents e369094 + 5f6cc99 commit c40e23c
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 14 deletions.
21 changes: 18 additions & 3 deletions source/taggedalgebraic/taggedunion.d
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ align(commonAlignment!(UnionKindTypes!(UnionFieldEnum!U))) struct TaggedUnion
See_Also: `set`, `opAssign`
*/
@property ref inout(FieldTypes[kind]) value(Kind kind)()
@property ref value(Kind kind)()
inout {
if (this.kind != kind) {
enum msg(.string k_is) = "Attempt to get kind "~kind.stringof~" from tagged union with kind "~k_is;
Expand All @@ -285,8 +285,7 @@ align(commonAlignment!(UnionKindTypes!(UnionFieldEnum!U))) struct TaggedUnion
assert(false, msg!n);
}
}
//return trustedGet!(FieldTypes[kind]);
return *() @trusted { return cast(const(FieldTypes[kind])*)m_data.ptr; } ();
return trustedGet!(FieldTypes[kind]);
}


Expand Down Expand Up @@ -606,6 +605,22 @@ nothrow unittest {
tv = tu;
}

unittest {
static struct S1 { int num; }
alias T1 = TaggedUnion!S1;
static assert(is(const(T1) : T1));
static assert(is(typeof(T1.init.value!int) == int));
static assert(is(typeof(T1.init.value!(T1.Kind.num)) == int));
static assert(is(typeof(T1.init.numValue) == int));
static assert(is(typeof(const(T1).init.value!int) == const(int)));
static assert(is(typeof(const(T1).init.value!(T1.Kind.num)) == const(int)));
static assert(is(typeof(const(T1).init.numValue) == const(int)));

static struct S2 { int[] nums; }
alias T2 = TaggedUnion!S2;
static assert(!is(const(T2) : T2));
}


enum isUnitType(T) = is(T == Void) || is(T == void) || is(T == typeof(null));

Expand Down
63 changes: 52 additions & 11 deletions source/taggedalgebraic/visit.d
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ module taggedalgebraic.visit;
import taggedalgebraic.taggedalgebraic;
import taggedalgebraic.taggedunion;

import std.meta : anySatisfy;
import std.traits : EnumMembers, isInstanceOf;
import std.meta : anySatisfy, staticMap;
import std.traits : Unqual, EnumMembers, isInstanceOf;


/** Dispatches the value contained on a `TaggedUnion` or `TaggedAlgebraic` to a
Expand Down Expand Up @@ -35,7 +35,7 @@ template visit(VISITORS...)
alias T = void;
else alias T = TU.FieldTypes[k];
alias h = selectHandler!(T, VISITORS);
static if (is(typeof(h) == typeof(null))) static assert(false, "No visitor defined for type type "~T.stringof);
static if (is(typeof(h) == typeof(null))) static assert(false, "No visitor defined for type "~T.stringof);
else static if (is(typeof(h) == string)) static assert(false, h);
else static if (is(T == void)) return h();
else return h(tu.value!k);
Expand Down Expand Up @@ -143,6 +143,44 @@ unittest {
);
}

unittest {
static struct S {
Void nothing;
int num;
int[] nums;
}
alias TU = TaggedUnion!S;

TU tu = [1];
tu.visit!(
() { assert(false); },
(int num) { assert(false); },
(int[] num) { assert(num == [1]); }
);
tu.visit!(
() { assert(false); },
(const int num) { assert(false); },
(const int[] num) { assert(num == [1]); }
);
tu.visit!(
() { assert(false); },
(const int num) { assert(false); },
(const(int)[] num) { assert(num == [1]); }
);

const(TU) tuc = TU([1]);
tuc.visit!(
() { assert(false); },
(int num) { assert(false); },
(const(int)[] num) { assert(num == [1]); }
);
tuc.visit!(
() { assert(false); },
(const(int) num) { assert(false); },
(const(int[]) num) { assert(num == [1]); }
);
}


/** The same as `visit`, except that failure to handle types is checked at runtime.
Expand Down Expand Up @@ -210,14 +248,15 @@ unittest {

private template validateHandlers(TU, VISITORS...)
{
import std.traits : isSomeFunction;
import std.traits : CopyConstness, isSomeFunction;

alias Types = TU.FieldTypes;
alias ApplyConst(T) = CopyConstness!(TU, T);
alias Types = staticMap!(ApplyConst, TU.FieldTypes);

static foreach (int i; 0 .. VISITORS.length) {
static if (isSomeFunction!(VISITORS[i])) {
static assert(anySatisfy!(matchesType!(VISITORS[i]), Types),
"Visitor at index "~i.stringof~" does not match any type of "~TU.FieldTypes.stringof);
"Visitor at index "~i.stringof~" does not match any type of "~Types.stringof);
} else {
static assert(__traits(isTemplate, VISITORS[i]),
"Visitor at index "~i.stringof~" must be a function/delegate literal: "~VISITORS[i].stringof);
Expand All @@ -231,13 +270,13 @@ private template matchesType(alias fun) {
template matchesType(T) {
static if (isSomeFunction!fun) {
alias Params = ParameterTypeTuple!fun;
static if (Params.length == 0 && isUnitType!T) enum matchesType = true;
else static if (Params.length == 1 && is(T == Params[0])) enum matchesType = true;
static if (Params.length == 0 && isUnitType!(Unqual!T)) enum matchesType = true;
else static if (Params.length == 1 && isMatch!(Params[0], T)) enum matchesType = true;
else enum matchesType = false;
} else static if (!isUnitType!T) {
} else static if (!isUnitType!(Unqual!T)) {
static if (__traits(compiles, fun!T) && isSomeFunction!(fun!T)) {
alias Params = ParameterTypeTuple!(fun!T);
static if (Params.length == 1 && is(T == Params[0])) enum matchesType = true;
static if (Params.length == 1 && isMatch!(Params[0], T)) enum matchesType = true;
else enum matchesType = false;
} else enum matchesType = false;
} else enum matchesType = false;
Expand All @@ -264,7 +303,7 @@ private template selectHandler(T, VISITORS...)
static if (isSomeFunction!fun) {
alias Params = ParameterTypeTuple!fun;
static if (Params.length > 1) enum typedIndex = "Visitor at index "~i.stringof~" must not take more than one parameter.";
else static if (Params.length == 0 && is(T == void) || Params.length == 1 && is(T == Params[0])) {
else static if (Params.length == 0 && is(Unqual!T == void) || Params.length == 1 && isMatch!(Params[0], T)) {
static if (matched_index >= 0) enum typedIndex = "Vistor at index "~i.stringof~" conflicts with visitor at index "~matched_index~".";
else enum typedIndex = typedIndex!(i+1, i);
} else enum typedIndex = typedIndex!(i+1, matched_index);
Expand Down Expand Up @@ -298,3 +337,5 @@ private template selectHandler(T, VISITORS...)
else static if (generic_index >= 0) alias selectHandler = VISITORS[generic_index];
else enum selectHandler = null;
}

private enum isMatch(PT, T) = is(Unqual!(immutable(T)) == Unqual!(immutable(PT))) && is(T : PT);

0 comments on commit c40e23c

Please sign in to comment.