1 /++
2 A sum type for modern D.
3 
4 [SumType] is an alternative to `std.variant.Algebraic` that features:
5 
6 $(LIST
7     * [match|Improved pattern-matching.]
8     * Full attribute correctness (`pure`, `@safe`, `@nogc`, and `nothrow` are
9       inferred whenever possible).
10     * A type-safe and memory-safe API compatible with DIP 1000 (`scope`).
11     * No dependency on runtime type information (`TypeInfo`).
12 )
13 
14 License: MIT
15 Authors: Paul Backus, Atila Neves
16 +/
17 module libwasm.sumtype;
18 
19 /+/// $(H3 Basic usage)
20 version (D_BetterC) {} else
21 @safe unittest {
22     import std.math: approxEqual;
23 
24     struct Fahrenheit { double degrees; }
25     struct Celsius { double degrees; }
26     struct Kelvin { double degrees; }
27 
28     alias Temperature = SumType!(Fahrenheit, Celsius, Kelvin);
29 
30     // Construct from any of the member types.
31     Temperature t1 = Fahrenheit(98.6);
32     Temperature t2 = Celsius(100);
33     Temperature t3 = Kelvin(273);
34 
35     // Use pattern matching to access the value.
36     pure @safe @nogc nothrow
37     Fahrenheit toFahrenheit(Temperature t)
38     {
39         return Fahrenheit(
40             t.match!(
41                 (Fahrenheit f) => f.degrees,
42                 (Celsius c) => c.degrees * 9.0/5 + 32,
43                 (Kelvin k) => k.degrees * 9.0/5 - 459.4
44             )
45         );
46     }
47 
48     assert(toFahrenheit(t1).degrees.approxEqual(98.6));
49     assert(toFahrenheit(t2).degrees.approxEqual(212));
50     assert(toFahrenheit(t3).degrees.approxEqual(32));
51 
52     // Use ref to modify the value in place.
53     pure @safe @nogc nothrow
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.approxEqual(32));
65 
66     // Use a catch-all handler to give a default result.
67     pure @safe @nogc nothrow
68     bool isFahrenheit(Temperature t)
69     {
70         return t.match!(
71             (Fahrenheit f) => true,
72             _ => false
73         );
74     }
75 
76     assert(isFahrenheit(t1));
77     assert(!isFahrenheit(t2));
78     assert(!isFahrenheit(t3));
79 }
80 
81 /** $(H3 Introspection-based matching)
82  *
83  * In the `length` and `horiz` functions below, the handlers for `match` do not
84  * specify the types of their arguments. Instead, matching is done based on how
85  * the argument is used in the body of the handler: any type with `x` and `y`
86  * properties will be matched by the `rect` handlers, and any type with `r` and
87  * `theta` properties will be matched by the `polar` handlers.
88  */
89 version (D_BetterC) {} else
90 @safe unittest {
91     import std.math: approxEqual, cos, PI, sqrt;
92 
93     struct Rectangular { double x, y; }
94     struct Polar { double r, theta; }
95     alias Vector = SumType!(Rectangular, Polar);
96 
97     pure @safe @nogc nothrow
98     double length(Vector v)
99     {
100         return v.match!(
101             rect => sqrt(rect.x^^2 + rect.y^^2),
102             polar => polar.r
103         );
104     }
105 
106     pure @safe @nogc nothrow
107     double horiz(Vector v)
108     {
109         return v.match!(
110             rect => rect.x,
111             polar => polar.r * cos(polar.theta)
112         );
113     }
114 
115     Vector u = Rectangular(1, 1);
116     Vector v = Polar(1, PI/4);
117 
118     assert(length(u).approxEqual(sqrt(2.0)));
119     assert(length(v).approxEqual(1));
120     assert(horiz(u).approxEqual(1));
121     assert(horiz(v).approxEqual(sqrt(0.5)));
122 }
123 +/
124 /// `This` placeholder, for use in self-referential types.
125 
126 import std.meta: NoDuplicates;
127 
128 /**
129  * A tagged union that can hold a single value from any of a specified set of
130  * types.
131  *
132  * The value in a `SumType` can be operated on using [match|pattern matching].
133  *
134  * To avoid ambiguity, duplicate types are not allowed (but see the
135  * [sumtype#basic-usage|"basic usage" example] for a workaround).
136  *
137  * The special type `This` can be used as a placeholder to create
138  * self-referential types, just like with `Algebraic`. See the
139  * [sumtype#arithmetic-expression-evaluator|"Arithmetic expression evaluator" example] for
140  * usage.
141  *
142  * A `SumType` is initialized by default to hold the `.init` value of its
143  * first member type, just like a regular union. The version identifier
144  * `SumTypeNoDefaultCtor` can be used to disable this behavior.
145  *
146  * Bugs:
147  *   Types with `@disable`d `opEquals` overloads cannot be members of a
148  *   `SumType`.
149  *
150  * See_Also: `std.variant.Algebraic`
151  */
152 template FlattenSumTypes(Types...) {
153   import std.meta : staticMap;
154   static template Impl(Type) {
155     static if (is(Type : SumType!(Ts), Ts))
156       alias Impl = Type.Types;
157     else
158       alias Impl = Type;
159   }
160   alias FlattenSumTypes = staticMap!(Impl, Types);
161 }
162 
163 struct SumType(TypeArgs...)
164 	if (is(NoDuplicates!TypeArgs == TypeArgs) && TypeArgs.length > 0)
165 {
166 	import std.meta: AliasSeq, Filter, anySatisfy, allSatisfy, staticIndexOf;
167 	import std.traits: hasElaborateCopyConstructor, hasElaborateDestructor;
168 	import std.traits: isAssignable, isCopyable, isStaticArray;
169 
170 	/// The types a `SumType` can hold.
171 	alias Types = FlattenSumTypes!(TypeArgs);//AliasSeq!(ReplaceTypeUnless!(isSumType, This, typeof(this), TypeArgs));
172 
173 private:
174 
175 	enum bool canHoldTag(T) = Types.length <= T.max;
176 	alias unsignedInts = AliasSeq!(ubyte, ushort, uint, ulong);
177 
178 	alias Tag = Filter!(canHoldTag, unsignedInts)[0];
179 
180 	union Storage
181 	{
182 		template memberName(T)
183 			if (staticIndexOf!(T, Types) >= 0)
184 		{
185 			mixin("enum memberName = `values_", staticIndexOf!(T, Types), "`;");
186 		}
187 
188 		static foreach (T; Types) {
189 			mixin("T ", memberName!T, ";");
190 		}
191 	}
192 
193 	Tag tag;
194 	Storage storage;
195 
196 	@trusted
197 	ref inout(T) get(T)() inout
198 		if (staticIndexOf!(T, Types) >= 0)
199       {
200         enum tid = staticIndexOf!(T, Types);
201         assert(tag == tid);
202         return __traits(getMember, storage, Storage.memberName!T);
203       }
204 
205 public:
206 
207 	@trusted
208 	ref inout(T) trustedGet(T)() inout
209 		if (staticIndexOf!(T, Types) >= 0)
210       {
211         enum tid = staticIndexOf!(T, Types);
212         assert(tag == tid);
213         return __traits(getMember, storage, Storage.memberName!T);
214       }
215 
216 	static foreach (tid, T; Types) {
217 		/// Constructs a `SumType` holding a specific value.
218 		this()(auto ref T value)
219 		{
220 			import core.lifetime: forward;
221 
222 			static if (isCopyable!T) {
223 				mixin("Storage newStorage = { ", Storage.memberName!T, ": value };");
224 			} else {
225 				mixin("Storage newStorage = { ", Storage.memberName!T, " : forward!value };");
226 			}
227 
228 			storage = newStorage;
229 			tag = tid;
230 		}
231 
232 		static if (isCopyable!T) {
233 			/// ditto
234 			this()(auto ref const(T) value) const
235 			{
236 				mixin("const(Storage) newStorage = { ", Storage.memberName!T, ": value };");
237 				storage = newStorage;
238 				tag = tid;
239 			}
240 
241 			/// ditto
242 			this()(auto ref immutable(T) value) immutable
243 			{
244 				mixin("immutable(Storage) newStorage = { ", Storage.memberName!T, ": value };");
245 				storage = newStorage;
246 				tag = tid;
247 			}
248 		} else {
249 			@disable this(const(T) value) const;
250 			@disable this(immutable(T) value) immutable;
251 		}
252 	}
253 
254 	static if (allSatisfy!(isCopyable, Types)) {
255 		static if (anySatisfy!(hasElaborateCopyConstructor, Types)) {
256 			/// Constructs a `SumType` that's a copy of another `SumType`
257 			this(ref SumType other)
258 			{
259 				storage = other.match!((ref value) {
260 					alias T = typeof(value);
261 
262 					mixin("Storage newStorage = { ", Storage.memberName!T, ": value };");
263 					return newStorage;
264 				});
265 
266 				tag = other.tag;
267 			}
268 
269 			/// ditto
270 			this(ref const(SumType) other) const
271 			{
272 				import std.meta: staticMap;
273 				import std.traits: ConstOf;
274 
275 				storage = other.match!((ref value) {
276 					alias OtherTypes = staticMap!(ConstOf, Types);
277 					enum tid = staticIndexOf!(typeof(value), OtherTypes);
278 					alias T = Types[tid];
279 
280 					mixin("const(Storage) newStorage = { ", Storage.memberName!T, ": value };");
281 					return newStorage;
282 				});
283 
284 				tag = other.tag;
285 			}
286 
287 			/// ditto
288 			this(ref immutable(SumType) other) immutable
289 			{
290 				import std.meta: staticMap;
291 				import std.traits: ImmutableOf;
292 
293 				storage = other.match!((ref value) {
294 					alias OtherTypes = staticMap!(ImmutableOf, Types);
295 					enum tid = staticIndexOf!(typeof(value), OtherTypes);
296 					alias T = Types[tid];
297 
298 					mixin("immutable(Storage) newStorage = { ", Storage.memberName!T, ": value };");
299 					return newStorage;
300 				});
301 
302 				tag = other.tag;
303 			}
304 		}
305 	} else {
306 		/// `@disable`d if any member type is non-copyable.
307 		@disable this(this);
308 	}
309 
310 	version(SumTypeNoDefaultCtor) {
311 		@disable this();
312 	}
313 
314 	static foreach (tid, T; Types) {
315 		static if (isAssignable!T) {
316 			/**
317 			 * Assigns a value to a `SumType`.
318 			 *
319 			 * Assigning to a `SumType` is `@system` if any of the
320 			 * `SumType`'s members contain pointers or references, since
321 			 * those members may be reachable through external references,
322 			 * and overwriting them could therefore lead to memory
323 			 * corruption.
324 			 *
325 			 * An individual assignment can be `@trusted` if the caller can
326 			 * guarantee that there are no outstanding references to $(I any)
327 			 * of the `SumType`'s members when the assignment occurs.
328 			 */
329 			void opAssign()(auto ref T rhs)
330 			{
331 				import core.lifetime: forward;
332 				import std.traits: hasIndirections, hasNested;
333 				import std.meta: Or = templateOr;
334 
335 				enum mayContainPointers =
336 					anySatisfy!(Or!(hasIndirections, hasNested), Types);
337 
338 				static if (mayContainPointers) {
339 					cast(void) () @system {}();
340 				}
341 
342 				this.match!((ref value) {
343 					static if (hasElaborateDestructor!(typeof(value))) {
344 						destroy(value);
345 					}
346 				});
347 
348 				mixin("Storage newStorage = { ", Storage.memberName!T, ": forward!rhs };");
349 				storage = newStorage;
350 				tag = tid;
351 			}
352 		}
353 	}
354 
355 	static if (allSatisfy!(isAssignable, Types)) {
356 		static if (allSatisfy!(isCopyable, Types)) {
357 			/**
358 			 * Copies the value from another `SumType` into this one.
359 			 *
360 			 * See the value-assignment overload for details on `@safe`ty.
361 			 *
362 			 * Copy assignment is `@disable`d if any of `Types` is non-copyable.
363 			 */
364 			void opAssign(ref SumType rhs)
365 			{
366 				rhs.match!((ref value) { this = value; });
367 			}
368 		} else {
369 			@disable void opAssign(ref SumType rhs);
370 		}
371 
372 		/**
373 		 * Moves the value from another `SumType` into this one.
374 		 *
375 		 * See the value-assignment overload for details on `@safe`ty.
376 		 */
377 		void opAssign(SumType rhs)
378 		{
379 			import core.lifetime: move;
380 
381 			rhs.match!((ref value) { this = move(value); });
382 		}
383 	}
384 
385 	/**
386 	 * Compares two `SumType`s for equality.
387 	 *
388 	 * Two `SumType`s are equal if they are the same kind of `SumType`, they
389 	 * contain values of the same type, and those values are equal.
390 	 */
391 	bool opEquals(const SumType rhs) const {
392 		return this.match!((ref value) {
393 			return rhs.match!((ref rhsValue) {
394 				static if (is(typeof(value) == typeof(rhsValue))) {
395 					return value == rhsValue;
396 				} else {
397 					return false;
398 				}
399 			});
400 		});
401 	}
402 
403 	// Workaround for dlang issue 19407
404 	static if (__traits(compiles, anySatisfy!(hasElaborateDestructor, Types))) {
405 		// If possible, include the destructor only when it's needed
406 		private enum includeDtor = anySatisfy!(hasElaborateDestructor, Types);
407 	} else {
408 		// If we can't tell, always include it, even when it does nothing
409 		private enum includeDtor = true;
410 	}
411 
412 	static if (includeDtor) {
413 		/// Calls the destructor of the `SumType`'s current value.
414 		~this()
415 		{
416 			this.match!((ref value) {
417 				static if (hasElaborateDestructor!(typeof(value))) {
418 					destroy(value);
419 				}
420 			});
421 		}
422 	}
423 
424 	invariant {
425 		this.match!((ref value) {
426 			static if (is(typeof(value) == class)) {
427 				if (value !is null) {
428 					assert(value);
429 				}
430 			} else static if (is(typeof(value) == struct)) {
431 				assert(&value);
432 			}
433 		});
434 	}
435 
436 	static if (allSatisfy!(isCopyable, Types)) {
437 		/**
438 		 * Returns a string representation of a `SumType`'s value.
439 		 *
440 		 * Not available when compiled with `-betterC`.
441 		 */
442 		version (D_BetterC) {} else
443 		string toString(this T)() {
444 			import std.conv: text;
445 			return this.match!((auto ref value) {
446 				return value.text;
447 			});
448 		}
449 	}
450 }
451 /+
452 // Construction
453 @safe unittest {
454 	alias MySum = SumType!(int, float);
455 
456 	assert(__traits(compiles, MySum(42)));
457 	assert(__traits(compiles, MySum(3.14)));
458 }
459 
460 // Assignment
461 @safe unittest {
462 	alias MySum = SumType!(int, float);
463 
464 	MySum x = MySum(42);
465 
466 	assert(__traits(compiles, x = 3.14));
467 }
468 
469 // Self assignment
470 @safe unittest {
471 	alias MySum = SumType!(int, float);
472 
473 	MySum x = MySum(42);
474 	MySum y = MySum(3.14);
475 
476 	assert(__traits(compiles, y = x));
477 }
478 
479 // Equality
480 @safe unittest {
481 	alias MySum = SumType!(int, float);
482 
483 	MySum x = MySum(123);
484 	MySum y = MySum(123);
485 	MySum z = MySum(456);
486 	MySum w = MySum(123.0);
487 	MySum v = MySum(456.0);
488 
489 	assert(x == y);
490 	assert(x != z);
491 	assert(x != w);
492 	assert(x != v);
493 }
494 
495 // Imported types
496 @safe unittest {
497 	import std.typecons: Tuple;
498 
499 	assert(__traits(compiles, {
500 		alias MySum = SumType!(Tuple!(int, int));
501 	}));
502 }
503 
504 // const and immutable types
505 @safe unittest {
506 	assert(__traits(compiles, {
507 		alias MySum = SumType!(const(int[]), immutable(float[]));
508 	}));
509 }
510 
511 // Works alongside Algebraic
512 version (D_BetterC) {} else
513 @safe unittest {
514 	import std.variant;
515 
516 	alias Bar = Algebraic!(This*);
517 
518 	assert(is(Bar.AllowedTypes[0] == Bar*));
519 }
520 
521 // Types with destructors and postblits
522 @system unittest {
523 	int copies;
524 
525 	static struct Test
526 	{
527 		bool initialized = false;
528 		int* copiesPtr;
529 
530 		this(this) { (*copiesPtr)++; }
531 		~this() { if (initialized) (*copiesPtr)--; }
532 	}
533 
534 	alias MySum = SumType!(int, Test);
535 
536 	Test t = Test(true, &copies);
537 
538 	{
539 		MySum x = t;
540 		assert(copies == 1);
541 	}
542 	assert(copies == 0);
543 
544 	{
545 		MySum x = 456;
546 		assert(copies == 0);
547 	}
548 	assert(copies == 0);
549 
550 	{
551 		MySum x = t;
552 		assert(copies == 1);
553 		x = 456;
554 		assert(copies == 0);
555 	}
556 
557 	{
558 		MySum x = 456;
559 		assert(copies == 0);
560 		x = t;
561 		assert(copies == 1);
562 	}
563 
564 	{
565 		MySum x = t;
566 		MySum y = x;
567 		assert(copies == 2);
568 	}
569 
570 	{
571 		MySum x = t;
572 		MySum y;
573 		y = x;
574 		assert(copies == 2);
575 	}
576 }
577 
578 // Doesn't destroy reference types
579 version (D_BetterC) {} else
580 @system unittest {
581 	bool destroyed;
582 
583 	class C
584 	{
585 		~this()
586 		{
587 			destroyed = true;
588 		}
589 	}
590 
591 	struct S
592 	{
593 		~this() {}
594 	}
595 
596 	alias MySum = SumType!(S, C);
597 
598 	C c = new C();
599 	{
600 		MySum x = c;
601 		destroyed = false;
602 	}
603 	assert(!destroyed);
604 
605 	{
606 		MySum x = c;
607 		destroyed = false;
608 		x = S();
609 		assert(!destroyed);
610 	}
611 }
612 
613 // Types with @disable this()
614 @safe unittest {
615 	static struct NoInit
616 	{
617 		@disable this();
618 	}
619 
620 	alias MySum = SumType!(NoInit, int);
621 
622 	assert(!__traits(compiles, MySum()));
623 	assert(__traits(compiles, MySum(42)));
624 }
625 
626 // const SumTypes
627 @safe unittest {
628 	assert(__traits(compiles,
629 		const(SumType!(int[]))([1, 2, 3])
630 	));
631 }
632 
633 // Equality of const SumTypes
634 @safe unittest {
635 	alias MySum = SumType!int;
636 
637 	assert(__traits(compiles,
638 		const(MySum)(123) == const(MySum)(456)
639 	));
640 }
641 
642 // Compares reference types using value equality
643 @safe unittest {
644 	import std.array: staticArray;
645 
646 	static struct Field {}
647 	static struct Struct { Field[] fields; }
648 	alias MySum = SumType!Struct;
649 
650 	static arr1 = staticArray([Field()]);
651 	static arr2 = staticArray([Field()]);
652 
653 	auto a = MySum(Struct(arr1[]));
654 	auto b = MySum(Struct(arr2[]));
655 
656 	assert(a == b);
657 }
658 
659 // toString
660 version (D_BetterC) {} else
661 @safe unittest {
662 	import std.conv: text;
663 
664 	static struct Int { int i; }
665 	static struct Double { double d; }
666 	alias Sum = SumType!(Int, Double);
667 
668 	assert(Sum(Int(42)).text == Int(42).text, Sum(Int(42)).text);
669 	assert(Sum(Double(33.3)).text == Double(33.3).text, Sum(Double(33.3)).text);
670 	assert((const(Sum)(Int(42))).text == (const(Int)(42)).text, (const(Sum)(Int(42))).text);
671 }
672 
673 // Stale pointers
674 version (D_BetterC) {} else
675 @system unittest {
676 	alias MySum = SumType!(ubyte, void*[2]);
677 
678 	MySum x = [null, cast(void*) 0x12345678];
679 	void** p = &x.get!(void*[2])[1];
680 	x = ubyte(123);
681 
682 	assert(*p != cast(void*) 0x12345678);
683 }
684 
685 // Exception-safe assignment
686 version (D_BetterC) {} else
687 @safe unittest {
688 	static struct A
689 	{
690 		int value = 123;
691 	}
692 
693 	static struct B
694 	{
695 		int value = 456;
696 		this(this) { throw new Exception("oops"); }
697 	}
698 
699 	alias MySum = SumType!(A, B);
700 
701 	MySum x;
702 	try {
703 		x = B();
704 	} catch (Exception e) {}
705 
706 	assert(
707 		(x.tag == 0 && x.get!A.value == 123) ||
708 		(x.tag == 1 && x.get!B.value == 456)
709 	);
710 }
711 
712 // Types with @disable this(this)
713 @safe unittest {
714 	import std.algorithm.mutation: move;
715 
716 	static struct NoCopy
717 	{
718 		@disable this(this);
719 	}
720 
721 	alias MySum = SumType!NoCopy;
722 
723 	NoCopy lval = NoCopy();
724 
725 	MySum x = NoCopy();
726 	MySum y = NoCopy();
727 
728 	assert(__traits(compiles, SumType!NoCopy(NoCopy())));
729 	assert(!__traits(compiles, SumType!NoCopy(lval)));
730 
731 	assert(__traits(compiles, y = NoCopy()));
732 	assert(__traits(compiles, y = move(x)));
733 	assert(!__traits(compiles, y = lval));
734 	assert(!__traits(compiles, y = x));
735 }
736 
737 // Static arrays of structs with postblits
738 version (D_BetterC) {} else
739 @safe unittest {
740 	static struct S
741 	{
742 		int n;
743 		this(this) { n++; }
744 	}
745 
746 	assert(__traits(compiles, SumType!(S[1])()));
747 
748 	SumType!(S[1]) x = [S(0)];
749 	SumType!(S[1]) y = x;
750 
751 	auto xval = x.get!(S[1])[0].n;
752 	auto yval = y.get!(S[1])[0].n;
753 
754 	assert(xval != yval);
755 }
756 
757 // Replacement does not happen inside SumType
758 version (D_BetterC) {} else
759 @safe unittest {
760 	import std.typecons : Tuple;
761 	alias A = Tuple!(This*,SumType!(This*))[SumType!(This*,string)[This]];
762 	alias TR = ReplaceTypeUnless!(isSumType, This, int, A);
763 	static assert(is(TR == Tuple!(int*,SumType!(This*))[SumType!(This*, string)[int]]));
764 }
765 
766 // Supports nested self-referential SumTypes
767 @safe unittest {
768 	import std.typecons : Tuple, Flag;
769 	alias Nat = SumType!(Flag!"0", Tuple!(This*));
770 	static assert(__traits(compiles, SumType!(Nat)));
771 	static assert(__traits(compiles, SumType!(Nat*, Tuple!(This*, This*))));
772 }
773 
774 // Doesn't call @system postblits in @safe code
775 @safe unittest {
776 	static struct SystemCopy { @system this(this) {} }
777 	SystemCopy original;
778 
779 	assert(!__traits(compiles, () @safe {
780 		SumType!SystemCopy copy = original;
781 	}));
782 
783 	assert(!__traits(compiles, () @safe {
784 		SumType!SystemCopy copy; copy = original;
785 	}));
786 }
787 
788 // Doesn't overwrite pointers in @safe code
789 @safe unittest {
790 	alias MySum = SumType!(int*, int);
791 
792 	MySum x;
793 
794 	assert(!__traits(compiles, () @safe {
795 		x = 123;
796 	}));
797 
798 	assert(!__traits(compiles, () @safe {
799 		x = MySum(123);
800 	}));
801 }
802 
803 // Types with invariants
804 version (D_BetterC) {} else
805 @system unittest {
806 	import std.exception: assertThrown;
807 	import core.exception: AssertError;
808 
809 	struct S
810 	{
811 		int i;
812 		invariant { assert(i >= 0); }
813 	}
814 
815 	class C
816 	{
817 		int i;
818 		invariant { assert(i >= 0); }
819 	}
820 
821 	SumType!S x;
822 	x.match!((ref v) { v.i = -1; });
823 	assertThrown!AssertError(assert(&x));
824 
825 	SumType!C y = new C();
826 	y.match!((ref v) { v.i = -1; });
827 	assertThrown!AssertError(assert(&y));
828 }
829 
830 // Calls value postblit on self-assignment
831 @safe unittest {
832 	static struct S
833 	{
834 		int n;
835 		this(this) { n++; }
836 	}
837 
838 	SumType!S x = S();
839 	SumType!S y;
840 	y = x;
841 
842 	auto xval = x.get!S.n;
843 	auto yval = y.get!S.n;
844 
845 	assert(xval != yval);
846 }
847 
848 // Github issue #29
849 @safe unittest {
850 	assert(__traits(compiles, () @safe {
851 		alias A = SumType!string;
852 
853 		@safe A createA(string arg) {
854 		return A(arg);
855 		}
856 
857 		@safe void test() {
858 		A a = createA("");
859 		}
860 	}));
861 }
862 
863 version(none) {
864 	// Known bug; needs fix for dlang issue 19902
865 	// Types with copy constructors
866 	@safe unittest {
867 		static struct S
868 		{
869 			int n;
870 			this(ref return scope inout S other) inout { n++; }
871 		}
872 
873 		SumType!S x = S();
874 		SumType!S y = x;
875 
876 		auto xval = x.get!S.n;
877 		auto yval = y.get!S.n;
878 
879 		assert(xval != yval);
880 	}
881 }
882 
883 version(none) {
884 	// Known bug; needs fix for dlang issue 19458
885 	// Types with disabled opEquals
886 	@safe unittest {
887 		static struct S
888 		{
889 			@disable bool opEquals(const S rhs) const;
890 		}
891 
892 		assert(__traits(compiles, SumType!S(S())));
893 	}
894 }
895 
896 version(none) {
897 	// Known bug; needs fix for dlang issue 19458
898 	@safe unittest {
899 		static struct S
900 		{
901 			int i;
902 			bool opEquals(S rhs) { return i == rhs.i; }
903 		}
904 
905 		assert(__traits(compiles, SumType!S(S(123))));
906 	}
907 }
908 +/
909 /// True if `T` is an instance of `SumType`, otherwise false.
910 enum isSumType(T) = is(T == SumType!Args, Args...);
911 
912 /+
913 unittest {
914 	static struct Wrapper
915 	{
916 		SumType!int s;
917 		alias s this;
918 	}
919 
920 	assert(isSumType!(SumType!int));
921 	assert(!isSumType!Wrapper);
922 }
923 +/
924 /**
925  * Calls a type-appropriate function with the value held in a [SumType].
926  *
927  * For each possible type the [SumType] can hold, the given handlers are
928  * checked, in order, to see whether they accept a single argument of that type.
929  * The first one that does is chosen as the match for that type.
930  *
931  * Every type must have a matching handler, and every handler must match at
932  * least one type. This is enforced at compile time.
933  *
934  * Handlers may be functions, delegates, or objects with opCall overloads. If a
935  * function with more than one overload is given as a handler, all of the
936  * overloads are considered as potential matches.
937  *
938  * Templated handlers are also accepted, and will match any type for which they
939  * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
940  * [sumtype#introspection-based-matching|"Introspection-based matching"] for an
941  * example of templated handler usage.
942  *
943  * Returns:
944  *   The value returned from the handler that matches the currently-held type.
945  *
946  * See_Also: `std.variant.visit`
947  */
948 template match(handlers...)
949 {
950 	import std.typecons: Yes;
951 
952 	/**
953 	 * The actual `match` function.
954 	 *
955 	 * Params:
956 	 *   self = A [SumType] object
957 	 */
958 	auto match(Self)(auto ref Self self)
959 		if (is(Self : SumType!TypeArgs, TypeArgs...))
960 	{
961 		return self.matchImpl!(Yes.exhaustive, handlers);
962 	}
963 }
964 /+
965 /**
966  * Attempts to call a type-appropriate function with the value held in a
967  * [SumType], and throws on failure.
968  *
969  * Matches are chosen using the same rules as [match], but are not required to
970  * be exhaustive—in other words, a type is allowed to have no matching handler.
971  * If a type without a handler is encountered at runtime, a [MatchException]
972  * is thrown.
973  *
974  * Not available when compiled with `-betterC`.
975  *
976  * Returns:
977  *   The value returned from the handler that matches the currently-held type,
978  *   if a handler was given for that type.
979  *
980  * Throws:
981  *   [MatchException], if the currently-held type has no matching handler.
982  *
983  * See_Also: `std.variant.tryVisit`
984  */
985 version (D_Exceptions)
986 template tryMatch(handlers...)
987 {
988 	import std.typecons: No;
989 
990 	/**
991 	 * The actual `tryMatch` function.
992 	 *
993 	 * Params:
994 	 *   self = A [SumType] object
995 	 */
996 	auto tryMatch(Self)(auto ref Self self)
997 		if (is(Self : SumType!TypeArgs, TypeArgs...))
998 	{
999 		return self.matchImpl!(No.exhaustive, handlers);
1000 	}
1001 }
1002 
1003 /**
1004  * Thrown by [tryMatch] when an unhandled type is encountered.
1005  *
1006  * Not available when compiled with `-betterC`.
1007  */
1008 version (D_Exceptions)
1009 class MatchException : Exception
1010 {
1011 	pure @safe @nogc nothrow
1012 	this(string msg, string file = __FILE__, size_t line = __LINE__)
1013 	{
1014 		super(msg, file, line);
1015 	}
1016 }
1017 +/
1018 /**
1019  * True if `handler` is a potential match for `T`, otherwise false.
1020  *
1021  * See the documentation for [match] for a full explanation of how matches are
1022  * chosen.
1023  */
1024 enum bool canMatch(alias handler, T) = is(typeof((T arg) { handler(arg); }));
1025 
1026 // Includes all overloads of the given handler
1027 // @safe unittest {
1028 // 	static struct OverloadSet
1029 // 	{
1030 // 		static void fun(int n) {}
1031 // 		static void fun(double d) {}
1032 // 	}
1033 
1034 // 	assert(canMatch!(OverloadSet.fun, int));
1035 // 	assert(canMatch!(OverloadSet.fun, double));
1036 // }
1037 
1038 import std.typecons: Flag;
1039 
1040 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
1041 {
1042 	auto matchImpl(Self)(auto ref Self self)
1043 		if (is(Self : SumType!TypeArgs, TypeArgs...))
1044 	{
1045 		alias Types = self.Types;
1046 		enum noMatch = size_t.max;
1047 
1048 		enum matches = () {
1049 			size_t[Types.length] matches;
1050 
1051 			// Workaround for dlang issue 19561
1052 			foreach (ref match; matches) {
1053 				match = noMatch;
1054 			}
1055 
1056 			static foreach (tid, T; Types) {
1057 				static foreach (hid, handler; handlers) {
1058 					static if (canMatch!(handler, typeof(self.get!T()))) {
1059 						if (matches[tid] == noMatch) {
1060 							matches[tid] = hid;
1061 						}
1062 					}
1063 				}
1064 			}
1065 
1066 			return matches;
1067 		}();
1068 
1069 		import std.algorithm.searching: canFind;
1070 
1071 		// Check for unreachable handlers
1072 		static foreach (hid, handler; handlers) {
1073 			static assert(matches[].canFind(hid),
1074 				"handler `" ~ __traits(identifier, handler) ~ "` " ~
1075 				"of type `" ~ ( __traits(isTemplate, handler)
1076 					? "template"
1077 					: typeof(handler).stringof
1078 				) ~ "` " ~
1079 				"never matches"
1080 			);
1081 		}
1082 
1083 		// Workaround for dlang issue 19993
1084 		static foreach (size_t hid, handler; handlers) {
1085 			mixin("alias handler", hid, " = handler;");
1086 		}
1087 
1088 		final switch (self.tag) {
1089 			static foreach (tid, T; Types) {
1090 				case tid:
1091 					static if (matches[tid] != noMatch) {
1092 						return mixin("handler", matches[tid])(self.get!T);
1093 					} else {
1094 						static if(exhaustive) {
1095 							static assert(false,
1096 								"No matching handler for type `" ~ T.stringof ~ "`");
1097 						} else {
1098 							throw new MatchException(
1099 								"No matching handler for type `" ~ T.stringof ~ "`");
1100 						}
1101 					}
1102 			}
1103 		}
1104 
1105 		assert(false); // unreached
1106 	}
1107 }
1108 /+
1109 // Matching
1110 @safe unittest {
1111 	alias MySum = SumType!(int, float);
1112 
1113 	MySum x = MySum(42);
1114 	MySum y = MySum(3.14);
1115 
1116 	assert(x.match!((int v) => true, (float v) => false));
1117 	assert(y.match!((int v) => false, (float v) => true));
1118 }
1119 
1120 // Missing handlers
1121 @safe unittest {
1122 	alias MySum = SumType!(int, float);
1123 
1124 	MySum x = MySum(42);
1125 
1126 	assert(!__traits(compiles, x.match!((int x) => true)));
1127 	assert(!__traits(compiles, x.match!()));
1128 }
1129 
1130 // Handlers with qualified parameters
1131 version (D_BetterC) {} else
1132 @safe unittest {
1133 	alias MySum = SumType!(int[], float[]);
1134 
1135 	MySum x = MySum([1, 2, 3]);
1136 	MySum y = MySum([1.0, 2.0, 3.0]);
1137 
1138 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
1139 	assert(y.match!((const(int[]) v) => false, (const(float[]) v) => true));
1140 }
1141 
1142 // Handlers for qualified types
1143 version (D_BetterC) {} else
1144 @safe unittest {
1145 	alias MySum = SumType!(immutable(int[]), immutable(float[]));
1146 
1147 	MySum x = MySum([1, 2, 3]);
1148 
1149 	assert(x.match!((immutable(int[]) v) => true, (immutable(float[]) v) => false));
1150 	assert(x.match!((const(int[]) v) => true, (const(float[]) v) => false));
1151 	// Tail-qualified parameters
1152 	assert(x.match!((immutable(int)[] v) => true, (immutable(float)[] v) => false));
1153 	assert(x.match!((const(int)[] v) => true, (const(float)[] v) => false));
1154 	// Generic parameters
1155 	assert(x.match!((immutable v) => true));
1156 	assert(x.match!((const v) => true));
1157 	// Unqualified parameters
1158 	assert(!__traits(compiles,
1159 		x.match!((int[] v) => true, (float[] v) => false)
1160 	));
1161 }
1162 
1163 // Delegate handlers
1164 version (D_BetterC) {} else
1165 @safe unittest {
1166 	alias MySum = SumType!(int, float);
1167 
1168 	int answer = 42;
1169 	MySum x = MySum(42);
1170 	MySum y = MySum(3.14);
1171 
1172 	assert(x.match!((int v) => v == answer, (float v) => v == answer));
1173 	assert(!y.match!((int v) => v == answer, (float v) => v == answer));
1174 }
1175 
1176 version(unittest) {
1177 	version(D_BetterC) {
1178 		// std.math.approxEqual depends on core.runtime.math, so use a
1179 		// libc-based version for testing with -betterC
1180 		@safe pure @nogc nothrow
1181 		private bool approxEqual(double lhs, double rhs)
1182 		{
1183 			import core.stdc.math: fabs;
1184 
1185 			return (lhs - rhs) < 1e-5;
1186 		}
1187 	} else {
1188 		import std.math: approxEqual;
1189 	}
1190 }
1191 
1192 // Generic handler
1193 @safe unittest {
1194 	alias MySum = SumType!(int, float);
1195 
1196 	MySum x = MySum(42);
1197 	MySum y = MySum(3.14);
1198 
1199 	assert(x.match!(v => v*2) == 84);
1200 	assert(y.match!(v => v*2).approxEqual(6.28));
1201 }
1202 
1203 // Fallback to generic handler
1204 version (D_BetterC) {} else
1205 @safe unittest {
1206 	import std.conv: to;
1207 
1208 	alias MySum = SumType!(int, float, string);
1209 
1210 	MySum x = MySum(42);
1211 	MySum y = MySum("42");
1212 
1213 	assert(x.match!((string v) => v.to!int, v => v*2) == 84);
1214 	assert(y.match!((string v) => v.to!int, v => v*2) == 42);
1215 }
1216 
1217 // Multiple non-overlapping generic handlers
1218 @safe unittest {
1219 	import std.array: staticArray;
1220 
1221 	alias MySum = SumType!(int, float, int[], char[]);
1222 
1223 	static ints = staticArray([1, 2, 3]);
1224 	static chars = staticArray(['a', 'b', 'c']);
1225 
1226 	MySum x = MySum(42);
1227 	MySum y = MySum(3.14);
1228 	MySum z = MySum(ints[]);
1229 	MySum w = MySum(chars[]);
1230 
1231 	assert(x.match!(v => v*2, v => v.length) == 84);
1232 	assert(y.match!(v => v*2, v => v.length).approxEqual(6.28));
1233 	assert(w.match!(v => v*2, v => v.length) == 3);
1234 	assert(z.match!(v => v*2, v => v.length) == 3);
1235 }
1236 
1237 // Structural matching
1238 @safe unittest {
1239 	static struct S1 { int x; }
1240 	static struct S2 { int y; }
1241 	alias MySum = SumType!(S1, S2);
1242 
1243 	MySum a = MySum(S1(0));
1244 	MySum b = MySum(S2(0));
1245 
1246 	assert(a.match!(s1 => s1.x + 1, s2 => s2.y - 1) == 1);
1247 	assert(b.match!(s1 => s1.x + 1, s2 => s2.y - 1) == -1);
1248 }
1249 
1250 // Separate opCall handlers
1251 @safe unittest {
1252 	static struct IntHandler
1253 	{
1254 		bool opCall(int arg)
1255 		{
1256 			return true;
1257 		}
1258 	}
1259 
1260 	static struct FloatHandler
1261 	{
1262 		bool opCall(float arg)
1263 		{
1264 			return false;
1265 		}
1266 	}
1267 
1268 	alias MySum = SumType!(int, float);
1269 
1270 	MySum x = MySum(42);
1271 	MySum y = MySum(3.14);
1272 
1273 	assert(x.match!(IntHandler.init, FloatHandler.init));
1274 	assert(!y.match!(IntHandler.init, FloatHandler.init));
1275 }
1276 
1277 // Compound opCall handler
1278 @safe unittest {
1279 	static struct CompoundHandler
1280 	{
1281 		bool opCall(int arg)
1282 		{
1283 			return true;
1284 		}
1285 
1286 		bool opCall(float arg)
1287 		{
1288 			return false;
1289 		}
1290 	}
1291 
1292 	alias MySum = SumType!(int, float);
1293 
1294 	MySum x = MySum(42);
1295 	MySum y = MySum(3.14);
1296 
1297 	assert(x.match!(CompoundHandler.init));
1298 	assert(!y.match!(CompoundHandler.init));
1299 }
1300 
1301 // Ordered matching
1302 @safe unittest {
1303 	alias MySum = SumType!(int, float);
1304 
1305 	MySum x = MySum(42);
1306 
1307 	assert(x.match!((int v) => true, v => false));
1308 }
1309 
1310 // Non-exhaustive matching
1311 version (D_Exceptions)
1312 @system unittest {
1313 	import std.exception: assertThrown, assertNotThrown;
1314 
1315 	alias MySum = SumType!(int, float);
1316 
1317 	MySum x = MySum(42);
1318 	MySum y = MySum(3.14);
1319 
1320 	assertNotThrown!MatchException(x.tryMatch!((int n) => true));
1321 	assertThrown!MatchException(y.tryMatch!((int n) => true));
1322 }
1323 
1324 // Non-exhaustive matching in @safe code
1325 version (D_Exceptions)
1326 @safe unittest {
1327 	SumType!(int, float) x;
1328 
1329 	assert(__traits(compiles,
1330 		x.tryMatch!(
1331 			(int n) => n + 1,
1332 		)
1333 	));
1334 
1335 }
1336 
1337 // Handlers with ref parameters
1338 @safe unittest {
1339 	import std.meta: staticIndexOf;
1340 
1341 	alias Value = SumType!(long, double);
1342 
1343 	auto value = Value(3.14);
1344 
1345 	value.match!(
1346 		(long) {},
1347 		(ref double d) { d *= 2; }
1348 	);
1349 
1350 	assert(value.get!double.approxEqual(6.28));
1351 }
1352 
1353 // Unreachable handlers
1354 @safe unittest {
1355 	alias MySum = SumType!(int, string);
1356 
1357 	MySum s;
1358 
1359 	assert(!__traits(compiles,
1360 		s.match!(
1361 			(int _) => 0,
1362 			(string _) => 1,
1363 			(double _) => 2
1364 		)
1365 	));
1366 
1367 	assert(!__traits(compiles,
1368 		s.match!(
1369 			_ => 0,
1370 			(int _) => 1
1371 		)
1372 	));
1373 }
1374 
1375 // Unsafe handlers
1376 unittest {
1377 	SumType!int x;
1378 	alias unsafeHandler = (int x) @system { return; };
1379 
1380 	assert(!__traits(compiles, () @safe {
1381 		x.match!unsafeHandler;
1382 	}));
1383 
1384 	assert(__traits(compiles, () @system {
1385 		return x.match!unsafeHandler;
1386 	}));
1387 }
1388 
1389 // Overloaded handlers
1390 @safe unittest {
1391 	static struct OverloadSet
1392 	{
1393 		static string fun(int i) { return "int"; }
1394 		static string fun(double d) { return "double"; }
1395 	}
1396 
1397 	alias MySum = SumType!(int, double);
1398 
1399 	MySum a = 42;
1400 	MySum b = 3.14;
1401 
1402 	assert(a.match!(OverloadSet.fun) == "int");
1403 	assert(b.match!(OverloadSet.fun) == "double");
1404 }
1405 
1406 // Overload sets with ref arguments
1407 @safe unittest {
1408 	static struct OverloadSet
1409 	{
1410 		static void fun(ref int i) { i = 42; }
1411 		static void fun(ref double d) { d = 3.14; }
1412 	}
1413 
1414 	alias MySum = SumType!(int, double);
1415 
1416 	MySum x = 0;
1417 	MySum y = 0.0;
1418 
1419 	x.match!(OverloadSet.fun);
1420 	y.match!(OverloadSet.fun);
1421 
1422 	assert(x.match!((value) => is(typeof(value) == int) && value == 42));
1423 	assert(y.match!((value) => is(typeof(value) == double) && value == 3.14));
1424 }
1425 
1426 // Overload sets with templates
1427 @safe unittest {
1428 	import std.traits: isNumeric;
1429 
1430 	static struct OverloadSet
1431 	{
1432 		static string fun(string arg)
1433 		{
1434 			return "string";
1435 		}
1436 
1437 		static string fun(T)(T arg)
1438 			if (isNumeric!T)
1439 		{
1440 			return "numeric";
1441 		}
1442 	}
1443 
1444 	alias MySum = SumType!(int, string);
1445 
1446 	MySum x = 123;
1447 	MySum y = "hello";
1448 
1449 	assert(x.match!(OverloadSet.fun) == "numeric");
1450 	assert(y.match!(OverloadSet.fun) == "string");
1451 }
1452 
1453 // Github issue #24
1454 @safe unittest {
1455 	assert(__traits(compiles, () @nogc {
1456 		int acc = 0;
1457 		SumType!int(1).match!((int x) => acc += x);
1458 	}));
1459 }
1460 
1461 // Github issue #31
1462 @safe unittest {
1463 	assert(__traits(compiles, () @nogc {
1464 		int acc = 0;
1465 
1466 		SumType!(int, string)(1).match!(
1467 			(int x) => acc += x,
1468 			(string _) => 0,
1469 		);
1470 	}));
1471 }
1472 
1473 // Types that `alias this` a SumType
1474 @safe unittest {
1475 	static struct A {}
1476 	static struct B {}
1477 	static struct D { SumType!(A, B) value; alias value this; }
1478 
1479 	assert(__traits(compiles, D().match!(_ => true)));
1480 }
1481 +/
1482 version(SumTypeTestBetterC) {
1483 	version(D_BetterC) {}
1484 	else static assert(false, "Must compile with -betterC to run betterC tests");
1485 
1486 	version(unittest) {}
1487 	else static assert(false, "Must compile with -unittest to run betterC tests");
1488 
1489 	extern(C) int main()
1490 	{
1491 		import core.stdc.stdio: puts;
1492 		static foreach (test; __traits(getUnitTests, mixin(__MODULE__))) {
1493 			test();
1494 		}
1495 
1496 		puts("All unit tests have been run successfully.");
1497 		return 0;
1498 	}
1499 }
1500 
1501 static if (__traits(compiles, { import std.typecons: ReplaceTypeUnless; })) {
1502 	import std.typecons: ReplaceTypeUnless;
1503 } else {
1504 /**
1505  * Replaces all occurrences of `From` into `To`, in one or more types `T`
1506  * whenever the predicate applied to `T` evaluates to false. For example, $(D
1507  * ReplaceTypeUnless!(isBoolean, int, uint, Tuple!(int, float)[string])) yields
1508  * $(D Tuple!(uint, float)[string]) while $(D ReplaceTypeUnless!(isTuple, int,
1509  * string, Tuple!(int, bool)[int])) yields $(D Tuple!(int, bool)[string]). The
1510  * types in which replacement is performed may be arbitrarily complex,
1511  * including qualifiers, built-in type constructors (pointers, arrays,
1512  * associative arrays, functions, and delegates), and template instantiations;
1513  * replacement proceeds transitively through the type definition.  However,
1514  * member types in `struct`s or `class`es are not replaced because there are no
1515  * ways to express the types resulting after replacement.
1516  *
1517  * This is an advanced type manipulation necessary e.g. for replacing the
1518  * placeholder type `This` in $(REF SumType).
1519  *
1520  * This template is a generalised version of the one in
1521  * https://github.com/dlang/phobos/blob/d1c8fb0b69dc12669554d5cb96d3045753549619/std/typecons.d
1522  *
1523  * Returns: `ReplaceTypeUnless` aliases itself to the type(s) that result after
1524  * replacement.
1525 */
1526 private template ReplaceTypeUnless(alias Pred, From, To, T...)
1527 {
1528 	import std.meta;
1529 
1530 	static if (T.length == 1)
1531 	{
1532 		static if (Pred!(T[0]))
1533 			alias ReplaceTypeUnless = T[0];
1534 		else static if (is(T[0] == From))
1535 			alias ReplaceTypeUnless = To;
1536 		else static if (is(T[0] == const(U), U))
1537 			alias ReplaceTypeUnless = const(ReplaceTypeUnless!(Pred, From, To, U));
1538 		else static if (is(T[0] == immutable(U), U))
1539 			alias ReplaceTypeUnless = immutable(ReplaceTypeUnless!(Pred, From, To, U));
1540 		else static if (is(T[0] == shared(U), U))
1541 			alias ReplaceTypeUnless = shared(ReplaceTypeUnless!(Pred, From, To, U));
1542 		else static if (is(T[0] == U*, U))
1543 		{
1544 			static if (is(U == function))
1545 				alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(Pred, From, To, T[0]);
1546 			else
1547 				alias ReplaceTypeUnless = ReplaceTypeUnless!(Pred, From, To, U)*;
1548 		}
1549 		else static if (is(T[0] == delegate))
1550 		{
1551 			alias ReplaceTypeUnless = replaceTypeInFunctionTypeUnless!(Pred, From, To, T[0]);
1552 		}
1553 		else static if (is(T[0] == function))
1554 		{
1555 			static assert(0, "Function types not supported," ~
1556 				" use a function pointer type instead of " ~ T[0].stringof);
1557 		}
1558 		else static if (is(T[0] == U!V, alias U, V...))
1559 		{
1560 			template replaceTemplateArgs(T...)
1561 			{
1562 				static if (is(typeof(T[0])))	// template argument is value or symbol
1563 					enum replaceTemplateArgs = T[0];
1564 				else
1565 					alias replaceTemplateArgs = ReplaceTypeUnless!(Pred, From, To, T[0]);
1566 			}
1567 			alias ReplaceTypeUnless = U!(staticMap!(replaceTemplateArgs, V));
1568 		}
1569 		else static if (is(T[0] == struct))
1570 			// don't match with alias this struct below (Issue 15168)
1571 			alias ReplaceTypeUnless = T[0];
1572 		else static if (is(T[0] == U[], U))
1573 			alias ReplaceTypeUnless = ReplaceTypeUnless!(Pred, From, To, U)[];
1574 		else static if (is(T[0] == U[n], U, size_t n))
1575 			alias ReplaceTypeUnless = ReplaceTypeUnless!(Pred, From, To, U)[n];
1576 		else static if (is(T[0] == U[V], U, V))
1577 			alias ReplaceTypeUnless =
1578 				ReplaceTypeUnless!(Pred, From, To, U)[ReplaceTypeUnless!(Pred, From, To, V)];
1579 		else
1580 			alias ReplaceTypeUnless = T[0];
1581 	}
1582 	else static if (T.length > 1)
1583 	{
1584 		alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(Pred, From, To, T[0]),
1585 			ReplaceTypeUnless!(Pred, From, To, T[1 .. $]));
1586 	}
1587 	else
1588 	{
1589 		alias ReplaceTypeUnless = AliasSeq!();
1590 	}
1591 }
1592 
1593 
1594 private template replaceTypeInFunctionTypeUnless(alias Pred, From, To, fun)
1595 {
1596 	import std.traits;
1597 	import std.meta: AliasSeq;
1598 
1599 	alias RX = ReplaceTypeUnless!(Pred, From, To, ReturnType!fun);
1600 	alias PX = AliasSeq!(ReplaceTypeUnless!(Pred, From, To, Parameters!fun));
1601 	// Wrapping with AliasSeq is neccesary because ReplaceType doesn't return
1602 	// tuple if Parameters!fun.length == 1
1603 
1604 	string gen()
1605 	{
1606 		enum  linkage = functionLinkage!fun;
1607 		alias attributes = functionAttributes!fun;
1608 		enum  variadicStyle = variadicFunctionStyle!fun;
1609 		alias storageClasses = ParameterStorageClassTuple!fun;
1610 
1611 		string result;
1612 
1613 		result ~= "extern(" ~ linkage ~ ") ";
1614 		static if (attributes & FunctionAttribute.ref_)
1615 		{
1616 			result ~= "ref ";
1617 		}
1618 
1619 		result ~= "RX";
1620 		static if (is(fun == delegate))
1621 			result ~= " delegate";
1622 		else
1623 			result ~= " function";
1624 
1625 		result ~= "(";
1626 		static foreach (i; 0 .. PX.length)
1627 		{
1628 			if (i)
1629 				result ~= ", ";
1630 			if (storageClasses[i] & ParameterStorageClass.scope_)
1631 				result ~= "scope ";
1632 			if (storageClasses[i] & ParameterStorageClass.out_)
1633 				result ~= "out ";
1634 			if (storageClasses[i] & ParameterStorageClass.ref_)
1635 				result ~= "ref ";
1636 			if (storageClasses[i] & ParameterStorageClass.lazy_)
1637 				result ~= "lazy ";
1638 			if (storageClasses[i] & ParameterStorageClass.return_)
1639 				result ~= "return ";
1640 
1641 			result ~= "PX[" ~ i.stringof ~ "]";
1642 		}
1643 		static if (variadicStyle == Variadic.typesafe)
1644 			result ~= " ...";
1645 		else static if (variadicStyle != Variadic.no)
1646 			result ~= ", ...";
1647 		result ~= ")";
1648 
1649 		static if (attributes & FunctionAttribute.pure_)
1650 			result ~= " pure";
1651 		static if (attributes & FunctionAttribute.nothrow_)
1652 			result ~= " nothrow";
1653 		static if (attributes & FunctionAttribute.property)
1654 			result ~= " @property";
1655 		static if (attributes & FunctionAttribute.trusted)
1656 			result ~= " @trusted";
1657 		static if (attributes & FunctionAttribute.safe)
1658 			result ~= " @safe";
1659 		static if (attributes & FunctionAttribute.nogc)
1660 			result ~= " @nogc";
1661 		static if (attributes & FunctionAttribute.system)
1662 			result ~= " @system";
1663 		static if (attributes & FunctionAttribute.const_)
1664 			result ~= " const";
1665 		static if (attributes & FunctionAttribute.immutable_)
1666 			result ~= " immutable";
1667 		static if (attributes & FunctionAttribute.inout_)
1668 			result ~= " inout";
1669 		static if (attributes & FunctionAttribute.shared_)
1670 			result ~= " shared";
1671 		static if (attributes & FunctionAttribute.return_)
1672 			result ~= " return";
1673 
1674 		return result;
1675 	}
1676 
1677 	mixin("alias replaceTypeInFunctionTypeUnless = " ~ gen() ~ ";");
1678 }
1679 
1680 // Adapted from:
1681 // https://github.com/dlang/phobos/blob/d1c8fb0b69dc12669554d5cb96d3045753549619/std/typecons.d
1682 @safe unittest {
1683 	import std.typecons: Tuple;
1684 	enum False(T) = false;
1685 	static assert(
1686 		is(ReplaceTypeUnless!(False, int, string, int[]) == string[]) &&
1687 		is(ReplaceTypeUnless!(False, int, string, int[int]) == string[string]) &&
1688 		is(ReplaceTypeUnless!(False, int, string, const(int)[]) == const(string)[]) &&
1689 		is(ReplaceTypeUnless!(False, int, string, Tuple!(int[], float))
1690 			== Tuple!(string[], float))
1691 	);
1692 }
1693 
1694 // Adapted from:
1695 // https://github.com/dlang/phobos/blob/d1c8fb0b69dc12669554d5cb96d3045753549619/std/typecons.d
1696 version (D_BetterC) {} else
1697 @safe unittest
1698 {
1699 	import std.typecons;
1700 
1701 	enum False(T) = false;
1702 	template Test(Ts...)
1703 	{
1704 		static if (Ts.length)
1705 		{
1706 			static assert(is(ReplaceTypeUnless!(False, Ts[0], Ts[1], Ts[2]) == Ts[3]),
1707 				"ReplaceTypeUnless!(False, "~Ts[0].stringof~", "~Ts[1].stringof~", "
1708 					~Ts[2].stringof~") == "
1709 					~ReplaceTypeUnless!(False, Ts[0], Ts[1], Ts[2]).stringof);
1710 			alias Test = Test!(Ts[4 .. $]);
1711 		}
1712 		else alias Test = void;
1713 	}
1714 
1715 	import core.stdc.stdio;
1716 	alias RefFun1 = ref int function(float, long);
1717 	alias RefFun2 = ref float function(float, long);
1718 	extern(C) int printf(const char*, ...) nothrow @nogc @system;
1719 	extern(C) float floatPrintf(const char*, ...) nothrow @nogc @system;
1720 	int func(float);
1721 
1722 	int x;
1723 	struct S1 { void foo() { x = 1; } }
1724 	struct S2 { void bar() { x = 2; } }
1725 
1726 	alias Pass = Test!(
1727 		int, float, typeof(&func), float delegate(float),
1728 		int, float, typeof(&printf), typeof(&floatPrintf),
1729 		int, float, int function(out long, ...),
1730 			float function(out long, ...),
1731 		int, float, int function(ref float, long),
1732 			float function(ref float, long),
1733 		int, float, int function(ref int, long),
1734 			float function(ref float, long),
1735 		int, float, int function(out int, long),
1736 			float function(out float, long),
1737 		int, float, int function(lazy int, long),
1738 			float function(lazy float, long),
1739 		int, float, int function(out long, ref const int),
1740 			float function(out long, ref const float),
1741 		int, int, int, int,
1742 		int, float, int, float,
1743 		int, float, const int, const float,
1744 		int, float, immutable int, immutable float,
1745 		int, float, shared int, shared float,
1746 		int, float, int*, float*,
1747 		int, float, const(int)*, const(float)*,
1748 		int, float, const(int*), const(float*),
1749 		const(int)*, float, const(int*), const(float),
1750 		int*, float, const(int)*, const(int)*,
1751 		int, float, int[], float[],
1752 		int, float, int[42], float[42],
1753 		int, float, const(int)[42], const(float)[42],
1754 		int, float, const(int[42]), const(float[42]),
1755 		int, float, int[int], float[float],
1756 		int, float, int[double], float[double],
1757 		int, float, double[int], double[float],
1758 		int, float, int function(float, long), float function(float, long),
1759 		int, float, int function(float), float function(float),
1760 		int, float, int function(float, int), float function(float, float),
1761 		int, float, int delegate(float, long), float delegate(float, long),
1762 		int, float, int delegate(float), float delegate(float),
1763 		int, float, int delegate(float, int), float delegate(float, float),
1764 		int, float, Unique!int, Unique!float,
1765 		int, float, Tuple!(float, int), Tuple!(float, float),
1766 		int, float, RefFun1, RefFun2,
1767 		S1, S2,
1768 			S1[1][][S1]* function(),
1769 			S2[1][][S2]* function(),
1770 		int, string,
1771 			   int[3] function(   int[] arr,	int[2] ...) pure @trusted,
1772 			string[3] function(string[] arr, string[2] ...) pure @trusted,
1773 	);
1774 
1775 	// Dlang Bugzilla 15168
1776 	static struct T1 { string s; alias s this; }
1777 	static struct T2 { char[10] s; alias s this; }
1778 	static struct T3 { string[string] s; alias s this; }
1779 	alias Pass2 = Test!(
1780 		ubyte, ubyte, T1, T1,
1781 		ubyte, ubyte, T2, T2,
1782 		ubyte, ubyte, T3, T3,
1783 	);
1784 }
1785 
1786 version (D_BetterC) {} else
1787 @safe unittest // Dlang Bugzilla 17116
1788 {
1789 	enum False(T) = false;
1790 	alias ConstDg = void delegate(float) const;
1791 	alias B = void delegate(int) const;
1792 	alias A = ReplaceTypeUnless!(False, float, int, ConstDg);
1793 	static assert(is(B == A));
1794 }
1795 
1796 // Github issue #27
1797 @safe unittest
1798 {
1799 	enum False(T) = false;
1800 	struct A(T) {}
1801 	struct B { A!int a; alias a this; }
1802 	static assert(is(ReplaceTypeUnless!(False, void, void, B) == B));
1803 }
1804 }