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