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 /* The number that the dim-th argument's tag is multiplied by when
1776  * converting TagTuples to and from case indices ("caseIds").
1777  *
1778  * Named by analogy to the stride that the dim-th index into a
1779  * multidimensional static array is multiplied by to calculate the
1780  * offset of a specific element.
1781  */
1782 private size_t stride(size_t dim, lengths...)()
1783 {
1784 	import core.checkedint: mulu;
1785 
1786 	size_t result = 1;
1787 	bool overflow = false;
1788 
1789 	static foreach (i; 0 .. dim) {
1790 		result = mulu(result, lengths[i], overflow);
1791 	}
1792 
1793 	/* The largest number matchImpl uses, numCases, is calculated with
1794 	 * stride!(SumTypes.length), so as long as this overflow check
1795 	 * passes, we don't need to check for overflow anywhere else.
1796 	 */
1797 	assert(!overflow, "Integer overflow");
1798 	return result;
1799 }
1800 
1801 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
1802 {
1803 	auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
1804 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1805 	{
1806 		alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
1807 
1808 		alias TagTuple = .TagTuple!SumTypes;
1809 
1810 		/*
1811 		 * A list of arguments to be passed to a handler needed for the case
1812 		 * labeled with `caseId`.
1813 		 */
1814 		template handlerArgs(size_t caseId)
1815 		{
1816 			enum tags = TagTuple.fromCaseId(caseId);
1817 			enum argsFrom(size_t i: tags.length) = "";
1818 			enum argsFrom(size_t i) = "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
1819 				".Types[" ~ toCtString!(tags[i]) ~ "])(), " ~ argsFrom!(i + 1);
1820 			enum handlerArgs = argsFrom!0;
1821 		}
1822 
1823 		/* An AliasSeq of the types of the member values in the argument list
1824 		 * returned by `handlerArgs!caseId`.
1825 		 *
1826 		 * Note that these are the actual (that is, qualified) types of the
1827 		 * member values, which may not be the same as the types listed in
1828 		 * the arguments' `.Types` properties.
1829 		 */
1830 		template valueTypes(size_t caseId)
1831 		{
1832 			enum tags = TagTuple.fromCaseId(caseId);
1833 
1834 			template getType(size_t i)
1835 			{
1836 				enum tid = tags[i];
1837 				alias T = SumTypes[i].Types[tid];
1838 				alias getType = typeof(args[i].get!T());
1839 			}
1840 
1841 			alias valueTypes = Map!(getType, Iota!(tags.length));
1842 		}
1843 
1844 		/* The total number of cases is
1845 		 *
1846 		 *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1847 		 *
1848 		 * Conveniently, this is equal to stride!(SumTypes.length), so we can
1849 		 * use that function to compute it.
1850 		 */
1851 		enum numCases = stride!(SumTypes.length);
1852 
1853 		/* Guaranteed to never be a valid handler index, since
1854 		 * handlers.length <= size_t.max.
1855 		 */
1856 		enum noMatch = size_t.max;
1857 
1858 		// An array that maps caseIds to handler indices ("hids").
1859 		enum matches = () {
1860 			size_t[numCases] matches;
1861 
1862 			// Workaround for dlang issue 19561
1863 			foreach (ref match; matches) {
1864 				match = noMatch;
1865 			}
1866 
1867 			static foreach (caseId; 0 .. numCases) {
1868 				static foreach (hid, handler; handlers) {
1869 					static if (canMatch!(handler, valueTypes!caseId)) {
1870 						if (matches[caseId] == noMatch) {
1871 							matches[caseId] = hid;
1872 						}
1873 					}
1874 				}
1875 			}
1876 
1877 			return matches;
1878 		}();
1879 
1880 		import std.algorithm.searching: canFind;
1881 
1882 		// Check for unreachable handlers
1883 		static foreach (hid, handler; handlers) {
1884 			static assert(matches[].canFind(hid),
1885 				"`handlers[" ~ toCtString!hid ~ "]` " ~
1886 				"of type `" ~ ( __traits(isTemplate, handler)
1887 					? "template"
1888 					: typeof(handler).stringof
1889 				) ~ "` " ~
1890 				"never matches. Perhaps the handler failed to compile"
1891 			);
1892 		}
1893 
1894 		// Workaround for dlang issue 19993
1895 		enum handlerName(size_t hid) = "handler" ~ toCtString!hid;
1896 
1897 		static foreach (size_t hid, handler; handlers) {
1898 			mixin("alias ", handlerName!hid, " = handler;");
1899 		}
1900 
1901 		immutable argsId = TagTuple(args).toCaseId;
1902 
1903 		final switch (argsId) {
1904 			static foreach (caseId; 0 .. numCases) {
1905 				case caseId:
1906 					static if (matches[caseId] != noMatch) {
1907 						return mixin(handlerName!(matches[caseId]), "(", handlerArgs!caseId, ")");
1908 					} else {
1909 						static if(exhaustive) {
1910 							static assert(false,
1911 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1912 						} else {
1913 							throw new MatchException(
1914 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1915 						}
1916 					}
1917 			}
1918 		}
1919 
1920 		assert(false, "unreachable");
1921 	}
1922 }
1923 
1924 private enum typeCount(SumType) = SumType.Types.length;
1925 
1926 /* A TagTuple represents a single possible set of tags that `args`
1927  * could have at runtime.
1928  *
1929  * Because D does not allow a struct to be the controlling expression
1930  * of a switch statement, we cannot dispatch on the TagTuple directly.
1931  * Instead, we must map each TagTuple to a unique integer and generate
1932  * a case label for each of those integers.
1933  *
1934  * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
1935  * the same technique that's used to map index tuples to memory offsets
1936  * in a multidimensional static array.
1937  *
1938  * For example, when `args` consists of two SumTypes with two member
1939  * types each, the TagTuples corresponding to each case label are:
1940  *
1941  *   case 0:  TagTuple([0, 0])
1942  *   case 1:  TagTuple([1, 0])
1943  *   case 2:  TagTuple([0, 1])
1944  *   case 3:  TagTuple([1, 1])
1945  *
1946  * When there is only one argument, the caseId is equal to that
1947  * argument's tag.
1948  */
1949 static struct TagTuple(SumTypes...)
1950 {
1951 	size_t[SumTypes.length] tags;
1952 	alias tags this;
1953 
1954 	alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
1955 
1956 	invariant {
1957 		static foreach (i; 0 .. tags.length) {
1958 			assert(tags[i] < SumTypes[i].Types.length);
1959 		}
1960 	}
1961 
1962 	this(ref const(SumTypes) args)
1963 	{
1964 		static foreach (i; 0 .. tags.length) {
1965 			tags[i] = args[i].tag;
1966 		}
1967 	}
1968 
1969 	static TagTuple fromCaseId(size_t caseId)
1970 	{
1971 		TagTuple result;
1972 
1973 		// Most-significant to least-significant
1974 		static foreach_reverse (i; 0 .. result.length) {
1975 			result[i] = caseId / stride!i;
1976 			caseId %= stride!i;
1977 		}
1978 
1979 		return result;
1980 	}
1981 
1982 	size_t toCaseId()
1983 	{
1984 		size_t result;
1985 
1986 		static foreach (i; 0 .. tags.length) {
1987 			result += tags[i] * stride!i;
1988 		}
1989 
1990 		return result;
1991 	}
1992 }
1993 
1994 // Matching
1995 @safe unittest {
1996 	alias MySum = SumType!(int, float);
1997 
1998 	MySum x = MySum(42);
1999 	MySum y = MySum(3.14);
2000 
2001 	assert(x.match!((int v) => true, (float v) => false));
2002 	assert(y.match!((int v) => false, (float v) => true));
2003 }
2004 
2005 // Missing handlers
2006 @safe unittest {
2007 	alias MySum = SumType!(int, float);
2008 
2009 	MySum x = MySum(42);
2010 
2011 	assert(!__traits(compiles, x.match!((int x) => true)));
2012 	assert(!__traits(compiles, x.match!()));
2013 }
2014 
2015 // Handlers with qualified parameters
2016 // Disabled in BetterC due to use of dynamic arrays
2017 version (D_BetterC) {} else
2018 @safe unittest {
2019 	alias MySum = SumType!(int[], float[]);
2020 
2021 	MySum x = MySum([1, 2, 3]);
2022 	MySum y = MySum([1.0, 2.0, 3.0]);
2023 
2024 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2025 	assert(y.match!((const(int[]) v) => false, (const(float[]) v) => true));
2026 }
2027 
2028 // Handlers for qualified types
2029 // Disabled in BetterC due to use of dynamic arrays
2030 version (D_BetterC) {} else
2031 @safe unittest {
2032 	alias MySum = SumType!(immutable(int[]), immutable(float[]));
2033 
2034 	MySum x = MySum([1, 2, 3]);
2035 
2036 	assert(x.match!((immutable(int[]) v) => true, (immutable(float[]) v) => false));
2037 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2038 	// Tail-qualified parameters
2039 	assert(x.match!((immutable(int)[] v) => true, (immutable(float)[] v) => false));
2040 	assert(x.match!((const(int)[] v) => true, (const(float)[] v) => false));
2041 	// Generic parameters
2042 	assert(x.match!((immutable v) => true));
2043 	assert(x.match!((const v) => true));
2044 	// Unqualified parameters
2045 	assert(!__traits(compiles,
2046 		x.match!((int[] v) => true, (float[] v) => false)
2047 	));
2048 }
2049 
2050 // Delegate handlers
2051 // Disabled in BetterC due to use of closures
2052 version (D_BetterC) {} else
2053 @safe unittest {
2054 	alias MySum = SumType!(int, float);
2055 
2056 	int answer = 42;
2057 	MySum x = MySum(42);
2058 	MySum y = MySum(3.14);
2059 
2060 	assert(x.match!((int v) => v == answer, (float v) => v == answer));
2061 	assert(!y.match!((int v) => v == answer, (float v) => v == answer));
2062 }
2063 
2064 version (unittest) {
2065 	version (D_BetterC) {
2066 		// std.math.isClose depends on core.runtime.math, so use a
2067 		// libc-based version for testing with -betterC
2068 		@safe pure @nogc nothrow
2069 		private bool isClose(double lhs, double rhs)
2070 		{
2071 			import core.stdc.math: fabs;
2072 
2073 			return fabs(lhs - rhs) < 1e-5;
2074 		}
2075 	} else {
2076 		import std.math: isClose;
2077 	}
2078 }
2079 
2080 // Generic handler
2081 @safe unittest {
2082 	alias MySum = SumType!(int, float);
2083 
2084 	MySum x = MySum(42);
2085 	MySum y = MySum(3.14);
2086 
2087 	assert(x.match!(v => v*2) == 84);
2088 	assert(y.match!(v => v*2).isClose(6.28));
2089 }
2090 
2091 // Fallback to generic handler
2092 // Disabled in BetterC due to use of std.conv.to
2093 version (D_BetterC) {} else
2094 @safe unittest {
2095 	import std.conv: to;
2096 
2097 	alias MySum = SumType!(int, float, string);
2098 
2099 	MySum x = MySum(42);
2100 	MySum y = MySum("42");
2101 
2102 	assert(x.match!((string v) => v.to!int, v => v*2) == 84);
2103 	assert(y.match!((string v) => v.to!int, v => v*2) == 42);
2104 }
2105 
2106 // Multiple non-overlapping generic handlers
2107 @safe unittest {
2108 	import std.array: staticArray;
2109 
2110 	alias MySum = SumType!(int, float, int[], char[]);
2111 
2112 	static ints = staticArray([1, 2, 3]);
2113 	static chars = staticArray(['a', 'b', 'c']);
2114 
2115 	MySum x = MySum(42);
2116 	MySum y = MySum(3.14);
2117 	MySum z = MySum(ints[]);
2118 	MySum w = MySum(chars[]);
2119 
2120 	assert(x.match!(v => v*2, v => v.length) == 84);
2121 	assert(y.match!(v => v*2, v => v.length).isClose(6.28));
2122 	assert(w.match!(v => v*2, v => v.length) == 3);
2123 	assert(z.match!(v => v*2, v => v.length) == 3);
2124 }
2125 
2126 // Structural matching
2127 @safe unittest {
2128 	static struct S1 { int x; }
2129 	static struct S2 { int y; }
2130 	alias MySum = SumType!(S1, S2);
2131 
2132 	MySum a = MySum(S1(0));
2133 	MySum b = MySum(S2(0));
2134 
2135 	assert(a.match!(s1 => s1.x + 1, s2 => s2.y - 1) == 1);
2136 	assert(b.match!(s1 => s1.x + 1, s2 => s2.y - 1) == -1);
2137 }
2138 
2139 // Separate opCall handlers
2140 @safe unittest {
2141 	static struct IntHandler
2142 	{
2143 		bool opCall(int arg)
2144 		{
2145 			return true;
2146 		}
2147 	}
2148 
2149 	static struct FloatHandler
2150 	{
2151 		bool opCall(float arg)
2152 		{
2153 			return false;
2154 		}
2155 	}
2156 
2157 	alias MySum = SumType!(int, float);
2158 
2159 	MySum x = MySum(42);
2160 	MySum y = MySum(3.14);
2161 
2162 	assert(x.match!(IntHandler.init, FloatHandler.init));
2163 	assert(!y.match!(IntHandler.init, FloatHandler.init));
2164 }
2165 
2166 // Compound opCall handler
2167 @safe unittest {
2168 	static struct CompoundHandler
2169 	{
2170 		bool opCall(int arg)
2171 		{
2172 			return true;
2173 		}
2174 
2175 		bool opCall(float arg)
2176 		{
2177 			return false;
2178 		}
2179 	}
2180 
2181 	alias MySum = SumType!(int, float);
2182 
2183 	MySum x = MySum(42);
2184 	MySum y = MySum(3.14);
2185 
2186 	assert(x.match!(CompoundHandler.init));
2187 	assert(!y.match!(CompoundHandler.init));
2188 }
2189 
2190 // Ordered matching
2191 @safe unittest {
2192 	alias MySum = SumType!(int, float);
2193 
2194 	MySum x = MySum(42);
2195 
2196 	assert(x.match!((int v) => true, v => false));
2197 }
2198 
2199 // Non-exhaustive matching
2200 version (D_Exceptions)
2201 @system unittest {
2202 	import std.exception: assertThrown, assertNotThrown;
2203 
2204 	alias MySum = SumType!(int, float);
2205 
2206 	MySum x = MySum(42);
2207 	MySum y = MySum(3.14);
2208 
2209 	assertNotThrown!MatchException(x.tryMatch!((int n) => true));
2210 	assertThrown!MatchException(y.tryMatch!((int n) => true));
2211 }
2212 
2213 // Non-exhaustive matching in @safe code
2214 version (D_Exceptions)
2215 @safe unittest {
2216 	SumType!(int, float) x;
2217 
2218 	assert(__traits(compiles,
2219 		x.tryMatch!(
2220 			(int n) => n + 1,
2221 		)
2222 	));
2223 
2224 }
2225 
2226 // Handlers with ref parameters
2227 @safe unittest {
2228 	alias Value = SumType!(long, double);
2229 
2230 	auto value = Value(3.14);
2231 
2232 	value.match!(
2233 		(long) {},
2234 		(ref double d) { d *= 2; }
2235 	);
2236 
2237 	assert(value.get!double.isClose(6.28));
2238 }
2239 
2240 // Handlers that return by ref
2241 @safe unittest {
2242 	SumType!int x = 123;
2243 
2244 	x.match!(ref (ref int n) => n) = 456;
2245 
2246 	assert(x.match!((int n) => n == 456));
2247 }
2248 
2249 // Unreachable handlers
2250 @safe unittest {
2251 	alias MySum = SumType!(int, string);
2252 
2253 	MySum s;
2254 
2255 	assert(!__traits(compiles,
2256 		s.match!(
2257 			(int _) => 0,
2258 			(string _) => 1,
2259 			(double _) => 2
2260 		)
2261 	));
2262 
2263 	assert(!__traits(compiles,
2264 		s.match!(
2265 			_ => 0,
2266 			(int _) => 1
2267 		)
2268 	));
2269 }
2270 
2271 // Unsafe handlers
2272 @system unittest {
2273 	SumType!int x;
2274 	alias unsafeHandler = (int x) @system { return; };
2275 
2276 	assert(!__traits(compiles, () @safe {
2277 		x.match!unsafeHandler;
2278 	}));
2279 
2280 	assert(__traits(compiles, () @system {
2281 		return x.match!unsafeHandler;
2282 	}));
2283 }
2284 
2285 // Overloaded handlers
2286 @safe unittest {
2287 	static struct OverloadSet
2288 	{
2289 		static string fun(int i) { return "int"; }
2290 		static string fun(double d) { return "double"; }
2291 	}
2292 
2293 	alias MySum = SumType!(int, double);
2294 
2295 	MySum a = 42;
2296 	MySum b = 3.14;
2297 
2298 	assert(a.match!(OverloadSet.fun) == "int");
2299 	assert(b.match!(OverloadSet.fun) == "double");
2300 }
2301 
2302 // Overload sets that include SumType arguments
2303 @safe unittest {
2304 	alias Inner = SumType!(int, double);
2305 	alias Outer = SumType!(Inner, string);
2306 
2307 	static struct OverloadSet
2308 	{
2309 		@safe:
2310 		static string fun(int i) { return "int"; }
2311 		static string fun(double d) { return "double"; }
2312 		static string fun(string s) { return "string"; }
2313 		static string fun(Inner i) { return i.match!fun; }
2314 		static string fun(Outer o) { return o.match!fun; }
2315 	}
2316 
2317 	Outer a = Inner(42);
2318 	Outer b = Inner(3.14);
2319 	Outer c = "foo";
2320 
2321 	assert(OverloadSet.fun(a) == "int");
2322 	assert(OverloadSet.fun(b) == "double");
2323 	assert(OverloadSet.fun(c) == "string");
2324 }
2325 
2326 // Overload sets with ref arguments
2327 @safe unittest {
2328 	static struct OverloadSet
2329 	{
2330 		static void fun(ref int i) { i = 42; }
2331 		static void fun(ref double d) { d = 3.14; }
2332 	}
2333 
2334 	alias MySum = SumType!(int, double);
2335 
2336 	MySum x = 0;
2337 	MySum y = 0.0;
2338 
2339 	x.match!(OverloadSet.fun);
2340 	y.match!(OverloadSet.fun);
2341 
2342 	assert(x.match!((value) => is(typeof(value) == int) && value == 42));
2343 	assert(y.match!((value) => is(typeof(value) == double) && value == 3.14));
2344 }
2345 
2346 // Overload sets with templates
2347 @safe unittest {
2348 	import std.traits: isNumeric;
2349 
2350 	static struct OverloadSet
2351 	{
2352 		static string fun(string arg)
2353 		{
2354 			return "string";
2355 		}
2356 
2357 		static string fun(T)(T arg)
2358 			if (isNumeric!T)
2359 		{
2360 			return "numeric";
2361 		}
2362 	}
2363 
2364 	alias MySum = SumType!(int, string);
2365 
2366 	MySum x = 123;
2367 	MySum y = "hello";
2368 
2369 	assert(x.match!(OverloadSet.fun) == "numeric");
2370 	assert(y.match!(OverloadSet.fun) == "string");
2371 }
2372 
2373 // Github issue #24
2374 @safe unittest {
2375 	assert(__traits(compiles, () @nogc {
2376 		int acc = 0;
2377 		SumType!int(1).match!((int x) => acc += x);
2378 	}));
2379 }
2380 
2381 // Github issue #31
2382 @safe unittest {
2383 	assert(__traits(compiles, () @nogc {
2384 		int acc = 0;
2385 
2386 		SumType!(int, string)(1).match!(
2387 			(int x) => acc += x,
2388 			(string _) => 0,
2389 		);
2390 	}));
2391 }
2392 
2393 // Types that `alias this` a SumType
2394 @safe unittest {
2395 	static struct A {}
2396 	static struct B {}
2397 	static struct D { SumType!(A, B) value; alias value this; }
2398 
2399 	assert(__traits(compiles, D().match!(_ => true)));
2400 }
2401 
2402 // Multiple dispatch
2403 @safe unittest {
2404 	alias MySum = SumType!(int, string);
2405 
2406 	static int fun(MySum x, MySum y)
2407 	{
2408 		import std.meta: Args = AliasSeq;
2409 
2410 		return Args!(x, y).match!(
2411 			(int    xv, int    yv) => 0,
2412 			(string xv, int    yv) => 1,
2413 			(int    xv, string yv) => 2,
2414 			(string xv, string yv) => 3
2415 		);
2416 	}
2417 
2418 	assert(fun(MySum(0),  MySum(0))  == 0);
2419 	assert(fun(MySum(""), MySum(0))  == 1);
2420 	assert(fun(MySum(0),  MySum("")) == 2);
2421 	assert(fun(MySum(""), MySum("")) == 3);
2422 }
2423 
2424 // inout SumTypes
2425 @safe unittest {
2426 	assert(__traits(compiles, {
2427 		inout(int[]) fun(inout(SumType!(int[])) x)
2428 		{
2429 			return x.match!((inout(int[]) a) => a);
2430 		}
2431 	}));
2432 }
2433 
2434 // return ref
2435 // issue: https://issues.dlang.org/show_bug.cgi?id=23101
2436 // Only test on compiler versions >= 2.100, to avoid compiler bugs
2437 static if (haveDip1000 && __VERSION__ >= 2100)
2438 @safe unittest {
2439 	assert(!__traits(compiles, () {
2440 		SumType!(int, string) st;
2441 		return st.match!(
2442 			function int* (string x) => null,
2443 			function int* (return ref int i) => &i,
2444 		);
2445 	}));
2446 
2447 	SumType!(int, string) st;
2448 	assert(__traits(compiles, () {
2449 		return st.match!(
2450 			function int* (string x) => null,
2451 			function int* (return ref int i) => &i,
2452 		);
2453 	}));
2454 }
2455 
2456 private void destroyIfOwner(T)(ref T value)
2457 {
2458 	static if (hasElaborateDestructor!T) {
2459 		destroy(value);
2460 	}
2461 }
2462 
2463 static if (__traits(compiles, { import std.traits: DeducedParameterType; })) {
2464 	import std.traits: DeducedParameterType;
2465 } else {
2466 	/**
2467 	 * The parameter type deduced by IFTI when an expression of type T is passed as
2468 	 * an argument to a template function.
2469 	 *
2470 	 * For all types other than pointer and slice types, `DeducedParameterType!T`
2471 	 * is the same as `T`. For pointer and slice types, it is `T` with the
2472 	 * outer-most layer of qualifiers dropped.
2473 	 */
2474 	private template DeducedParameterType(T)
2475 	{
2476 		import std.traits: Unqual;
2477 
2478 		static if (is(T == U*, U) || is(T == U[], U))
2479 			alias DeducedParameterType = Unqual!T;
2480 		else
2481 			alias DeducedParameterType = T;
2482 	}
2483 
2484 	@safe unittest
2485 	{
2486 		static assert(is(DeducedParameterType!(const(int)) == const(int)));
2487 		static assert(is(DeducedParameterType!(const(int[2])) == const(int[2])));
2488 
2489 		static assert(is(DeducedParameterType!(const(int*)) == const(int)*));
2490 		static assert(is(DeducedParameterType!(const(int[])) == const(int)[]));
2491 	}
2492 
2493 	@safe unittest
2494 	{
2495 		static struct NoCopy
2496 		{
2497 			@disable this(this);
2498 		}
2499 
2500 		static assert(is(DeducedParameterType!NoCopy == NoCopy));
2501 	}
2502 
2503 	@safe unittest
2504 	{
2505 		static assert(is(DeducedParameterType!(inout(int[])) == inout(int)[]));
2506 	}
2507 }