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