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 private enum memberName(size_t tid) = "values_" ~ toCtString!tid;
260 
261 // Workaround for dlang issue 19669
262 private enum haveDip1000 = __traits(compiles, () @safe {
263 	int x;
264 	int* p;
265 	p = &x;
266 });
267 
268 /**
269  * A [tagged union](https://en.wikipedia.org/wiki/Tagged_union) that can hold a
270  * single value from any of a specified set of types.
271  *
272  * The value in a `SumType` can be operated on using [match|pattern matching].
273  *
274  * To avoid ambiguity, duplicate types are not allowed (but see the
275  * [sumtype#basic-usage|"basic usage" example] for a workaround).
276  *
277  * The special type `This` can be used as a placeholder to create
278  * self-referential types, just like with `Algebraic`. See the
279  * [sumtype#arithmetic-expression-evaluator|"Arithmetic expression evaluator" example] for
280  * usage.
281  *
282  * A `SumType` is initialized by default to hold the `.init` value of its
283  * first member type, just like a regular union. The version identifier
284  * `SumTypeNoDefaultCtor` can be used to disable this behavior.
285  *
286  * See_Also: `std.variant.Algebraic`
287  */
288 struct SumType(Types...)
289 	if (is(NoDuplicates!Types == Types) && Types.length > 0)
290 {
291 	/// The types a `SumType` can hold.
292 	alias Types = AliasSeq!(
293 		ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType)
294 	);
295 
296 private:
297 
298 	enum bool canHoldTag(T) = Types.length <= T.max;
299 	alias unsignedInts = AliasSeq!(ubyte, ushort, uint, ulong);
300 
301 	alias Tag = Filter!(canHoldTag, unsignedInts)[0];
302 
303 	union Storage
304 	{
305 		static foreach (tid, T; Types) {
306 			/+
307 			Giving these fields individual names makes it possible to use brace
308 			initialization for Storage.
309 			+/
310 			mixin("T ", memberName!tid, ";");
311 		}
312 	}
313 
314 	Storage storage;
315 	Tag tag;
316 
317 	/**
318 	 * Accesses the value stored in a SumType by its index.
319 	 *
320 	 * This method is memory-safe, provided that:
321 	 *
322 	 *   1. A SumType's tag is always accurate.
323 	 *   2. A SumType's value cannot be unsafely aliased in @safe code.
324 	 *
325 	 * All code that accesses a SumType's tag or storage directly, including
326 	 * @safe code in this module, must be manually checked to ensure that it
327 	 * does not violate either of the above requirements.
328 	 */
329 	@trusted
330 	// Explicit return type omitted
331 	// Workaround for https://github.com/dlang/dmd/issues/20549
332 	ref getByIndex(size_t tid)() inout
333 		if (tid < Types.length)
334 	{
335 		assert(tag == tid,
336 			"This `" ~ SumType.stringof ~ "`" ~
337 			"does not contain a(n) `" ~ Types[tid].stringof ~ "`"
338 		);
339 		return storage.tupleof[tid];
340 	}
341 
342 public:
343 
344 	static foreach (tid, T; Types) {
345 		/// Constructs a `SumType` holding a specific value.
346 		this(T value)
347 		{
348 			import core.lifetime: forward;
349 
350 			static if (isCopyable!T) {
351 				// Workaround for dlang issue 21542
352 				storage.tupleof[tid] = __ctfe ? value : forward!value;
353 			} else {
354 				storage.tupleof[tid] = forward!value;
355 			}
356 
357 			tag = tid;
358 		}
359 
360 		static if (isCopyable!(const(T))) {
361 			// Avoid defining the same constructor multiple times
362 			static if (IndexOf!(const(T), Map!(ConstOf, Types)) == tid) {
363 				/// ditto
364 				this(const(T) value) const
365 				{
366 					storage.tupleof[tid] = value;
367 					tag = tid;
368 				}
369 			}
370 		} else {
371 			@disable this(const(T) value) const;
372 		}
373 
374 		static if (isCopyable!(immutable(T))) {
375 			static if (IndexOf!(immutable(T), Map!(ImmutableOf, Types)) == tid) {
376 				/// ditto
377 				this(immutable(T) value) immutable
378 				{
379 					storage.tupleof[tid] = value;
380 					tag = tid;
381 				}
382 			}
383 		} else {
384 			@disable this(immutable(T) value) immutable;
385 		}
386 
387 		static if (isCopyable!(inout(T))) {
388 			static if (IndexOf!(inout(T), Map!(InoutOf, Types)) == tid) {
389 				/// ditto
390 				this(Value)(Value value) inout
391 					if (is(Value == DeducedParameterType!(inout(T))))
392 				{
393 					storage.tupleof[tid] = value;
394 					tag = tid;
395 				}
396 			}
397 		} else {
398 			@disable this(Value)(Value value) inout
399 				if (is(Value == DeducedParameterType!(inout(T))));
400 		}
401 	}
402 
403 	static if (anySatisfy!(hasElaborateCopyConstructor, Types)) {
404 		static if (
405 			allSatisfy!(isCopyable, Map!(InoutOf, Types))
406 			&& !anySatisfy!(hasPostblit, Map!(InoutOf, Types))
407 			&& allSatisfy!(isInout, Map!(InoutOf, Types))
408 		) {
409 			/// Constructs a `SumType` that's a copy of another `SumType`.
410 			this(ref inout(SumType) other) inout
411 			{
412 				storage = other.match!((ref value) {
413 					alias OtherTypes = Map!(InoutOf, Types);
414 					enum tid = IndexOf!(typeof(value), OtherTypes);
415 
416 					mixin("inout(Storage) newStorage = { ",
417 						memberName!tid, ": value",
418 					" };");
419 
420 					return newStorage;
421 				});
422 
423 				tag = other.tag;
424 			}
425 		} else {
426 			static if (allSatisfy!(isCopyable, Types)) {
427 				/// ditto
428 				this(ref SumType other)
429 				{
430 					storage = other.match!((ref value) {
431 						enum tid = IndexOf!(typeof(value), Types);
432 
433 						mixin("Storage newStorage = { ",
434 							memberName!tid, ": value",
435 						" };");
436 
437 						return newStorage;
438 					});
439 
440 					tag = other.tag;
441 				}
442 			} else {
443 				@disable this(ref SumType other);
444 			}
445 
446 			static if (allSatisfy!(isCopyable, Map!(ConstOf, Types))) {
447 				/// ditto
448 				this(ref const(SumType) other) const
449 				{
450 					storage = other.match!((ref value) {
451 						alias OtherTypes = Map!(ConstOf, Types);
452 						enum tid = IndexOf!(typeof(value), OtherTypes);
453 
454 						mixin("const(Storage) newStorage = { ",
455 							memberName!tid, ": value",
456 						" };");
457 
458 						return newStorage;
459 					});
460 
461 					tag = other.tag;
462 				}
463 			} else {
464 				@disable this(ref const(SumType) other) const;
465 			}
466 
467 			static if (allSatisfy!(isCopyable, Map!(ImmutableOf, Types))) {
468 				/// ditto
469 				this(ref immutable(SumType) other) immutable
470 				{
471 					storage = other.match!((ref value) {
472 						alias OtherTypes = Map!(ImmutableOf, Types);
473 						enum tid = IndexOf!(typeof(value), OtherTypes);
474 
475 						mixin("immutable(Storage) newStorage = { ",
476 							memberName!tid, ": 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 			 * If any of the `SumType`'s members other than the one being assigned
500 			 * to contain pointers or references, it is possible for the assignment
501 			 * to cause memory corruption (see the
502 			 * ["Memory corruption" example](#memory-corruption) below for an
503 			 * illustration of how). Therefore, such assignments are considered
504 			 * `@system`.
505 			 *
506 			 * An individual assignment can be `@trusted` if the caller can
507 			 * guarantee that there are no outstanding references to any `SumType`
508 			 * members that contain pointers or references at the time the
509 			 * assignment occurs.
510 			 *
511 			 * Examples:
512 			 *
513 			 * $(H3 Memory corruption)
514 			 *
515 			 * This example shows how assignment to a `SumType` can be used to
516 			 * cause memory corruption in `@system` code. In `@safe` code, the
517 			 * assignment `s = 123` would not be allowed.
518 			 *
519 			 * ---
520 			 * SumType!(int*, int) s = new int;
521 			 * s.tryMatch!(
522 			 *     (ref int* p) {
523 			 *         s = 123; // overwrites `p`
524 			 *         return *p; // undefined behavior
525 			 *     }
526 			 * );
527 			 * ---
528 			 */
529 			ref SumType opAssign(T rhs)
530 			{
531 				import core.lifetime: forward;
532 				import std.traits: hasIndirections, hasNested;
533 				import std.meta: AliasSeq, Or = templateOr;
534 
535 				alias OtherTypes =
536 					AliasSeq!(Types[0 .. tid], Types[tid + 1 .. $]);
537 				enum unsafeToOverwrite =
538 					anySatisfy!(Or!(hasIndirections, hasNested), OtherTypes);
539 
540 				static if (unsafeToOverwrite) {
541 					cast(void) () @system {}();
542 				}
543 
544 				this.match!destroyIfOwner;
545 
546 				static if (isCopyable!T) {
547 					// Workaround for dlang issue 21542
548 					mixin("Storage newStorage = { ",
549 						memberName!tid, ": __ctfe ? rhs : forward!rhs",
550 					" };");
551 				} else {
552 					mixin("Storage newStorage = { ",
553 						memberName!tid, ": forward!rhs",
554 					" };");
555 				}
556 
557 				storage = newStorage;
558 				tag = tid;
559 
560 				return this;
561 			}
562 		}
563 	}
564 
565 	static if (allSatisfy!(isAssignableTo, Types)) {
566 		static if (allSatisfy!(isCopyable, Types)) {
567 			/**
568 			 * Copies the value from another `SumType` into this one.
569 			 *
570 			 * See the value-assignment overload for details on `@safe`ty.
571 			 *
572 			 * Copy assignment is `@disable`d if any of `Types` is non-copyable.
573 			 */
574 			ref SumType opAssign(ref SumType rhs)
575 			{
576 				rhs.match!((ref value) { this = value; });
577 				return this;
578 			}
579 		} else {
580 			@disable ref SumType opAssign(ref SumType rhs);
581 		}
582 
583 		/**
584 		 * Moves the value from another `SumType` into this one.
585 		 *
586 		 * See the value-assignment overload for details on `@safe`ty.
587 		 */
588 		ref SumType opAssign(SumType rhs)
589 		{
590 			import core.lifetime: move;
591 
592 			rhs.match!((ref value) {
593 				static if (isCopyable!(typeof(value))) {
594 					// Workaround for dlang issue 21542
595 					this = __ctfe ? value : move(value);
596 				} else {
597 					this = move(value);
598 				}
599 			});
600 			return this;
601 		}
602 	}
603 
604 	/**
605 	 * Compares two `SumType`s for equality.
606 	 *
607 	 * Two `SumType`s are equal if they are the same kind of `SumType`, they
608 	 * contain values of the same type, and those values are equal.
609 	 */
610 	bool opEquals(this This, Rhs)(auto ref Rhs rhs)
611 		if (!is(CommonType!(This, Rhs) == void))
612 	{
613 		static if (is(This == Rhs)) {
614 			return AliasSeq!(this, rhs).match!((ref value, ref rhsValue) {
615 				static if (is(typeof(value) == typeof(rhsValue))) {
616 					return value == rhsValue;
617 				} else {
618 					return false;
619 				}
620 			});
621 		} else {
622 			alias CommonSumType = CommonType!(This, Rhs);
623 			return cast(CommonSumType) this == cast(CommonSumType) rhs;
624 		}
625 	}
626 
627 	// Workaround for dlang issue 19407
628 	static if (__traits(compiles, anySatisfy!(hasElaborateDestructor, Types))) {
629 		// If possible, include the destructor only when it's needed
630 		private enum includeDtor = anySatisfy!(hasElaborateDestructor, Types);
631 	} else {
632 		// If we can't tell, always include it, even when it does nothing
633 		private enum includeDtor = true;
634 	}
635 
636 	static if (includeDtor) {
637 		/// Calls the destructor of the `SumType`'s current value.
638 		~this()
639 		{
640 			this.match!destroyIfOwner;
641 		}
642 	}
643 
644 	version (D_BetterC) {} else
645 	/**
646 	 * Returns a string representation of the `SumType`'s current value.
647 	 *
648 	 * Not available when compiled with `-betterC`.
649 	 */
650 	string toString(this This)()
651 	{
652 		import std.conv: to;
653 
654 		return this.match!(to!string);
655 	}
656 
657 	version (D_BetterC) {} else
658 	/**
659 	 * Handles formatted writing of the `SumType`'s current value.
660 	 *
661 	 * Not available when compiled with `-betterC`.
662 	 *
663 	 * Params:
664 	 *   sink = Output range to write to.
665 	 *   fmt = Format specifier to use.
666 	 *
667 	 * See_Also: `std.format.formatValue`
668 	 */
669 	void toString(this This, Sink, Char)(ref Sink sink, const ref FormatSpec!Char fmt)
670 	{
671 		import std.format: formatValue;
672 
673 		this.match!((ref value) {
674 			formatValue(sink, value, fmt);
675 		});
676 	}
677 
678 	static if (allSatisfy!(isHashable, Map!(ConstOf, Types))) {
679 		// Workaround for dlang issue 20095
680 		version (D_BetterC) {} else
681 		/**
682 		 * Returns the hash of the `SumType`'s current value.
683 		 *
684 		 * Not available when compiled with `-betterC`.
685 		 */
686 		size_t toHash() const
687 		{
688 			return this.match!hashOf;
689 		}
690 	}
691 
692 	/**
693 	 * Returns the index of the type of the `SumType`'s current value in the
694 	 * `SumType`'s [Types].
695 	 *
696 	 * If the `SumType` is qualified, returns the index of the type in [Types]
697 	 * whose qualified version matches the `SumType`'s current value.
698 	 */
699 	size_t typeIndex() const
700 	{
701 		return tag;
702 	}
703 }
704 
705 // Construction
706 @safe unittest {
707 	alias MySum = SumType!(int, float);
708 
709 	assert(__traits(compiles, MySum(42)));
710 	assert(__traits(compiles, MySum(3.14)));
711 }
712 
713 // Assignment
714 @safe unittest {
715 	alias MySum = SumType!(int, float);
716 
717 	MySum x = MySum(42);
718 
719 	assert(__traits(compiles, x = 3.14));
720 }
721 
722 // Self assignment
723 @safe unittest {
724 	alias MySum = SumType!(int, float);
725 
726 	MySum x = MySum(42);
727 	MySum y = MySum(3.14);
728 
729 	assert(__traits(compiles, y = x));
730 }
731 
732 // Equality
733 @safe unittest {
734 	alias MySum = SumType!(int, float);
735 
736 	assert(MySum(123) == MySum(123));
737 	assert(MySum(123) != MySum(456));
738 	assert(MySum(123) != MySum(123.0));
739 	assert(MySum(123) != MySum(456.0));
740 
741 }
742 
743 // Equality of differently-qualified SumTypes
744 // Disabled in BetterC due to use of dynamic arrays
745 version (D_BetterC) {} else
746 @safe unittest {
747 	alias SumA = SumType!(int, float);
748 	alias SumB = SumType!(const(int[]), int[]);
749 	alias SumC = SumType!(int[], const(int[]));
750 
751 	int[] ma = [1, 2, 3];
752 	const(int[]) ca = [1, 2, 3];
753 
754 	assert(const(SumA)(123) == SumA(123));
755 	assert(const(SumB)(ma[]) == SumB(ca[]));
756 	assert(const(SumC)(ma[]) == SumC(ca[]));
757 }
758 
759 // Imported types
760 @safe unittest {
761 	import std.typecons: Tuple;
762 
763 	assert(__traits(compiles, {
764 		alias MySum = SumType!(Tuple!(int, int));
765 	}));
766 }
767 
768 // const and immutable types
769 @safe unittest {
770 	assert(__traits(compiles, {
771 		alias MySum = SumType!(const(int[]), immutable(float[]));
772 	}));
773 }
774 
775 // Recursive types
776 @safe unittest {
777 	alias MySum = SumType!(This*);
778 	assert(is(MySum.Types[0] == MySum*));
779 }
780 
781 // Allowed types
782 @safe unittest {
783 	import std.meta: AliasSeq;
784 
785 	alias MySum = SumType!(int, float, This*);
786 
787 	assert(is(MySum.Types == AliasSeq!(int, float, MySum*)));
788 }
789 
790 // Types with destructors and postblits
791 @system unittest {
792 	int copies;
793 
794 	static struct Test
795 	{
796 		bool initialized = false;
797 		int* copiesPtr;
798 
799 		this(this) { (*copiesPtr)++; }
800 		~this() { if (initialized) (*copiesPtr)--; }
801 	}
802 
803 	alias MySum = SumType!(int, Test);
804 
805 	Test t = Test(true, &copies);
806 
807 	{
808 		MySum x = t;
809 		assert(copies == 1);
810 	}
811 	assert(copies == 0);
812 
813 	{
814 		MySum x = 456;
815 		assert(copies == 0);
816 	}
817 	assert(copies == 0);
818 
819 	{
820 		MySum x = t;
821 		assert(copies == 1);
822 		x = 456;
823 		assert(copies == 0);
824 	}
825 
826 	{
827 		MySum x = 456;
828 		assert(copies == 0);
829 		x = t;
830 		assert(copies == 1);
831 	}
832 
833 	{
834 		MySum x = t;
835 		MySum y = x;
836 		assert(copies == 2);
837 	}
838 
839 	{
840 		MySum x = t;
841 		MySum y;
842 		y = x;
843 		assert(copies == 2);
844 	}
845 }
846 
847 // Doesn't destroy reference types
848 // Disabled in BetterC due to use of classes
849 version (D_BetterC) {} else
850 @system unittest {
851 	bool destroyed;
852 
853 	class C
854 	{
855 		~this()
856 		{
857 			destroyed = true;
858 		}
859 	}
860 
861 	struct S
862 	{
863 		~this() {}
864 	}
865 
866 	alias MySum = SumType!(S, C);
867 
868 	C c = new C();
869 	{
870 		MySum x = c;
871 		destroyed = false;
872 	}
873 	assert(!destroyed);
874 
875 	{
876 		MySum x = c;
877 		destroyed = false;
878 		x = S();
879 		assert(!destroyed);
880 	}
881 }
882 
883 // Types with @disable this()
884 @safe unittest {
885 	static struct NoInit
886 	{
887 		@disable this();
888 	}
889 
890 	alias MySum = SumType!(NoInit, int);
891 
892 	assert(!__traits(compiles, MySum()));
893 	assert(__traits(compiles, MySum(42)));
894 	auto x = MySum(42);
895 }
896 
897 // const SumTypes
898 @safe unittest {
899 	assert(__traits(compiles,
900 		const(SumType!(int[]))([1, 2, 3])
901 	));
902 }
903 
904 // Equality of const SumTypes
905 @safe unittest {
906 	alias MySum = SumType!int;
907 
908 	assert(__traits(compiles,
909 		const(MySum)(123) == const(MySum)(456)
910 	));
911 }
912 
913 // Compares reference types using value equality
914 @safe unittest {
915 	import std.array: staticArray;
916 
917 	static struct Field {}
918 	static struct Struct { Field[] fields; }
919 	alias MySum = SumType!Struct;
920 
921 	static arr1 = staticArray([Field()]);
922 	static arr2 = staticArray([Field()]);
923 
924 	auto a = MySum(Struct(arr1[]));
925 	auto b = MySum(Struct(arr2[]));
926 
927 	assert(a == b);
928 }
929 
930 // toString
931 // Disabled in BetterC due to use of std.conv.text
932 version (D_BetterC) {} else
933 @safe unittest {
934 	import std.conv: text;
935 
936 	static struct Int { int i; }
937 	static struct Double { double d; }
938 	alias Sum = SumType!(Int, Double);
939 
940 	assert(Sum(Int(42)).text == Int(42).text, Sum(Int(42)).text);
941 	assert(Sum(Double(33.3)).text == Double(33.3).text, Sum(Double(33.3)).text);
942 	assert((const(Sum)(Int(42))).text == (const(Int)(42)).text, (const(Sum)(Int(42))).text);
943 }
944 
945 // string formatting
946 // Disabled in BetterC due to use of std.format.format
947 version (D_BetterC) {} else
948 @safe unittest {
949 	import std.format: format;
950 
951 	SumType!int x = 123;
952 
953 	assert(format!"%s"(x) == format!"%s"(123));
954 	assert(format!"%x"(x) == format!"%x"(123));
955 }
956 
957 // string formatting of qualified SumTypes
958 // Disabled in BetterC due to use of std.format.format and dynamic arrays
959 version (D_BetterC) {} else
960 @safe unittest {
961 	import std.format: format;
962 
963 	int[] a = [1, 2, 3];
964 	const(SumType!(int[])) x = a;
965 
966 	assert(format!"%(%d, %)"(x) == format!"%(%s, %)"(a));
967 }
968 
969 // Github issue #16
970 // Disabled in BetterC due to use of dynamic arrays
971 version (D_BetterC) {} else
972 @safe unittest {
973 	alias Node = SumType!(This[], string);
974 
975 	// override inference of @system attribute for cyclic functions
976 	assert((() @trusted =>
977 		Node([Node([Node("x")])])
978 		==
979 		Node([Node([Node("x")])])
980 	)());
981 }
982 
983 // Github issue #16 with const
984 // Disabled in BetterC due to use of dynamic arrays
985 version (D_BetterC) {} else
986 @safe unittest {
987 	alias Node = SumType!(const(This)[], string);
988 
989 	// override inference of @system attribute for cyclic functions
990 	assert((() @trusted =>
991 		Node([Node([Node("x")])])
992 		==
993 		Node([Node([Node("x")])])
994 	)());
995 }
996 
997 // Stale pointers
998 // Disabled in BetterC due to use of dynamic arrays
999 version (D_BetterC) {} else
1000 @system unittest {
1001 	alias MySum = SumType!(ubyte, void*[2]);
1002 
1003 	MySum x = [null, cast(void*) 0x12345678];
1004 	void** p = &x.getByIndex!1[1];
1005 	x = ubyte(123);
1006 
1007 	assert(*p != cast(void*) 0x12345678);
1008 }
1009 
1010 // Exception-safe assignment
1011 // Disabled in BetterC due to use of exceptions
1012 version (D_BetterC) {} else
1013 @safe unittest {
1014 	static struct A
1015 	{
1016 		int value = 123;
1017 	}
1018 
1019 	static struct B
1020 	{
1021 		int value = 456;
1022 		this(this) { throw new Exception("oops"); }
1023 	}
1024 
1025 	alias MySum = SumType!(A, B);
1026 
1027 	MySum x;
1028 	try {
1029 		x = B();
1030 	} catch (Exception e) {}
1031 
1032 	assert(
1033 		(x.tag == 0 && x.getByIndex!0.value == 123) ||
1034 		(x.tag == 1 && x.getByIndex!1.value == 456)
1035 	);
1036 }
1037 
1038 // Types with @disable this(this)
1039 @safe unittest {
1040 	import core.lifetime: move;
1041 
1042 	static struct NoCopy
1043 	{
1044 		@disable this(this);
1045 	}
1046 
1047 	alias MySum = SumType!NoCopy;
1048 
1049 	NoCopy lval = NoCopy();
1050 
1051 	MySum x = NoCopy();
1052 	MySum y = NoCopy();
1053 
1054 	assert(__traits(compiles, SumType!NoCopy(NoCopy())));
1055 	assert(!__traits(compiles, SumType!NoCopy(lval)));
1056 
1057 	assert(__traits(compiles, y = NoCopy()));
1058 	assert(__traits(compiles, y = move(x)));
1059 	assert(!__traits(compiles, y = lval));
1060 	assert(!__traits(compiles, y = x));
1061 
1062 	assert(__traits(compiles, x == y));
1063 }
1064 
1065 // Github issue #22
1066 // Disabled in BetterC due to use of std.typecons.Nullable
1067 version (D_BetterC) {} else
1068 @safe unittest {
1069 	import std.typecons;
1070 	assert(__traits(compiles, {
1071 		static struct A {
1072 			SumType!(Nullable!int) a = Nullable!int.init;
1073 		}
1074 	}));
1075 }
1076 
1077 // Static arrays of structs with postblits
1078 // Disabled in BetterC due to use of dynamic arrays
1079 version (D_BetterC) {} else
1080 @safe unittest {
1081 	static struct S
1082 	{
1083 		int n;
1084 		this(this) { n++; }
1085 	}
1086 
1087 	assert(__traits(compiles, SumType!(S[1])()));
1088 
1089 	SumType!(S[1]) x = [S(0)];
1090 	SumType!(S[1]) y = x;
1091 
1092 	auto xval = x.getByIndex!0[0].n;
1093 	auto yval = y.getByIndex!0[0].n;
1094 
1095 	assert(xval != yval);
1096 }
1097 
1098 // Replacement does not happen inside SumType
1099 // Disabled in BetterC due to use of associative arrays
1100 version (D_BetterC) {} else
1101 @safe unittest {
1102 	import std.typecons : Tuple, ReplaceTypeUnless;
1103 	alias A = Tuple!(This*,SumType!(This*))[SumType!(This*,string)[This]];
1104 	alias TR = ReplaceTypeUnless!(isSumTypeInstance, This, int, A);
1105 	static assert(is(TR == Tuple!(int*,SumType!(This*))[SumType!(This*, string)[int]]));
1106 }
1107 
1108 // Supports nested self-referential SumTypes
1109 @safe unittest {
1110 	import std.typecons : Tuple, Flag;
1111 	alias Nat = SumType!(Flag!"0", Tuple!(This*));
1112 	static assert(__traits(compiles, SumType!(Nat)));
1113 	static assert(__traits(compiles, SumType!(Nat*, Tuple!(This*, This*))));
1114 }
1115 
1116 // Self-referential SumTypes inside Algebraic
1117 // Disabled in BetterC due to use of std.variant.Algebraic
1118 version (D_BetterC) {} else
1119 @safe unittest {
1120 	import std.variant: Algebraic;
1121 
1122 	alias T = Algebraic!(SumType!(This*));
1123 
1124 	assert(is(T.AllowedTypes[0].Types[0] == T.AllowedTypes[0]*));
1125 }
1126 
1127 // Doesn't call @system postblits in @safe code
1128 @safe unittest {
1129 	static struct SystemCopy { @system this(this) {} }
1130 	SystemCopy original;
1131 
1132 	assert(!__traits(compiles, () @safe {
1133 		SumType!SystemCopy copy = original;
1134 	}));
1135 
1136 	assert(!__traits(compiles, () @safe {
1137 		SumType!SystemCopy copy; copy = original;
1138 	}));
1139 }
1140 
1141 // Doesn't overwrite pointers in @safe code
1142 @safe unittest {
1143 	alias MySum = SumType!(int*, int);
1144 
1145 	MySum x;
1146 
1147 	assert(!__traits(compiles, () @safe {
1148 		x = 123;
1149 	}));
1150 
1151 	assert(!__traits(compiles, () @safe {
1152 		x = MySum(123);
1153 	}));
1154 }
1155 
1156 // Calls value postblit on self-assignment
1157 @safe unittest {
1158 	static struct S
1159 	{
1160 		int n;
1161 		this(this) { n++; }
1162 	}
1163 
1164 	SumType!S x = S();
1165 	SumType!S y;
1166 	y = x;
1167 
1168 	auto xval = x.getByIndex!0.n;
1169 	auto yval = y.getByIndex!0.n;
1170 
1171 	assert(xval != yval);
1172 }
1173 
1174 // Github issue #29
1175 @safe unittest {
1176 	assert(__traits(compiles, () @safe {
1177 		alias A = SumType!string;
1178 
1179 		@safe A createA(string arg) {
1180 		return A(arg);
1181 		}
1182 
1183 		@safe void test() {
1184 		A a = createA("");
1185 		}
1186 	}));
1187 }
1188 
1189 // SumTypes as associative array keys
1190 // Disabled in BetterC due to use of associative arrays
1191 version (D_BetterC) {} else
1192 @safe unittest {
1193 	assert(__traits(compiles, {
1194 		int[SumType!(int, string)] aa;
1195 	}));
1196 }
1197 
1198 // toString with non-copyable types
1199 // Disabled in BetterC due to use of std.conv.to (in toString)
1200 version (D_BetterC) {} else
1201 @safe unittest {
1202 	struct NoCopy
1203 	{
1204 		@disable this(this);
1205 	}
1206 
1207 	SumType!NoCopy x;
1208 
1209 	assert(__traits(compiles, x.toString()));
1210 }
1211 
1212 // Can use the result of assignment
1213 @safe unittest {
1214 	alias MySum = SumType!(int, float);
1215 
1216 	MySum a = MySum(123);
1217 	MySum b = MySum(3.14);
1218 
1219 	assert((a = b) == b);
1220 	assert((a = MySum(123)) == MySum(123));
1221 	assert((a = 3.14) == MySum(3.14));
1222 	assert(((a = b) = MySum(123)) == MySum(123));
1223 }
1224 
1225 // Types with copy constructors
1226 @safe unittest {
1227 	static struct S
1228 	{
1229 		int n;
1230 
1231 		this(ref return scope inout S other) inout
1232 		{
1233 			n = other.n + 1;
1234 		}
1235 	}
1236 
1237 	SumType!S x = S();
1238 	SumType!S y = x;
1239 
1240 	auto xval = x.getByIndex!0.n;
1241 	auto yval = y.getByIndex!0.n;
1242 
1243 	assert(xval != yval);
1244 }
1245 
1246 // Copyable by generated copy constructors
1247 @safe unittest {
1248 	static struct Inner
1249 	{
1250 		ref this(ref inout Inner other) {}
1251 	}
1252 
1253 	static struct Outer
1254 	{
1255 		SumType!Inner inner;
1256 	}
1257 
1258 	Outer x;
1259 	Outer y = x;
1260 }
1261 
1262 // Types with qualified copy constructors
1263 @safe unittest {
1264 	static struct ConstCopy
1265 	{
1266 		int n;
1267 		this(inout int n) inout { this.n = n; }
1268 		this(ref const typeof(this) other) const { this.n = other.n; }
1269 	}
1270 
1271 	static struct ImmutableCopy
1272 	{
1273 		int n;
1274 		this(inout int n) inout { this.n = n; }
1275 		this(ref immutable typeof(this) other) immutable { this.n = other.n; }
1276 	}
1277 
1278 	const SumType!ConstCopy x = const(ConstCopy)(1);
1279 	immutable SumType!ImmutableCopy y = immutable(ImmutableCopy)(1);
1280 }
1281 
1282 // Types with disabled opEquals
1283 @safe unittest {
1284 	static struct S
1285 	{
1286 		@disable bool opEquals(const S rhs) const;
1287 	}
1288 
1289 	assert(__traits(compiles, SumType!S(S())));
1290 }
1291 
1292 // Types with non-const opEquals
1293 @safe unittest {
1294 	static struct S
1295 	{
1296 		int i;
1297 		bool opEquals(S rhs) { return i == rhs.i; }
1298 	}
1299 
1300 	assert(__traits(compiles, SumType!S(S(123))));
1301 }
1302 
1303 // Incomparability of different SumTypes
1304 @safe unittest {
1305 	SumType!(int, string) x = 123;
1306 	SumType!(string, int) y = 123;
1307 
1308 	assert(!__traits(compiles, x != y));
1309 }
1310 
1311 // Self-reference in return/parameter type of function pointer member
1312 @safe unittest {
1313 	assert(__traits(compiles, {
1314 		alias T = SumType!(int, This delegate(This));
1315 	}));
1316 }
1317 
1318 // Construction and assignment from implicitly-convertible lvalue
1319 @safe unittest {
1320 	alias MySum = SumType!bool;
1321 
1322 	const(bool) b = true;
1323 
1324 	assert(__traits(compiles, { MySum x = b; }));
1325 	assert(__traits(compiles, { MySum x; x = b; }));
1326 }
1327 
1328 // Type index
1329 @safe unittest {
1330 	alias MySum = SumType!(int, float);
1331 
1332 	static bool isIndexOf(Target, Types...)(size_t i)
1333 	{
1334 		switch (i) {
1335 			static foreach (tid, T; Types)
1336 				case tid: return is(T == Target);
1337 			default: return false;
1338 		}
1339 	}
1340 
1341 	assert(isIndexOf!(int, MySum.Types)(MySum(42).typeIndex));
1342 	assert(isIndexOf!(float, MySum.Types)(MySum(3.14).typeIndex));
1343 }
1344 
1345 // Type index for qualified SumTypes
1346 // Disabled in BetterC due to use of dynamic arrays
1347 version (D_BetterC) {} else
1348 @safe unittest {
1349 	alias MySum = SumType!(const(int[]), int[]);
1350 
1351 	static bool isIndexOf(Target, Types...)(size_t i)
1352 	{
1353 		switch (i) {
1354 			static foreach (tid, T; Types)
1355 				case tid: return is(T == Target);
1356 			default: return false;
1357 		}
1358 	}
1359 
1360 	int[] ma = [1, 2, 3];
1361 	// Construct as mutable and convert to const to get mismatched type + tag
1362 	auto x = MySum(ma);
1363 	const y = MySum(ma);
1364 	auto z = const(MySum)(ma);
1365 
1366 	assert(isIndexOf!(int[], MySum.Types)(x.typeIndex));
1367 	assert(isIndexOf!(const(int[]), Map!(ConstOf, MySum.Types))(y.typeIndex));
1368 	assert(isIndexOf!(const(int[]), Map!(ConstOf, MySum.Types))(z.typeIndex));
1369 }
1370 
1371 // Type index for differently-qualified versions of the same SumType
1372 // Disabled in BetterC due to use of dynamic arrays
1373 version (D_BetterC) {} else
1374 @safe unittest {
1375 	alias MySum = SumType!(const(int[]), int[]);
1376 
1377 	int[] ma = [1, 2, 3];
1378 	auto x = MySum(ma);
1379 	const y = x;
1380 
1381 	assert(x.typeIndex == y.typeIndex);
1382 }
1383 
1384 // @safe assignment to the only pointer in a SumType
1385 @safe unittest {
1386 	SumType!(string, int) sm = 123;
1387 
1388 	assert(__traits(compiles, () @safe {
1389 		sm = "this should be @safe";
1390 	}));
1391 }
1392 
1393 // Pointers to local variables
1394 @safe unittest {
1395 	enum haveDip1000 = __traits(compiles, () @safe {
1396 		int n;
1397 		int* p = &n;
1398 	});
1399 
1400 	static if (haveDip1000) {
1401 		int n = 123;
1402 		immutable int ni = 456;
1403 
1404 		SumType!(int*) s = &n;
1405 		const SumType!(int*) sc = &n;
1406 		immutable SumType!(int*) si = &ni;
1407 	}
1408 }
1409 
1410 // Dlang issue 22572: immutable member type with copy constructor
1411 @safe unittest {
1412 	static struct CopyConstruct
1413 	{
1414 		this(ref inout CopyConstruct other) inout {}
1415 	}
1416 
1417 	static immutable struct Value
1418 	{
1419 		CopyConstruct c;
1420 	}
1421 
1422 	SumType!Value s;
1423 }
1424 
1425 // Construction of inout-qualified SumTypes
1426 @safe unittest {
1427 	static inout(SumType!(int[])) example(inout(int[]) arr)
1428 	{
1429 		return inout(SumType!(int[]))(arr);
1430 	}
1431 }
1432 
1433 // Assignment of struct with overloaded opAssign in CTFE
1434 @safe unittest {
1435 	static struct HasOpAssign
1436 	{
1437 		void opAssign(HasOpAssign rhs) {}
1438 	}
1439 
1440 	static SumType!HasOpAssign test()
1441 	{
1442 		SumType!HasOpAssign s;
1443 		// Test both overloads
1444 		s = HasOpAssign();
1445 		s = SumType!HasOpAssign();
1446 		return s;
1447 	}
1448 
1449 	enum result = test();
1450 }
1451 
1452 /// True if `T` is an instance of the `SumType` template, otherwise false.
1453 private enum bool isSumTypeInstance(T) = is(T == SumType!Args, Args...);
1454 
1455 @safe unittest {
1456 	static struct Wrapper
1457 	{
1458 		SumType!int s;
1459 		alias s this;
1460 	}
1461 
1462 	assert(isSumTypeInstance!(SumType!int));
1463 	assert(!isSumTypeInstance!Wrapper);
1464 }
1465 
1466 /// True if `T` is a [SumType] or implicitly converts to one, otherwise false.
1467 template isSumType(T)
1468 {
1469 	static if (is(T : SumType!Args, Args...)) {
1470 		enum isSumType = true;
1471 	} else static if (is(T == struct) && __traits(getAliasThis, T).length > 0) {
1472 		// Workaround for dlang issue 21975
1473 		import std.traits: ReturnType;
1474 
1475 		alias AliasThisType = ReturnType!((T t) =>
1476 			__traits(getMember, t, __traits(getAliasThis, T)[0])
1477 		);
1478 		enum isSumType = .isSumType!AliasThisType;
1479 	} else {
1480 		enum isSumType = false;
1481 	}
1482 }
1483 
1484 ///
1485 @safe unittest {
1486 	static struct ConvertsToSumType
1487 	{
1488 		SumType!int payload;
1489 		alias payload this;
1490 	}
1491 
1492 	static struct ContainsSumType
1493 	{
1494 		SumType!int payload;
1495 	}
1496 
1497 	assert(isSumType!(SumType!int));
1498 	assert(isSumType!ConvertsToSumType);
1499 	assert(!isSumType!ContainsSumType);
1500 }
1501 
1502 @safe unittest {
1503 	static struct AliasThisVar(T)
1504 	{
1505 		SumType!T payload;
1506 		alias payload this;
1507 	}
1508 
1509 	static struct AliasThisFunc(T)
1510 	{
1511 		SumType!T payload;
1512 		ref get() { return payload; }
1513 		alias get this;
1514 	}
1515 
1516 	static assert(isSumType!(AliasThisVar!int));
1517 	static assert(isSumType!(AliasThisFunc!int));
1518 }
1519 
1520 /**
1521  * Calls a type-appropriate function with the value held in a [SumType].
1522  *
1523  * For each possible type the [SumType] can hold, the given handlers are
1524  * checked, in order, to see whether they accept a single argument of that type.
1525  * The first one that does is chosen as the match for that type. (Note that the
1526  * first match may not always be the most exact match.
1527  * See [#avoiding-unintentional-matches|"Avoiding unintentional matches"] for
1528  * one common pitfall.)
1529  *
1530  * Every type must have a matching handler, and every handler must match at
1531  * least one type. This is enforced at compile time.
1532  *
1533  * Handlers may be functions, delegates, or objects with `opCall` overloads. If
1534  * a function with more than one overload is given as a handler, all of the
1535  * overloads are considered as potential matches.
1536  *
1537  * Templated handlers are also accepted, and will match any type for which they
1538  * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
1539  * [sumtype#introspection-based-matching|"Introspection-based matching"] for an
1540  * example of templated handler usage.
1541  *
1542  * If multiple [SumType]s are passed to `match`, their values are passed to the
1543  * handlers as separate arguments, and matching is done for each possible
1544  * combination of value types. See [#multiple-dispatch|"Multiple dispatch"] for
1545  * an example.
1546  *
1547  * Returns:
1548  *   The value returned from the handler that matches the currently-held type.
1549  *
1550  * See_Also: `std.variant.visit`
1551  */
1552 template match(handlers...)
1553 {
1554 	import std.typecons: Yes;
1555 
1556 	/**
1557 	 * The actual `match` function.
1558 	 *
1559 	 * Params:
1560 	 *   args = One or more [SumType] objects.
1561 	 */
1562 	auto ref match(SumTypes...)(auto ref SumTypes args)
1563 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1564 	{
1565 		return matchImpl!(Yes.exhaustive, handlers)(args);
1566 	}
1567 }
1568 
1569 /** $(H3 Avoiding unintentional matches)
1570  *
1571  * Sometimes, implicit conversions may cause a handler to match more types than
1572  * intended. The example below shows two solutions to this problem.
1573  */
1574 @safe unittest {
1575     alias Number = SumType!(double, int);
1576 
1577     Number x;
1578 
1579     // Problem: because int implicitly converts to double, the double
1580     // handler is used for both types, and the int handler never matches.
1581     assert(!__traits(compiles,
1582         x.match!(
1583             (double d) => "got double",
1584             (int n) => "got int"
1585         )
1586     ));
1587 
1588     // Solution 1: put the handler for the "more specialized" type (in this
1589     // case, int) before the handler for the type it converts to.
1590     assert(__traits(compiles,
1591         x.match!(
1592             (int n) => "got int",
1593             (double d) => "got double"
1594         )
1595     ));
1596 
1597     // Solution 2: use a template that only accepts the exact type it's
1598     // supposed to match, instead of any type that implicitly converts to it.
1599     alias exactly(T, alias fun) = function (arg) {
1600         static assert(is(typeof(arg) == T));
1601         return fun(arg);
1602     };
1603 
1604     // Now, even if we put the double handler first, it will only be used for
1605     // doubles, not ints.
1606     assert(__traits(compiles,
1607         x.match!(
1608             exactly!(double, d => "got double"),
1609             exactly!(int, n => "got int")
1610         )
1611     ));
1612 }
1613 
1614 /** $(H3 Multiple dispatch)
1615  *
1616  * Pattern matching can be performed on multiple `SumType`s at once by passing
1617  * handlers with multiple arguments. This usually leads to more concise code
1618  * than using nested calls to `match`, as show below.
1619  */
1620 @safe unittest {
1621     struct Point2D { double x, y; }
1622     struct Point3D { double x, y, z; }
1623 
1624     alias Point = SumType!(Point2D, Point3D);
1625 
1626     version (none) {
1627         // This function works, but the code is ugly and repetitive.
1628         // It uses three separate calls to match!
1629         @safe pure nothrow @nogc
1630         bool sameDimensions(Point p1, Point p2)
1631         {
1632             return p1.match!(
1633                 (Point2D _) => p2.match!(
1634                     (Point2D _) => true,
1635                     _ => false
1636                 ),
1637                 (Point3D _) => p2.match!(
1638                     (Point3D _) => true,
1639                     _ => false
1640                 )
1641             );
1642         }
1643     }
1644 
1645     // This version is much nicer.
1646     @safe pure nothrow @nogc
1647     bool sameDimensions(Point p1, Point p2)
1648     {
1649         alias doMatch = match!(
1650             (Point2D _1, Point2D _2) => true,
1651             (Point3D _1, Point3D _2) => true,
1652             (_1, _2) => false
1653         );
1654 
1655         return doMatch(p1, p2);
1656     }
1657 
1658     Point a = Point2D(1, 2);
1659     Point b = Point2D(3, 4);
1660     Point c = Point3D(5, 6, 7);
1661     Point d = Point3D(8, 9, 0);
1662 
1663     assert( sameDimensions(a, b));
1664     assert( sameDimensions(c, d));
1665     assert(!sameDimensions(a, c));
1666     assert(!sameDimensions(d, b));
1667 }
1668 
1669 version (D_Exceptions)
1670 /**
1671  * Attempts to call a type-appropriate function with the value held in a
1672  * [SumType], and throws on failure.
1673  *
1674  * Matches are chosen using the same rules as [match], but are not required to
1675  * be exhaustive—in other words, a type (or combination of types) is allowed to
1676  * have no matching handler. If a type without a handler is encountered at
1677  * runtime, a [MatchException] is thrown.
1678  *
1679  * Not available when compiled with `-betterC`.
1680  *
1681  * Returns:
1682  *   The value returned from the handler that matches the currently-held type,
1683  *   if a handler was given for that type.
1684  *
1685  * Throws:
1686  *   [MatchException], if the currently-held type has no matching handler.
1687  *
1688  * See_Also: `std.variant.tryVisit`
1689  */
1690 template tryMatch(handlers...)
1691 {
1692 	import std.typecons: No;
1693 
1694 	/**
1695 	 * The actual `tryMatch` function.
1696 	 *
1697 	 * Params:
1698 	 *   args = One or more [SumType] objects.
1699 	 */
1700 	auto ref tryMatch(SumTypes...)(auto ref SumTypes args)
1701 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1702 	{
1703 		return matchImpl!(No.exhaustive, handlers)(args);
1704 	}
1705 }
1706 
1707 version (D_Exceptions)
1708 /**
1709  * Thrown by [tryMatch] when an unhandled type is encountered.
1710  *
1711  * Not available when compiled with `-betterC`.
1712  */
1713 class MatchException : Exception
1714 {
1715 	///
1716 	pure @safe @nogc nothrow
1717 	this(string msg, string file = __FILE__, size_t line = __LINE__)
1718 	{
1719 		super(msg, file, line);
1720 	}
1721 }
1722 
1723 /**
1724  * True if `handler` is a potential match for `Ts`, otherwise false.
1725  *
1726  * See the documentation for [match] for a full explanation of how matches are
1727  * chosen.
1728  */
1729 template canMatch(alias handler, Ts...)
1730 	if (Ts.length > 0)
1731 {
1732 	enum canMatch = is(typeof(auto ref (ref Ts args) => handler(args)));
1733 }
1734 
1735 ///
1736 @safe unittest {
1737     alias handleInt = (int i) => "got an int";
1738 
1739     assert( canMatch!(handleInt, int));
1740     assert(!canMatch!(handleInt, string));
1741 }
1742 
1743 // Includes all overloads of the given handler
1744 @safe unittest {
1745 	static struct OverloadSet
1746 	{
1747 		static void fun(int n) {}
1748 		static void fun(double d) {}
1749 	}
1750 
1751 	assert(canMatch!(OverloadSet.fun, int));
1752 	assert(canMatch!(OverloadSet.fun, double));
1753 }
1754 
1755 // Allows returning non-copyable types by ref
1756 // https://github.com/dlang/phobos/issues/10647
1757 @safe unittest {
1758 	static struct NoCopy
1759 	{
1760 		@disable this(this);
1761 	}
1762 
1763 	static NoCopy lvalue;
1764 	static ref handler(int _) => lvalue;
1765 
1766 	assert(canMatch!(handler, int));
1767 }
1768 
1769 // Like aliasSeqOf!(iota(n)), but works in BetterC
1770 private template Iota(size_t n)
1771 {
1772 	static if (n == 0) {
1773 		alias Iota = AliasSeq!();
1774 	} else {
1775 		alias Iota = AliasSeq!(Iota!(n - 1), n - 1);
1776 	}
1777 }
1778 
1779 @safe unittest {
1780 	assert(is(Iota!0 == AliasSeq!()));
1781 	assert(Iota!1 == AliasSeq!(0));
1782 	assert(Iota!3 == AliasSeq!(0, 1, 2));
1783 }
1784 
1785 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
1786 {
1787 	auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
1788 		if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
1789 	{
1790 		// Single dispatch (fast path)
1791 		static if (args.length == 1) {
1792 			/* When there's only one argument, the caseId is just that
1793 			 * argument's tag, so there's no need to use TagTuple.
1794 			 */
1795 			enum handlerArgs(size_t caseId) =
1796 				"args[0].getByIndex!(" ~ toCtString!caseId ~ ")()";
1797 
1798 			alias valueTypes(size_t caseId) =
1799 				typeof(args[0].getByIndex!(caseId)());
1800 
1801 			enum numCases = SumTypes[0].Types.length;
1802 		// Multiple dispatch (slow path)
1803 		} else {
1804 			alias typeCounts = Map!(typeCount, SumTypes);
1805 			alias stride(size_t i) = .stride!(i, typeCounts);
1806 			alias TagTuple = .TagTuple!typeCounts;
1807 
1808 			alias handlerArgs(size_t caseId) = .handlerArgs!(caseId, typeCounts);
1809 
1810 			/* An AliasSeq of the types of the member values in the argument
1811 			 * list returned by `handlerArgs!caseId`.
1812 			 *
1813 			 * Note that these are the actual (that is, qualified) types of the
1814 			 * member values, which may not be the same as the types listed in
1815 			 * the arguments' `.Types` properties.
1816 			 */
1817 			template valueTypes(size_t caseId)
1818 			{
1819 				enum tags = TagTuple.fromCaseId(caseId);
1820 
1821 				template getType(size_t i)
1822 				{
1823 					alias getType = typeof(args[i].getByIndex!(tags[i])());
1824 				}
1825 
1826 				alias valueTypes = Map!(getType, Iota!(tags.length));
1827 			}
1828 
1829 			/* The total number of cases is
1830 			 *
1831 			 *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
1832 			 *
1833 			 * Conveniently, this is equal to stride!(SumTypes.length), so we
1834 			 * can use that function to compute it.
1835 			 */
1836 			enum numCases = stride!(SumTypes.length);
1837 		}
1838 
1839 		/* Guaranteed to never be a valid handler index, since
1840 		 * handlers.length <= size_t.max.
1841 		 */
1842 		enum noMatch = size_t.max;
1843 
1844 		// An array that maps caseIds to handler indices ("hids").
1845 		enum matches = () {
1846 			size_t[numCases] matches;
1847 
1848 			// Workaround for dlang issue 19561
1849 			foreach (ref match; matches) {
1850 				match = noMatch;
1851 			}
1852 
1853 			static foreach (caseId; 0 .. numCases) {
1854 				static foreach (hid, handler; handlers) {
1855 					static if (canMatch!(handler, valueTypes!caseId)) {
1856 						if (matches[caseId] == noMatch) {
1857 							matches[caseId] = hid;
1858 						}
1859 					}
1860 				}
1861 			}
1862 
1863 			return matches;
1864 		}();
1865 
1866 		import std.algorithm.searching: canFind;
1867 
1868 		// Check for unreachable handlers
1869 		static foreach (hid, handler; handlers) {
1870 			static assert(matches[].canFind(hid),
1871 				"`handlers[" ~ toCtString!hid ~ "]` " ~
1872 				"of type `" ~ ( __traits(isTemplate, handler)
1873 					? "template"
1874 					: typeof(handler).stringof
1875 				) ~ "` " ~
1876 				"never matches. Perhaps the handler failed to compile"
1877 			);
1878 		}
1879 
1880 		// Workaround for dlang issue 19993
1881 		enum handlerName(size_t hid) = "handler" ~ toCtString!hid;
1882 
1883 		static foreach (size_t hid, handler; handlers) {
1884 			mixin("alias ", handlerName!hid, " = handler;");
1885 		}
1886 
1887 		// Single dispatch (fast path)
1888 		static if (args.length == 1) {
1889 			immutable argsId = args[0].tag;
1890 		// Multiple dispatch (slow path)
1891 		} else {
1892 			immutable argsId = TagTuple(args).toCaseId;
1893 		}
1894 
1895 		final switch (argsId) {
1896 			static foreach (caseId; 0 .. numCases) {
1897 				case caseId:
1898 					static if (matches[caseId] != noMatch) {
1899 						return mixin(handlerName!(matches[caseId]), "(", handlerArgs!caseId, ")");
1900 					} else {
1901 						static if(exhaustive) {
1902 							static assert(false,
1903 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1904 						} else {
1905 							throw new MatchException(
1906 								"No matching handler for types `" ~ valueTypes!caseId.stringof ~ "`");
1907 						}
1908 					}
1909 			}
1910 		}
1911 
1912 		assert(false, "unreachable");
1913 	}
1914 }
1915 
1916 /* A TagTuple represents a single possible set of tags that the arguments to
1917  * `matchImpl` could have at runtime.
1918  *
1919  * Because D does not allow a struct to be the controlling expression
1920  * of a switch statement, we cannot dispatch on the TagTuple directly.
1921  * Instead, we must map each TagTuple to a unique integer and generate
1922  * a case label for each of those integers.
1923  *
1924  * This mapping is implemented in `fromCaseId` and `toCaseId`. It uses
1925  * the same technique that's used to map index tuples to memory offsets
1926  * in a multidimensional static array.
1927  *
1928  * For example, when `args` consists of two SumTypes with two member
1929  * types each, the TagTuples corresponding to each case label are:
1930  *
1931  *   case 0:  TagTuple([0, 0])
1932  *   case 1:  TagTuple([1, 0])
1933  *   case 2:  TagTuple([0, 1])
1934  *   case 3:  TagTuple([1, 1])
1935  *
1936  * When there is only one argument, the caseId is equal to that
1937  * argument's tag.
1938  */
1939 private struct TagTuple(typeCounts...)
1940 {
1941 	size_t[typeCounts.length] tags;
1942 	alias tags this;
1943 
1944 	alias stride(size_t i) = .stride!(i, typeCounts);
1945 
1946 	invariant {
1947 		static foreach (i; 0 .. tags.length) {
1948 			assert(tags[i] < typeCounts[i]);
1949 		}
1950 	}
1951 
1952 	this(SumTypes...)(ref const SumTypes args)
1953 		if (allSatisfy!(isSumType, SumTypes) && args.length == typeCounts.length)
1954 	{
1955 		static foreach (i; 0 .. tags.length) {
1956 			tags[i] = args[i].tag;
1957 		}
1958 	}
1959 
1960 	static TagTuple fromCaseId(size_t caseId)
1961 	{
1962 		TagTuple result;
1963 
1964 		// Most-significant to least-significant
1965 		static foreach_reverse (i; 0 .. result.length) {
1966 			result[i] = caseId / stride!i;
1967 			caseId %= stride!i;
1968 		}
1969 
1970 		return result;
1971 	}
1972 
1973 	size_t toCaseId()
1974 	{
1975 		size_t result;
1976 
1977 		static foreach (i; 0 .. tags.length) {
1978 			result += tags[i] * stride!i;
1979 		}
1980 
1981 		return result;
1982 	}
1983 }
1984 
1985 /* The number that the dim-th argument's tag is multiplied by when
1986  * converting TagTuples to and from case indices ("caseIds").
1987  *
1988  * Named by analogy to the stride that the dim-th index into a
1989  * multidimensional static array is multiplied by to calculate the
1990  * offset of a specific element.
1991  */
1992 private size_t stride(size_t dim, lengths...)()
1993 {
1994 	import core.checkedint: mulu;
1995 
1996 	size_t result = 1;
1997 	bool overflow = false;
1998 
1999 	static foreach (i; 0 .. dim) {
2000 		result = mulu(result, lengths[i], overflow);
2001 	}
2002 
2003 	/* The largest number matchImpl uses, numCases, is calculated with
2004 	 * stride!(SumTypes.length), so as long as this overflow check
2005 	 * passes, we don't need to check for overflow anywhere else.
2006 	 */
2007 	assert(!overflow, "Integer overflow");
2008 	return result;
2009 }
2010 
2011 // Predicate for staticMap
2012 private enum typeCount(SumType) = SumType.Types.length;
2013 
2014 /* A list of arguments to be passed to a handler needed for the case
2015  * labeled with `caseId`.
2016  */
2017 template handlerArgs(size_t caseId, typeCounts...)
2018 {
2019 	enum tags = TagTuple!typeCounts.fromCaseId(caseId);
2020 
2021 	alias handlerArgs = AliasSeq!();
2022 
2023 	static foreach (i; 0 .. tags.length) {
2024 		handlerArgs = AliasSeq!(
2025 			handlerArgs,
2026 			"args[" ~ toCtString!i ~ "].getByIndex!(" ~ toCtString!(tags[i]) ~ ")(), "
2027 		);
2028 	}
2029 }
2030 
2031 // Matching
2032 @safe unittest {
2033 	alias MySum = SumType!(int, float);
2034 
2035 	MySum x = MySum(42);
2036 	MySum y = MySum(3.14);
2037 
2038 	assert(x.match!((int v) => true, (float v) => false));
2039 	assert(y.match!((int v) => false, (float v) => true));
2040 }
2041 
2042 // Missing handlers
2043 @safe unittest {
2044 	alias MySum = SumType!(int, float);
2045 
2046 	MySum x = MySum(42);
2047 
2048 	assert(!__traits(compiles, x.match!((int x) => true)));
2049 	assert(!__traits(compiles, x.match!()));
2050 }
2051 
2052 // Handlers with qualified parameters
2053 // Disabled in BetterC due to use of dynamic arrays
2054 version (D_BetterC) {} else
2055 @safe unittest {
2056 	alias MySum = SumType!(int[], float[]);
2057 
2058 	MySum x = MySum([1, 2, 3]);
2059 	MySum y = MySum([1.0, 2.0, 3.0]);
2060 
2061 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2062 	assert(y.match!((const(int[]) v) => false, (const(float[]) v) => true));
2063 }
2064 
2065 // Handlers for qualified types
2066 // Disabled in BetterC due to use of dynamic arrays
2067 version (D_BetterC) {} else
2068 @safe unittest {
2069 	alias MySum = SumType!(immutable(int[]), immutable(float[]));
2070 
2071 	MySum x = MySum([1, 2, 3]);
2072 
2073 	assert(x.match!((immutable(int[]) v) => true, (immutable(float[]) v) => false));
2074 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
2075 	// Tail-qualified parameters
2076 	assert(x.match!((immutable(int)[] v) => true, (immutable(float)[] v) => false));
2077 	assert(x.match!((const(int)[] v) => true, (const(float)[] v) => false));
2078 	// Generic parameters
2079 	assert(x.match!((immutable v) => true));
2080 	assert(x.match!((const v) => true));
2081 	// Unqualified parameters
2082 	assert(!__traits(compiles,
2083 		x.match!((int[] v) => true, (float[] v) => false)
2084 	));
2085 }
2086 
2087 // Delegate handlers
2088 // Disabled in BetterC due to use of closures
2089 version (D_BetterC) {} else
2090 @safe unittest {
2091 	alias MySum = SumType!(int, float);
2092 
2093 	int answer = 42;
2094 	MySum x = MySum(42);
2095 	MySum y = MySum(3.14);
2096 
2097 	assert(x.match!((int v) => v == answer, (float v) => v == answer));
2098 	assert(!y.match!((int v) => v == answer, (float v) => v == answer));
2099 }
2100 
2101 version (unittest) {
2102 	version (D_BetterC) {
2103 		// std.math.isClose depends on core.runtime.math, so use a
2104 		// libc-based version for testing with -betterC
2105 		@safe pure @nogc nothrow
2106 		private bool isClose(double lhs, double rhs)
2107 		{
2108 			import core.stdc.math: fabs;
2109 
2110 			return fabs(lhs - rhs) < 1e-5;
2111 		}
2112 	} else {
2113 		import std.math: isClose;
2114 	}
2115 }
2116 
2117 // Generic handler
2118 @safe unittest {
2119 	alias MySum = SumType!(int, float);
2120 
2121 	MySum x = MySum(42);
2122 	MySum y = MySum(3.14);
2123 
2124 	assert(x.match!(v => v*2) == 84);
2125 	assert(y.match!(v => v*2).isClose(6.28));
2126 }
2127 
2128 // Fallback to generic handler
2129 // Disabled in BetterC due to use of std.conv.to
2130 version (D_BetterC) {} else
2131 @safe unittest {
2132 	import std.conv: to;
2133 
2134 	alias MySum = SumType!(int, float, string);
2135 
2136 	MySum x = MySum(42);
2137 	MySum y = MySum("42");
2138 
2139 	assert(x.match!((string v) => v.to!int, v => v*2) == 84);
2140 	assert(y.match!((string v) => v.to!int, v => v*2) == 42);
2141 }
2142 
2143 // Multiple non-overlapping generic handlers
2144 @safe unittest {
2145 	import std.array: staticArray;
2146 
2147 	alias MySum = SumType!(int, float, int[], char[]);
2148 
2149 	static ints = staticArray([1, 2, 3]);
2150 	static chars = staticArray(['a', 'b', 'c']);
2151 
2152 	MySum x = MySum(42);
2153 	MySum y = MySum(3.14);
2154 	MySum z = MySum(ints[]);
2155 	MySum w = MySum(chars[]);
2156 
2157 	assert(x.match!(v => v*2, v => v.length) == 84);
2158 	assert(y.match!(v => v*2, v => v.length).isClose(6.28));
2159 	assert(w.match!(v => v*2, v => v.length) == 3);
2160 	assert(z.match!(v => v*2, v => v.length) == 3);
2161 }
2162 
2163 // Structural matching
2164 @safe unittest {
2165 	static struct S1 { int x; }
2166 	static struct S2 { int y; }
2167 	alias MySum = SumType!(S1, S2);
2168 
2169 	MySum a = MySum(S1(0));
2170 	MySum b = MySum(S2(0));
2171 
2172 	assert(a.match!(s1 => s1.x + 1, s2 => s2.y - 1) == 1);
2173 	assert(b.match!(s1 => s1.x + 1, s2 => s2.y - 1) == -1);
2174 }
2175 
2176 // Separate opCall handlers
2177 @safe unittest {
2178 	static struct IntHandler
2179 	{
2180 		bool opCall(int arg)
2181 		{
2182 			return true;
2183 		}
2184 	}
2185 
2186 	static struct FloatHandler
2187 	{
2188 		bool opCall(float arg)
2189 		{
2190 			return false;
2191 		}
2192 	}
2193 
2194 	alias MySum = SumType!(int, float);
2195 
2196 	MySum x = MySum(42);
2197 	MySum y = MySum(3.14);
2198 
2199 	assert(x.match!(IntHandler.init, FloatHandler.init));
2200 	assert(!y.match!(IntHandler.init, FloatHandler.init));
2201 }
2202 
2203 // Compound opCall handler
2204 @safe unittest {
2205 	static struct CompoundHandler
2206 	{
2207 		bool opCall(int arg)
2208 		{
2209 			return true;
2210 		}
2211 
2212 		bool opCall(float arg)
2213 		{
2214 			return false;
2215 		}
2216 	}
2217 
2218 	alias MySum = SumType!(int, float);
2219 
2220 	MySum x = MySum(42);
2221 	MySum y = MySum(3.14);
2222 
2223 	assert(x.match!(CompoundHandler.init));
2224 	assert(!y.match!(CompoundHandler.init));
2225 }
2226 
2227 // Ordered matching
2228 @safe unittest {
2229 	alias MySum = SumType!(int, float);
2230 
2231 	MySum x = MySum(42);
2232 
2233 	assert(x.match!((int v) => true, v => false));
2234 }
2235 
2236 // Non-exhaustive matching
2237 version (D_Exceptions)
2238 @system unittest {
2239 	import std.exception: assertThrown, assertNotThrown;
2240 
2241 	alias MySum = SumType!(int, float);
2242 
2243 	MySum x = MySum(42);
2244 	MySum y = MySum(3.14);
2245 
2246 	assertNotThrown!MatchException(x.tryMatch!((int n) => true));
2247 	assertThrown!MatchException(y.tryMatch!((int n) => true));
2248 }
2249 
2250 // Non-exhaustive matching in @safe code
2251 version (D_Exceptions)
2252 @safe unittest {
2253 	SumType!(int, float) x;
2254 
2255 	assert(__traits(compiles,
2256 		x.tryMatch!(
2257 			(int n) => n + 1,
2258 		)
2259 	));
2260 
2261 }
2262 
2263 // Handlers with ref parameters
2264 @safe unittest {
2265 	alias Value = SumType!(long, double);
2266 
2267 	auto value = Value(3.14);
2268 
2269 	value.match!(
2270 		(long) {},
2271 		(ref double d) { d *= 2; }
2272 	);
2273 
2274 	assert(value.getByIndex!1.isClose(6.28));
2275 }
2276 
2277 // Handlers that return by ref
2278 @safe unittest {
2279 	SumType!int x = 123;
2280 
2281 	x.match!(ref (ref int n) => n) = 456;
2282 
2283 	assert(x.match!((int n) => n == 456));
2284 }
2285 
2286 // Unreachable handlers
2287 @safe unittest {
2288 	alias MySum = SumType!(int, string);
2289 
2290 	MySum s;
2291 
2292 	assert(!__traits(compiles,
2293 		s.match!(
2294 			(int _) => 0,
2295 			(string _) => 1,
2296 			(double _) => 2
2297 		)
2298 	));
2299 
2300 	assert(!__traits(compiles,
2301 		s.match!(
2302 			_ => 0,
2303 			(int _) => 1
2304 		)
2305 	));
2306 }
2307 
2308 // Unsafe handlers
2309 @system unittest {
2310 	SumType!int x;
2311 	alias unsafeHandler = (int x) @system { return; };
2312 
2313 	assert(!__traits(compiles, () @safe {
2314 		x.match!unsafeHandler;
2315 	}));
2316 
2317 	assert(__traits(compiles, () @system {
2318 		return x.match!unsafeHandler;
2319 	}));
2320 }
2321 
2322 // Overloaded handlers
2323 @safe unittest {
2324 	static struct OverloadSet
2325 	{
2326 		static string fun(int i) { return "int"; }
2327 		static string fun(double d) { return "double"; }
2328 	}
2329 
2330 	alias MySum = SumType!(int, double);
2331 
2332 	MySum a = 42;
2333 	MySum b = 3.14;
2334 
2335 	assert(a.match!(OverloadSet.fun) == "int");
2336 	assert(b.match!(OverloadSet.fun) == "double");
2337 }
2338 
2339 // Overload sets that include SumType arguments
2340 @safe unittest {
2341 	alias Inner = SumType!(int, double);
2342 	alias Outer = SumType!(Inner, string);
2343 
2344 	static struct OverloadSet
2345 	{
2346 		@safe:
2347 		static string fun(int i) { return "int"; }
2348 		static string fun(double d) { return "double"; }
2349 		static string fun(string s) { return "string"; }
2350 		static string fun(Inner i) { return i.match!fun; }
2351 		static string fun(Outer o) { return o.match!fun; }
2352 	}
2353 
2354 	Outer a = Inner(42);
2355 	Outer b = Inner(3.14);
2356 	Outer c = "foo";
2357 
2358 	assert(OverloadSet.fun(a) == "int");
2359 	assert(OverloadSet.fun(b) == "double");
2360 	assert(OverloadSet.fun(c) == "string");
2361 }
2362 
2363 // Overload sets with ref arguments
2364 @safe unittest {
2365 	static struct OverloadSet
2366 	{
2367 		static void fun(ref int i) { i = 42; }
2368 		static void fun(ref double d) { d = 3.14; }
2369 	}
2370 
2371 	alias MySum = SumType!(int, double);
2372 
2373 	MySum x = 0;
2374 	MySum y = 0.0;
2375 
2376 	x.match!(OverloadSet.fun);
2377 	y.match!(OverloadSet.fun);
2378 
2379 	assert(x.match!((value) => is(typeof(value) == int) && value == 42));
2380 	assert(y.match!((value) => is(typeof(value) == double) && value == 3.14));
2381 }
2382 
2383 // Overload sets with templates
2384 @safe unittest {
2385 	import std.traits: isNumeric;
2386 
2387 	static struct OverloadSet
2388 	{
2389 		static string fun(string arg)
2390 		{
2391 			return "string";
2392 		}
2393 
2394 		static string fun(T)(T arg)
2395 			if (isNumeric!T)
2396 		{
2397 			return "numeric";
2398 		}
2399 	}
2400 
2401 	alias MySum = SumType!(int, string);
2402 
2403 	MySum x = 123;
2404 	MySum y = "hello";
2405 
2406 	assert(x.match!(OverloadSet.fun) == "numeric");
2407 	assert(y.match!(OverloadSet.fun) == "string");
2408 }
2409 
2410 // Github issue #24
2411 @safe unittest {
2412 	assert(__traits(compiles, () @nogc {
2413 		int acc = 0;
2414 		SumType!int(1).match!((int x) => acc += x);
2415 	}));
2416 }
2417 
2418 // Github issue #31
2419 @safe unittest {
2420 	assert(__traits(compiles, () @nogc {
2421 		int acc = 0;
2422 
2423 		SumType!(int, string)(1).match!(
2424 			(int x) => acc += x,
2425 			(string _) => 0,
2426 		);
2427 	}));
2428 }
2429 
2430 // Types that `alias this` a SumType
2431 @safe unittest {
2432 	static struct A {}
2433 	static struct B {}
2434 	static struct D { SumType!(A, B) value; alias value this; }
2435 
2436 	assert(__traits(compiles, D().match!(_ => true)));
2437 }
2438 
2439 // Multiple dispatch
2440 @safe unittest {
2441 	alias MySum = SumType!(int, string);
2442 
2443 	static int fun(MySum x, MySum y)
2444 	{
2445 		import std.meta: Args = AliasSeq;
2446 
2447 		return Args!(x, y).match!(
2448 			(int    xv, int    yv) => 0,
2449 			(string xv, int    yv) => 1,
2450 			(int    xv, string yv) => 2,
2451 			(string xv, string yv) => 3
2452 		);
2453 	}
2454 
2455 	assert(fun(MySum(0),  MySum(0))  == 0);
2456 	assert(fun(MySum(""), MySum(0))  == 1);
2457 	assert(fun(MySum(0),  MySum("")) == 2);
2458 	assert(fun(MySum(""), MySum("")) == 3);
2459 }
2460 
2461 // inout SumTypes
2462 @safe unittest {
2463 	assert(__traits(compiles, {
2464 		inout(int[]) fun(inout(SumType!(int[])) x)
2465 		{
2466 			return x.match!((inout(int[]) a) => a);
2467 		}
2468 	}));
2469 }
2470 
2471 // return ref
2472 // issue: https://issues.dlang.org/show_bug.cgi?id=23101
2473 // Only test on compiler versions >= 2.100, to avoid compiler bugs
2474 static if (haveDip1000 && __VERSION__ >= 2100)
2475 @safe unittest {
2476 	assert(!__traits(compiles, () {
2477 		SumType!(int, string) st;
2478 		return st.match!(
2479 			function int* (string x) => null,
2480 			function int* (return ref int i) => &i,
2481 		);
2482 	}));
2483 
2484 	SumType!(int, string) st;
2485 	assert(__traits(compiles, () {
2486 		return st.match!(
2487 			function int* (string x) => null,
2488 			function int* (return ref int i) => &i,
2489 		);
2490 	}));
2491 }
2492 
2493 /**
2494  * Checks whether a `SumType` contains a value of a given type.
2495  *
2496  * The types must match exactly, without implicit conversions.
2497  *
2498  * Params:
2499  *   T = the type to check for.
2500  */
2501 template has(T)
2502 {
2503 	/**
2504 	 * The actual `has` function.
2505 	 *
2506 	 * Params:
2507 	 *   self = the `SumType` to check.
2508 	 *
2509 	 * Returns: true if `self` contains a `T`, otherwise false.
2510 	 */
2511 	bool has(Self)(auto ref Self self)
2512 		if (isSumType!Self)
2513 	{
2514 		return self.match!checkType;
2515 	}
2516 
2517 	// Helper to avoid redundant template instantiations
2518 	private bool checkType(Value)(ref Value value)
2519 	{
2520 		return is(Value == T);
2521 	}
2522 }
2523 
2524 /// Basic usage
2525 @safe unittest {
2526 	SumType!(string, double) example = "hello";
2527 
2528 	assert( example.has!string);
2529 	assert(!example.has!double);
2530 
2531 	// If T isn't part of the SumType, has!T will always return false
2532 	assert(!example.has!int);
2533 }
2534 
2535 /// With type qualifiers
2536 @safe unittest {
2537 	alias Example = SumType!(string, double);
2538 
2539 	Example m = "mutable";
2540 	const Example c = "const";
2541 	immutable Example i = "immutable";
2542 
2543 	assert( m.has!string);
2544 	assert(!m.has!(const(string)));
2545 	assert(!m.has!(immutable(string)));
2546 
2547 	assert(!c.has!string);
2548 	assert( c.has!(const(string)));
2549 	assert(!c.has!(immutable(string)));
2550 
2551 	assert(!i.has!string);
2552 	assert(!i.has!(const(string)));
2553 	assert( i.has!(immutable(string)));
2554 }
2555 
2556 /// As a predicate
2557 version (D_BetterC) {} else
2558 @safe unittest {
2559 	import std.algorithm.iteration: filter;
2560 	import std.algorithm.comparison: equal;
2561 
2562 	alias Example = SumType!(string, double);
2563 
2564 	auto arr = [
2565 		Example("foo"),
2566 		Example(0),
2567 		Example("bar"),
2568 		Example(1),
2569 		Example(2),
2570 		Example("baz")
2571 	];
2572 
2573 	auto strings = arr.filter!(has!string);
2574 	auto nums = arr.filter!(has!double);
2575 
2576 	assert(strings.equal([Example("foo"), Example("bar"), Example("baz")]));
2577 	assert(nums.equal([Example(0), Example(1), Example(2)]));
2578 }
2579 
2580 // Non-copyable types
2581 @safe unittest {
2582 	static struct NoCopy
2583 	{
2584 		@disable this(this);
2585 	}
2586 
2587 	SumType!NoCopy x;
2588 
2589 	assert(x.has!NoCopy);
2590 }
2591 
2592 /**
2593  * Accesses a `SumType`'s value.
2594  *
2595  * The value must be of the specified type. Use [has] to check.
2596  * 
2597  * Params:
2598  *   T = the type of the value being accessed.
2599  */
2600 template get(T)
2601 {
2602 	/**
2603 	 * The actual `get` function.
2604 	 *
2605 	 * Params:
2606 	 *   self = the `SumType` whose value is being accessed.
2607 	 *
2608 	 * Returns: the `SumType`'s value.
2609 	 */
2610 	auto ref T get(Self)(auto ref Self self)
2611 		if (isSumType!Self)
2612 	{
2613 		import std.typecons : No;
2614 
2615 		static if (__traits(isRef, self))
2616 			return self.match!(getLvalue!(No.try_, T));
2617 		else
2618 			return self.match!(getRvalue!(No.try_, T));
2619 	}
2620 }
2621 
2622 /// Basic usage
2623 @safe unittest {
2624 	SumType!(string, double) example1 = "hello";
2625 	SumType!(string, double) example2 = 3.14;
2626 
2627 	assert(example1.get!string == "hello");
2628 	assert(example2.get!double == 3.14);
2629 }
2630 
2631 /// With type qualifiers
2632 @safe unittest {
2633 	alias Example = SumType!(string, double);
2634 
2635 	Example m = "mutable";
2636 	const(Example) c = "const";
2637 	immutable(Example) i = "immutable";
2638 
2639 	assert(m.get!string == "mutable");
2640 	assert(c.get!(const(string)) == "const");
2641 	assert(i.get!(immutable(string)) == "immutable");
2642 }
2643 
2644 /// As a predicate
2645 version (D_BetterC) {} else
2646 @safe unittest {
2647 	import std.algorithm.iteration: map;
2648 	import std.algorithm.comparison: equal;
2649 
2650 	alias Example = SumType!(string, double);
2651 
2652 	auto arr = [Example(0), Example(1), Example(2)];
2653 	auto values = arr.map!(get!double);
2654 
2655 	assert(values.equal([0, 1, 2]));
2656 }
2657 
2658 // Non-copyable types
2659 @safe unittest {
2660 	static struct NoCopy
2661 	{
2662 		@disable this(this);
2663 	}
2664 
2665 	SumType!NoCopy lvalue;
2666 	auto rvalue() { return SumType!NoCopy(); }
2667 
2668 	assert(lvalue.get!NoCopy == NoCopy());
2669 	assert(rvalue.get!NoCopy == NoCopy());
2670 }
2671 
2672 // Immovable rvalues
2673 @safe unittest {
2674 	auto rvalue() { return const(SumType!string)("hello"); }
2675 
2676 	assert(rvalue.get!(const(string)) == "hello");
2677 }
2678 
2679 // Nontrivial rvalues at compile time
2680 @safe unittest {
2681 	static struct ElaborateCopy
2682 	{
2683 		this(this) {}
2684 	}
2685 
2686 	enum rvalue = SumType!ElaborateCopy();
2687 	enum ctResult = rvalue.get!ElaborateCopy;
2688 
2689 	assert(ctResult == ElaborateCopy());
2690 }
2691 
2692 /**
2693  * Attempt to access a `SumType`'s value.
2694  *
2695  * If the `SumType` does not contain a value of the specified type, an
2696  * exception is thrown.
2697  *
2698  * Params:
2699  *   T = the type of the value being accessed.
2700  */
2701 version (D_Exceptions)
2702 template tryGet(T)
2703 {
2704 	/**
2705 	 * The actual `tryGet` function.
2706 	 *
2707 	 * Params:
2708 	 *   self = the `SumType` whose value is being accessed.
2709 	 *
2710 	 * Throws: `MatchException` if the value does not have the expected type.
2711 	 *
2712 	 * Returns: the `SumType`'s value.
2713 	 */
2714 	auto ref T tryGet(Self)(auto ref Self self)
2715 		if (isSumType!Self)
2716 	{
2717 		import std.typecons: Yes;
2718 
2719 		static if (__traits(isRef, self))
2720 			return self.match!(getLvalue!(Yes.try_, T));
2721 		else
2722 			return self.match!(getRvalue!(Yes.try_, T));
2723 	}
2724 }
2725 
2726 /// Basic usage
2727 version (D_Exceptions)
2728 @safe unittest {
2729 	SumType!(string, double) example = "hello";
2730 
2731 	assert(example.tryGet!string == "hello");
2732 
2733 	double result = double.nan;
2734 	try
2735 		result = example.tryGet!double;
2736 	catch (MatchException e)
2737 		result = 0;
2738 
2739 	// Exception was thrown
2740 	assert(result == 0);
2741 }
2742 
2743 /// With type qualifiers
2744 version (D_Exceptions)
2745 @safe unittest {
2746 	import std.exception: assertThrown;
2747 
2748 	const(SumType!(string, double)) example = "const";
2749 
2750 	// Qualifier mismatch; throws exception
2751 	assertThrown!MatchException(example.tryGet!string);
2752 	// Qualifier matches; no exception
2753 	assert(example.tryGet!(const(string)) == "const");
2754 }
2755 
2756 /// As a predicate
2757 version (D_BetterC) {} else
2758 @safe unittest {
2759 	import std.algorithm.iteration: map, sum;
2760 	import std.functional: pipe;
2761 	import std.exception: assertThrown;
2762 
2763 	alias Example = SumType!(string, double);
2764 
2765 	auto arr1 = [Example(0), Example(1), Example(2)];
2766 	auto arr2 = [Example("foo"), Example("bar"), Example("baz")];
2767 
2768 	alias trySum = pipe!(map!(tryGet!double), sum);
2769 
2770 	assert(trySum(arr1) == 0 + 1 + 2);
2771 	assertThrown!MatchException(trySum(arr2));
2772 }
2773 
2774 // Throws if requested type is impossible
2775 version (D_Exceptions)
2776 @safe unittest {
2777 	import std.exception: assertThrown;
2778 
2779 	SumType!int x;
2780 
2781 	assertThrown!MatchException(x.tryGet!string);
2782 }
2783 
2784 // Non-copyable types
2785 version (D_Exceptions)
2786 @safe unittest {
2787 	static struct NoCopy
2788 	{
2789 		@disable this(this);
2790 	}
2791 
2792 	SumType!NoCopy lvalue;
2793 	auto rvalue() { return SumType!NoCopy(); }
2794 
2795 	assert(lvalue.tryGet!NoCopy == NoCopy());
2796 	assert(rvalue.tryGet!NoCopy == NoCopy());
2797 }
2798 
2799 // Immovable types
2800 version (D_Exceptions)
2801 @safe unittest {
2802 	auto rvalue() { return const(SumType!string)("hello"); }
2803 
2804 	assert(rvalue.tryGet!(const(string)) == "hello");
2805 }
2806 
2807 // Nontrivial rvalues at compile time
2808 version (D_Exceptions)
2809 @safe unittest {
2810 	static struct ElaborateCopy
2811 	{
2812 		this(this) {}
2813 	}
2814 
2815 	enum rvalue = SumType!ElaborateCopy();
2816 	enum ctResult = rvalue.tryGet!ElaborateCopy;
2817 
2818 	assert(ctResult == ElaborateCopy());
2819 }
2820 
2821 private template failedGetMessage(Expected, Actual)
2822 {
2823 	static if (Expected.stringof == Actual.stringof) {
2824 		enum expectedStr = __traits(fullyQualifiedName, Expected);
2825 		enum actualStr = __traits(fullyQualifiedName, Actual);
2826 	} else {
2827 		enum expectedStr = Expected.stringof;
2828 		enum actualStr = Actual.stringof;
2829 	}
2830 
2831 	enum failedGetMessage =
2832 		"Tried to get `" ~ expectedStr ~ "`" ~
2833 		" but found `" ~ actualStr ~ "`";
2834 }
2835 
2836 private template getLvalue(Flag!"try_" try_, T)
2837 {
2838 	ref T getLvalue(Value)(ref Value value)
2839 	{
2840 		static if (is(Value == T)) {
2841 			return value;
2842 		} else {
2843 			static if (try_)
2844 				throw new MatchException(failedGetMessage!(T, Value));
2845 			else
2846 				assert(false, failedGetMessage!(T, Value));
2847 		}
2848 	}
2849 }
2850 
2851 private template getRvalue(Flag!"try_" try_, T)
2852 {
2853 	T getRvalue(Value)(ref Value value)
2854 	{
2855 		static if (is(Value == T)) {
2856 			import core.lifetime: move;
2857 
2858 			// Move if possible; otherwise fall back to copy
2859 			static if (is(typeof(move(value)))) {
2860 				static if (isCopyable!Value)
2861 					// Workaround for https://issues.dlang.org/show_bug.cgi?id=21542
2862 					return __ctfe ? value : move(value);
2863 				else
2864 					return move(value);
2865 			} else {
2866 				return value;
2867 			}
2868 		} else {
2869 			static if (try_)
2870 				throw new MatchException(failedGetMessage!(T, Value));
2871 			else
2872 				assert(false, failedGetMessage!(T, Value));
2873 		}
2874 	}
2875 }
2876 
2877 private void destroyIfOwner(T)(ref T value)
2878 {
2879 	static if (hasElaborateDestructor!T) {
2880 		destroy(value);
2881 	}
2882 }
2883 
2884 static if (__traits(compiles, { import std.traits: DeducedParameterType; })) {
2885 	import std.traits: DeducedParameterType;
2886 } else {
2887 	/**
2888 	 * The parameter type deduced by IFTI when an expression of type T is passed as
2889 	 * an argument to a template function.
2890 	 *
2891 	 * For all types other than pointer and slice types, `DeducedParameterType!T`
2892 	 * is the same as `T`. For pointer and slice types, it is `T` with the
2893 	 * outer-most layer of qualifiers dropped.
2894 	 */
2895 	private template DeducedParameterType(T)
2896 	{
2897 		import std.traits: Unqual;
2898 
2899 		static if (is(T == U*, U) || is(T == U[], U))
2900 			alias DeducedParameterType = Unqual!T;
2901 		else
2902 			alias DeducedParameterType = T;
2903 	}
2904 
2905 	@safe unittest
2906 	{
2907 		static assert(is(DeducedParameterType!(const(int)) == const(int)));
2908 		static assert(is(DeducedParameterType!(const(int[2])) == const(int[2])));
2909 
2910 		static assert(is(DeducedParameterType!(const(int*)) == const(int)*));
2911 		static assert(is(DeducedParameterType!(const(int[])) == const(int)[]));
2912 	}
2913 
2914 	@safe unittest
2915 	{
2916 		static struct NoCopy
2917 		{
2918 			@disable this(this);
2919 		}
2920 
2921 		static assert(is(DeducedParameterType!NoCopy == NoCopy));
2922 	}
2923 
2924 	@safe unittest
2925 	{
2926 		static assert(is(DeducedParameterType!(inout(int[])) == inout(int)[]));
2927 	}
2928 }