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 /// $(H3 Basic usage)
22 version (D_BetterC) {} else
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 /** $(H3 Introspection-based matching)
81  *
82  * In the `length` and `horiz` functions below, the handlers for `match` do not
83  * specify the types of their arguments. Instead, matching is done based on how
84  * the argument is used in the body of the handler: any type with `x` and `y`
85  * properties will be matched by the `rect` handlers, and any type with `r` and
86  * `theta` properties will be matched by the `polar` handlers.
87  */
88 version (D_BetterC) {} else
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 /** $(H3 Arithmetic expression evaluator)
122  *
123  * This example makes use of the special placeholder type `This` to define a
124  * [https://en.wikipedia.org/wiki/Recursive_data_type|recursive data type]: an
125  * [https://en.wikipedia.org/wiki/Abstract_syntax_tree|abstract syntax tree] for
126  * representing simple arithmetic expressions.
127  */
128 version (D_BetterC) {} else
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, 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 /**
258  * A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) that can hold a
259  * single value from any of a specified set of types.
260  *
261  * The value in a `SumType` can be operated on using [match|pattern matching].
262  *
263  * To avoid ambiguity, duplicate types are not allowed (but see the
264  * [sumtype#basic-usage|"basic usage" example] for a workaround).
265  *
266  * The special type `This` can be used as a placeholder to create
267  * self-referential types, just like with `Algebraic`. See the
268  * [sumtype#arithmetic-expression-evaluator|"Arithmetic expression evaluator" example] for
269  * usage.
270  *
271  * A `SumType` is initialized by default to hold the `.init` value of its
272  * first member type, just like a regular union. The version identifier
273  * `SumTypeNoDefaultCtor` can be used to disable this behavior.
274  *
275  * See_Also: `std.variant.Algebraic`
276  */
277 struct SumType(Types...)
278 	if (is(NoDuplicates!Types == Types) && Types.length > 0)
279 {
280 	/// The types a `SumType` can hold.
281 	alias Types = AliasSeq!(
282 		ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType)
283 	);
284 
285 private:
286 
287 	enum bool canHoldTag(T) = Types.length <= T.max;
288 	alias unsignedInts = AliasSeq!(ubyte, ushort, uint, ulong);
289 
290 	alias Tag = Filter!(canHoldTag, unsignedInts)[0];
291 
292 	union Storage
293 	{
294 		// Workaround for dlang issue 20068
295 		template memberName(T)
296 			if (IndexOf!(T, Types) >= 0)
297 		{
298 			enum tid = IndexOf!(T, Types);
299 			mixin("enum memberName = `values_", toCtString!tid, "`;");
300 		}
301 
302 		static foreach (T; Types) {
303 			mixin("T ", memberName!T, ";");
304 		}
305 	}
306 
307 	Storage storage;
308 	Tag tag;
309 
310 	/**
311 	 * Accesses the value stored in a SumType.
312 	 *
313 	 * This method is memory-safe, provided that:
314 	 *
315 	 *   1. A SumType's tag is always accurate.
316 	 *   2. A SumType cannot be assigned to in @safe code if that assignment
317 	 *      could cause unsafe aliasing.
318 	 *
319 	 * All code that accesses a SumType's tag or storage directly, including
320 	 * @safe code in this module, must be manually checked to ensure that it
321 	 * does not violate either of the above requirements.
322 	 */
323 	@trusted
324 	ref inout(T) get(T)() inout
325 		if (IndexOf!(T, Types) >= 0)
326 	{
327 		enum tid = IndexOf!(T, Types);
328 		assert(tag == tid,
329 			"This `" ~ SumType.stringof ~
330 			"` does not contain a(n) `" ~ T.stringof ~ "`"
331 		);
332 		return __traits(getMember, storage, Storage.memberName!T);
333 	}
334 
335 public:
336 
337 	static foreach (tid, T; Types) {
338 		/// Constructs a `SumType` holding a specific value.
339 		this(T value)
340 		{
341 			import core.lifetime: forward;
342 
343 			// Workaround for dlang issue 21229
344 			storage = () {
345 				static if (isCopyable!T) {
346 					mixin("Storage newStorage = { ",
347 						// Workaround for dlang issue 21542
348 						Storage.memberName!T, ": (__ctfe ? value : forward!value)",
349 					" };");
350 				} else {
351 					mixin("Storage newStorage = { ",
352 						Storage.memberName!T, " : forward!value",
353 					" };");
354 				}
355 
356 				return newStorage;
357 			}();
358 
359 			tag = tid;
360 		}
361 
362 		static if (isCopyable!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 					storage = () {
369 						mixin("const(Storage) newStorage = { ",
370 							Storage.memberName!T, ": value",
371 						" };");
372 
373 						return newStorage;
374 					}();
375 
376 					tag = tid;
377 				}
378 			}
379 
380 			static if (IndexOf!(immutable(T), Map!(ImmutableOf, Types)) == tid) {
381 				/// ditto
382 				this(immutable(T) value) immutable
383 				{
384 					storage = () {
385 						mixin("immutable(Storage) newStorage = { ",
386 							Storage.memberName!T, ": value",
387 						" };");
388 
389 						return newStorage;
390 					}();
391 
392 					tag = tid;
393 				}
394 			}
395 		} else {
396 			@disable this(const(T) value) const;
397 			@disable this(immutable(T) value) immutable;
398 		}
399 	}
400 
401 	static if (anySatisfy!(hasElaborateCopyConstructor, Types)) {
402 		static if (
403 			allSatisfy!(isCopyable, Map!(InoutOf, Types))
404 			&& !anySatisfy!(hasPostblit, Map!(InoutOf, Types))
405 		) {
406 			/// Constructs a `SumType` that's a copy of another `SumType`.
407 			this(ref inout(SumType) other) inout
408 			{
409 				storage = other.match!((ref value) {
410 					alias OtherTypes = Map!(InoutOf, Types);
411 					enum tid = IndexOf!(typeof(value), OtherTypes);
412 					alias T = Types[tid];
413 
414 					mixin("inout(Storage) newStorage = { ",
415 						Storage.memberName!T, ": value",
416 					" };");
417 
418 					return newStorage;
419 				});
420 
421 				tag = other.tag;
422 			}
423 		} else {
424 			static if (allSatisfy!(isCopyable, Types)) {
425 				/// ditto
426 				this(ref SumType other)
427 				{
428 					storage = other.match!((ref value) {
429 						alias T = typeof(value);
430 
431 						mixin("Storage newStorage = { ",
432 							Storage.memberName!T, ": value",
433 						" };");
434 
435 						return newStorage;
436 					});
437 
438 					tag = other.tag;
439 				}
440 			} else {
441 				@disable this(ref SumType other);
442 			}
443 
444 			static if (allSatisfy!(isCopyable, Map!(ConstOf, Types))) {
445 				/// ditto
446 				this(ref const(SumType) other) const
447 				{
448 					storage = other.match!((ref value) {
449 						alias OtherTypes = Map!(ConstOf, Types);
450 						enum tid = IndexOf!(typeof(value), OtherTypes);
451 						alias T = Types[tid];
452 
453 						mixin("const(Storage) newStorage = { ",
454 							Storage.memberName!T, ": value",
455 						" };");
456 
457 						return newStorage;
458 					});
459 
460 					tag = other.tag;
461 				}
462 			} else {
463 				@disable this(ref const(SumType) other) const;
464 			}
465 
466 			static if (allSatisfy!(isCopyable, Map!(ImmutableOf, Types))) {
467 				/// ditto
468 				this(ref immutable(SumType) other) immutable
469 				{
470 					storage = other.match!((ref value) {
471 						alias OtherTypes = Map!(ImmutableOf, Types);
472 						enum tid = IndexOf!(typeof(value), OtherTypes);
473 						alias T = Types[tid];
474 
475 						mixin("immutable(Storage) newStorage = { ",
476 							Storage.memberName!T, ": value",
477 						" };");
478 
479 						return newStorage;
480 					});
481 
482 					tag = other.tag;
483 				}
484 			} else {
485 				@disable this(ref immutable(SumType) other) immutable;
486 			}
487 		}
488 	}
489 
490 	version (SumTypeNoDefaultCtor) {
491 		@disable this();
492 	}
493 
494 	static foreach (tid, T; Types) {
495 		static if (isAssignableTo!T) {
496 			/**
497 			 * Assigns a value to a `SumType`.
498 			 *
499 			 * Assigning to a `SumType` is `@system` if any of the
500 			 * `SumType`'s members contain pointers or references, since
501 			 * those members may be reachable through external references,
502 			 * and overwriting them could therefore lead to memory
503 			 * corruption.
504 			 *
505 			 * An individual assignment can be `@trusted` if the caller can
506 			 * guarantee that there are no outstanding references to $(I any)
507 			 * of the `SumType`'s members when the assignment occurs.
508 			 */
509 			ref SumType opAssign(T rhs)
510 			{
511 				import core.lifetime: forward;
512 				import std.traits: hasIndirections, hasNested;
513 				import std.meta: Or = templateOr;
514 
515 				enum mayContainPointers =
516 					anySatisfy!(Or!(hasIndirections, hasNested), Types);
517 
518 				static if (mayContainPointers) {
519 					cast(void) () @system {}();
520 				}
521 
522 				this.match!destroyIfOwner;
523 
524 				mixin("Storage newStorage = { ",
525 					Storage.memberName!T, ": forward!rhs",
526 				" };");
527 
528 				storage = newStorage;
529 				tag = tid;
530 
531 				return this;
532 			}
533 		}
534 	}
535 
536 	static if (allSatisfy!(isAssignableTo, Types)) {
537 		static if (allSatisfy!(isCopyable, Types)) {
538 			/**
539 			 * Copies the value from another `SumType` into this one.
540 			 *
541 			 * See the value-assignment overload for details on `@safe`ty.
542 			 *
543 			 * Copy assignment is `@disable`d if any of `Types` is non-copyable.
544 			 */
545 			ref SumType opAssign(ref SumType rhs)
546 			{
547 				rhs.match!((ref value) { this = value; });
548 				return this;
549 			}
550 		} else {
551 			@disable ref SumType opAssign(ref SumType rhs);
552 		}
553 
554 		/**
555 		 * Moves the value from another `SumType` into this one.
556 		 *
557 		 * See the value-assignment overload for details on `@safe`ty.
558 		 */
559 		ref SumType opAssign(SumType rhs)
560 		{
561 			import core.lifetime: move;
562 
563 			rhs.match!((ref value) { this = move(value); });
564 			return this;
565 		}
566 	}
567 
568 	/**
569 	 * Compares two `SumType`s for equality.
570 	 *
571 	 * Two `SumType`s are equal if they are the same kind of `SumType`, they
572 	 * contain values of the same type, and those values are equal.
573 	 */
574 	bool opEquals(this This, Rhs)(auto ref Rhs rhs)
575 		if (!is(CommonType!(This, Rhs) == void))
576 	{
577 		static if (is(This == Rhs)) {
578 			return AliasSeq!(this, rhs).match!((ref value, ref rhsValue) {
579 				static if (is(typeof(value) == typeof(rhsValue))) {
580 					return value == rhsValue;
581 				} else {
582 					return false;
583 				}
584 			});
585 		} else {
586 			alias CommonSumType = CommonType!(This, Rhs);
587 			return cast(CommonSumType) this == cast(CommonSumType) rhs;
588 		}
589 	}
590 
591 	// Workaround for dlang issue 19407
592 	static if (__traits(compiles, anySatisfy!(hasElaborateDestructor, Types))) {
593 		// If possible, include the destructor only when it's needed
594 		private enum includeDtor = anySatisfy!(hasElaborateDestructor, Types);
595 	} else {
596 		// If we can't tell, always include it, even when it does nothing
597 		private enum includeDtor = true;
598 	}
599 
600 	static if (includeDtor) {
601 		/// Calls the destructor of the `SumType`'s current value.
602 		~this()
603 		{
604 			this.match!destroyIfOwner;
605 		}
606 	}
607 
608 	invariant {
609 		this.match!((ref value) {
610 			static if (is(typeof(value) == class)) {
611 				if (value !is null) {
612 					assert(value);
613 				}
614 			} else static if (is(typeof(value) == struct)) {
615 				assert(&value);
616 			}
617 		});
618 	}
619 
620 	version (D_BetterC) {} else
621 	/**
622 	 * Returns a string representation of the `SumType`'s current value.
623 	 *
624 	 * Not available when compiled with `-betterC`.
625 	 */
626 	string toString(this This)()
627 	{
628 		import std.conv: to;
629 
630 		return this.match!(to!string);
631 	}
632 
633 	version (D_BetterC) {} else
634 	/**
635 	 * Handles formatted writing of the `SumType`'s current value.
636 	 *
637 	 * Not available when compiled with `-betterC`.
638 	 *
639 	 * Params:
640 	 *   sink = Output range to write to.
641 	 *   fmt = Format specifier to use.
642 	 *
643 	 * See_Also: `std.format.formatValue`
644 	 */
645 	void toString(this This, Sink, Char)(ref Sink sink, const ref FormatSpec!Char fmt)
646 	{
647 		import std.format: formatValue;
648 
649 		this.match!((ref value) {
650 			formatValue(sink, value, fmt);
651 		});
652 	}
653 
654 	static if (allSatisfy!(isHashable, Map!(ConstOf, Types))) {
655 		// Workaround for dlang issue 20095
656 		version (D_BetterC) {} else
657 		/**
658 		 * Returns the hash of the `SumType`'s current value.
659 		 *
660 		 * Not available when compiled with `-betterC`.
661 		 */
662 		size_t toHash() const
663 		{
664 			return this.match!hashOf;
665 		}
666 	}
667 
668 	/**
669 	 * Returns the index of the type of the `SumType`'s current value in the
670 	 * `SumType`'s [Types].
671 	 *
672 	 * If the `SumType` is qualified, then its qualifiers are applied to
673 	 * [Types] before determining the index.
674 	 */
675 	size_t typeIndex() const
676 	{
677 		return tag;
678 	}
679 }
680 
681 // Construction
682 @safe unittest {
683 	alias MySum = SumType!(int, float);
684 
685 	assert(__traits(compiles, MySum(42)));
686 	assert(__traits(compiles, MySum(3.14)));
687 }
688 
689 // Assignment
690 @safe unittest {
691 	alias MySum = SumType!(int, float);
692 
693 	MySum x = MySum(42);
694 
695 	assert(__traits(compiles, x = 3.14));
696 }
697 
698 // Self assignment
699 @safe unittest {
700 	alias MySum = SumType!(int, float);
701 
702 	MySum x = MySum(42);
703 	MySum y = MySum(3.14);
704 
705 	assert(__traits(compiles, y = x));
706 }
707 
708 // Equality
709 @safe unittest {
710 	alias MySum = SumType!(int, float);
711 
712 	assert(MySum(123) == MySum(123));
713 	assert(MySum(123) != MySum(456));
714 	assert(MySum(123) != MySum(123.0));
715 	assert(MySum(123) != MySum(456.0));
716 
717 }
718 
719 // Equality of differently-qualified SumTypes
720 // Disabled in BetterC due to use of dynamic arrays
721 version (D_BetterC) {} else
722 @safe unittest {
723 	alias SumA = SumType!(int, float);
724 	alias SumB = SumType!(const(int[]), int[]);
725 	alias SumC = SumType!(int[], const(int[]));
726 
727 	int[] ma = [1, 2, 3];
728 	const(int[]) ca = [1, 2, 3];
729 
730 	assert(const(SumA)(123) == SumA(123));
731 	assert(const(SumB)(ma[]) == SumB(ca[]));
732 	assert(const(SumC)(ma[]) == SumC(ca[]));
733 }
734 
735 // Imported types
736 @safe unittest {
737 	import std.typecons: Tuple;
738 
739 	assert(__traits(compiles, {
740 		alias MySum = SumType!(Tuple!(int, int));
741 	}));
742 }
743 
744 // const and immutable types
745 @safe unittest {
746 	assert(__traits(compiles, {
747 		alias MySum = SumType!(const(int[]), immutable(float[]));
748 	}));
749 }
750 
751 // Recursive types
752 @safe unittest {
753 	alias MySum = SumType!(This*);
754 	assert(is(MySum.Types[0] == MySum*));
755 }
756 
757 // Allowed types
758 @safe unittest {
759 	import std.meta: AliasSeq;
760 
761 	alias MySum = SumType!(int, float, This*);
762 
763 	assert(is(MySum.Types == AliasSeq!(int, float, MySum*)));
764 }
765 
766 // Types with destructors and postblits
767 @system unittest {
768 	int copies;
769 
770 	static struct Test
771 	{
772 		bool initialized = false;
773 		int* copiesPtr;
774 
775 		this(this) { (*copiesPtr)++; }
776 		~this() { if (initialized) (*copiesPtr)--; }
777 	}
778 
779 	alias MySum = SumType!(int, Test);
780 
781 	Test t = Test(true, &copies);
782 
783 	{
784 		MySum x = t;
785 		assert(copies == 1);
786 	}
787 	assert(copies == 0);
788 
789 	{
790 		MySum x = 456;
791 		assert(copies == 0);
792 	}
793 	assert(copies == 0);
794 
795 	{
796 		MySum x = t;
797 		assert(copies == 1);
798 		x = 456;
799 		assert(copies == 0);
800 	}
801 
802 	{
803 		MySum x = 456;
804 		assert(copies == 0);
805 		x = t;
806 		assert(copies == 1);
807 	}
808 
809 	{
810 		MySum x = t;
811 		MySum y = x;
812 		assert(copies == 2);
813 	}
814 
815 	{
816 		MySum x = t;
817 		MySum y;
818 		y = x;
819 		assert(copies == 2);
820 	}
821 }
822 
823 // Doesn't destroy reference types
824 // Disabled in BetterC due to use of classes
825 version (D_BetterC) {} else
826 @system unittest {
827 	bool destroyed;
828 
829 	class C
830 	{
831 		~this()
832 		{
833 			destroyed = true;
834 		}
835 	}
836 
837 	struct S
838 	{
839 		~this() {}
840 	}
841 
842 	alias MySum = SumType!(S, C);
843 
844 	C c = new C();
845 	{
846 		MySum x = c;
847 		destroyed = false;
848 	}
849 	assert(!destroyed);
850 
851 	{
852 		MySum x = c;
853 		destroyed = false;
854 		x = S();
855 		assert(!destroyed);
856 	}
857 }
858 
859 // Types with @disable this()
860 @safe unittest {
861 	static struct NoInit
862 	{
863 		@disable this();
864 	}
865 
866 	alias MySum = SumType!(NoInit, int);
867 
868 	assert(!__traits(compiles, MySum()));
869 	assert(__traits(compiles, MySum(42)));
870 	auto x = MySum(42);
871 }
872 
873 // const SumTypes
874 @safe unittest {
875 	assert(__traits(compiles,
876 		const(SumType!(int[]))([1, 2, 3])
877 	));
878 }
879 
880 // Equality of const SumTypes
881 @safe unittest {
882 	alias MySum = SumType!int;
883 
884 	assert(__traits(compiles,
885 		const(MySum)(123) == const(MySum)(456)
886 	));
887 }
888 
889 // Compares reference types using value equality
890 @safe unittest {
891 	import std.array: staticArray;
892 
893 	static struct Field {}
894 	static struct Struct { Field[] fields; }
895 	alias MySum = SumType!Struct;
896 
897 	static arr1 = staticArray([Field()]);
898 	static arr2 = staticArray([Field()]);
899 
900 	auto a = MySum(Struct(arr1[]));
901 	auto b = MySum(Struct(arr2[]));
902 
903 	assert(a == b);
904 }
905 
906 // toString
907 // Disabled in BetterC due to use of std.conv.text
908 version (D_BetterC) {} else
909 @safe unittest {
910 	import std.conv: text;
911 
912 	static struct Int { int i; }
913 	static struct Double { double d; }
914 	alias Sum = SumType!(Int, Double);
915 
916 	assert(Sum(Int(42)).text == Int(42).text, Sum(Int(42)).text);
917 	assert(Sum(Double(33.3)).text == Double(33.3).text, Sum(Double(33.3)).text);
918 	assert((const(Sum)(Int(42))).text == (const(Int)(42)).text, (const(Sum)(Int(42))).text);
919 }
920 
921 // string formatting
922 // Disabled in BetterC due to use of std.format.format
923 version (D_BetterC) {} else
924 @safe unittest {
925 	import std.format: format;
926 
927 	SumType!int x = 123;
928 
929 	assert(format!"%s"(x) == format!"%s"(123));
930 	assert(format!"%x"(x) == format!"%x"(123));
931 }
932 
933 // string formatting of qualified SumTypes
934 // Disabled in BetterC due to use of std.format.format and dynamic arrays
935 version (D_BetterC) {} else
936 @safe unittest {
937 	import std.format: format;
938 
939 	int[] a = [1, 2, 3];
940 	const(SumType!(int[])) x = a;
941 
942 	assert(format!"%(%d, %)"(x) == format!"%(%s, %)"(a));
943 }
944 
945 // Github issue #16
946 // Disabled in BetterC due to use of dynamic arrays
947 version (D_BetterC) {} else
948 @safe unittest {
949 	alias Node = SumType!(This[], string);
950 
951 	// override inference of @system attribute for cyclic functions
952 	assert((() @trusted =>
953 		Node([Node([Node("x")])])
954 		==
955 		Node([Node([Node("x")])])
956 	)());
957 }
958 
959 // Github issue #16 with const
960 // Disabled in BetterC due to use of dynamic arrays
961 version (D_BetterC) {} else
962 @safe unittest {
963 	alias Node = SumType!(const(This)[], string);
964 
965 	// override inference of @system attribute for cyclic functions
966 	assert((() @trusted =>
967 		Node([Node([Node("x")])])
968 		==
969 		Node([Node([Node("x")])])
970 	)());
971 }
972 
973 // Stale pointers
974 // Disabled in BetterC due to use of dynamic arrays
975 version (D_BetterC) {} else
976 @system unittest {
977 	alias MySum = SumType!(ubyte, void*[2]);
978 
979 	MySum x = [null, cast(void*) 0x12345678];
980 	void** p = &x.get!(void*[2])[1];
981 	x = ubyte(123);
982 
983 	assert(*p != cast(void*) 0x12345678);
984 }
985 
986 // Exception-safe assignment
987 // Disabled in BetterC due to use of exceptions
988 version (D_BetterC) {} else
989 @safe unittest {
990 	static struct A
991 	{
992 		int value = 123;
993 	}
994 
995 	static struct B
996 	{
997 		int value = 456;
998 		this(this) { throw new Exception("oops"); }
999 	}
1000 
1001 	alias MySum = SumType!(A, B);
1002 
1003 	MySum x;
1004 	try {
1005 		x = B();
1006 	} catch (Exception e) {}
1007 
1008 	assert(
1009 		(x.tag == 0 && x.get!A.value == 123) ||
1010 		(x.tag == 1 && x.get!B.value == 456)
1011 	);
1012 }
1013 
1014 // Types with @disable this(this)
1015 @safe unittest {
1016 	import core.lifetime: move;
1017 
1018 	static struct NoCopy
1019 	{
1020 		@disable this(this);
1021 	}
1022 
1023 	alias MySum = SumType!NoCopy;
1024 
1025 	NoCopy lval = NoCopy();
1026 
1027 	MySum x = NoCopy();
1028 	MySum y = NoCopy();
1029 
1030 	assert(__traits(compiles, SumType!NoCopy(NoCopy())));
1031 	assert(!__traits(compiles, SumType!NoCopy(lval)));
1032 
1033 	assert(__traits(compiles, y = NoCopy()));
1034 	assert(__traits(compiles, y = move(x)));
1035 	assert(!__traits(compiles, y = lval));
1036 	assert(!__traits(compiles, y = x));
1037 
1038 	assert(__traits(compiles, x == y));
1039 }
1040 
1041 // Github issue #22
1042 // Disabled in BetterC due to use of std.typecons.Nullable
1043 version (D_BetterC) {} else
1044 @safe unittest {
1045 	import std.typecons;
1046 	assert(__traits(compiles, {
1047 		static struct A {
1048 			SumType!(Nullable!int) a = Nullable!int.init;
1049 		}
1050 	}));
1051 }
1052 
1053 // Static arrays of structs with postblits
1054 // Disabled in BetterC due to use of dynamic arrays
1055 version (D_BetterC) {} else
1056 @safe unittest {
1057 	static struct S
1058 	{
1059 		int n;
1060 		this(this) { n++; }
1061 	}
1062 
1063 	assert(__traits(compiles, SumType!(S[1])()));
1064 
1065 	SumType!(S[1]) x = [S(0)];
1066 	SumType!(S[1]) y = x;
1067 
1068 	auto xval = x.get!(S[1])[0].n;
1069 	auto yval = y.get!(S[1])[0].n;
1070 
1071 	assert(xval != yval);
1072 }
1073 
1074 // Replacement does not happen inside SumType
1075 // Disabled in BetterC due to use of associative arrays
1076 version (D_BetterC) {} else
1077 @safe unittest {
1078 	import std.typecons : Tuple, ReplaceTypeUnless;
1079 	alias A = Tuple!(This*,SumType!(This*))[SumType!(This*,string)[This]];
1080 	alias TR = ReplaceTypeUnless!(isSumTypeInstance, This, int, A);
1081 	static assert(is(TR == Tuple!(int*,SumType!(This*))[SumType!(This*, string)[int]]));
1082 }
1083 
1084 // Supports nested self-referential SumTypes
1085 @safe unittest {
1086 	import std.typecons : Tuple, Flag;
1087 	alias Nat = SumType!(Flag!"0", Tuple!(This*));
1088 	static assert(__traits(compiles, SumType!(Nat)));
1089 	static assert(__traits(compiles, SumType!(Nat*, Tuple!(This*, This*))));
1090 }
1091 
1092 // Self-referential SumTypes inside Algebraic
1093 // Disabled in BetterC due to use of std.variant.Algebraic
1094 version (D_BetterC) {} else
1095 @safe unittest {
1096 	import std.variant: Algebraic;
1097 
1098 	alias T = Algebraic!(SumType!(This*));
1099 
1100 	assert(is(T.AllowedTypes[0].Types[0] == T.AllowedTypes[0]*));
1101 }
1102 
1103 // Doesn't call @system postblits in @safe code
1104 @safe unittest {
1105 	static struct SystemCopy { @system this(this) {} }
1106 	SystemCopy original;
1107 
1108 	assert(!__traits(compiles, () @safe {
1109 		SumType!SystemCopy copy = original;
1110 	}));
1111 
1112 	assert(!__traits(compiles, () @safe {
1113 		SumType!SystemCopy copy; copy = original;
1114 	}));
1115 }
1116 
1117 // Doesn't overwrite pointers in @safe code
1118 @safe unittest {
1119 	alias MySum = SumType!(int*, int);
1120 
1121 	MySum x;
1122 
1123 	assert(!__traits(compiles, () @safe {
1124 		x = 123;
1125 	}));
1126 
1127 	assert(!__traits(compiles, () @safe {
1128 		x = MySum(123);
1129 	}));
1130 }
1131 
1132 // Types with invariants
1133 // Disabled in BetterC due to use of exceptions
1134 version (D_BetterC) {} else
1135 @system unittest {
1136 	import std.exception: assertThrown;
1137 	import core.exception: AssertError;
1138 
1139 	struct S
1140 	{
1141 		int i;
1142 		invariant { assert(i >= 0); }
1143 	}
1144 
1145 	class C
1146 	{
1147 		int i;
1148 		invariant { assert(i >= 0); }
1149 	}
1150 
1151 	SumType!S x;
1152 	x.match!((ref v) { v.i = -1; });
1153 	assertThrown!AssertError(assert(&x));
1154 
1155 	SumType!C y = new C();
1156 	y.match!((ref v) { v.i = -1; });
1157 	assertThrown!AssertError(assert(&y));
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 disabled opEquals
1267 @safe unittest {
1268 	static struct S
1269 	{
1270 		@disable bool opEquals(const S rhs) const;
1271 	}
1272 
1273 	assert(__traits(compiles, SumType!S(S())));
1274 }
1275 
1276 // Types with non-const opEquals
1277 @safe unittest {
1278 	static struct S
1279 	{
1280 		int i;
1281 		bool opEquals(S rhs) { return i == rhs.i; }
1282 	}
1283 
1284 	assert(__traits(compiles, SumType!S(S(123))));
1285 }
1286 
1287 // Incomparability of different SumTypes
1288 @safe unittest {
1289 	SumType!(int, string) x = 123;
1290 	SumType!(string, int) y = 123;
1291 
1292 	assert(!__traits(compiles, x != y));
1293 }
1294 
1295 // Self-reference in return/parameter type of function pointer member
1296 @safe unittest {
1297 	assert(__traits(compiles, {
1298 		alias T = SumType!(int, This delegate(This));
1299 	}));
1300 }
1301 
1302 // Construction and assignment from implicitly-convertible lvalue
1303 @safe unittest {
1304 	alias MySum = SumType!bool;
1305 
1306 	const(bool) b = true;
1307 
1308 	assert(__traits(compiles, { MySum x = b; }));
1309 	assert(__traits(compiles, { MySum x; x = b; }));
1310 }
1311 
1312 // Type index
1313 @safe unittest {
1314 	alias MySum = SumType!(int, float);
1315 
1316 	static bool isIndexOf(Target, Types...)(size_t i)
1317 	{
1318 		switch (i) {
1319 			static foreach (tid, T; Types)
1320 				case tid: return is(T == Target);
1321 			default: return false;
1322 		}
1323 	}
1324 
1325 	assert(isIndexOf!(int, MySum.Types)(MySum(42).typeIndex));
1326 	assert(isIndexOf!(float, MySum.Types)(MySum(3.14).typeIndex));
1327 }
1328 
1329 // Type index for qualified SumTypes
1330 // Disabled in BetterC due to use of dynamic arrays
1331 version (D_BetterC) {} else
1332 @safe unittest {
1333 	alias MySum = SumType!(const(int[]), int[]);
1334 
1335 	static bool isIndexOf(Target, Types...)(size_t i)
1336 	{
1337 		switch (i) {
1338 			static foreach (tid, T; Types)
1339 				case tid: return is(T == Target);
1340 			default: return false;
1341 		}
1342 	}
1343 
1344 	int[] ma = [1, 2, 3];
1345 	// Construct as mutable and convert to const to get mismatched type + tag
1346 	auto x = MySum(ma);
1347 	const y = MySum(ma);
1348 	auto z = const(MySum)(ma);
1349 
1350 	assert(isIndexOf!(int[], MySum.Types)(x.typeIndex));
1351 	assert(isIndexOf!(const(int[]), Map!(ConstOf, MySum.Types))(y.typeIndex));
1352 	assert(isIndexOf!(const(int[]), Map!(ConstOf, MySum.Types))(z.typeIndex));
1353 }
1354 
1355 // Type index for differently-qualified versions of the same SumType
1356 // Disabled in BetterC due to use of dynamic arrays
1357 version (D_BetterC) {} else
1358 @safe unittest {
1359 	alias MySum = SumType!(const(int[]), int[]);
1360 
1361 	int[] ma = [1, 2, 3];
1362 	auto x = MySum(ma);
1363 	const y = x;
1364 
1365 	assert(x.typeIndex == y.typeIndex);
1366 }
1367 
1368 /// True if `T` is an instance of the `SumType` template, otherwise false.
1369 private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
1370 
1371 @safe unittest {
1372 	static struct Wrapper
1373 	{
1374 		SumType!int s;
1375 		alias s this;
1376 	}
1377 
1378 	assert(isSumTypeInstance!(SumType!int));
1379 	assert(!isSumTypeInstance!Wrapper);
1380 }
1381 
1382 /// True if `T` is a [SumType] or implicitly converts to one, otherwise false.
1383 enum bool isSumType(T) = is(T : SumType!Args, Args...);
1384 
1385 ///
1386 @safe unittest {
1387 	static struct ConvertsToSumType
1388 	{
1389 		SumType!int payload;
1390 		alias payload this;
1391 	}
1392 
1393 	static struct ContainsSumType
1394 	{
1395 		SumType!int payload;
1396 	}
1397 
1398 	assert(isSumType!(SumType!int));
1399 	assert(isSumType!ConvertsToSumType);
1400 	assert(!isSumType!ContainsSumType);
1401 }
1402 
1403 /**
1404  * Calls a type-appropriate function with the value held in a [SumType].
1405  *
1406  * For each possible type the [SumType] can hold, the given handlers are
1407  * checked, in order, to see whether they accept a single argument of that type.
1408  * The first one that does is chosen as the match for that type. (Note that the
1409  * first match may not always be the most exact match.
1410  * See [#avoiding-unintentional-matches|"Avoiding unintentional matches"] for
1411  * one common pitfall.)
1412  *
1413  * Every type must have a matching handler, and every handler must match at
1414  * least one type. This is enforced at compile time.
1415  *
1416  * Handlers may be functions, delegates, or objects with `opCall` overloads. If
1417  * a function with more than one overload is given as a handler, all of the
1418  * overloads are considered as potential matches.
1419  *
1420  * Templated handlers are also accepted, and will match any type for which they
1421  * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
1422  * [sumtype#introspection-based-matching|"Introspection-based matching"] for an
1423  * example of templated handler usage.
1424  *
1425  * If multiple [SumType]s are passed to `match`, their values are passed to the
1426  * handlers as separate arguments, and matching is done for each possible
1427  * combination of value types. See [#multiple-dispatch|"Multiple dispatch"] for
1428  * an example.
1429  *
1430  * Returns:
1431  *   The value returned from the handler that matches the currently-held type.
1432  *
1433  * See_Also: `std.variant.visit`
1434  */
1435 template match(handlers...)
1436 {
1437 	import std.typecons: Yes;
1438 
1439 	/**
1440 	 * The actual `match` function.
1441 	 *
1442 	 * Params:
1443 	 *   args = One or more [SumType] objects.
1444 	 */
1445 	auto ref match(SumTypes...)(auto ref SumTypes args)
1446 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1447 	{
1448 		return matchImpl!(Yes.exhaustive, handlers)(args);
1449 	}
1450 }
1451 
1452 /** $(H3 Avoiding unintentional matches)
1453  *
1454  * Sometimes, implicit conversions may cause a handler to match more types than
1455  * intended. The example below shows two solutions to this problem.
1456  */
1457 @safe unittest {
1458     alias Number = SumType!(double, int);
1459 
1460     Number x;
1461 
1462     // Problem: because int implicitly converts to double, the double
1463     // handler is used for both types, and the int handler never matches.
1464     assert(!__traits(compiles,
1465         x.match!(
1466             (double d) => "got double",
1467             (int n) => "got int"
1468         )
1469     ));
1470 
1471     // Solution 1: put the handler for the "more specialized" type (in this
1472     // case, int) before the handler for the type it converts to.
1473     assert(__traits(compiles,
1474         x.match!(
1475             (int n) => "got int",
1476             (double d) => "got double"
1477         )
1478     ));
1479 
1480     // Solution 2: use a template that only accepts the exact type it's
1481     // supposed to match, instead of any type that implicitly converts to it.
1482     alias exactly(T, alias fun) = function (arg) {
1483         static assert(is(typeof(arg) == T));
1484         return fun(arg);
1485     };
1486 
1487     // Now, even if we put the double handler first, it will only be used for
1488     // doubles, not ints.
1489     assert(__traits(compiles,
1490         x.match!(
1491             exactly!(double, d => "got double"),
1492             exactly!(int, n => "got int")
1493         )
1494     ));
1495 }
1496 
1497 /** $(H3 Multiple dispatch)
1498  *
1499  * Pattern matching can be performed on multiple `SumType`s at once by passing
1500  * handlers with multiple arguments. This usually leads to more concise code
1501  * than using nested calls to `match`, as show below.
1502  */
1503 @safe unittest {
1504     struct Point2D { double x, y; }
1505     struct Point3D { double x, y, z; }
1506 
1507     alias Point = SumType!(Point2D, Point3D);
1508 
1509     version (none) {
1510         // This function works, but the code is ugly and repetitive.
1511         // It uses three separate calls to match!
1512         @safe pure nothrow @nogc
1513         bool sameDimensions(Point p1, Point p2)
1514         {
1515             return p1.match!(
1516                 (Point2D _) => p2.match!(
1517                     (Point2D _) => true,
1518                     _ => false
1519                 ),
1520                 (Point3D _) => p2.match!(
1521                     (Point3D _) => true,
1522                     _ => false
1523                 )
1524             );
1525         }
1526     }
1527 
1528     // This version is much nicer.
1529     @safe pure nothrow @nogc
1530     bool sameDimensions(Point p1, Point p2)
1531     {
1532         alias doMatch = match!(
1533             (Point2D _1, Point2D _2) => true,
1534             (Point3D _1, Point3D _2) => true,
1535             (_1, _2) => false
1536         );
1537 
1538         return doMatch(p1, p2);
1539     }
1540 
1541     Point a = Point2D(1, 2);
1542     Point b = Point2D(3, 4);
1543     Point c = Point3D(5, 6, 7);
1544     Point d = Point3D(8, 9, 0);
1545 
1546     assert( sameDimensions(a, b));
1547     assert( sameDimensions(c, d));
1548     assert(!sameDimensions(a, c));
1549     assert(!sameDimensions(d, b));
1550 }
1551 
1552 /**
1553  * Attempts to call a type-appropriate function with the value held in a
1554  * [SumType], and throws on failure.
1555  *
1556  * Matches are chosen using the same rules as [match], but are not required to
1557  * be exhaustive—in other words, a type (or combination of types) is allowed to
1558  * have no matching handler. If a type without a handler is encountered at
1559  * runtime, a [MatchException] is thrown.
1560  *
1561  * Not available when compiled with `-betterC`.
1562  *
1563  * Returns:
1564  *   The value returned from the handler that matches the currently-held type,
1565  *   if a handler was given for that type.
1566  *
1567  * Throws:
1568  *   [MatchException], if the currently-held type has no matching handler.
1569  *
1570  * See_Also: `std.variant.tryVisit`
1571  */
1572 version (D_Exceptions)
1573 template tryMatch(handlers...)
1574 {
1575 	import std.typecons: No;
1576 
1577 	/**
1578 	 * The actual `tryMatch` function.
1579 	 *
1580 	 * Params:
1581 	 *   args = One or more [SumType] objects.
1582 	 */
1583 	auto ref tryMatch(SumTypes...)(auto ref SumTypes args)
1584 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1585 	{
1586 		return matchImpl!(No.exhaustive, handlers)(args);
1587 	}
1588 }
1589 
1590 /**
1591  * Thrown by [tryMatch] when an unhandled type is encountered.
1592  *
1593  * Not available when compiled with `-betterC`.
1594  */
1595 version (D_Exceptions)
1596 class MatchException : Exception
1597 {
1598 	///
1599 	pure @safe @nogc nothrow
1600 	this(string msg, string file = __FILE__, size_t line = __LINE__)
1601 	{
1602 		super(msg, file, line);
1603 	}
1604 }
1605 
1606 /**
1607  * True if `handler` is a potential match for `Ts`, otherwise false.
1608  *
1609  * See the documentation for [match] for a full explanation of how matches are
1610  * chosen.
1611  */
1612 template canMatch(alias handler, Ts...)
1613 	if (Ts.length > 0)
1614 {
1615 	enum canMatch = is(typeof((Ts args) => handler(args)));
1616 }
1617 
1618 ///
1619 @safe unittest {
1620     alias handleInt = (int i) => "got an int";
1621 
1622     assert( canMatch!(handleInt, int));
1623     assert(!canMatch!(handleInt, string));
1624 }
1625 
1626 // Includes all overloads of the given handler
1627 @safe unittest {
1628 	static struct OverloadSet
1629 	{
1630 		static void fun(int n) {}
1631 		static void fun(double d) {}
1632 	}
1633 
1634 	assert(canMatch!(OverloadSet.fun, int));
1635 	assert(canMatch!(OverloadSet.fun, double));
1636 }
1637 
1638 // Like aliasSeqOf!(iota(n)), but works in BetterC
1639 private template Iota(size_t n)
1640 {
1641 	static if (n == 0) {
1642 		alias Iota = AliasSeq!();
1643 	} else {
1644 		alias Iota = AliasSeq!(Iota!(n - 1), n - 1);
1645 	}
1646 }
1647 
1648 @safe unittest {
1649 	assert(is(Iota!0 == AliasSeq!()));
1650 	assert(Iota!1 == AliasSeq!(0));
1651 	assert(Iota!3 == AliasSeq!(0, 1, 2));
1652 }
1653 
1654 /* The number that the dim-th argument's tag is multiplied by when
1655  * converting TagTuples to and from case indices ("caseIds").
1656  *
1657  * Named by analogy to the stride that the dim-th index into a
1658  * multidimensional static array is multiplied by to calculate the
1659  * offset of a specific element.
1660  */
1661 private size_t stride(size_t dim, lengths...)()
1662 {
1663 	import core.checkedint: mulu;
1664 
1665 	size_t result = 1;
1666 	bool overflow = false;
1667 
1668 	static foreach (i; 0 .. dim) {
1669 		result = mulu(result, lengths[i], overflow);
1670 	}
1671 
1672 	/* The largest number matchImpl uses, numCases, is calculated with
1673 	 * stride!(SumTypes.length), so as long as this overflow check
1674 	 * passes, we don't need to check for overflow anywhere else.
1675 	 */
1676 	assert(!overflow, "Integer overflow");
1677 	return result;
1678 }
1679 
1680 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
1681 {
1682 	auto matchImpl(SumTypes...)(auto ref SumTypes args)
1683 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1684 	{
1685 		enum typeCount(SumType) = SumType.Types.length;
1686 		alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
1687 
1688 		/* A TagTuple represents a single possible set of tags that `args`
1689 		 * could have at runtime.
1690 		 *
1691 		 * Because D does not allow a struct to be the controlling expression
1692 		 * of a switch statement, we cannot dispatch on the TagTuple directly.
1693 		 * Instead, we must map each TagTuple to a unique integer and generate
1694 		 * a case label for each of those integers.
1695 		 *
1696 		 * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
1697 		 * the same technique that's used to map index tuples to memory offsets
1698 		 * in a multidimensional static array.
1699 		 *
1700 		 * For example, when `args` consists of two SumTypes with two member
1701 		 * types each, the TagTuples corresponding to each case label are:
1702 		 *
1703 		 *   case 0:  TagTuple([0, 0])
1704 		 *   case 1:  TagTuple([1, 0])
1705 		 *   case 2:  TagTuple([0, 1])
1706 		 *   case 3:  TagTuple([1, 1])
1707 		 *
1708 		 * When there is only one argument, the caseId is equal to that
1709 		 * argument's tag.
1710 		 */
1711 		static struct TagTuple
1712 		{
1713 			size_t[SumTypes.length] tags;
1714 			alias tags this;
1715 
1716 			invariant {
1717 				static foreach (i; 0 .. tags.length) {
1718 					assert(tags[i] < SumTypes[i].Types.length);
1719 				}
1720 			}
1721 
1722 			this(ref const(SumTypes) args)
1723 			{
1724 				static foreach (i; 0 .. tags.length) {
1725 					tags[i] = args[i].tag;
1726 				}
1727 			}
1728 
1729 			static TagTuple fromCaseId(size_t caseId)
1730 			{
1731 				TagTuple result;
1732 
1733 				// Most-significant to least-significant
1734 				static foreach_reverse (i; 0 .. result.length) {
1735 					result[i] = caseId / stride!i;
1736 					caseId %= stride!i;
1737 				}
1738 
1739 				return result;
1740 			}
1741 
1742 			size_t toCaseId()
1743 			{
1744 				size_t result;
1745 
1746 				static foreach (i; 0 .. tags.length) {
1747 					result += tags[i] * stride!i;
1748 				}
1749 
1750 				return result;
1751 			}
1752 		}
1753 
1754 		/*
1755 		 * A list of arguments to be passed to a handler needed for the case
1756 		 * labeled with `caseId`.
1757 		 */
1758 		template handlerArgs(size_t caseId)
1759 		{
1760 			enum tags = TagTuple.fromCaseId(caseId);
1761 			enum argsFrom(size_t i: tags.length) = "";
1762 			enum argsFrom(size_t i) = "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
1763 				".Types[" ~ toCtString!(tags[i]) ~ "])(), " ~ argsFrom!(i + 1);
1764 			enum handlerArgs = argsFrom!0;
1765 		}
1766 
1767 		/* An AliasSeq of the types of the member values in the argument list
1768 		 * returned by `handlerArgs!caseId`.
1769 		 *
1770 		 * Note that these are the actual (that is, qualified) types of the
1771 		 * member values, which may not be the same as the types listed in
1772 		 * the arguments' `.Types` properties.
1773 		 */
1774 		template valueTypes(size_t caseId)
1775 		{
1776 			enum tags = TagTuple.fromCaseId(caseId);
1777 
1778 			template getType(size_t i)
1779 			{
1780 				enum tid = tags[i];
1781 				alias T = SumTypes[i].Types[tid];
1782 				alias getType = typeof(args[i].get!T());
1783 			}
1784 
1785 			alias valueTypes = Map!(getType, Iota!(tags.length));
1786 		}
1787 
1788 		/* The total number of cases is
1789 		 *
1790 		 *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1791 		 *
1792 		 * Conveniently, this is equal to stride!(SumTypes.length), so we can
1793 		 * use that function to compute it.
1794 		 */
1795 		enum numCases = stride!(SumTypes.length);
1796 
1797 		/* Guaranteed to never be a valid handler index, since
1798 		 * handlers.length <= size_t.max.
1799 		 */
1800 		enum noMatch = size_t.max;
1801 
1802 		// An array that maps caseIds to handler indices ("hids").
1803 		enum matches = () {
1804 			size_t[numCases] matches;
1805 
1806 			// Workaround for dlang issue 19561
1807 			foreach (ref match; matches) {
1808 				match = noMatch;
1809 			}
1810 
1811 			static foreach (caseId; 0 .. numCases) {
1812 				static foreach (hid, handler; handlers) {
1813 					static if (canMatch!(handler, valueTypes!caseId)) {
1814 						if (matches[caseId] == noMatch) {
1815 							matches[caseId] = hid;
1816 						}
1817 					}
1818 				}
1819 			}
1820 
1821 			return matches;
1822 		}();
1823 
1824 		import std.algorithm.searching: canFind;
1825 
1826 		// Check for unreachable handlers
1827 		static foreach (hid, handler; handlers) {
1828 			static assert(matches[].canFind(hid),
1829 				"`handlers[" ~ toCtString!hid ~ "]` " ~
1830 				"of type `" ~ ( __traits(isTemplate, handler)
1831 					? "template"
1832 					: typeof(handler).stringof
1833 				) ~ "` " ~
1834 				"never matches"
1835 			);
1836 		}
1837 
1838 		// Workaround for dlang issue 19993
1839 		enum handlerName(size_t hid) = "handler" ~ toCtString!hid;
1840 
1841 		static foreach (size_t hid, handler; handlers) {
1842 			mixin("alias ", handlerName!hid, " = handler;");
1843 		}
1844 
1845 		immutable argsId = TagTuple(args).toCaseId;
1846 
1847 		final switch (argsId) {
1848 			static foreach (caseId; 0 .. numCases) {
1849 				case caseId:
1850 					static if (matches[caseId] != noMatch) {
1851 						return mixin(handlerName!(matches[caseId]), "(", handlerArgs!caseId, ")");
1852 					} else {
1853 						static if(exhaustive) {
1854 							static assert(false,
1855 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1856 						} else {
1857 							throw new MatchException(
1858 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1859 						}
1860 					}
1861 			}
1862 		}
1863 
1864 		assert(false, "unreachable");
1865 	}
1866 }
1867 
1868 // Matching
1869 @safe unittest {
1870 	alias MySum = SumType!(int, float);
1871 
1872 	MySum x = MySum(42);
1873 	MySum y = MySum(3.14);
1874 
1875 	assert(x.match!((int v) => true, (float v) => false));
1876 	assert(y.match!((int v) => false, (float v) => true));
1877 }
1878 
1879 // Missing handlers
1880 @safe unittest {
1881 	alias MySum = SumType!(int, float);
1882 
1883 	MySum x = MySum(42);
1884 
1885 	assert(!__traits(compiles, x.match!((int x) => true)));
1886 	assert(!__traits(compiles, x.match!()));
1887 }
1888 
1889 // Handlers with qualified parameters
1890 // Disabled in BetterC due to use of dynamic arrays
1891 version (D_BetterC) {} else
1892 @safe unittest {
1893 	alias MySum = SumType!(int[], float[]);
1894 
1895 	MySum x = MySum([1, 2, 3]);
1896 	MySum y = MySum([1.0, 2.0, 3.0]);
1897 
1898 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
1899 	assert(y.match!((const(int[]) v) => false, (const(float[]) v) => true));
1900 }
1901 
1902 // Handlers for qualified types
1903 // Disabled in BetterC due to use of dynamic arrays
1904 version (D_BetterC) {} else
1905 @safe unittest {
1906 	alias MySum = SumType!(immutable(int[]), immutable(float[]));
1907 
1908 	MySum x = MySum([1, 2, 3]);
1909 
1910 	assert(x.match!((immutable(int[]) v) => true, (immutable(float[]) v) => false));
1911 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
1912 	// Tail-qualified parameters
1913 	assert(x.match!((immutable(int)[] v) => true, (immutable(float)[] v) => false));
1914 	assert(x.match!((const(int)[] v) => true, (const(float)[] v) => false));
1915 	// Generic parameters
1916 	assert(x.match!((immutable v) => true));
1917 	assert(x.match!((const v) => true));
1918 	// Unqualified parameters
1919 	assert(!__traits(compiles,
1920 		x.match!((int[] v) => true, (float[] v) => false)
1921 	));
1922 }
1923 
1924 // Delegate handlers
1925 // Disabled in BetterC due to use of closures
1926 version (D_BetterC) {} else
1927 @safe unittest {
1928 	alias MySum = SumType!(int, float);
1929 
1930 	int answer = 42;
1931 	MySum x = MySum(42);
1932 	MySum y = MySum(3.14);
1933 
1934 	assert(x.match!((int v) => v == answer, (float v) => v == answer));
1935 	assert(!y.match!((int v) => v == answer, (float v) => v == answer));
1936 }
1937 
1938 version (unittest) {
1939 	version (D_BetterC) {
1940 		// std.math.isClose depends on core.runtime.math, so use a
1941 		// libc-based version for testing with -betterC
1942 		@safe pure @nogc nothrow
1943 		private bool isClose(double lhs, double rhs)
1944 		{
1945 			import core.stdc.math: fabs;
1946 
1947 			return fabs(lhs - rhs) < 1e-5;
1948 		}
1949 	} else {
1950 		import std.math: isClose;
1951 	}
1952 }
1953 
1954 // Generic handler
1955 @safe unittest {
1956 	alias MySum = SumType!(int, float);
1957 
1958 	MySum x = MySum(42);
1959 	MySum y = MySum(3.14);
1960 
1961 	assert(x.match!(v => v*2) == 84);
1962 	assert(y.match!(v => v*2).isClose(6.28));
1963 }
1964 
1965 // Fallback to generic handler
1966 // Disabled in BetterC due to use of std.conv.to
1967 version (D_BetterC) {} else
1968 @safe unittest {
1969 	import std.conv: to;
1970 
1971 	alias MySum = SumType!(int, float, string);
1972 
1973 	MySum x = MySum(42);
1974 	MySum y = MySum("42");
1975 
1976 	assert(x.match!((string v) => v.to!int, v => v*2) == 84);
1977 	assert(y.match!((string v) => v.to!int, v => v*2) == 42);
1978 }
1979 
1980 // Multiple non-overlapping generic handlers
1981 @safe unittest {
1982 	import std.array: staticArray;
1983 
1984 	alias MySum = SumType!(int, float, int[], char[]);
1985 
1986 	static ints = staticArray([1, 2, 3]);
1987 	static chars = staticArray(['a', 'b', 'c']);
1988 
1989 	MySum x = MySum(42);
1990 	MySum y = MySum(3.14);
1991 	MySum z = MySum(ints[]);
1992 	MySum w = MySum(chars[]);
1993 
1994 	assert(x.match!(v => v*2, v => v.length) == 84);
1995 	assert(y.match!(v => v*2, v => v.length).isClose(6.28));
1996 	assert(w.match!(v => v*2, v => v.length) == 3);
1997 	assert(z.match!(v => v*2, v => v.length) == 3);
1998 }
1999 
2000 // Structural matching
2001 @safe unittest {
2002 	static struct S1 { int x; }
2003 	static struct S2 { int y; }
2004 	alias MySum = SumType!(S1, S2);
2005 
2006 	MySum a = MySum(S1(0));
2007 	MySum b = MySum(S2(0));
2008 
2009 	assert(a.match!(s1 => s1.x + 1, s2 => s2.y - 1) == 1);
2010 	assert(b.match!(s1 => s1.x + 1, s2 => s2.y - 1) == -1);
2011 }
2012 
2013 // Separate opCall handlers
2014 @safe unittest {
2015 	static struct IntHandler
2016 	{
2017 		bool opCall(int arg)
2018 		{
2019 			return true;
2020 		}
2021 	}
2022 
2023 	static struct FloatHandler
2024 	{
2025 		bool opCall(float arg)
2026 		{
2027 			return false;
2028 		}
2029 	}
2030 
2031 	alias MySum = SumType!(int, float);
2032 
2033 	MySum x = MySum(42);
2034 	MySum y = MySum(3.14);
2035 
2036 	assert(x.match!(IntHandler.init, FloatHandler.init));
2037 	assert(!y.match!(IntHandler.init, FloatHandler.init));
2038 }
2039 
2040 // Compound opCall handler
2041 @safe unittest {
2042 	static struct CompoundHandler
2043 	{
2044 		bool opCall(int arg)
2045 		{
2046 			return true;
2047 		}
2048 
2049 		bool opCall(float arg)
2050 		{
2051 			return false;
2052 		}
2053 	}
2054 
2055 	alias MySum = SumType!(int, float);
2056 
2057 	MySum x = MySum(42);
2058 	MySum y = MySum(3.14);
2059 
2060 	assert(x.match!(CompoundHandler.init));
2061 	assert(!y.match!(CompoundHandler.init));
2062 }
2063 
2064 // Ordered matching
2065 @safe unittest {
2066 	alias MySum = SumType!(int, float);
2067 
2068 	MySum x = MySum(42);
2069 
2070 	assert(x.match!((int v) => true, v => false));
2071 }
2072 
2073 // Non-exhaustive matching
2074 version (D_Exceptions)
2075 @system unittest {
2076 	import std.exception: assertThrown, assertNotThrown;
2077 
2078 	alias MySum = SumType!(int, float);
2079 
2080 	MySum x = MySum(42);
2081 	MySum y = MySum(3.14);
2082 
2083 	assertNotThrown!MatchException(x.tryMatch!((int n) => true));
2084 	assertThrown!MatchException(y.tryMatch!((int n) => true));
2085 }
2086 
2087 // Non-exhaustive matching in @safe code
2088 version (D_Exceptions)
2089 @safe unittest {
2090 	SumType!(int, float) x;
2091 
2092 	assert(__traits(compiles,
2093 		x.tryMatch!(
2094 			(int n) => n + 1,
2095 		)
2096 	));
2097 
2098 }
2099 
2100 // Handlers with ref parameters
2101 @safe unittest {
2102 	alias Value = SumType!(long, double);
2103 
2104 	auto value = Value(3.14);
2105 
2106 	value.match!(
2107 		(long) {},
2108 		(ref double d) { d *= 2; }
2109 	);
2110 
2111 	assert(value.get!double.isClose(6.28));
2112 }
2113 
2114 // Unreachable handlers
2115 @safe unittest {
2116 	alias MySum = SumType!(int, string);
2117 
2118 	MySum s;
2119 
2120 	assert(!__traits(compiles,
2121 		s.match!(
2122 			(int _) => 0,
2123 			(string _) => 1,
2124 			(double _) => 2
2125 		)
2126 	));
2127 
2128 	assert(!__traits(compiles,
2129 		s.match!(
2130 			_ => 0,
2131 			(int _) => 1
2132 		)
2133 	));
2134 }
2135 
2136 // Unsafe handlers
2137 @system unittest {
2138 	SumType!int x;
2139 	alias unsafeHandler = (int x) @system { return; };
2140 
2141 	assert(!__traits(compiles, () @safe {
2142 		x.match!unsafeHandler;
2143 	}));
2144 
2145 	assert(__traits(compiles, () @system {
2146 		return x.match!unsafeHandler;
2147 	}));
2148 }
2149 
2150 // Overloaded handlers
2151 @safe unittest {
2152 	static struct OverloadSet
2153 	{
2154 		static string fun(int i) { return "int"; }
2155 		static string fun(double d) { return "double"; }
2156 	}
2157 
2158 	alias MySum = SumType!(int, double);
2159 
2160 	MySum a = 42;
2161 	MySum b = 3.14;
2162 
2163 	assert(a.match!(OverloadSet.fun) == "int");
2164 	assert(b.match!(OverloadSet.fun) == "double");
2165 }
2166 
2167 // Overload sets that include SumType arguments
2168 @safe unittest {
2169 	alias Inner = SumType!(int, double);
2170 	alias Outer = SumType!(Inner, string);
2171 
2172 	static struct OverloadSet
2173 	{
2174 		@safe:
2175 		static string fun(int i) { return "int"; }
2176 		static string fun(double d) { return "double"; }
2177 		static string fun(string s) { return "string"; }
2178 		static string fun(Inner i) { return i.match!fun; }
2179 		static string fun(Outer o) { return o.match!fun; }
2180 	}
2181 
2182 	Outer a = Inner(42);
2183 	Outer b = Inner(3.14);
2184 	Outer c = "foo";
2185 
2186 	assert(OverloadSet.fun(a) == "int");
2187 	assert(OverloadSet.fun(b) == "double");
2188 	assert(OverloadSet.fun(c) == "string");
2189 }
2190 
2191 // Overload sets with ref arguments
2192 @safe unittest {
2193 	static struct OverloadSet
2194 	{
2195 		static void fun(ref int i) { i = 42; }
2196 		static void fun(ref double d) { d = 3.14; }
2197 	}
2198 
2199 	alias MySum = SumType!(int, double);
2200 
2201 	MySum x = 0;
2202 	MySum y = 0.0;
2203 
2204 	x.match!(OverloadSet.fun);
2205 	y.match!(OverloadSet.fun);
2206 
2207 	assert(x.match!((value) => is(typeof(value) == int) && value == 42));
2208 	assert(y.match!((value) => is(typeof(value) == double) && value == 3.14));
2209 }
2210 
2211 // Overload sets with templates
2212 @safe unittest {
2213 	import std.traits: isNumeric;
2214 
2215 	static struct OverloadSet
2216 	{
2217 		static string fun(string arg)
2218 		{
2219 			return "string";
2220 		}
2221 
2222 		static string fun(T)(T arg)
2223 			if (isNumeric!T)
2224 		{
2225 			return "numeric";
2226 		}
2227 	}
2228 
2229 	alias MySum = SumType!(int, string);
2230 
2231 	MySum x = 123;
2232 	MySum y = "hello";
2233 
2234 	assert(x.match!(OverloadSet.fun) == "numeric");
2235 	assert(y.match!(OverloadSet.fun) == "string");
2236 }
2237 
2238 // Github issue #24
2239 @safe unittest {
2240 	assert(__traits(compiles, () @nogc {
2241 		int acc = 0;
2242 		SumType!int(1).match!((int x) => acc += x);
2243 	}));
2244 }
2245 
2246 // Github issue #31
2247 @safe unittest {
2248 	assert(__traits(compiles, () @nogc {
2249 		int acc = 0;
2250 
2251 		SumType!(int, string)(1).match!(
2252 			(int x) => acc += x,
2253 			(string _) => 0,
2254 		);
2255 	}));
2256 }
2257 
2258 // Types that `alias this` a SumType
2259 @safe unittest {
2260 	static struct A {}
2261 	static struct B {}
2262 	static struct D { SumType!(A, B) value; alias value this; }
2263 
2264 	assert(__traits(compiles, D().match!(_ => true)));
2265 }
2266 
2267 // Multiple dispatch
2268 @safe unittest {
2269 	alias MySum = SumType!(int, string);
2270 
2271 	static int fun(MySum x, MySum y)
2272 	{
2273 		import std.meta: Args = AliasSeq;
2274 
2275 		return Args!(x, y).match!(
2276 			(int    xv, int    yv) => 0,
2277 			(string xv, int    yv) => 1,
2278 			(int    xv, string yv) => 2,
2279 			(string xv, string yv) => 3
2280 		);
2281 	}
2282 
2283 	assert(fun(MySum(0),  MySum(0))  == 0);
2284 	assert(fun(MySum(""), MySum(0))  == 1);
2285 	assert(fun(MySum(0),  MySum("")) == 2);
2286 	assert(fun(MySum(""), MySum("")) == 3);
2287 }
2288 
2289 // inout SumTypes
2290 @safe unittest {
2291 	assert(__traits(compiles, {
2292 		inout(int[]) fun(inout(SumType!(int[])) x)
2293 		{
2294 			return x.match!((inout(int[]) a) => a);
2295 		}
2296 	}));
2297 }
2298 
2299 static if (__traits(compiles, { import std.traits: isRvalueAssignable; })) {
2300 	import std.traits: isRvalueAssignable;
2301 } else private {
2302 	enum isRvalueAssignable(Lhs, Rhs = Lhs) = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs);
2303 	struct __InoutWorkaroundStruct{}
2304 	@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
2305 	@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
2306 }
2307 
2308 private void destroyIfOwner(T)(ref T value)
2309 {
2310 	static if (hasElaborateDestructor!T) {
2311 		destroy(value);
2312 	}
2313 }