1 module d.ir.type;
2 
3 import d.ir.error;
4 import d.ir.symbol;
5 
6 public import d.common.builtintype;
7 public import d.common.qualifier;
8 
9 import source.context;
10 import d.common.type;
11 
12 // Conflict with Interface in object.di
13 alias Interface = d.ir.symbol.Interface;
14 
15 enum TypeKind : ubyte {
16 	Builtin,
17 
18 	// Symbols
19 	Alias,
20 	Struct,
21 	Class,
22 	Interface,
23 	Union,
24 	Enum,
25 
26 	// Context
27 	Context,
28 
29 	// Type constructors
30 	Pointer,
31 	Slice,
32 	Array,
33 
34 	// Sequence
35 	Sequence,
36 
37 	// Complex types
38 	Function,
39 
40 	// Template Pattern matching for IFTI.
41 	Pattern,
42 
43 	// Error
44 	Error,
45 }
46 
47 struct Type {
48 private:
49 	mixin TypeMixin!(TypeKind, Payload);
50 
51 	this(Desc d, inout Payload p = Payload.init) inout {
52 		desc = d;
53 		payload = p;
54 	}
55 
56 	import util.fastcast;
57 	this(Desc d, inout Symbol s) inout {
58 		this(d, fastCast!(inout Payload)(s));
59 	}
60 
61 	this(Desc d, inout Type* t) inout {
62 		this(d, fastCast!(inout Payload)(t));
63 	}
64 
65 	this(Desc d, inout Pattern.Payload p) inout {
66 		this(d, fastCast!(inout Payload)(p));
67 	}
68 
69 	this(Desc d, inout CompileError e) inout {
70 		this(d, fastCast!(inout Payload)(e));
71 	}
72 
73 	Type getConstructedType(this T)(TypeKind k, TypeQualifier q) {
74 		return qualify(q).getConstructedMixin(k, q);
75 	}
76 
77 	auto acceptImpl(T)(T t) {
78 		final switch (kind) with (TypeKind) {
79 			case Builtin:
80 				return t.visit(builtin);
81 
82 			case Struct:
83 				return t.visit(dstruct);
84 
85 			case Class:
86 				return t.visit(dclass);
87 
88 			case Enum:
89 				return t.visit(denum);
90 
91 			case Alias:
92 				// XXX: consider how to propagate the qualifier properly.
93 				return t.visit(dalias);
94 
95 			case Interface:
96 				return t.visit(dinterface);
97 
98 			case Union:
99 				return t.visit(dunion);
100 
101 			case Context:
102 				return t.visit(context);
103 
104 			case Pointer:
105 				return t.visitPointerOf(element);
106 
107 			case Slice:
108 				return t.visitSliceOf(element);
109 
110 			case Array:
111 				return t.visitArrayOf(size, element);
112 
113 			case Sequence:
114 				return t.visit(sequence);
115 
116 			case Function:
117 				return t.visit(asFunctionType());
118 
119 			case Pattern:
120 				return t.visit(pattern);
121 
122 			case Error:
123 				return t.visit(error);
124 		}
125 	}
126 
127 public:
128 	auto accept(T)(ref T t) if (is(T == struct)) {
129 		return acceptImpl(&t);
130 	}
131 
132 	auto accept(T)(T t) if (is(T == class)) {
133 		return acceptImpl(t);
134 	}
135 
136 	Type qualify(TypeQualifier q) {
137 		auto nq = q.add(qualifier);
138 		if (nq == qualifier) {
139 			return Type(desc, payload);
140 		}
141 
142 		switch (kind) with (TypeKind) {
143 			case Builtin, Struct, Class, Enum, Alias:
144 			case Interface, Union, Context, Function:
145 				auto d = desc;
146 				d.qualifier = nq;
147 				return Type(d, payload);
148 
149 			case Pointer:
150 				return element.qualify(nq).getPointer(nq);
151 
152 			case Slice:
153 				return element.qualify(nq).getSlice(nq);
154 
155 			case Array:
156 				return element.qualify(nq).getArray(size, nq);
157 
158 			default:
159 				assert(0, "Not implemented");
160 		}
161 	}
162 
163 	Type unqual() {
164 		auto d = desc;
165 		d.qualifier = TypeQualifier.Mutable;
166 		return Type(d, payload);
167 	}
168 
169 	@property
170 	BuiltinType builtin() inout in {
171 		assert(kind == TypeKind.Builtin, "Not a builtin type.");
172 	} do {
173 		return cast(BuiltinType) desc.data;
174 	}
175 
176 	bool isAggregate() const {
177 		return (kind >= TypeKind.Struct) && (kind <= TypeKind.Union);
178 	}
179 
180 	@property
181 	auto aggregate() inout in {
182 		assert(isAggregate, "Not an aggregate type.");
183 	} do {
184 		return payload.agg;
185 	}
186 
187 	@property
188 	auto dstruct() inout in {
189 		assert(kind == TypeKind.Struct);
190 	} do {
191 		return payload.dstruct;
192 	}
193 
194 	@property
195 	auto dclass() inout in {
196 		assert(kind == TypeKind.Class);
197 	} do {
198 		return payload.dclass;
199 	}
200 
201 	@property
202 	auto denum() inout in {
203 		assert(kind == TypeKind.Enum);
204 	} do {
205 		return payload.denum;
206 	}
207 
208 	@property
209 	auto dalias() inout in {
210 		assert(kind == TypeKind.Alias);
211 	} do {
212 		return payload.dalias;
213 	}
214 
215 	auto getCanonical() {
216 		auto t = this;
217 		auto q = qualifier;
218 		while (t.kind == TypeKind.Alias) {
219 			// FIXME: Make sure alias is signed.
220 			t = t.dalias.type;
221 			q = q.add(t.qualifier);
222 		}
223 
224 		return t.qualify(q);
225 	}
226 
227 	auto getCanonicalAndPeelEnum() {
228 		auto t = this.getCanonical();
229 		auto q = qualifier;
230 		while (t.kind == TypeKind.Enum) {
231 			// FIXME: Make sure enum is signed.
232 			t = t.denum.type.getCanonical();
233 			q = q.add(t.qualifier);
234 		}
235 
236 		return t.qualify(q);
237 	}
238 
239 	@property
240 	auto dinterface() inout in {
241 		assert(kind == TypeKind.Interface);
242 	} do {
243 		return payload.dinterface;
244 	}
245 
246 	@property
247 	auto dunion() inout in {
248 		assert(kind == TypeKind.Union);
249 	} do {
250 		return payload.dunion;
251 	}
252 
253 	@property
254 	auto context() inout in {
255 		assert(kind == TypeKind.Context);
256 	} do {
257 		return payload.context;
258 	}
259 
260 	@property
261 	auto pattern() inout in {
262 		assert(kind == TypeKind.Pattern);
263 	} do {
264 		return inout(Pattern)(desc, payload.patternPayload);
265 	}
266 
267 	@property
268 	auto error() inout in {
269 		assert(kind == TypeKind.Error);
270 	} do {
271 		return payload.error;
272 	}
273 
274 	Type getPointer(TypeQualifier q = TypeQualifier.Mutable) {
275 		return getConstructedType(TypeKind.Pointer, q);
276 	}
277 
278 	Type getSlice(TypeQualifier q = TypeQualifier.Mutable) {
279 		return getConstructedType(TypeKind.Slice, q);
280 	}
281 
282 	Type getArray(uint size, TypeQualifier q = TypeQualifier.Mutable) {
283 		auto t = qualify(q);
284 
285 		// XXX: Consider caching in context.
286 		auto n = new Type(t.desc, t.payload);
287 		return Type(Desc(TypeKind.Array, q, size), n);
288 	}
289 
290 	bool hasElement() const {
291 		return (kind >= TypeKind.Pointer) && (kind <= TypeKind.Array);
292 	}
293 
294 	@property
295 	auto element() inout in {
296 		assert(hasElement, "element called on a type with no element.");
297 	} do {
298 		if (kind == TypeKind.Array) {
299 			return *payload.next;
300 		}
301 
302 		return getElementMixin();
303 	}
304 
305 	@property
306 	uint size() const in {
307 		assert(kind == TypeKind.Array, "Only array have size.");
308 	} do {
309 		assert(desc.data <= uint.max);
310 		return cast(uint) desc.data;
311 	}
312 
313 	@property
314 	auto sequence() inout in {
315 		assert(kind == TypeKind.Sequence, "Not a sequence type.");
316 	} do {
317 		return payload.next[0 .. desc.data];
318 	}
319 
320 	bool hasPointerABI() const {
321 		switch (kind) with (TypeKind) {
322 			case Class, Pointer:
323 				return true;
324 
325 			case Alias:
326 				return dalias.type.hasPointerABI();
327 
328 			case Function:
329 				return asFunctionType().contexts.length == 0;
330 
331 			default:
332 				return false;
333 		}
334 	}
335 
336 	bool hasIndirection() {
337 		auto t = getCanonicalAndPeelEnum();
338 		final switch (t.kind) with (TypeKind) {
339 			case Builtin:
340 				// Is this, really ?
341 				return t.builtin == BuiltinType.Null;
342 
343 			case Alias, Enum, Pattern, Error:
344 				assert(0);
345 
346 			case Pointer, Slice, Class, Interface, Context:
347 				return true;
348 
349 			case Array:
350 				return element.hasIndirection;
351 
352 			case Struct:
353 				return t.dstruct.hasIndirection;
354 
355 			case Union:
356 				return t.dunion.hasIndirection;
357 
358 			case Function:
359 				import std.algorithm;
360 				return asFunctionType()
361 					.contexts.any!(t => t.isRef || t.getType().hasIndirection);
362 
363 			case Sequence:
364 				import std.algorithm;
365 				return sequence.any!(t => t.hasIndirection);
366 		}
367 	}
368 
369 	string toString(const Context c,
370 	                TypeQualifier q = TypeQualifier.Mutable) const {
371 		auto s = toUnqualString(c);
372 		if (q == qualifier) {
373 			return s;
374 		}
375 
376 		final switch (qualifier) with (TypeQualifier) {
377 			case Mutable:
378 				return s;
379 
380 			case Inout:
381 				return "inout(" ~ s ~ ")";
382 
383 			case Const:
384 				return "const(" ~ s ~ ")";
385 
386 			case Shared:
387 				return "shared(" ~ s ~ ")";
388 
389 			case ConstShared:
390 				assert(0, "const shared isn't supported");
391 
392 			case Immutable:
393 				return "immutable(" ~ s ~ ")";
394 		}
395 	}
396 
397 	string toUnqualString(const Context c) const {
398 		final switch (kind) with (TypeKind) {
399 			case Builtin:
400 				import d.common.builtintype : toString;
401 				return toString(builtin);
402 
403 			case Struct:
404 				return dstruct.name.toString(c);
405 
406 			case Class:
407 				return dclass.name.toString(c);
408 
409 			case Enum:
410 				return denum.name.toString(c);
411 
412 			case Alias:
413 				return dalias.name.toString(c);
414 
415 			case Interface:
416 				return dinterface.name.toString(c);
417 
418 			case Union:
419 				return dunion.name.toString(c);
420 
421 			case Context:
422 				return "__ctx";
423 
424 			case Pointer:
425 				return element.toString(c, qualifier) ~ "*";
426 
427 			case Slice:
428 				return element.toString(c, qualifier) ~ "[]";
429 
430 			case Array:
431 				import std.conv;
432 				return element.toString(c, qualifier) ~ "[" ~ to!string(size)
433 					~ "]";
434 
435 			case Sequence:
436 				import std.algorithm, std.range;
437 				// XXX: need to use this because of identifier hijacking in the import.
438 				return "(" ~ this.sequence.map!(e => e.toString(c, qualifier))
439 				                 .join(", ") ~ ")";
440 
441 			case Function:
442 				auto f = asFunctionType();
443 
444 				auto linkage = "";
445 				if (f.linkage != Linkage.D) {
446 					import std.conv;
447 					linkage = "extern(" ~ f.linkage.to!string() ~ ") ";
448 				}
449 
450 				auto ret = f.returnType.toString(c);
451 				auto base = f.contexts.length ? " delegate(" : " function(";
452 				import std.algorithm, std.range;
453 				auto args = f.parameters.map!(p => p.toString(c)).join(", ");
454 				return linkage ~ ret ~ base ~ args
455 					~ (f.isVariadic ? ", ...)" : ")");
456 
457 			case Pattern:
458 				return pattern.toString(c);
459 
460 			case Error:
461 				return "__error__(" ~ error.toString(c) ~ ")";
462 		}
463 	}
464 
465 static:
466 	Type get(BuiltinType bt, TypeQualifier q = TypeQualifier.Mutable) {
467 		Payload p; // Needed because of lolbug in inout
468 		return Type(Desc(TypeKind.Builtin, q, bt), p);
469 	}
470 
471 	Type get(Struct s, TypeQualifier q = TypeQualifier.Mutable) {
472 		return Type(Desc(TypeKind.Struct, q), s);
473 	}
474 
475 	Type get(Class c, TypeQualifier q = TypeQualifier.Mutable) {
476 		return Type(Desc(TypeKind.Class, q), c);
477 	}
478 
479 	Type get(Enum e, TypeQualifier q = TypeQualifier.Mutable) {
480 		return Type(Desc(TypeKind.Enum, q), e);
481 	}
482 
483 	Type get(TypeAlias a, TypeQualifier q = TypeQualifier.Mutable) {
484 		return Type(Desc(TypeKind.Alias, q), a);
485 	}
486 
487 	Type get(Interface i, TypeQualifier q = TypeQualifier.Mutable) {
488 		return Type(Desc(TypeKind.Interface, q), i);
489 	}
490 
491 	Type get(Union u, TypeQualifier q = TypeQualifier.Mutable) {
492 		return Type(Desc(TypeKind.Union, q), u);
493 	}
494 
495 	Type get(Type[] elements, TypeQualifier q = TypeQualifier.Mutable) {
496 		return Type(Desc(TypeKind.Sequence, q, elements.length), elements.ptr);
497 	}
498 
499 	Type get(TypeTemplateParameter p, TypeQualifier q = TypeQualifier.Mutable) {
500 		return Pattern(p).getType(q);
501 	}
502 
503 	Type getContextType(Function f, TypeQualifier q = TypeQualifier.Mutable) {
504 		return Type(Desc(TypeKind.Context, q), f);
505 	}
506 
507 	Type get(CompileError e, TypeQualifier q = TypeQualifier.Mutable) {
508 		return Type(Desc(TypeKind.Error, q), e);
509 	}
510 }
511 
512 unittest {
513 	auto i = Type.get(BuiltinType.Int);
514 	auto pi = i.getPointer();
515 	assert(i == pi.element);
516 
517 	auto ci = i.qualify(TypeQualifier.Const);
518 	auto cpi = pi.qualify(TypeQualifier.Const);
519 	assert(ci == cpi.element);
520 	assert(i != cpi.element);
521 }
522 
523 unittest {
524 	auto i = Type.get(BuiltinType.Int);
525 	auto t = i;
526 	foreach (_; 0 .. 64) {
527 		t = t.getPointer().getSlice();
528 	}
529 
530 	foreach (_; 0 .. 64) {
531 		assert(t.kind == TypeKind.Slice);
532 		t = t.element;
533 		assert(t.kind == TypeKind.Pointer);
534 		t = t.element;
535 	}
536 
537 	assert(t == i);
538 }
539 
540 unittest {
541 	auto i = Type.get(BuiltinType.Int);
542 	auto ai = i.getArray(42);
543 	assert(i == ai.element);
544 	assert(ai.size == 42);
545 }
546 
547 unittest {
548 	auto i = Type.get(BuiltinType.Int);
549 	auto ci = Type.get(BuiltinType.Int, TypeQualifier.Const);
550 	auto cpi = i.getPointer(TypeQualifier.Const);
551 	assert(ci == cpi.element);
552 
553 	auto csi = i.getSlice(TypeQualifier.Const);
554 	assert(ci == csi.element);
555 
556 	auto cai = i.getArray(42, TypeQualifier.Const);
557 	assert(ci == cai.element);
558 }
559 
560 unittest {
561 	import source.location, source.name, d.ir.symbol;
562 	auto m = new Module(Location.init, BuiltinName!"", null);
563 	auto c = new Class(Location.init, m, BuiltinName!"", []);
564 	auto tc = Type.get(c);
565 	assert(tc.isAggregate);
566 	assert(tc.aggregate is c);
567 
568 	auto cc = Type.get(c, TypeQualifier.Const);
569 	auto csc = tc.getSlice(TypeQualifier.Const);
570 	assert(cc == csc.element);
571 }
572 
573 unittest {
574 	import source.location, source.name, d.ir.symbol;
575 	auto i = Type.get(BuiltinType.Int);
576 	auto a1 = new TypeAlias(Location.init, BuiltinName!"", i);
577 	auto a1t = Type.get(a1);
578 	assert(a1t.getCanonical() == i);
579 
580 	auto a2 = new TypeAlias(Location.init, BuiltinName!"", a1t);
581 	auto a2t = Type.get(a2, TypeQualifier.Immutable);
582 	assert(a2t.getCanonical() == i.qualify(TypeQualifier.Immutable));
583 
584 	auto a3 = new TypeAlias(Location.init, BuiltinName!"", a2t);
585 	auto a3t = Type.get(a3, TypeQualifier.Const);
586 	assert(a3t.getCanonical() == i.qualify(TypeQualifier.Immutable));
587 }
588 
589 unittest {
590 	import source.location, source.name, d.ir.symbol;
591 	auto f = Type.get(BuiltinType.Float, TypeQualifier.Const);
592 	auto a = new TypeAlias(Location.init, BuiltinName!"", f);
593 
594 	auto m = new Module(Location.init, BuiltinName!"", null);
595 	auto e1 = new Enum(Location.init, m, BuiltinName!"", Type.get(a), []);
596 	auto e1t = Type.get(e1);
597 	assert(e1t.getCanonicalAndPeelEnum() == f);
598 
599 	auto e2 = new Enum(Location.init, m, BuiltinName!"", e1t, []);
600 	auto e2t = Type.get(e2, TypeQualifier.Immutable);
601 	assert(e2t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable));
602 
603 	auto e3 = new Enum(Location.init, m, BuiltinName!"", e2t, []);
604 	auto e3t = Type.get(e3, TypeQualifier.Const);
605 	assert(e3t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable));
606 }
607 
608 alias ParamType = Type.ParamType;
609 
610 string toString(const ParamType t, const Context c) {
611 	string s;
612 	final switch (t.paramKind) with (ParamKind) {
613 		case Regular:
614 			s = "";
615 			break;
616 
617 		case Final:
618 			s = "final ";
619 			break;
620 
621 		case Ref:
622 			s = "ref ";
623 			break;
624 	}
625 
626 	return s ~ t.getType().toString(c);
627 }
628 
629 inout(ParamType) getParamType(inout ParamType t, ParamKind kind) {
630 	return t.getType().getParamType(kind);
631 }
632 
633 @property
634 bool isRef(const ParamType t) {
635 	return t.paramKind == ParamKind.Ref;
636 }
637 
638 @property
639 bool isFinal(const ParamType t) {
640 	return t.paramKind == ParamKind.Final;
641 }
642 
643 unittest {
644 	auto pi = Type.get(BuiltinType.Int).getPointer(TypeQualifier.Const);
645 	auto p = pi.getParamType(ParamKind.Ref);
646 
647 	assert(p.paramKind == ParamKind.Ref);
648 	assert(p.qualifier == TypeQualifier.Const);
649 
650 	auto pt = p.getType();
651 	assert(pt == pi);
652 }
653 
654 alias FunctionType = Type.FunctionType;
655 
656 unittest {
657 	auto r =
658 		Type.get(BuiltinType.Void).getPointer().getParamType(ParamKind.Regular);
659 	auto c =
660 		Type.get(BuiltinType.Null).getSlice().getParamType(ParamKind.Final);
661 	auto p = Type.get(BuiltinType.Float).getSlice(TypeQualifier.Immutable)
662 	             .getParamType(ParamKind.Ref);
663 	auto f = FunctionType(Linkage.Java, r, [c, p], true);
664 
665 	assert(f.linkage == Linkage.Java);
666 	assert(f.isVariadic == true);
667 	assert(f.isPure == false);
668 	assert(f.returnType == r);
669 	assert(f.parameters.length == 2);
670 	assert(f.parameters[0] == c);
671 	assert(f.parameters[1] == p);
672 
673 	auto ft = f.getType();
674 	assert(ft.asFunctionType() == f);
675 
676 	auto d = f.getDelegate();
677 	assert(d.linkage == Linkage.Java);
678 	assert(d.isVariadic == true);
679 	assert(d.isPure == false);
680 	assert(d.returnType == r);
681 	assert(d.contexts.length == 1);
682 	assert(d.contexts[0] == c);
683 	assert(d.parameters.length == 1);
684 	assert(d.parameters[0] == p);
685 
686 	auto dt = d.getType();
687 	assert(dt.asFunctionType() == d);
688 	assert(dt.asFunctionType() != f);
689 
690 	auto d2 = d.getDelegate(2);
691 	assert(d2.contexts.length == 2);
692 	assert(d2.parameters.length == 0);
693 	assert(d2.getFunction() == f);
694 }
695 
696 // Facility for IFTI pattern matching.
697 enum PatternKind : ubyte {
698 	Parameter,
699 	Instance,
700 	TypeBracketValue,
701 	TypeBracketType,
702 }
703 
704 struct Pattern {
705 private:
706 	alias Desc = Type.Desc;
707 
708 	import util.bitfields;
709 	enum KindSize = EnumSize!PatternKind;
710 	enum Pad = ulong.sizeof * 8 - Type.Desc.DataSize;
711 	enum CountSize = ulong.sizeof * 8 - KindSize - Pad;
712 
713 	import std.bitmanip;
714 	mixin(bitfields!(
715 		// sdfmt off
716 		PatternKind, "kind", KindSize,
717 		ulong, "argCount", CountSize,
718 		uint, "", Pad, // Pad for TypeKind and qualifier
719 		// sdfmt on
720 	));
721 
722 	union Payload {
723 		TypeTemplateParameter param;
724 		TypeValuePair* typeValuePair;
725 		TemplateArgument* args;
726 	}
727 
728 	Payload payload;
729 
730 	static assert(Payload.sizeof == ulong.sizeof,
731 	              "Payload must be the same size as ulong.");
732 
733 	this(Desc desc, inout Payload payload) inout {
734 		// /!\ Black magic ahead.
735 		auto raw_desc = cast(ulong*) &desc;
736 
737 		// Remove the TypeKind and qualifier
738 		*raw_desc = (*raw_desc >> Pad);
739 
740 		// This should point to an area of memory that have
741 		// the correct layout for the bitfield.
742 		auto p = cast(Pattern*) raw_desc;
743 
744 		// unqual trick required for bitfield
745 		auto unqual_this = cast(Pattern*) &this;
746 		unqual_this.kind = p.kind;
747 		unqual_this.argCount = p.argCount;
748 
749 		this.payload = payload;
750 	}
751 
752 	this(PatternKind k, ulong c, Payload p) {
753 		kind = k;
754 		argCount = c;
755 		payload = p;
756 	}
757 
758 	struct TypeValuePair {
759 		Type type;
760 		ValueTemplateParameter value;
761 	}
762 
763 	auto getTypeValuePair() inout in {
764 		assert(kind == PatternKind.TypeBracketValue);
765 	} do {
766 		return payload.typeValuePair;
767 	}
768 
769 	struct Instantiation {
770 		Symbol instantiated;
771 		TemplateArgument[] args;
772 	}
773 
774 	auto getInstatiation() inout in {
775 		assert(kind == PatternKind.Instance);
776 	} do {
777 		auto c = argCount;
778 		return inout(Instantiation)(
779 			payload.args[c].get!(TemplateArgument.Tag.Symbol),
780 			payload.args[0 .. c]);
781 	}
782 
783 public:
784 	import util.fastcast;
785 	this(TypeTemplateParameter p) {
786 		this(PatternKind.Parameter, 0, fastCast!Payload(p));
787 	}
788 
789 	this(Type t, ValueTemplateParameter v) {
790 		auto p = new TypeValuePair(t, v);
791 		this(PatternKind.TypeBracketValue, 0, fastCast!Payload(p));
792 	}
793 
794 	this(Symbol instantiated, TemplateArgument[] args) {
795 		args ~= TemplateArgument(instantiated);
796 		this(PatternKind.Instance, args.length - 1, fastCast!Payload(args.ptr));
797 	}
798 
799 	@property
800 	auto parameter() inout in {
801 		assert(kind == PatternKind.Parameter);
802 	} do {
803 		return payload.param;
804 	}
805 
806 	Type getType(TypeQualifier q = TypeQualifier.Mutable) {
807 		ulong d = *cast(ulong*) &this;
808 		return Type(Desc(TypeKind.Pattern, q, d), payload);
809 	}
810 
811 	auto accept(T)(ref T t) if (is(T == struct)) {
812 		return acceptImpl(&t);
813 	}
814 
815 	auto accept(T)(T t) if (is(T == class)) {
816 		return acceptImpl(t);
817 	}
818 
819 	string toString(const Context c) const {
820 		final switch (kind) with (PatternKind) {
821 			case Parameter:
822 				return parameter.name.toString(c);
823 
824 			case Instance:
825 				assert(0, "Not implemented");
826 
827 			case TypeBracketValue:
828 				auto p = getTypeValuePair();
829 				return
830 					p.type.toString(c) ~ '[' ~ p.value.name.toString(c) ~ ']';
831 
832 			case TypeBracketType:
833 				assert(0, "Not implemented");
834 		}
835 	}
836 
837 private:
838 	auto acceptImpl(T)(T t) {
839 		final switch (kind) with (PatternKind) {
840 			case Parameter:
841 				return t.visit(parameter);
842 
843 			case Instance:
844 				auto i = getInstatiation();
845 				return t.visit(i.instantiated, i.args);
846 
847 			case TypeBracketValue:
848 				auto p = getTypeValuePair();
849 				return t.visit(p.type, p.value);
850 
851 			case TypeBracketType:
852 				assert(0, "Not implemented");
853 		}
854 	}
855 }
856 
857 private:
858 
859 // XXX: we put it as a UFCS property to avoid forward reference.
860 @property
861 inout(ParamType)* params(inout Payload p) {
862 	import util.fastcast;
863 	return cast(inout ParamType*) p.next;
864 }
865 
866 union Payload {
867 	Type* next;
868 
869 	// Symbols
870 	TypeAlias dalias;
871 	Class dclass;
872 	Interface dinterface;
873 	Struct dstruct;
874 	Union dunion;
875 	Enum denum;
876 
877 	// Context
878 	Function context;
879 
880 	// For function and delegates.
881 	// ParamType* params;
882 
883 	// For template instanciation.
884 	Pattern.Payload patternPayload;
885 
886 	// For speculative compilation.
887 	CompileError error;
888 
889 	// For simple construction
890 	Symbol sym;
891 	Aggregate agg;
892 }