1 /++
2  This module was copied from Phobos at commit 87c6e7e35 (2022-07-06).
3  This is necessary to include https://github.com/dlang/phobos/pull/8501
4  which is a fix needed for DIP1000 compatibility. A couple minor changes
5  where also required to deal with `package(std)` imports.
6 
7 [SumType] is a generic discriminated union implementation that uses
8 design-by-introspection to generate safe and efficient code. Its features
9 include:
10 
11 * [Pattern matching.][match]
12 * Support for self-referential types.
13 * Full attribute correctness (`pure`, `@safe`, `@nogc`, and `nothrow` are
14     inferred whenever possible).
15 * A type-safe and memory-safe API compatible with DIP 1000 (`scope`).
16 * No dependency on runtime type information (`TypeInfo`).
17 * Compatibility with BetterC.
18 
19 License: Boost License 1.0
20 Authors: Paul Backus
21 Source: $(PHOBOSSRC std/sumtype.d)
22 +/
23 module dyaml.stdsumtype;
24 
25 /// $(DIVID basic-usage,$(H3 Basic usage))
26 version (D_BetterC) {} else
27 @safe unittest
28 {
29     import std.math.operations : isClose;
30 
31     struct Fahrenheit { double degrees; }
32     struct Celsius { double degrees; }
33     struct Kelvin { double degrees; }
34 
35     alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin);
36 
37     // Construct from any of the member types.
38     Temperature t1 = Fahrenheit(98.6);
39     Temperature t2 = Celsius(100);
40     Temperature t3 = Kelvin(273);
41 
42     // Use pattern matching to access the value.
43     Fahrenheit toFahrenheit(Temperature t)
44     {
45         return Fahrenheit(
46             t.match!(
47                 (Fahrenheit f) => f.degrees,
48                 (Celsius c) => c.degrees * 9.0/5 + 32,
49                 (Kelvin k) => k.degrees * 9.0/5 - 459.4
50             )
51         );
52     }
53 
54     assert(toFahrenheit(t1).degrees.isClose(98.6));
55     assert(toFahrenheit(t2).degrees.isClose(212));
56     assert(toFahrenheit(t3).degrees.isClose(32));
57 
58     // Use ref to modify the value in place.
59     void freeze(ref Temperature t)
60     {
61         t.match!(
62             (ref Fahrenheit f) => f.degrees = 32,
63             (ref Celsius c) => c.degrees = 0,
64             (ref Kelvin k) => k.degrees = 273
65         );
66     }
67 
68     freeze(t1);
69     assert(toFahrenheit(t1).degrees.isClose(32));
70 
71     // Use a catch-all handler to give a default result.
72     bool isFahrenheit(Temperature t)
73     {
74         return t.match!(
75             (Fahrenheit f) => true,
76             _ => false
77         );
78     }
79 
80     assert(isFahrenheit(t1));
81     assert(!isFahrenheit(t2));
82     assert(!isFahrenheit(t3));
83 }
84 
85 /** $(DIVID introspection-based-matching, $(H3 Introspection-based matching))
86  *
87  * In the `length` and `horiz` functions below, the handlers for `match` do not
88  * specify the types of their arguments. Instead, matching is done based on how
89  * the argument is used in the body of the handler: any type with `x` and `y`
90  * properties will be matched by the `rect` handlers, and any type with `r` and
91  * `theta` properties will be matched by the `polar` handlers.
92  */
93 version (D_BetterC) {} else
94 @safe unittest
95 {
96     import std.math.operations : isClose;
97     import std.math.trigonometry : cos;
98     import std.math.constants : PI;
99     import std.math.algebraic : sqrt;
100 
101     struct Rectangular { double x, y; }
102     struct Polar { double r, theta; }
103     alias Vector = SumType!(Rectangular, Polar);
104 
105     double length(Vector v)
106     {
107         return v.match!(
108             rect => sqrt(rect.x^^2 + rect.y^^2),
109             polar => polar.r
110         );
111     }
112 
113     double horiz(Vector v)
114     {
115         return v.match!(
116             rect => rect.x,
117             polar => polar.r * cos(polar.theta)
118         );
119     }
120 
121     Vector u = Rectangular(1, 1);
122     Vector v = Polar(1, PI/4);
123 
124     assert(length(u).isClose(sqrt(2.0)));
125     assert(length(v).isClose(1));
126     assert(horiz(u).isClose(1));
127     assert(horiz(v).isClose(sqrt(0.5)));
128 }
129 
130 /** $(DIVID arithmetic-expression-evaluator, $(H3 Arithmetic expression evaluator))
131  *
132  * This example makes use of the special placeholder type `This` to define a
133  * [recursive data type](https://en.wikipedia.org/wiki/Recursive_data_type): an
134  * [abstract syntax tree](https://en.wikipedia.org/wiki/Abstract_syntax_tree) for
135  * representing simple arithmetic expressions.
136  */
137 version (D_BetterC) {} else
138 @system unittest
139 {
140     import std.functional : partial;
141     import std.traits : EnumMembers;
142     import std.typecons : Tuple;
143 
144     enum Op : string
145     {
146         Plus  = "+",
147         Minus = "-",
148         Times = "*",
149         Div   = "/"
150     }
151 
152     // An expression is either
153     //  - a number,
154     //  - a variable, or
155     //  - a binary operation combining two sub-expressions.
156     alias Expr = SumType!(
157         double,
158         string,
159         Tuple!(Op, "op", This*, "lhs", This*, "rhs")
160     );
161 
162     // Shorthand for Tuple!(Op, "op", Expr*, "lhs", Expr*, "rhs"),
163     // the Tuple type above with Expr substituted for This.
164     alias BinOp = Expr.Types[2];
165 
166     // Factory function for number expressions
167     Expr* num(double value)
168     {
169         return new Expr(value);
170     }
171 
172     // Factory function for variable expressions
173     Expr* var(string name)
174     {
175         return new Expr(name);
176     }
177 
178     // Factory function for binary operation expressions
179     Expr* binOp(Op op, Expr* lhs, Expr* rhs)
180     {
181         return new Expr(BinOp(op, lhs, rhs));
182     }
183 
184     // Convenience wrappers for creating BinOp expressions
185     alias sum  = partial!(binOp, Op.Plus);
186     alias diff = partial!(binOp, Op.Minus);
187     alias prod = partial!(binOp, Op.Times);
188     alias quot = partial!(binOp, Op.Div);
189 
190     // Evaluate expr, looking up variables in env
191     double eval(Expr expr, double[string] env)
192     {
193         return expr.match!(
194             (double num) => num,
195             (string var) => env[var],
196             (BinOp bop)
197             {
198                 double lhs = eval(*bop.lhs, env);
199                 double rhs = eval(*bop.rhs, env);
200                 final switch (bop.op)
201                 {
202                     static foreach (op; EnumMembers!Op)
203                     {
204                         case op:
205                             return mixin("lhs" ~ op ~ "rhs");
206                     }
207                 }
208             }
209         );
210     }
211 
212     // Return a "pretty-printed" representation of expr
213     string pprint(Expr expr)
214     {
215         import std.format : format;
216 
217         return expr.match!(
218             (double num) => "%g".format(num),
219             (string var) => var,
220             (BinOp bop) => "(%s %s %s)".format(
221                 pprint(*bop.lhs),
222                 cast(string) bop.op,
223                 pprint(*bop.rhs)
224             )
225         );
226     }
227 
228     Expr* myExpr = sum(var("a"), prod(num(2), var("b")));
229     double[string] myEnv = ["a":3, "b":4, "c":7];
230 
231     assert(eval(*myExpr, myEnv) == 11);
232     assert(pprint(*myExpr) == "(a + (2 * b))");
233 }
234 
235 import std.format.spec : FormatSpec, singleSpec;
236 import std.meta : AliasSeq, Filter, IndexOf = staticIndexOf, Map = staticMap;
237 import std.meta : NoDuplicates;
238 import std.meta : anySatisfy, allSatisfy;
239 import std.traits : hasElaborateCopyConstructor, hasElaborateDestructor;
240 import std.traits : isAssignable, isCopyable, isStaticArray, isRvalueAssignable;
241 import std.traits : ConstOf, ImmutableOf, InoutOf, TemplateArgsOf;
242 
243 // FIXME: std.sumtype : `std.traits : DeducedParameterType` and `std.conv : toCtString`
244 // are `package(std)` but trivial, hence copied below
245 import std.traits : CommonType, /*DeducatedParameterType*/ Unqual;
246 private template DeducedParameterType(T)
247 {
248     static if (is(T == U*, U) || is(T == U[], U))
249         alias DeducedParameterType = Unqual!T;
250     else
251         alias DeducedParameterType = T;
252 }
253 
254 import std.typecons : ReplaceTypeUnless;
255 import std.typecons : Flag;
256 //import std.conv : toCtString;
257 private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
258 
259 /// Placeholder used to refer to the enclosing [SumType].
260 struct This {}
261 
262 // True if a variable of type T can appear on the lhs of an assignment
263 private enum isAssignableTo(T) =
264     isAssignable!T || (!isCopyable!T && isRvalueAssignable!T);
265 
266 // toHash is required by the language spec to be nothrow and @safe
267 private enum isHashable(T) = __traits(compiles,
268     () nothrow @safe { hashOf(T.init); }
269 );
270 
271 private enum hasPostblit(T) = __traits(hasPostblit, T);
272 
273 private enum isInout(T) = is(T == inout);
274 
275 /**
276  * A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) that can hold a
277  * single value from any of a specified set of types.
278  *
279  * The value in a `SumType` can be operated on using [pattern matching][match].
280  *
281  * To avoid ambiguity, duplicate types are not allowed (but see the
282  * ["basic usage" example](#basic-usage) for a workaround).
283  *
284  * The special type `This` can be used as a placeholder to create
285  * self-referential types, just like with `Algebraic`. See the
286  * ["Arithmetic expression evaluator" example](#arithmetic-expression-evaluator) for
287  * usage.
288  *
289  * A `SumType` is initialized by default to hold the `.init` value of its
290  * first member type, just like a regular union. The version identifier
291  * `SumTypeNoDefaultCtor` can be used to disable this behavior.
292  *
293  * See_Also: $(REF Algebraic, std,variant)
294  */
295 struct SumType(Types...)
296 if (is(NoDuplicates!Types == Types) && Types.length > 0)
297 {
298     /// The types a `SumType` can hold.
299     alias Types = AliasSeq!(
300         ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType)
301     );
302 
303 private:
304 
305     enum bool canHoldTag(T) = Types.length <= T.max;
306     alias unsignedInts = AliasSeq!(ubyte, ushort, uint, ulong);
307 
308     alias Tag = Filter!(canHoldTag, unsignedInts)[0];
309 
310     union Storage
311     {
312         // Workaround for https://issues.dlang.org/show_bug.cgi?id=20068
313         template memberName(T)
314         if (IndexOf!(T, Types) >= 0)
315         {
316             enum tid = IndexOf!(T, Types);
317             mixin("enum memberName = `values_", toCtString!tid, "`;");
318         }
319 
320         static foreach (T; Types)
321         {
322             mixin("T ", memberName!T, ";");
323         }
324     }
325 
326     Storage storage;
327     Tag tag;
328 
329     /* Accesses the value stored in a SumType.
330      *
331      * This method is memory-safe, provided that:
332      *
333      *   1. A SumType's tag is always accurate.
334      *   2. A SumType cannot be assigned to in @safe code if that assignment
335      *      could cause unsafe aliasing.
336      *
337      * All code that accesses a SumType's tag or storage directly, including
338      * @safe code in this module, must be manually checked to ensure that it
339      * does not violate either of the above requirements.
340      */
341     @trusted
342     ref inout(T) get(T)() inout
343     if (IndexOf!(T, Types) >= 0)
344     {
345         enum tid = IndexOf!(T, Types);
346         assert(tag == tid,
347             "This `" ~ SumType.stringof ~
348             "` does not contain a(n) `" ~ T.stringof ~ "`"
349         );
350         return __traits(getMember, storage, Storage.memberName!T);
351     }
352 
353 public:
354 
355     // Workaround for https://issues.dlang.org/show_bug.cgi?id=21399
356     version (StdDdoc)
357     {
358         // Dummy type to stand in for loop variable
359         private struct T;
360 
361         /// Constructs a `SumType` holding a specific value.
362         this(T value);
363 
364         /// ditto
365         this(const(T) value) const;
366 
367         /// ditto
368         this(immutable(T) value) immutable;
369 
370         /// ditto
371         this(Value)(Value value) inout
372         if (is(Value == DeducedParameterType!(inout(T))));
373     }
374 
375     static foreach (tid, T; Types)
376     {
377         /// Constructs a `SumType` holding a specific value.
378         this(T value)
379         {
380             import core.lifetime : forward;
381 
382             static if (isCopyable!T)
383             {
384                 // Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
385                 __traits(getMember, storage, Storage.memberName!T) = __ctfe ? value : forward!value;
386             }
387             else
388             {
389                 __traits(getMember, storage, Storage.memberName!T) = forward!value;
390             }
391 
392             tag = tid;
393         }
394 
395         static if (isCopyable!(const(T)))
396         {
397             static if (IndexOf!(const(T), Map!(ConstOf, Types)) == tid)
398             {
399                 /// ditto
400                 this(const(T) value) const
401                 {
402                     __traits(getMember, storage, Storage.memberName!T) = value;
403                     tag = tid;
404                 }
405             }
406         }
407         else
408         {
409             @disable this(const(T) value) const;
410         }
411 
412         static if (isCopyable!(immutable(T)))
413         {
414             static if (IndexOf!(immutable(T), Map!(ImmutableOf, Types)) == tid)
415             {
416                 /// ditto
417                 this(immutable(T) value) immutable
418                 {
419                     __traits(getMember, storage, Storage.memberName!T) = value;
420                     tag = tid;
421                 }
422             }
423         }
424         else
425         {
426             @disable this(immutable(T) value) immutable;
427         }
428 
429         static if (isCopyable!(inout(T)))
430         {
431             static if (IndexOf!(inout(T), Map!(InoutOf, Types)) == tid)
432             {
433                 /// ditto
434                 this(Value)(Value value) inout
435                 if (is(Value == DeducedParameterType!(inout(T))))
436                 {
437                     __traits(getMember, storage, Storage.memberName!T) = value;
438                     tag = tid;
439                 }
440             }
441         }
442         else
443         {
444             @disable this(Value)(Value value) inout
445             if (is(Value == DeducedParameterType!(inout(T))));
446         }
447     }
448 
449     static if (anySatisfy!(hasElaborateCopyConstructor, Types))
450     {
451         static if
452         (
453             allSatisfy!(isCopyable, Map!(InoutOf, Types))
454             && !anySatisfy!(hasPostblit, Map!(InoutOf, Types))
455             && allSatisfy!(isInout, Map!(InoutOf, Types))
456         )
457         {
458             /// Constructs a `SumType` that's a copy of another `SumType`.
459             this(ref inout(SumType) other) inout
460             {
461                 storage = other.match!((ref value) {
462                     alias OtherTypes = Map!(InoutOf, Types);
463                     enum tid = IndexOf!(typeof(value), OtherTypes);
464                     alias T = Types[tid];
465 
466                     mixin("inout(Storage) newStorage = { ",
467                         Storage.memberName!T, ": value",
468                     " };");
469 
470                     return newStorage;
471                 });
472 
473                 tag = other.tag;
474             }
475         }
476         else
477         {
478             static if (allSatisfy!(isCopyable, Types))
479             {
480                 /// ditto
481                 this(ref SumType other)
482                 {
483                     storage = other.match!((ref value) {
484                         alias T = typeof(value);
485 
486                         mixin("Storage newStorage = { ",
487                             Storage.memberName!T, ": value",
488                         " };");
489 
490                         return newStorage;
491                     });
492 
493                     tag = other.tag;
494                 }
495             }
496             else
497             {
498                 @disable this(ref SumType other);
499             }
500 
501             static if (allSatisfy!(isCopyable, Map!(ConstOf, Types)))
502             {
503                 /// ditto
504                 this(ref const(SumType) other) const
505                 {
506                     storage = other.match!((ref value) {
507                         alias OtherTypes = Map!(ConstOf, Types);
508                         enum tid = IndexOf!(typeof(value), OtherTypes);
509                         alias T = Types[tid];
510 
511                         mixin("const(Storage) newStorage = { ",
512                             Storage.memberName!T, ": value",
513                         " };");
514 
515                         return newStorage;
516                     });
517 
518                     tag = other.tag;
519                 }
520             }
521             else
522             {
523                 @disable this(ref const(SumType) other) const;
524             }
525 
526             static if (allSatisfy!(isCopyable, Map!(ImmutableOf, Types)))
527             {
528                 /// ditto
529                 this(ref immutable(SumType) other) immutable
530                 {
531                     storage = other.match!((ref value) {
532                         alias OtherTypes = Map!(ImmutableOf, Types);
533                         enum tid = IndexOf!(typeof(value), OtherTypes);
534                         alias T = Types[tid];
535 
536                         mixin("immutable(Storage) newStorage = { ",
537                             Storage.memberName!T, ": value",
538                         " };");
539 
540                         return newStorage;
541                     });
542 
543                     tag = other.tag;
544                 }
545             }
546             else
547             {
548                 @disable this(ref immutable(SumType) other) immutable;
549             }
550         }
551     }
552 
553     version (SumTypeNoDefaultCtor)
554     {
555         @disable this();
556     }
557 
558     // Workaround for https://issues.dlang.org/show_bug.cgi?id=21399
559     version (StdDdoc)
560     {
561         // Dummy type to stand in for loop variable
562         private struct T;
563 
564         /**
565          * Assigns a value to a `SumType`.
566          *
567          * If any of the `SumType`'s members other than the one being assigned
568          * to contain pointers or references, it is possible for the assignment
569          * to cause memory corruption (see the
570          * ["Memory corruption" example](#memory-corruption) below for an
571          * illustration of how). Therefore, such assignments are considered
572          * `@system`.
573          *
574          * An individual assignment can be `@trusted` if the caller can
575          * guarantee that there are no outstanding references to any `SumType`
576          * members that contain pointers or references at the time the
577          * assignment occurs.
578          *
579          * Examples:
580          *
581          * $(DIVID memory-corruption, $(H3 Memory corruption))
582          *
583          * This example shows how assignment to a `SumType` can be used to
584          * cause memory corruption in `@system` code. In `@safe` code, the
585          * assignment `s = 123` would not be allowed.
586          *
587          * ---
588          * SumType!(int*, int) s = new int;
589          * s.tryMatch!(
590          *     (ref int* p) {
591          *         s = 123; // overwrites `p`
592          *         return *p; // undefined behavior
593          *     }
594          * );
595          * ---
596          */
597         ref SumType opAssign(T rhs);
598     }
599 
600     static foreach (tid, T; Types)
601     {
602         static if (isAssignableTo!T)
603         {
604             /**
605              * Assigns a value to a `SumType`.
606              *
607              * If any of the `SumType`'s members other than the one being assigned
608              * to contain pointers or references, it is possible for the assignment
609              * to cause memory corruption (see the
610              * ["Memory corruption" example](#memory-corruption) below for an
611              * illustration of how). Therefore, such assignments are considered
612              * `@system`.
613              *
614              * An individual assignment can be `@trusted` if the caller can
615              * guarantee that there are no outstanding references to any `SumType`
616              * members that contain pointers or references at the time the
617              * assignment occurs.
618              *
619              * Examples:
620              *
621              * $(DIVID memory-corruption, $(H3 Memory corruption))
622              *
623              * This example shows how assignment to a `SumType` can be used to
624              * cause memory corruption in `@system` code. In `@safe` code, the
625              * assignment `s = 123` would not be allowed.
626              *
627              * ---
628              * SumType!(int*, int) s = new int;
629              * s.tryMatch!(
630              *     (ref int* p) {
631              *         s = 123; // overwrites `p`
632              *         return *p; // undefined behavior
633              *     }
634              * );
635              * ---
636              */
637             ref SumType opAssign(T rhs)
638             {
639                 import core.lifetime : forward;
640                 import std.traits : hasIndirections, hasNested;
641                 import std.meta : AliasSeq, Or = templateOr;
642 
643                 alias OtherTypes =
644                     AliasSeq!(Types[0 .. tid], Types[tid + 1 .. $]);
645                 enum unsafeToOverwrite =
646                     anySatisfy!(Or!(hasIndirections, hasNested), OtherTypes);
647 
648                 static if (unsafeToOverwrite)
649                 {
650                     cast(void) () @system {}();
651                 }
652 
653                 this.match!destroyIfOwner;
654 
655                 static if (isCopyable!T)
656                 {
657                     // Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
658                     mixin("Storage newStorage = { ",
659                         Storage.memberName!T, ": __ctfe ? rhs : forward!rhs",
660                     " };");
661                 }
662                 else
663                 {
664                     mixin("Storage newStorage = { ",
665                         Storage.memberName!T, ": forward!rhs",
666                     " };");
667                 }
668 
669                 storage = newStorage;
670                 tag = tid;
671 
672                 return this;
673             }
674         }
675     }
676 
677     static if (allSatisfy!(isAssignableTo, Types))
678     {
679         static if (allSatisfy!(isCopyable, Types))
680         {
681             /**
682              * Copies the value from another `SumType` into this one.
683              *
684              * See the value-assignment overload for details on `@safe`ty.
685              *
686              * Copy assignment is `@disable`d if any of `Types` is non-copyable.
687              */
688             ref SumType opAssign(ref SumType rhs)
689             {
690                 rhs.match!((ref value) { this = value; });
691                 return this;
692             }
693         }
694         else
695         {
696             @disable ref SumType opAssign(ref SumType rhs);
697         }
698 
699         /**
700          * Moves the value from another `SumType` into this one.
701          *
702          * See the value-assignment overload for details on `@safe`ty.
703          */
704         ref SumType opAssign(SumType rhs)
705         {
706             import core.lifetime : move;
707 
708             rhs.match!((ref value) {
709                 static if (isCopyable!(typeof(value)))
710                 {
711                     // Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
712                     this = __ctfe ? value : move(value);
713                 }
714                 else
715                 {
716                     this = move(value);
717                 }
718             });
719             return this;
720         }
721     }
722 
723     /**
724      * Compares two `SumType`s for equality.
725      *
726      * Two `SumType`s are equal if they are the same kind of `SumType`, they
727      * contain values of the same type, and those values are equal.
728      */
729     bool opEquals(this This, Rhs)(auto ref Rhs rhs)
730     if (!is(CommonType!(This, Rhs) == void))
731     {
732         static if (is(This == Rhs))
733         {
734             return AliasSeq!(this, rhs).match!((ref value, ref rhsValue) {
735                 static if (is(typeof(value) == typeof(rhsValue)))
736                 {
737                     return value == rhsValue;
738                 }
739                 else
740                 {
741                     return false;
742                 }
743             });
744         }
745         else
746         {
747             alias CommonSumType = CommonType!(This, Rhs);
748             return cast(CommonSumType) this == cast(CommonSumType) rhs;
749         }
750     }
751 
752     // Workaround for https://issues.dlang.org/show_bug.cgi?id=19407
753     static if (__traits(compiles, anySatisfy!(hasElaborateDestructor, Types)))
754     {
755         // If possible, include the destructor only when it's needed
756         private enum includeDtor = anySatisfy!(hasElaborateDestructor, Types);
757     }
758     else
759     {
760         // If we can't tell, always include it, even when it does nothing
761         private enum includeDtor = true;
762     }
763 
764     static if (includeDtor)
765     {
766         /// Calls the destructor of the `SumType`'s current value.
767         ~this()
768         {
769             this.match!destroyIfOwner;
770         }
771     }
772 
773     invariant
774     {
775         this.match!((ref value) {
776             static if (is(typeof(value) == class))
777             {
778                 if (value !is null)
779                 {
780                     assert(value);
781                 }
782             }
783             else static if (is(typeof(value) == struct))
784             {
785                 assert(&value);
786             }
787         });
788     }
789 
790     // Workaround for https://issues.dlang.org/show_bug.cgi?id=21400
791     version (StdDdoc)
792     {
793         /**
794          * Returns a string representation of the `SumType`'s current value.
795          *
796          * Not available when compiled with `-betterC`.
797          */
798         string toString(this This)();
799 
800         /**
801          * Handles formatted writing of the `SumType`'s current value.
802          *
803          * Not available when compiled with `-betterC`.
804          *
805          * Params:
806          *   sink = Output range to write to.
807          *   fmt = Format specifier to use.
808          *
809          * See_Also: $(REF formatValue, std,format)
810          */
811         void toString(this This, Sink, Char)(ref Sink sink, const ref FormatSpec!Char fmt);
812     }
813 
814     version (D_BetterC) {} else
815     /**
816      * Returns a string representation of the `SumType`'s current value.
817      *
818      * Not available when compiled with `-betterC`.
819      */
820     string toString(this This)()
821     {
822         import std.conv : to;
823 
824         return this.match!(to!string);
825     }
826 
827     version (D_BetterC) {} else
828     /**
829      * Handles formatted writing of the `SumType`'s current value.
830      *
831      * Not available when compiled with `-betterC`.
832      *
833      * Params:
834      *   sink = Output range to write to.
835      *   fmt = Format specifier to use.
836      *
837      * See_Also: $(REF formatValue, std,format)
838      */
839     void toString(this This, Sink, Char)(ref Sink sink, const ref FormatSpec!Char fmt)
840     {
841         import std.format.write : formatValue;
842 
843         this.match!((ref value) {
844             formatValue(sink, value, fmt);
845         });
846     }
847 
848     static if (allSatisfy!(isHashable, Map!(ConstOf, Types)))
849     {
850         // Workaround for https://issues.dlang.org/show_bug.cgi?id=21400
851         version (StdDdoc)
852         {
853             /**
854              * Returns the hash of the `SumType`'s current value.
855              *
856              * Not available when compiled with `-betterC`.
857              */
858             size_t toHash() const;
859         }
860 
861         // Workaround for https://issues.dlang.org/show_bug.cgi?id=20095
862         version (D_BetterC) {} else
863         /**
864          * Returns the hash of the `SumType`'s current value.
865          *
866          * Not available when compiled with `-betterC`.
867          */
868         size_t toHash() const
869         {
870             return this.match!hashOf;
871         }
872     }
873 }
874 
875 // Construction
876 @safe unittest
877 {
878     alias MySum = SumType!(int, float);
879 
880     MySum x = MySum(42);
881     MySum y = MySum(3.14);
882 }
883 
884 // Assignment
885 @safe unittest
886 {
887     alias MySum = SumType!(int, float);
888 
889     MySum x = MySum(42);
890     x = 3.14;
891 }
892 
893 // Self assignment
894 @safe unittest
895 {
896     alias MySum = SumType!(int, float);
897 
898     MySum x = MySum(42);
899     MySum y = MySum(3.14);
900     y = x;
901 }
902 
903 // Equality
904 @safe unittest
905 {
906     alias MySum = SumType!(int, float);
907 
908     assert(MySum(123) == MySum(123));
909     assert(MySum(123) != MySum(456));
910     assert(MySum(123) != MySum(123.0));
911     assert(MySum(123) != MySum(456.0));
912 
913 }
914 
915 // Equality of differently-qualified SumTypes
916 // Disabled in BetterC due to use of dynamic arrays
917 version (D_BetterC) {} else
918 @safe unittest
919 {
920     alias SumA = SumType!(int, float);
921     alias SumB = SumType!(const(int[]), int[]);
922     alias SumC = SumType!(int[], const(int[]));
923 
924     int[] ma = [1, 2, 3];
925     const(int[]) ca = [1, 2, 3];
926 
927     assert(const(SumA)(123) == SumA(123));
928     assert(const(SumB)(ma[]) == SumB(ca[]));
929     assert(const(SumC)(ma[]) == SumC(ca[]));
930 }
931 
932 // Imported types
933 @safe unittest
934 {
935     import std.typecons : Tuple;
936 
937     alias MySum = SumType!(Tuple!(int, int));
938 }
939 
940 // const and immutable types
941 @safe unittest
942 {
943     alias MySum = SumType!(const(int[]), immutable(float[]));
944 }
945 
946 // Recursive types
947 @safe unittest
948 {
949     alias MySum = SumType!(This*);
950     assert(is(MySum.Types[0] == MySum*));
951 }
952 
953 // Allowed types
954 @safe unittest
955 {
956     import std.meta : AliasSeq;
957 
958     alias MySum = SumType!(int, float, This*);
959 
960     assert(is(MySum.Types == AliasSeq!(int, float, MySum*)));
961 }
962 
963 // Types with destructors and postblits
964 @system unittest
965 {
966     int copies;
967 
968     static struct Test
969     {
970         bool initialized = false;
971         int* copiesPtr;
972 
973         this(this) { (*copiesPtr)++; }
974         ~this() { if (initialized) (*copiesPtr)--; }
975     }
976 
977     alias MySum = SumType!(int, Test);
978 
979     Test t = Test(true, &copies);
980 
981     {
982         MySum x = t;
983         assert(copies == 1);
984     }
985     assert(copies == 0);
986 
987     {
988         MySum x = 456;
989         assert(copies == 0);
990     }
991     assert(copies == 0);
992 
993     {
994         MySum x = t;
995         assert(copies == 1);
996         x = 456;
997         assert(copies == 0);
998     }
999 
1000     {
1001         MySum x = 456;
1002         assert(copies == 0);
1003         x = t;
1004         assert(copies == 1);
1005     }
1006 
1007     {
1008         MySum x = t;
1009         MySum y = x;
1010         assert(copies == 2);
1011     }
1012 
1013     {
1014         MySum x = t;
1015         MySum y;
1016         y = x;
1017         assert(copies == 2);
1018     }
1019 }
1020 
1021 // Doesn't destroy reference types
1022 // Disabled in BetterC due to use of classes
1023 version (D_BetterC) {} else
1024 @system unittest
1025 {
1026     bool destroyed;
1027 
1028     class C
1029     {
1030         ~this()
1031         {
1032             destroyed = true;
1033         }
1034     }
1035 
1036     struct S
1037     {
1038         ~this() {}
1039     }
1040 
1041     alias MySum = SumType!(S, C);
1042 
1043     C c = new C();
1044     {
1045         MySum x = c;
1046         destroyed = false;
1047     }
1048     assert(!destroyed);
1049 
1050     {
1051         MySum x = c;
1052         destroyed = false;
1053         x = S();
1054         assert(!destroyed);
1055     }
1056 }
1057 
1058 // Types with @disable this()
1059 @safe unittest
1060 {
1061     static struct NoInit
1062     {
1063         @disable this();
1064     }
1065 
1066     alias MySum = SumType!(NoInit, int);
1067 
1068     assert(!__traits(compiles, MySum()));
1069     auto _ = MySum(42);
1070 }
1071 
1072 // const SumTypes
1073 version (D_BetterC) {} else // not @nogc, https://issues.dlang.org/show_bug.cgi?id=22117
1074 @safe unittest
1075 {
1076     auto _ = const(SumType!(int[]))([1, 2, 3]);
1077 }
1078 
1079 // Equality of const SumTypes
1080 @safe unittest
1081 {
1082     alias MySum = SumType!int;
1083 
1084     auto _ = const(MySum)(123) == const(MySum)(456);
1085 }
1086 
1087 // Compares reference types using value equality
1088 @safe unittest
1089 {
1090     import std.array : staticArray;
1091 
1092     static struct Field {}
1093     static struct Struct { Field[] fields; }
1094     alias MySum = SumType!Struct;
1095 
1096     static arr1 = staticArray([Field()]);
1097     static arr2 = staticArray([Field()]);
1098 
1099     auto a = MySum(Struct(arr1[]));
1100     auto b = MySum(Struct(arr2[]));
1101 
1102     assert(a == b);
1103 }
1104 
1105 // toString
1106 // Disabled in BetterC due to use of std.conv.text
1107 version (D_BetterC) {} else
1108 @safe unittest
1109 {
1110     import std.conv : text;
1111 
1112     static struct Int { int i; }
1113     static struct Double { double d; }
1114     alias Sum = SumType!(Int, Double);
1115 
1116     assert(Sum(Int(42)).text == Int(42).text, Sum(Int(42)).text);
1117     assert(Sum(Double(33.3)).text == Double(33.3).text, Sum(Double(33.3)).text);
1118     assert((const(Sum)(Int(42))).text == (const(Int)(42)).text, (const(Sum)(Int(42))).text);
1119 }
1120 
1121 // string formatting
1122 // Disabled in BetterC due to use of std.format.format
1123 version (D_BetterC) {} else
1124 @safe unittest
1125 {
1126     import std.format : format;
1127 
1128     SumType!int x = 123;
1129 
1130     assert(format!"%s"(x) == format!"%s"(123));
1131     assert(format!"%x"(x) == format!"%x"(123));
1132 }
1133 
1134 // string formatting of qualified SumTypes
1135 // Disabled in BetterC due to use of std.format.format and dynamic arrays
1136 version (D_BetterC) {} else
1137 @safe unittest
1138 {
1139     import std.format : format;
1140 
1141     int[] a = [1, 2, 3];
1142     const(SumType!(int[])) x = a;
1143 
1144     assert(format!"%(%d, %)"(x) == format!"%(%s, %)"(a));
1145 }
1146 
1147 // Github issue #16
1148 // Disabled in BetterC due to use of dynamic arrays
1149 version (D_BetterC) {} else
1150 @safe unittest
1151 {
1152     alias Node = SumType!(This[], string);
1153 
1154     // override inference of @system attribute for cyclic functions
1155     assert((() @trusted =>
1156         Node([Node([Node("x")])])
1157         ==
1158         Node([Node([Node("x")])])
1159     )());
1160 }
1161 
1162 // Github issue #16 with const
1163 // Disabled in BetterC due to use of dynamic arrays
1164 version (D_BetterC) {} else
1165 @safe unittest
1166 {
1167     alias Node = SumType!(const(This)[], string);
1168 
1169     // override inference of @system attribute for cyclic functions
1170     assert((() @trusted =>
1171         Node([Node([Node("x")])])
1172         ==
1173         Node([Node([Node("x")])])
1174     )());
1175 }
1176 
1177 // Stale pointers
1178 // Disabled in BetterC due to use of dynamic arrays
1179 version (D_BetterC) {} else
1180 @system unittest
1181 {
1182     alias MySum = SumType!(ubyte, void*[2]);
1183 
1184     MySum x = [null, cast(void*) 0x12345678];
1185     void** p = &x.get!(void*[2])[1];
1186     x = ubyte(123);
1187 
1188     assert(*p != cast(void*) 0x12345678);
1189 }
1190 
1191 // Exception-safe assignment
1192 // Disabled in BetterC due to use of exceptions
1193 version (D_BetterC) {} else
1194 @safe unittest
1195 {
1196     static struct A
1197     {
1198         int value = 123;
1199     }
1200 
1201     static struct B
1202     {
1203         int value = 456;
1204         this(this) { throw new Exception("oops"); }
1205     }
1206 
1207     alias MySum = SumType!(A, B);
1208 
1209     MySum x;
1210     try
1211     {
1212         x = B();
1213     }
1214     catch (Exception e) {}
1215 
1216     assert(
1217         (x.tag == 0 && x.get!A.value == 123) ||
1218         (x.tag == 1 && x.get!B.value == 456)
1219     );
1220 }
1221 
1222 // Types with @disable this(this)
1223 @safe unittest
1224 {
1225     import core.lifetime : move;
1226 
1227     static struct NoCopy
1228     {
1229         @disable this(this);
1230     }
1231 
1232     alias MySum = SumType!NoCopy;
1233 
1234     NoCopy lval = NoCopy();
1235 
1236     MySum x = NoCopy();
1237     MySum y = NoCopy();
1238 
1239 
1240     assert(!__traits(compiles, SumType!NoCopy(lval)));
1241 
1242     y = NoCopy();
1243     y = move(x);
1244     assert(!__traits(compiles, y = lval));
1245     assert(!__traits(compiles, y = x));
1246 
1247     bool b = x == y;
1248 }
1249 
1250 // Github issue #22
1251 // Disabled in BetterC due to use of std.typecons.Nullable
1252 version (D_BetterC) {} else
1253 @safe unittest
1254 {
1255     import std.typecons;
1256 
1257     static struct A
1258     {
1259         SumType!(Nullable!int) a = Nullable!int.init;
1260     }
1261 }
1262 
1263 // Static arrays of structs with postblits
1264 // Disabled in BetterC due to use of dynamic arrays
1265 version (D_BetterC) {} else
1266 @safe unittest
1267 {
1268     static struct S
1269     {
1270         int n;
1271         this(this) { n++; }
1272     }
1273 
1274     SumType!(S[1]) x = [S(0)];
1275     SumType!(S[1]) y = x;
1276 
1277     auto xval = x.get!(S[1])[0].n;
1278     auto yval = y.get!(S[1])[0].n;
1279 
1280     assert(xval != yval);
1281 }
1282 
1283 // Replacement does not happen inside SumType
1284 // Disabled in BetterC due to use of associative arrays
1285 version (D_BetterC) {} else
1286 @safe unittest
1287 {
1288     import std.typecons : Tuple, ReplaceTypeUnless;
1289     alias A = Tuple!(This*,SumType!(This*))[SumType!(This*,string)[This]];
1290     alias TR = ReplaceTypeUnless!(isSumTypeInstance, This, int, A);
1291     static assert(is(TR == Tuple!(int*,SumType!(This*))[SumType!(This*, string)[int]]));
1292 }
1293 
1294 // Supports nested self-referential SumTypes
1295 @safe unittest
1296 {
1297     import std.typecons : Tuple, Flag;
1298     alias Nat = SumType!(Flag!"0", Tuple!(This*));
1299     alias Inner = SumType!Nat;
1300     alias Outer = SumType!(Nat*, Tuple!(This*, This*));
1301 }
1302 
1303 // Self-referential SumTypes inside Algebraic
1304 // Disabled in BetterC due to use of std.variant.Algebraic
1305 version (D_BetterC) {} else
1306 @safe unittest
1307 {
1308     import std.variant : Algebraic;
1309 
1310     alias T = Algebraic!(SumType!(This*));
1311 
1312     assert(is(T.AllowedTypes[0].Types[0] == T.AllowedTypes[0]*));
1313 }
1314 
1315 // Doesn't call @system postblits in @safe code
1316 @safe unittest
1317 {
1318     static struct SystemCopy { @system this(this) {} }
1319     SystemCopy original;
1320 
1321     assert(!__traits(compiles, () @safe
1322             {
1323         SumType!SystemCopy copy = original;
1324     }));
1325 
1326     assert(!__traits(compiles, () @safe
1327             {
1328         SumType!SystemCopy copy; copy = original;
1329     }));
1330 }
1331 
1332 // Doesn't overwrite pointers in @safe code
1333 @safe unittest
1334 {
1335     alias MySum = SumType!(int*, int);
1336 
1337     MySum x;
1338 
1339     assert(!__traits(compiles, () @safe
1340             {
1341         x = 123;
1342     }));
1343 
1344     assert(!__traits(compiles, () @safe
1345             {
1346         x = MySum(123);
1347     }));
1348 }
1349 
1350 // Types with invariants
1351 // Disabled in BetterC due to use of exceptions
1352 version (D_BetterC) {} else
1353 version (D_Invariants)
1354 @system unittest
1355 {
1356     import std.exception : assertThrown;
1357     import core.exception : AssertError;
1358 
1359     struct S
1360     {
1361         int i;
1362         invariant { assert(i >= 0); }
1363     }
1364 
1365     class C
1366     {
1367         int i;
1368         invariant { assert(i >= 0); }
1369     }
1370 
1371     SumType!S x;
1372     x.match!((ref v) { v.i = -1; });
1373     assertThrown!AssertError(assert(&x));
1374 
1375     SumType!C y = new C();
1376     y.match!((ref v) { v.i = -1; });
1377     assertThrown!AssertError(assert(&y));
1378 }
1379 
1380 // Calls value postblit on self-assignment
1381 @safe unittest
1382 {
1383     static struct S
1384     {
1385         int n;
1386         this(this) { n++; }
1387     }
1388 
1389     SumType!S x = S();
1390     SumType!S y;
1391     y = x;
1392 
1393     auto xval = x.get!S.n;
1394     auto yval = y.get!S.n;
1395 
1396     assert(xval != yval);
1397 }
1398 
1399 // Github issue #29
1400 @safe unittest
1401 {
1402     alias A = SumType!string;
1403 
1404     @safe A createA(string arg)
1405     {
1406         return A(arg);
1407     }
1408 
1409     @safe void test()
1410     {
1411         A a = createA("");
1412     }
1413 }
1414 
1415 // SumTypes as associative array keys
1416 // Disabled in BetterC due to use of associative arrays
1417 version (D_BetterC) {} else
1418 @safe unittest
1419 {
1420     int[SumType!(int, string)] aa;
1421 }
1422 
1423 // toString with non-copyable types
1424 // Disabled in BetterC due to use of std.conv.to (in toString)
1425 version (D_BetterC) {} else
1426 @safe unittest
1427 {
1428     struct NoCopy
1429     {
1430         @disable this(this);
1431     }
1432 
1433     SumType!NoCopy x;
1434 
1435     auto _ = x.toString();
1436 }
1437 
1438 // Can use the result of assignment
1439 @safe unittest
1440 {
1441     alias MySum = SumType!(int, float);
1442 
1443     MySum a = MySum(123);
1444     MySum b = MySum(3.14);
1445 
1446     assert((a = b) == b);
1447     assert((a = MySum(123)) == MySum(123));
1448     assert((a = 3.14) == MySum(3.14));
1449     assert(((a = b) = MySum(123)) == MySum(123));
1450 }
1451 
1452 // Types with copy constructors
1453 @safe unittest
1454 {
1455     static struct S
1456     {
1457         int n;
1458 
1459         this(ref return scope inout S other) inout
1460         {
1461             n = other.n + 1;
1462         }
1463     }
1464 
1465     SumType!S x = S();
1466     SumType!S y = x;
1467 
1468     auto xval = x.get!S.n;
1469     auto yval = y.get!S.n;
1470 
1471     assert(xval != yval);
1472 }
1473 
1474 // Copyable by generated copy constructors
1475 @safe unittest
1476 {
1477     static struct Inner
1478     {
1479         ref this(ref inout Inner other) {}
1480     }
1481 
1482     static struct Outer
1483     {
1484         SumType!Inner inner;
1485     }
1486 
1487     Outer x;
1488     Outer y = x;
1489 }
1490 
1491 // Types with qualified copy constructors
1492 @safe unittest
1493 {
1494     static struct ConstCopy
1495     {
1496         int n;
1497         this(inout int n) inout { this.n = n; }
1498         this(ref const typeof(this) other) const { this.n = other.n; }
1499     }
1500 
1501     static struct ImmutableCopy
1502     {
1503         int n;
1504         this(inout int n) inout { this.n = n; }
1505         this(ref immutable typeof(this) other) immutable { this.n = other.n; }
1506     }
1507 
1508     const SumType!ConstCopy x = const(ConstCopy)(1);
1509     immutable SumType!ImmutableCopy y = immutable(ImmutableCopy)(1);
1510 }
1511 
1512 // Types with disabled opEquals
1513 @safe unittest
1514 {
1515     static struct S
1516     {
1517         @disable bool opEquals(const S rhs) const;
1518     }
1519 
1520     auto _ = SumType!S(S());
1521 }
1522 
1523 // Types with non-const opEquals
1524 @safe unittest
1525 {
1526     static struct S
1527     {
1528         int i;
1529         bool opEquals(S rhs) { return i == rhs.i; }
1530     }
1531 
1532     auto _ = SumType!S(S(123));
1533 }
1534 
1535 // Incomparability of different SumTypes
1536 @safe unittest
1537 {
1538     SumType!(int, string) x = 123;
1539     SumType!(string, int) y = 123;
1540 
1541     assert(!__traits(compiles, x != y));
1542 }
1543 
1544 // Self-reference in return/parameter type of function pointer member
1545 // Disabled in BetterC due to use of delegates
1546 version (D_BetterC) {} else
1547 @safe unittest
1548 {
1549     alias T = SumType!(int, This delegate(This));
1550 }
1551 
1552 // Construction and assignment from implicitly-convertible lvalue
1553 @safe unittest
1554 {
1555     alias MySum = SumType!bool;
1556 
1557     const(bool) b = true;
1558 
1559     MySum x = b;
1560     MySum y; y = b;
1561 }
1562 
1563 // @safe assignment to the only pointer type in a SumType
1564 @safe unittest
1565 {
1566     SumType!(string, int) sm = 123;
1567     sm = "this should be @safe";
1568 }
1569 
1570 // Immutable member type with copy constructor
1571 // https://issues.dlang.org/show_bug.cgi?id=22572
1572 @safe unittest
1573 {
1574     static struct CopyConstruct
1575     {
1576         this(ref inout CopyConstruct other) inout {}
1577     }
1578 
1579     static immutable struct Value
1580     {
1581         CopyConstruct c;
1582     }
1583 
1584     SumType!Value s;
1585 }
1586 
1587 // Construction of inout-qualified SumTypes
1588 // https://issues.dlang.org/show_bug.cgi?id=22901
1589 @safe unittest
1590 {
1591     static inout(SumType!(int[])) example(inout(int[]) arr)
1592     {
1593         return inout(SumType!(int[]))(arr);
1594     }
1595 }
1596 
1597 // Assignment of struct with overloaded opAssign in CTFE
1598 // https://issues.dlang.org/show_bug.cgi?id=23182
1599 @safe unittest
1600 {
1601     static struct HasOpAssign
1602     {
1603         void opAssign(HasOpAssign rhs) {}
1604     }
1605 
1606     static SumType!HasOpAssign test()
1607     {
1608         SumType!HasOpAssign s;
1609         // Test both overloads
1610         s = HasOpAssign();
1611         s = SumType!HasOpAssign();
1612         return s;
1613     }
1614 
1615     // Force CTFE
1616     enum result = test();
1617 }
1618 
1619 /// True if `T` is an instance of the `SumType` template, otherwise false.
1620 private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
1621 
1622 @safe unittest
1623 {
1624     static struct Wrapper
1625     {
1626         SumType!int s;
1627         alias s this;
1628     }
1629 
1630     assert(isSumTypeInstance!(SumType!int));
1631     assert(!isSumTypeInstance!Wrapper);
1632 }
1633 
1634 /// True if `T` is a [SumType] or implicitly converts to one, otherwise false.
1635 enum bool isSumType(T) = is(T : SumType!Args, Args...);
1636 
1637 ///
1638 @safe unittest
1639 {
1640     static struct ConvertsToSumType
1641     {
1642         SumType!int payload;
1643         alias payload this;
1644     }
1645 
1646     static struct ContainsSumType
1647     {
1648         SumType!int payload;
1649     }
1650 
1651     assert(isSumType!(SumType!int));
1652     assert(isSumType!ConvertsToSumType);
1653     assert(!isSumType!ContainsSumType);
1654 }
1655 
1656 /**
1657  * Calls a type-appropriate function with the value held in a [SumType].
1658  *
1659  * For each possible type the [SumType] can hold, the given handlers are
1660  * checked, in order, to see whether they accept a single argument of that type.
1661  * The first one that does is chosen as the match for that type. (Note that the
1662  * first match may not always be the most exact match.
1663  * See ["Avoiding unintentional matches"](#avoiding-unintentional-matches) for
1664  * one common pitfall.)
1665  *
1666  * Every type must have a matching handler, and every handler must match at
1667  * least one type. This is enforced at compile time.
1668  *
1669  * Handlers may be functions, delegates, or objects with `opCall` overloads. If
1670  * a function with more than one overload is given as a handler, all of the
1671  * overloads are considered as potential matches.
1672  *
1673  * Templated handlers are also accepted, and will match any type for which they
1674  * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
1675  * ["Introspection-based matching"](#introspection-based-matching) for an
1676  * example of templated handler usage.
1677  *
1678  * If multiple [SumType]s are passed to match, their values are passed to the
1679  * handlers as separate arguments, and matching is done for each possible
1680  * combination of value types. See ["Multiple dispatch"](#multiple-dispatch) for
1681  * an example.
1682  *
1683  * Returns:
1684  *   The value returned from the handler that matches the currently-held type.
1685  *
1686  * See_Also: $(REF visit, std,variant)
1687  */
1688 template match(handlers...)
1689 {
1690     import std.typecons : Yes;
1691 
1692     /**
1693      * The actual `match` function.
1694      *
1695      * Params:
1696      *   args = One or more [SumType] objects.
1697      */
1698     auto ref match(SumTypes...)(auto ref SumTypes args)
1699     if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1700     {
1701         return matchImpl!(Yes.exhaustive, handlers)(args);
1702     }
1703 }
1704 
1705 /** $(DIVID avoiding-unintentional-matches, $(H3 Avoiding unintentional matches))
1706  *
1707  * Sometimes, implicit conversions may cause a handler to match more types than
1708  * intended. The example below shows two solutions to this problem.
1709  */
1710 @safe unittest
1711 {
1712     alias Number = SumType!(double, int);
1713 
1714     Number x;
1715 
1716     // Problem: because int implicitly converts to double, the double
1717     // handler is used for both types, and the int handler never matches.
1718     assert(!__traits(compiles,
1719         x.match!(
1720             (double d) => "got double",
1721             (int n) => "got int"
1722         )
1723     ));
1724 
1725     // Solution 1: put the handler for the "more specialized" type (in this
1726     // case, int) before the handler for the type it converts to.
1727     assert(__traits(compiles,
1728         x.match!(
1729             (int n) => "got int",
1730             (double d) => "got double"
1731         )
1732     ));
1733 
1734     // Solution 2: use a template that only accepts the exact type it's
1735     // supposed to match, instead of any type that implicitly converts to it.
1736     alias exactly(T, alias fun) = function (arg)
1737     {
1738         static assert(is(typeof(arg) == T));
1739         return fun(arg);
1740     };
1741 
1742     // Now, even if we put the double handler first, it will only be used for
1743     // doubles, not ints.
1744     assert(__traits(compiles,
1745         x.match!(
1746             exactly!(double, d => "got double"),
1747             exactly!(int, n => "got int")
1748         )
1749     ));
1750 }
1751 
1752 /** $(DIVID multiple-dispatch, $(H3 Multiple dispatch))
1753  *
1754  * Pattern matching can be performed on multiple `SumType`s at once by passing
1755  * handlers with multiple arguments. This usually leads to more concise code
1756  * than using nested calls to `match`, as show below.
1757  */
1758 @safe unittest
1759 {
1760     struct Point2D { double x, y; }
1761     struct Point3D { double x, y, z; }
1762 
1763     alias Point = SumType!(Point2D, Point3D);
1764 
1765     version (none)
1766     {
1767         // This function works, but the code is ugly and repetitive.
1768         // It uses three separate calls to match!
1769         @safe pure nothrow @nogc
1770         bool sameDimensions(Point p1, Point p2)
1771         {
1772             return p1.match!(
1773                 (Point2D _) => p2.match!(
1774                     (Point2D _) => true,
1775                     _ => false
1776                 ),
1777                 (Point3D _) => p2.match!(
1778                     (Point3D _) => true,
1779                     _ => false
1780                 )
1781             );
1782         }
1783     }
1784 
1785     // This version is much nicer.
1786     @safe pure nothrow @nogc
1787     bool sameDimensions(Point p1, Point p2)
1788     {
1789         alias doMatch = match!(
1790             (Point2D _1, Point2D _2) => true,
1791             (Point3D _1, Point3D _2) => true,
1792             (_1, _2) => false
1793         );
1794 
1795         return doMatch(p1, p2);
1796     }
1797 
1798     Point a = Point2D(1, 2);
1799     Point b = Point2D(3, 4);
1800     Point c = Point3D(5, 6, 7);
1801     Point d = Point3D(8, 9, 0);
1802 
1803     assert( sameDimensions(a, b));
1804     assert( sameDimensions(c, d));
1805     assert(!sameDimensions(a, c));
1806     assert(!sameDimensions(d, b));
1807 }
1808 
1809 /**
1810  * Attempts to call a type-appropriate function with the value held in a
1811  * [SumType], and throws on failure.
1812  *
1813  * Matches are chosen using the same rules as [match], but are not required to
1814  * be exhaustive—in other words, a type (or combination of types) is allowed to
1815  * have no matching handler. If a type without a handler is encountered at
1816  * runtime, a [MatchException] is thrown.
1817  *
1818  * Not available when compiled with `-betterC`.
1819  *
1820  * Returns:
1821  *   The value returned from the handler that matches the currently-held type,
1822  *   if a handler was given for that type.
1823  *
1824  * Throws:
1825  *   [MatchException], if the currently-held type has no matching handler.
1826  *
1827  * See_Also: $(REF tryVisit, std,variant)
1828  */
1829 version (D_Exceptions)
1830 template tryMatch(handlers...)
1831 {
1832     import std.typecons : No;
1833 
1834     /**
1835      * The actual `tryMatch` function.
1836      *
1837      * Params:
1838      *   args = One or more [SumType] objects.
1839      */
1840     auto ref tryMatch(SumTypes...)(auto ref SumTypes args)
1841     if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1842     {
1843         return matchImpl!(No.exhaustive, handlers)(args);
1844     }
1845 }
1846 
1847 /**
1848  * Thrown by [tryMatch] when an unhandled type is encountered.
1849  *
1850  * Not available when compiled with `-betterC`.
1851  */
1852 version (D_Exceptions)
1853 class MatchException : Exception
1854 {
1855     ///
1856     pure @safe @nogc nothrow
1857     this(string msg, string file = __FILE__, size_t line = __LINE__)
1858     {
1859         super(msg, file, line);
1860     }
1861 }
1862 
1863 /**
1864  * True if `handler` is a potential match for `Ts`, otherwise false.
1865  *
1866  * See the documentation for [match] for a full explanation of how matches are
1867  * chosen.
1868  */
1869 template canMatch(alias handler, Ts...)
1870 if (Ts.length > 0)
1871 {
1872     enum canMatch = is(typeof((ref Ts args) => handler(args)));
1873 }
1874 
1875 ///
1876 @safe unittest
1877 {
1878     alias handleInt = (int i) => "got an int";
1879 
1880     assert( canMatch!(handleInt, int));
1881     assert(!canMatch!(handleInt, string));
1882 }
1883 
1884 // Includes all overloads of the given handler
1885 @safe unittest
1886 {
1887     static struct OverloadSet
1888     {
1889         static void fun(int n) {}
1890         static void fun(double d) {}
1891     }
1892 
1893     assert(canMatch!(OverloadSet.fun, int));
1894     assert(canMatch!(OverloadSet.fun, double));
1895 }
1896 
1897 // Like aliasSeqOf!(iota(n)), but works in BetterC
1898 private template Iota(size_t n)
1899 {
1900     static if (n == 0)
1901     {
1902         alias Iota = AliasSeq!();
1903     }
1904     else
1905     {
1906         alias Iota = AliasSeq!(Iota!(n - 1), n - 1);
1907     }
1908 }
1909 
1910 @safe unittest
1911 {
1912     assert(is(Iota!0 == AliasSeq!()));
1913     assert(Iota!1 == AliasSeq!(0));
1914     assert(Iota!3 == AliasSeq!(0, 1, 2));
1915 }
1916 
1917 /* The number that the dim-th argument's tag is multiplied by when
1918  * converting TagTuples to and from case indices ("caseIds").
1919  *
1920  * Named by analogy to the stride that the dim-th index into a
1921  * multidimensional static array is multiplied by to calculate the
1922  * offset of a specific element.
1923  */
1924 private size_t stride(size_t dim, lengths...)()
1925 {
1926     import core.checkedint : mulu;
1927 
1928     size_t result = 1;
1929     bool overflow = false;
1930 
1931     static foreach (i; 0 .. dim)
1932     {
1933         result = mulu(result, lengths[i], overflow);
1934     }
1935 
1936     /* The largest number matchImpl uses, numCases, is calculated with
1937      * stride!(SumTypes.length), so as long as this overflow check
1938      * passes, we don't need to check for overflow anywhere else.
1939      */
1940     assert(!overflow, "Integer overflow");
1941     return result;
1942 }
1943 
1944 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
1945 {
1946     auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
1947     if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1948     {
1949         alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
1950         alias TagTuple = .TagTuple!(SumTypes);
1951 
1952         /*
1953          * A list of arguments to be passed to a handler needed for the case
1954          * labeled with `caseId`.
1955          */
1956         template handlerArgs(size_t caseId)
1957         {
1958             enum tags = TagTuple.fromCaseId(caseId);
1959             enum argsFrom(size_t i : tags.length) = "";
1960             enum argsFrom(size_t i) = "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
1961                 ".Types[" ~ toCtString!(tags[i]) ~ "])(), " ~ argsFrom!(i + 1);
1962             enum handlerArgs = argsFrom!0;
1963         }
1964 
1965         /* An AliasSeq of the types of the member values in the argument list
1966          * returned by `handlerArgs!caseId`.
1967          *
1968          * Note that these are the actual (that is, qualified) types of the
1969          * member values, which may not be the same as the types listed in
1970          * the arguments' `.Types` properties.
1971          */
1972         template valueTypes(size_t caseId)
1973         {
1974             enum tags = TagTuple.fromCaseId(caseId);
1975 
1976             template getType(size_t i)
1977             {
1978                 enum tid = tags[i];
1979                 alias T = SumTypes[i].Types[tid];
1980                 alias getType = typeof(args[i].get!T());
1981             }
1982 
1983             alias valueTypes = Map!(getType, Iota!(tags.length));
1984         }
1985 
1986         /* The total number of cases is
1987          *
1988          *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1989          *
1990          * Or, equivalently,
1991          *
1992          *   ubyte[SumTypes[0].Types.length]...[SumTypes[$-1].Types.length].sizeof
1993          *
1994          * Conveniently, this is equal to stride!(SumTypes.length), so we can
1995          * use that function to compute it.
1996          */
1997         enum numCases = stride!(SumTypes.length);
1998 
1999         /* Guaranteed to never be a valid handler index, since
2000          * handlers.length <= size_t.max.
2001          */
2002         enum noMatch = size_t.max;
2003 
2004         // An array that maps caseIds to handler indices ("hids").
2005         enum matches = ()
2006         {
2007             size_t[numCases] matches;
2008 
2009             // Workaround for https://issues.dlang.org/show_bug.cgi?id=19561
2010             foreach (ref match; matches)
2011             {
2012                 match = noMatch;
2013             }
2014 
2015             static foreach (caseId; 0 .. numCases)
2016             {
2017                 static foreach (hid, handler; handlers)
2018                 {
2019                     static if (canMatch!(handler, valueTypes!caseId))
2020                     {
2021                         if (matches[caseId] == noMatch)
2022                         {
2023                             matches[caseId] = hid;
2024                         }
2025                     }
2026                 }
2027             }
2028 
2029             return matches;
2030         }();
2031 
2032         import std.algorithm.searching : canFind;
2033 
2034         // Check for unreachable handlers
2035         static foreach (hid, handler; handlers)
2036         {
2037             static assert(matches[].canFind(hid),
2038                 "`handlers[" ~ toCtString!hid ~ "]` " ~
2039                 "of type `" ~ ( __traits(isTemplate, handler)
2040                     ? "template"
2041                     : typeof(handler).stringof
2042                 ) ~ "` " ~
2043                 "never matches"
2044             );
2045         }
2046 
2047         // Workaround for https://issues.dlang.org/show_bug.cgi?id=19993
2048         enum handlerName(size_t hid) = "handler" ~ toCtString!hid;
2049 
2050         static foreach (size_t hid, handler; handlers)
2051         {
2052             mixin("alias ", handlerName!hid, " = handler;");
2053         }
2054 
2055         immutable argsId = TagTuple(args).toCaseId;
2056 
2057         final switch (argsId)
2058         {
2059             static foreach (caseId; 0 .. numCases)
2060             {
2061                 case caseId:
2062                     static if (matches[caseId] != noMatch)
2063                     {
2064                         return mixin(handlerName!(matches[caseId]), "(", handlerArgs!caseId, ")");
2065                     }
2066                     else
2067                     {
2068                         static if (exhaustive)
2069                         {
2070                             static assert(false,
2071                                 "No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
2072                         }
2073                         else
2074                         {
2075                             throw new MatchException(
2076                                 "No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
2077                         }
2078                     }
2079             }
2080         }
2081 
2082         assert(false, "unreachable");
2083     }
2084 }
2085 
2086 private enum typeCount(SumType) = SumType.Types.length;
2087 
2088 /* A TagTuple represents a single possible set of tags that `args`
2089  * could have at runtime.
2090  *
2091  * Because D does not allow a struct to be the controlling expression
2092  * of a switch statement, we cannot dispatch on the TagTuple directly.
2093  * Instead, we must map each TagTuple to a unique integer and generate
2094  * a case label for each of those integers.
2095  *
2096  * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
2097  * the same technique that's used to map index tuples to memory offsets
2098  * in a multidimensional static array.
2099  *
2100  * For example, when `args` consists of two SumTypes with two member
2101  * types each, the TagTuples corresponding to each case label are:
2102  *
2103  *   case 0:  TagTuple([0, 0])
2104  *   case 1:  TagTuple([1, 0])
2105  *   case 2:  TagTuple([0, 1])
2106  *   case 3:  TagTuple([1, 1])
2107  *
2108  * When there is only one argument, the caseId is equal to that
2109  * argument's tag.
2110  */
2111 private struct TagTuple(SumTypes...)
2112 {
2113     size_t[SumTypes.length] tags;
2114     alias tags this;
2115 
2116     alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
2117 
2118     invariant
2119     {
2120         static foreach (i; 0 .. tags.length)
2121         {
2122             assert(tags[i] < SumTypes[i].Types.length, "Invalid tag");
2123         }
2124     }
2125 
2126     this(ref const(SumTypes) args)
2127     {
2128         static foreach (i; 0 .. tags.length)
2129         {
2130             tags[i] = args[i].tag;
2131         }
2132     }
2133 
2134     static TagTuple fromCaseId(size_t caseId)
2135     {
2136         TagTuple result;
2137 
2138         // Most-significant to least-significant
2139         static foreach_reverse (i; 0 .. result.length)
2140         {
2141             result[i] = caseId / stride!i;
2142             caseId %= stride!i;
2143         }
2144 
2145         return result;
2146     }
2147 
2148     size_t toCaseId()
2149     {
2150         size_t result;
2151 
2152         static foreach (i; 0 .. tags.length)
2153         {
2154             result += tags[i] * stride!i;
2155         }
2156 
2157         return result;
2158     }
2159 }
2160 
2161 // Matching
2162 @safe unittest
2163 {
2164     alias MySum = SumType!(int, float);
2165 
2166     MySum x = MySum(42);
2167     MySum y = MySum(3.14);
2168 
2169     assert(x.match!((int v) => true, (float v) => false));
2170     assert(y.match!((int v) => false, (float v) => true));
2171 }
2172 
2173 // Missing handlers
2174 @safe unittest
2175 {
2176     alias MySum = SumType!(int, float);
2177 
2178     MySum x = MySum(42);
2179 
2180     assert(!__traits(compiles, x.match!((int x) => true)));
2181     assert(!__traits(compiles, x.match!()));
2182 }
2183 
2184 // Handlers with qualified parameters
2185 // Disabled in BetterC due to use of dynamic arrays
2186 version (D_BetterC) {} else
2187 @safe unittest
2188 {
2189     alias MySum = SumType!(int[], float[]);
2190 
2191     MySum x = MySum([1, 2, 3]);
2192     MySum y = MySum([1.0, 2.0, 3.0]);
2193 
2194     assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2195     assert(y.match!((const(int[]) v) => false, (const(float[]) v) => true));
2196 }
2197 
2198 // Handlers for qualified types
2199 // Disabled in BetterC due to use of dynamic arrays
2200 version (D_BetterC) {} else
2201 @safe unittest
2202 {
2203     alias MySum = SumType!(immutable(int[]), immutable(float[]));
2204 
2205     MySum x = MySum([1, 2, 3]);
2206 
2207     assert(x.match!((immutable(int[]) v) => true, (immutable(float[]) v) => false));
2208     assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2209     // Tail-qualified parameters
2210     assert(x.match!((immutable(int)[] v) => true, (immutable(float)[] v) => false));
2211     assert(x.match!((const(int)[] v) => true, (const(float)[] v) => false));
2212     // Generic parameters
2213     assert(x.match!((immutable v) => true));
2214     assert(x.match!((const v) => true));
2215     // Unqualified parameters
2216     assert(!__traits(compiles,
2217         x.match!((int[] v) => true, (float[] v) => false)
2218     ));
2219 }
2220 
2221 // Delegate handlers
2222 // Disabled in BetterC due to use of closures
2223 version (D_BetterC) {} else
2224 @safe unittest
2225 {
2226     alias MySum = SumType!(int, float);
2227 
2228     int answer = 42;
2229     MySum x = MySum(42);
2230     MySum y = MySum(3.14);
2231 
2232     assert(x.match!((int v) => v == answer, (float v) => v == answer));
2233     assert(!y.match!((int v) => v == answer, (float v) => v == answer));
2234 }
2235 
2236 version (unittest)
2237 {
2238     version (D_BetterC)
2239     {
2240         // std.math.isClose depends on core.runtime.math, so use a
2241         // libc-based version for testing with -betterC
2242         @safe pure @nogc nothrow
2243         private bool isClose(double lhs, double rhs)
2244         {
2245             import core.stdc.math : fabs;
2246 
2247             return fabs(lhs - rhs) < 1e-5;
2248         }
2249     }
2250     else
2251     {
2252         import std.math.operations : isClose;
2253     }
2254 }
2255 
2256 // Generic handler
2257 @safe unittest
2258 {
2259     alias MySum = SumType!(int, float);
2260 
2261     MySum x = MySum(42);
2262     MySum y = MySum(3.14);
2263 
2264     assert(x.match!(v => v*2) == 84);
2265     assert(y.match!(v => v*2).isClose(6.28));
2266 }
2267 
2268 // Fallback to generic handler
2269 // Disabled in BetterC due to use of std.conv.to
2270 version (D_BetterC) {} else
2271 @safe unittest
2272 {
2273     import std.conv : to;
2274 
2275     alias MySum = SumType!(int, float, string);
2276 
2277     MySum x = MySum(42);
2278     MySum y = MySum("42");
2279 
2280     assert(x.match!((string v) => v.to!int, v => v*2) == 84);
2281     assert(y.match!((string v) => v.to!int, v => v*2) == 42);
2282 }
2283 
2284 // Multiple non-overlapping generic handlers
2285 @safe unittest
2286 {
2287     import std.array : staticArray;
2288 
2289     alias MySum = SumType!(int, float, int[], char[]);
2290 
2291     static ints = staticArray([1, 2, 3]);
2292     static chars = staticArray(['a', 'b', 'c']);
2293 
2294     MySum x = MySum(42);
2295     MySum y = MySum(3.14);
2296     MySum z = MySum(ints[]);
2297     MySum w = MySum(chars[]);
2298 
2299     assert(x.match!(v => v*2, v => v.length) == 84);
2300     assert(y.match!(v => v*2, v => v.length).isClose(6.28));
2301     assert(w.match!(v => v*2, v => v.length) == 3);
2302     assert(z.match!(v => v*2, v => v.length) == 3);
2303 }
2304 
2305 // Structural matching
2306 @safe unittest
2307 {
2308     static struct S1 { int x; }
2309     static struct S2 { int y; }
2310     alias MySum = SumType!(S1, S2);
2311 
2312     MySum a = MySum(S1(0));
2313     MySum b = MySum(S2(0));
2314 
2315     assert(a.match!(s1 => s1.x + 1, s2 => s2.y - 1) == 1);
2316     assert(b.match!(s1 => s1.x + 1, s2 => s2.y - 1) == -1);
2317 }
2318 
2319 // Separate opCall handlers
2320 @safe unittest
2321 {
2322     static struct IntHandler
2323     {
2324         bool opCall(int arg)
2325         {
2326             return true;
2327         }
2328     }
2329 
2330     static struct FloatHandler
2331     {
2332         bool opCall(float arg)
2333         {
2334             return false;
2335         }
2336     }
2337 
2338     alias MySum = SumType!(int, float);
2339 
2340     MySum x = MySum(42);
2341     MySum y = MySum(3.14);
2342 
2343     assert(x.match!(IntHandler.init, FloatHandler.init));
2344     assert(!y.match!(IntHandler.init, FloatHandler.init));
2345 }
2346 
2347 // Compound opCall handler
2348 @safe unittest
2349 {
2350     static struct CompoundHandler
2351     {
2352         bool opCall(int arg)
2353         {
2354             return true;
2355         }
2356 
2357         bool opCall(float arg)
2358         {
2359             return false;
2360         }
2361     }
2362 
2363     alias MySum = SumType!(int, float);
2364 
2365     MySum x = MySum(42);
2366     MySum y = MySum(3.14);
2367 
2368     assert(x.match!(CompoundHandler.init));
2369     assert(!y.match!(CompoundHandler.init));
2370 }
2371 
2372 // Ordered matching
2373 @safe unittest
2374 {
2375     alias MySum = SumType!(int, float);
2376 
2377     MySum x = MySum(42);
2378 
2379     assert(x.match!((int v) => true, v => false));
2380 }
2381 
2382 // Non-exhaustive matching
2383 version (D_Exceptions)
2384 @system unittest
2385 {
2386     import std.exception : assertThrown, assertNotThrown;
2387 
2388     alias MySum = SumType!(int, float);
2389 
2390     MySum x = MySum(42);
2391     MySum y = MySum(3.14);
2392 
2393     assertNotThrown!MatchException(x.tryMatch!((int n) => true));
2394     assertThrown!MatchException(y.tryMatch!((int n) => true));
2395 }
2396 
2397 // Non-exhaustive matching in @safe code
2398 version (D_Exceptions)
2399 @safe unittest
2400 {
2401     SumType!(int, float) x;
2402 
2403     auto _ = x.tryMatch!(
2404         (int n) => n + 1,
2405     );
2406 }
2407 
2408 // Handlers with ref parameters
2409 @safe unittest
2410 {
2411     alias Value = SumType!(long, double);
2412 
2413     auto value = Value(3.14);
2414 
2415     value.match!(
2416         (long) {},
2417         (ref double d) { d *= 2; }
2418     );
2419 
2420     assert(value.get!double.isClose(6.28));
2421 }
2422 
2423 // Unreachable handlers
2424 @safe unittest
2425 {
2426     alias MySum = SumType!(int, string);
2427 
2428     MySum s;
2429 
2430     assert(!__traits(compiles,
2431         s.match!(
2432             (int _) => 0,
2433             (string _) => 1,
2434             (double _) => 2
2435         )
2436     ));
2437 
2438     assert(!__traits(compiles,
2439         s.match!(
2440             _ => 0,
2441             (int _) => 1
2442         )
2443     ));
2444 }
2445 
2446 // Unsafe handlers
2447 @system unittest
2448 {
2449     SumType!int x;
2450     alias unsafeHandler = (int x) @system { return; };
2451 
2452     assert(!__traits(compiles, () @safe
2453             {
2454         x.match!unsafeHandler;
2455     }));
2456 
2457     auto test() @system
2458     {
2459         return x.match!unsafeHandler;
2460     }
2461 }
2462 
2463 // Overloaded handlers
2464 @safe unittest
2465 {
2466     static struct OverloadSet
2467     {
2468         static string fun(int i) { return "int"; }
2469         static string fun(double d) { return "double"; }
2470     }
2471 
2472     alias MySum = SumType!(int, double);
2473 
2474     MySum a = 42;
2475     MySum b = 3.14;
2476 
2477     assert(a.match!(OverloadSet.fun) == "int");
2478     assert(b.match!(OverloadSet.fun) == "double");
2479 }
2480 
2481 // Overload sets that include SumType arguments
2482 @safe unittest
2483 {
2484     alias Inner = SumType!(int, double);
2485     alias Outer = SumType!(Inner, string);
2486 
2487     static struct OverloadSet
2488     {
2489         @safe:
2490         static string fun(int i) { return "int"; }
2491         static string fun(double d) { return "double"; }
2492         static string fun(string s) { return "string"; }
2493         static string fun(Inner i) { return i.match!fun; }
2494         static string fun(Outer o) { return o.match!fun; }
2495     }
2496 
2497     Outer a = Inner(42);
2498     Outer b = Inner(3.14);
2499     Outer c = "foo";
2500 
2501     assert(OverloadSet.fun(a) == "int");
2502     assert(OverloadSet.fun(b) == "double");
2503     assert(OverloadSet.fun(c) == "string");
2504 }
2505 
2506 // Overload sets with ref arguments
2507 @safe unittest
2508 {
2509     static struct OverloadSet
2510     {
2511         static void fun(ref int i) { i = 42; }
2512         static void fun(ref double d) { d = 3.14; }
2513     }
2514 
2515     alias MySum = SumType!(int, double);
2516 
2517     MySum x = 0;
2518     MySum y = 0.0;
2519 
2520     x.match!(OverloadSet.fun);
2521     y.match!(OverloadSet.fun);
2522 
2523     assert(x.match!((value) => is(typeof(value) == int) && value == 42));
2524     assert(y.match!((value) => is(typeof(value) == double) && value == 3.14));
2525 }
2526 
2527 // Overload sets with templates
2528 @safe unittest
2529 {
2530     import std.traits : isNumeric;
2531 
2532     static struct OverloadSet
2533     {
2534         static string fun(string arg)
2535         {
2536             return "string";
2537         }
2538 
2539         static string fun(T)(T arg)
2540         if (isNumeric!T)
2541         {
2542             return "numeric";
2543         }
2544     }
2545 
2546     alias MySum = SumType!(int, string);
2547 
2548     MySum x = 123;
2549     MySum y = "hello";
2550 
2551     assert(x.match!(OverloadSet.fun) == "numeric");
2552     assert(y.match!(OverloadSet.fun) == "string");
2553 }
2554 
2555 // Github issue #24
2556 @safe unittest
2557 {
2558     void test() @nogc
2559     {
2560         int acc = 0;
2561         SumType!int(1).match!((int x) => acc += x);
2562     }
2563 }
2564 
2565 // Github issue #31
2566 @safe unittest
2567 {
2568     void test() @nogc
2569     {
2570         int acc = 0;
2571 
2572         SumType!(int, string)(1).match!(
2573             (int x) => acc += x,
2574             (string _) => 0,
2575         );
2576     }
2577 }
2578 
2579 // Types that `alias this` a SumType
2580 @safe unittest
2581 {
2582     static struct A {}
2583     static struct B {}
2584     static struct D { SumType!(A, B) value; alias value this; }
2585 
2586     auto _ = D().match!(_ => true);
2587 }
2588 
2589 // Multiple dispatch
2590 @safe unittest
2591 {
2592     alias MySum = SumType!(int, string);
2593 
2594     static int fun(MySum x, MySum y)
2595     {
2596         import std.meta : Args = AliasSeq;
2597 
2598         return Args!(x, y).match!(
2599             (int    xv, int    yv) => 0,
2600             (string xv, int    yv) => 1,
2601             (int    xv, string yv) => 2,
2602             (string xv, string yv) => 3
2603         );
2604     }
2605 
2606     assert(fun(MySum(0),  MySum(0))  == 0);
2607     assert(fun(MySum(""), MySum(0))  == 1);
2608     assert(fun(MySum(0),  MySum("")) == 2);
2609     assert(fun(MySum(""), MySum("")) == 3);
2610 }
2611 
2612 // inout SumTypes
2613 @safe unittest
2614 {
2615     inout(int[]) fun(inout(SumType!(int[])) x)
2616     {
2617         return x.match!((inout(int[]) a) => a);
2618     }
2619 }
2620 
2621 private void destroyIfOwner(T)(ref T value)
2622 {
2623     static if (hasElaborateDestructor!T)
2624     {
2625         destroy(value);
2626     }
2627 }