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