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