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