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
362 					.any!(t => t.isRef || t.getType().hasIndirection);
363 
364 			case Sequence:
365 				import std.algorithm;
366 				return sequence.any!(t => t.hasIndirection);
367 		}
368 	}
369 	
370 	string toString(const Context c, 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)
433 					~ "[" ~ to!string(size) ~ "]";
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)).join(", ") ~ ")";
439 			
440 			case Function:
441 				auto f = asFunctionType();
442 				
443 				auto linkage = "";
444 				if (f.linkage != Linkage.D) {
445 					import std.conv;
446 					linkage = "extern(" ~ f.linkage.to!string() ~ ") ";
447 				}
448 				
449 				auto ret = f.returnType.toString(c);
450 				auto base = f.contexts.length ? " delegate(" : " function(";
451 				import std.algorithm, std.range;
452 				auto args = f.parameters.map!(p => p.toString(c)).join(", ");
453 				return linkage ~ ret ~ base ~ args ~ (f.isVariadic ? ", ...)" : ")");
454 			
455 			case Pattern:
456 				return pattern.toString(c);
457 			
458 			case Error:
459 				return "__error__(" ~ error.toString(c) ~ ")";
460 		}
461 	}
462 	
463 static:
464 	Type get(BuiltinType bt, TypeQualifier q = TypeQualifier.Mutable) {
465 		Payload p; // Needed because of lolbug in inout
466 		return Type(Desc(TypeKind.Builtin, q, bt), p);
467 	}
468 	
469 	Type get(Struct s, TypeQualifier q = TypeQualifier.Mutable) {
470 		return Type(Desc(TypeKind.Struct, q), s);
471 	}
472 	
473 	Type get(Class c, TypeQualifier q = TypeQualifier.Mutable) {
474 		return Type(Desc(TypeKind.Class, q), c);
475 	}
476 	
477 	Type get(Enum e, TypeQualifier q = TypeQualifier.Mutable) {
478 		return Type(Desc(TypeKind.Enum, q), e);
479 	}
480 	
481 	Type get(TypeAlias a, TypeQualifier q = TypeQualifier.Mutable) {
482 		return Type(Desc(TypeKind.Alias, q), a);
483 	}
484 	
485 	Type get(Interface i, TypeQualifier q = TypeQualifier.Mutable) {
486 		return Type(Desc(TypeKind.Interface, q), i);
487 	}
488 	
489 	Type get(Union u, TypeQualifier q = TypeQualifier.Mutable) {
490 		return Type(Desc(TypeKind.Union, q), u);
491 	}
492 	
493 	Type get(Type[] elements, TypeQualifier q = TypeQualifier.Mutable) {
494 		return Type(Desc(TypeKind.Sequence, q, elements.length), elements.ptr);
495 	}
496 	
497 	Type get(TypeTemplateParameter p, TypeQualifier q = TypeQualifier.Mutable) {
498 		return Pattern(p).getType(q);
499 	}
500 	
501 	Type getContextType(Function f, TypeQualifier q = TypeQualifier.Mutable) {
502 		return Type(Desc(TypeKind.Context, q), f);
503 	}
504 	
505 	Type get(CompileError e, TypeQualifier q = TypeQualifier.Mutable) {
506 		return Type(Desc(TypeKind.Error, q), e);
507 	}
508 }
509 
510 unittest {
511 	auto i = Type.get(BuiltinType.Int);
512 	auto pi = i.getPointer();
513 	assert(i == pi.element);
514 	
515 	auto ci = i.qualify(TypeQualifier.Const);
516 	auto cpi = pi.qualify(TypeQualifier.Const);
517 	assert(ci == cpi.element);
518 	assert(i != cpi.element);
519 }
520 
521 unittest {
522 	auto i = Type.get(BuiltinType.Int);
523 	auto t = i;
524 	foreach(_; 0 .. 64) {
525 		t = t.getPointer().getSlice();
526 	}
527 	
528 	foreach(_; 0 .. 64) {
529 		assert(t.kind == TypeKind.Slice);
530 		t = t.element;
531 		assert(t.kind == TypeKind.Pointer);
532 		t = t.element;
533 	}
534 	
535 	assert(t == i);
536 }
537 
538 unittest {
539 	auto i = Type.get(BuiltinType.Int);
540 	auto ai = i.getArray(42);
541 	assert(i == ai.element);
542 	assert(ai.size == 42);
543 }
544 
545 unittest {
546 	auto i = Type.get(BuiltinType.Int);
547 	auto ci = Type.get(BuiltinType.Int, TypeQualifier.Const);
548 	auto cpi = i.getPointer(TypeQualifier.Const);
549 	assert(ci == cpi.element);
550 	
551 	auto csi = i.getSlice(TypeQualifier.Const);
552 	assert(ci == csi.element);
553 	
554 	auto cai = i.getArray(42, TypeQualifier.Const);
555 	assert(ci == cai.element);
556 }
557 
558 unittest {
559 	import source.location, source.name, d.ir.symbol;
560 	auto m = new Module(Location.init, BuiltinName!"", null);
561 	auto c = new Class(Location.init, m, BuiltinName!"", []);
562 	auto tc = Type.get(c);
563 	assert(tc.isAggregate);
564 	assert(tc.aggregate is c);
565 	
566 	auto cc = Type.get(c, TypeQualifier.Const);
567 	auto csc = tc.getSlice(TypeQualifier.Const);
568 	assert(cc == csc.element);
569 }
570 
571 unittest {
572 	import source.location, source.name, d.ir.symbol;
573 	auto i = Type.get(BuiltinType.Int);
574 	auto a1 = new TypeAlias(Location.init, BuiltinName!"", i);
575 	auto a1t = Type.get(a1);
576 	assert(a1t.getCanonical() == i);
577 	
578 	auto a2 = new TypeAlias(Location.init, BuiltinName!"", a1t);
579 	auto a2t = Type.get(a2, TypeQualifier.Immutable);
580 	assert(a2t.getCanonical() == i.qualify(TypeQualifier.Immutable));
581 	
582 	auto a3 = new TypeAlias(Location.init, BuiltinName!"", a2t);
583 	auto a3t = Type.get(a3, TypeQualifier.Const);
584 	assert(a3t.getCanonical() == i.qualify(TypeQualifier.Immutable));
585 }
586 
587 unittest {
588 	import source.location, source.name, d.ir.symbol;
589 	auto f = Type.get(BuiltinType.Float, TypeQualifier.Const);
590 	auto a = new TypeAlias(Location.init, BuiltinName!"", f);
591 	
592 	auto m = new Module(Location.init, BuiltinName!"", null);
593 	auto e1 = new Enum(Location.init, m, BuiltinName!"", Type.get(a), []);
594 	auto e1t = Type.get(e1);
595 	assert(e1t.getCanonicalAndPeelEnum() == f);
596 
597 	auto e2 = new Enum(Location.init, m, BuiltinName!"", e1t, []);
598 	auto e2t = Type.get(e2, TypeQualifier.Immutable);
599 	assert(e2t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable));
600 
601 	auto e3 = new Enum(Location.init, m, BuiltinName!"", e2t, []);
602 	auto e3t = Type.get(e3, TypeQualifier.Const);
603 	assert(e3t.getCanonicalAndPeelEnum() == f.qualify(TypeQualifier.Immutable));
604 }
605 
606 alias ParamType = Type.ParamType;
607 
608 string toString(const ParamType t, const Context c) {
609 	string s;
610 	final switch (t.paramKind) with(ParamKind) {
611 		case Regular:
612 			s = "";
613 			break;
614 		
615 		case Final:
616 			s = "final ";
617 			break;
618 		
619 		case Ref:
620 			s = "ref ";
621 			break;
622 	}
623 	
624 	return s ~ t.getType().toString(c);
625 }
626 
627 inout(ParamType) getParamType(inout ParamType t, ParamKind kind) {
628 	return t.getType().getParamType(kind);
629 }
630 
631 @property isRef(const ParamType t) {
632 	return t.paramKind == ParamKind.Ref;
633 }
634 
635 @property isFinal(const ParamType t) {
636 	return t.paramKind == ParamKind.Final;
637 }
638 
639 unittest {
640 	auto pi = Type.get(BuiltinType.Int).getPointer(TypeQualifier.Const);
641 	auto p = pi.getParamType(ParamKind.Ref);
642 	
643 	assert(p.paramKind == ParamKind.Ref);
644 	assert(p.qualifier == TypeQualifier.Const);
645 	
646 	auto pt = p.getType();
647 	assert(pt == pi);
648 }
649 
650 alias FunctionType = Type.FunctionType;
651 
652 unittest {
653 	auto r = Type.get(BuiltinType.Void).getPointer()
654 		.getParamType(ParamKind.Regular);
655 	auto c = Type.get(BuiltinType.Null).getSlice()
656 		.getParamType(ParamKind.Final);
657 	auto p = Type.get(BuiltinType.Float).getSlice(TypeQualifier.Immutable)
658 		.getParamType(ParamKind.Ref);
659 	auto f = FunctionType(Linkage.Java, r, [c, p], true);
660 	
661 	assert(f.linkage == Linkage.Java);
662 	assert(f.isVariadic == true);
663 	assert(f.isPure == false);
664 	assert(f.returnType == r);
665 	assert(f.parameters.length == 2);
666 	assert(f.parameters[0] == c);
667 	assert(f.parameters[1] == p);
668 	
669 	auto ft = f.getType();
670 	assert(ft.asFunctionType() == f);
671 	
672 	auto d = f.getDelegate();
673 	assert(d.linkage == Linkage.Java);
674 	assert(d.isVariadic == true);
675 	assert(d.isPure == false);
676 	assert(d.returnType == r);
677 	assert(d.contexts.length == 1);
678 	assert(d.contexts[0] == c);
679 	assert(d.parameters.length == 1);
680 	assert(d.parameters[0] == p);
681 	
682 	auto dt = d.getType();
683 	assert(dt.asFunctionType() == d);
684 	assert(dt.asFunctionType() != f);
685 	
686 	auto d2 = d.getDelegate(2);
687 	assert(d2.contexts.length == 2);
688 	assert(d2.parameters.length == 0);
689 	assert(d2.getFunction() == f);
690 }
691 
692 // Facility for IFTI pattern matching.
693 enum PatternKind : ubyte {
694 	Parameter,
695 	Instance,
696 	TypeBracketValue,
697 	TypeBracketType,
698 }
699 
700 struct Pattern {
701 private:
702 	alias Desc = Type.Desc;
703 	
704 	import util.bitfields;
705 	enum KindSize = EnumSize!PatternKind;
706 	enum Pad = ulong.sizeof * 8 - Type.Desc.DataSize;
707 	enum CountSize = ulong.sizeof * 8 - KindSize - Pad;
708 	
709 	import std.bitmanip;
710 	mixin(bitfields!(
711 		PatternKind, "kind", KindSize,
712 		ulong, "argCount", CountSize,
713 		uint, "", Pad, // Pad for TypeKind and qualifier
714 	));
715 	
716 	union Payload {
717 		TypeTemplateParameter param;
718 		TypeValuePair* typeValuePair;
719 		TemplateArgument* args;
720 	}
721 	
722 	Payload payload;
723 	
724 	static assert(Payload.sizeof == ulong.sizeof, "Payload must be the same size as ulong.");
725 	
726 	this(Desc desc, inout Payload payload) inout {
727 		// /!\ Black magic ahead.
728 		auto raw_desc = cast(ulong*) &desc;
729 		
730 		// Remove the TypeKind and qualifier
731 		*raw_desc = (*raw_desc >> Pad);
732 		
733 		// This should point to an area of memory that have
734 		// the correct layout for the bitfield.
735 		auto p = cast(Pattern*) raw_desc;
736 		
737 		// unqual trick required for bitfield
738 		auto unqual_this = cast(Pattern*) &this;
739 		unqual_this.kind = p.kind;
740 		unqual_this.argCount = p.argCount;
741 		
742 		this.payload = payload;
743 	}
744 	
745 	this(PatternKind k, ulong c, Payload p) {
746 		kind = k;
747 		argCount = c;
748 		payload = p;
749 	}
750 	
751 	struct TypeValuePair {
752 		Type type;
753 		ValueTemplateParameter value;
754 	}
755 	
756 	auto getTypeValuePair() inout in {
757 		assert(kind == PatternKind.TypeBracketValue);
758 	} do {
759 		return payload.typeValuePair;
760 	}
761 	
762 	struct Instantiation {
763 		Symbol instantiated;
764 		TemplateArgument[] args;
765 	}
766 	
767 	auto getInstatiation() inout in {
768 		assert(kind == PatternKind.Instance);
769 	} do {
770 		auto c = argCount;
771 		return inout(Instantiation)(
772 			payload.args[c].get!(TemplateArgument.Tag.Symbol),
773 			payload.args[0 .. c],
774 		);
775 	}
776 	
777 public:
778 	import util.fastcast;
779 	this(TypeTemplateParameter p) {
780 		this(PatternKind.Parameter, 0, fastCast!Payload(p));
781 	}
782 	
783 	this(Type t, ValueTemplateParameter v) {
784 		auto p = new TypeValuePair(t, v);
785 		this(PatternKind.TypeBracketValue, 0, fastCast!Payload(p));
786 	}
787 	
788 	this(Symbol instantiated, TemplateArgument[] args) {
789 		args ~= TemplateArgument(instantiated);
790 		this(
791 			PatternKind.Instance,
792 			args.length - 1,
793 			fastCast!Payload(args.ptr),
794 		);
795 	}
796 	
797 	@property parameter() inout in {
798 		assert(kind == PatternKind.Parameter);
799 	} do {
800 		return payload.param;
801 	}
802 	
803 	Type getType(TypeQualifier q = TypeQualifier.Mutable) {
804 		ulong d = *cast(ulong*) &this;
805 		return Type(Desc(TypeKind.Pattern, q, d), payload);
806 	}
807 	
808 	auto accept(T)(ref T t) if(is(T == struct)) {
809 		return acceptImpl(&t);
810 	}
811 	
812 	auto accept(T)(T t) if(is(T == class)) {
813 		return acceptImpl(t);
814 	}
815 	
816 	string toString(const Context c) const {
817 		final switch (kind) with(PatternKind) {
818 			case Parameter:
819 				return parameter.name.toString(c);
820 			
821 			case Instance:
822 				assert(0, "Not implemented");
823 			
824 			case TypeBracketValue:
825 				auto p = getTypeValuePair();
826 				return p.type.toString(c) ~ '[' ~ p.value.name.toString(c) ~ ']';
827 			
828 			case TypeBracketType:
829 				assert(0, "Not implemented");
830 		}
831 	}
832 	
833 private:
834 	auto acceptImpl(T)(T t) {
835 		final switch(kind) with(PatternKind) {
836 			case Parameter:
837 				return t.visit(parameter);
838 			
839 			case Instance:
840 				auto i = getInstatiation();
841 				return t.visit(i.instantiated, i.args);
842 			
843 			case TypeBracketValue:
844 				auto p = getTypeValuePair();
845 				return t.visit(p.type, p.value);
846 			
847 			case TypeBracketType:
848 				assert(0, "Not implemented");
849 		}
850 	}
851 }
852 
853 private:
854 
855 // XXX: we put it as a UFCS property to avoid forward reference.
856 @property
857 inout(ParamType)* params(inout Payload p) {
858 	import util.fastcast;
859 	return cast(inout ParamType*) p.next;
860 }
861 
862 union Payload {
863 	Type* next;
864 	
865 	// Symbols
866 	TypeAlias dalias;
867 	Class dclass;
868 	Interface dinterface;
869 	Struct dstruct;
870 	Union dunion;
871 	Enum denum;
872 	
873 	// Context
874 	Function context;
875 	
876 	// For function and delegates.
877 	// ParamType* params;
878 	
879 	// For template instanciation.
880 	Pattern.Payload patternPayload;
881 	
882 	// For speculative compilation.
883 	CompileError error;
884 	
885 	// For simple construction
886 	Symbol sym;
887 	Aggregate agg;
888 }