1 module d.semantic.identifier;
2 
3 import d.semantic.semantic;
4 
5 import d.ast.identifier;
6 
7 import d.ir.error;
8 import d.ir.expression;
9 import d.ir.symbol;
10 import d.ir.type;
11 
12 import source.location;
13 import source.name;
14 
15 alias Identifiable = Type.UnionType!(Symbol, Expression);
16 
17 auto apply(alias handler)(Identifiable i) {
18 	alias Tag = typeof(i.tag);
19 	final switch(i.tag) with(Tag) {
20 		case Symbol :
21 			return handler(i.get!Symbol);
22 		
23 		case Expression :
24 			return handler(i.get!Expression);
25 		
26 		case Type :
27 			return handler(i.get!Type);
28 	}
29 }
30 
31 /**
32  * General entry point to resolve identifiers.
33  *
34  * The resolve method family will fallback on the symbol itself in case of ambiguity.
35  * The build method family will post process the symbols to get to a type/expression.
36  */
37 struct IdentifierResolver {
38 private:
39 	SemanticPass pass;
40 	alias pass this;
41 	
42 	Expression thisExpr;
43 	
44 public:
45 	this(SemanticPass pass) {
46 		this.pass = pass;
47 	}
48 	
49 	~this() {
50 		if (thisExpr is null) {
51 			return;
52 		}
53 		
54 		auto e = getError(
55 			thisExpr,
56 			thisExpr.location,
57 			"thisExpr has not been consumed",
58 		);
59 		
60 		import source.exception;
61 		throw new CompileException(e.location, e.message);
62 	}
63 	
64 	Identifiable build(Identifier i) {
65 		return postProcess(i.location, IdentifierVisitor(&this).visit(i));
66 	}
67 	
68 	Identifiable build(Location location, Name name) {
69 		auto s = IdentifierVisitor(&this).resolve(location, name);
70 		return postProcess(location, s);
71 	}
72 	
73 	Identifiable buildIn(I)(
74 		Location location,
75 		I i,
76 		Name name,
77 	) if (isIdentifiable!I) {
78 		auto ii = IdentifierVisitor(&this).resolveIn(location, i, name);
79 		return postProcess(location, ii);
80 	}
81 	
82 	Identifiable build(
83 		TemplateInstantiation i,
84 		Expression[] fargs = [],
85 	) {
86 		auto ti = IdentifierVisitor(&this).resolve(i, fargs);
87 		return postProcess(i.location, ti);
88 	}
89 	
90 	Identifiable postProcess(I)(Location location, I i) {
91 		return SymbolPostProcessor(&this, location).visit(i);
92 	}
93 	
94 	Identifiable finalize(I)(Location location, I i) {
95 		return AliasPostProcessor(&this, location).visit(i);
96 	}
97 	
98 	Identifiable resolve(Identifier i) {
99 		return finalize(i.location, IdentifierVisitor(&this).visit(i));
100 	}
101 	
102 	Identifiable resolveIn(I)(
103 		Location location,
104 		I i,
105 		Name name,
106 	) if (isIdentifiable!I) {
107 		return finalize(
108 			location,
109 			IdentifierVisitor(&this).resolveIn(location, i, name),
110 		);
111 	}
112 	
113 private:
114 	Expression wrap(Location location, Expression e) {
115 		if (thisExpr is null) {
116 			return e;
117 		}
118 		
119 		import d.ir.expression : build;
120 		return build!BinaryExpression(
121 			location,
122 			e.type,
123 			BinaryOp.Comma,
124 			getThis(location),
125 			e,
126 		);
127 	}
128 	
129 	void setThis(Expression thisExpr) in {
130 		assert(this.thisExpr is null);
131 	} do {
132 		this.thisExpr = thisExpr;
133 	}
134 	
135 	Expression acquireThis() {
136 		// Make sure we don't consume this twice.
137 		scope(exit) thisExpr = null;
138 		return thisExpr;
139 	}
140 	
141 	Expression getThis(Location location) {
142 		if (thisExpr) {
143 			return acquireThis();
144 		}
145 		
146 		import d.semantic.expression;
147 		return ExpressionVisitor(pass).getThis(location);
148 	}
149 }
150 
151 // XXX: probably a "feature" this can't be passed as alias this if private.
152 Identifiable identifiableHandler(T)(T t) {
153 	return Identifiable(t);
154 }
155 
156 private:
157 
158 enum isIdentifiable(T) = is(T : Expression) || is(T : Type) || is(T : Symbol) || is(T : Identifiable);
159 
160 alias IdentifierPass = IdentifierResolver*;
161 
162 struct IdentifierVisitor {
163 private:
164 	IdentifierPass pass;
165 	alias pass this;
166 	
167 	this(IdentifierPass pass) {
168 		this.pass = pass;
169 	}
170 	
171 public:
172 	Identifiable visit(Identifier i) {
173 		return this.dispatch(i);
174 	}
175 	
176 	Identifiable visit(BasicIdentifier i) {
177 		return Identifiable(resolve(i.location, i.name));
178 	}
179 	
180 	Identifiable visit(IdentifierDotIdentifier i) {
181 		return resolveIn(i.location, visit(i.identifier), i.name);
182 	}
183 	
184 	Identifiable visit(TemplateInstantiation i) {
185 		return resolve(i);
186 	}
187 	
188 	Identifiable visit(DotIdentifier i) {
189 		return resolveIn(i.location, currentScope.getModule(), i.name);
190 	}
191 	
192 	Identifiable visit(ExpressionDotIdentifier i) {
193 		import d.semantic.expression;
194 		auto e = ExpressionVisitor(pass.pass).visit(i.expression);
195 		return resolveIn(i.location, e, i.name);
196 	}
197 	
198 	Identifiable visit(TypeDotIdentifier i) {
199 		import d.semantic.type;
200 		auto t = TypeVisitor(pass.pass).visit(i.type);
201 		return resolveIn(i.location, t, i.name);
202 	}
203 	
204 	Identifiable visit(IdentifierBracketIdentifier i) {
205 		return resolveBracket(i.location, i.indexed, i.index);
206 	}
207 	
208 	Identifiable visit(IdentifierBracketExpression i) {
209 		import d.semantic.expression;
210 		auto e = ExpressionVisitor(pass.pass).visit(i.index);
211 		return resolveBracket(i.location, i.indexed, e);
212 	}
213 	
214 private:
215 	Symbol resolve(Location location, Name name) {
216 		auto symbol = currentScope.search(location, name);
217 		
218 		// I wish we had ?:
219 		return symbol ? symbol : resolveImport(location, name);
220 	}
221 	
222 	Identifiable resolveIn(Location location, Identifiable i, Name name) {
223 		return i.apply!(ii => resolveIn(location, ii, name))();
224 	}
225 	
226 	Identifiable resolveIn(Location location, Expression e, Name name) {
227 		return ExpressionDotIdentifierResolver(pass, location, name).visit(e);
228 	}
229 	
230 	Identifiable resolveIn(Location location, Type t, Name name) {
231 		return TypeDotIdentifierResolver(pass, location, name).visit(t);
232 	}
233 	
234 	Identifiable resolveIn(Location location, Symbol s, Name name) {
235 		return SymbolDotIdentifierResolver(pass, location, name).visit(s);
236 	}
237 	
238 	Symbol resolveImport(Location location, Name name) {
239 		auto dscope = currentScope;
240 		
241 		while (true) {
242 			Symbol symbol;
243 			
244 			foreach(m; dscope.getImports()) {
245 				scheduler.require(m, Step.Populated);
246 				
247 				auto symInMod = m.resolve(location, name);
248 				if (symInMod) {
249 					if (symbol) {
250 						return new CompileError(
251 							location,
252 							"Ambiguous symbol " ~ name.toString(context),
253 						).symbol;
254 					}
255 					
256 					symbol = symInMod;
257 				}
258 			}
259 			
260 			if (symbol) {
261 				return symbol;
262 			}
263 			
264 			dscope = dscope.getParentScope();
265 			if (dscope is null) {
266 				return new CompileError(
267 					location,
268 					"Symbol " ~ name.toString(context) ~ " has not been found",
269 				).symbol;
270 			}
271 			
272 			if (auto sscope = cast(Symbol) dscope) {
273 				scheduler.require(sscope, Step.Populated);
274 			}
275 		}
276 	}
277 	
278 	Identifiable resolve(
279 		TemplateInstantiation i,
280 		Expression[] fargs = [],
281 	) in {
282 		// We don't want to resolve argument with the same context we have here.
283 		assert(acquireThis() is null);
284 	} do {
285 		alias astapply = d.ast.identifier.apply;
286 		
287 		import d.semantic.dtemplate : TemplateInstancier;
288 		import d.ast.type : AstType;
289 		import std.algorithm, std.array;
290 		auto args = i.arguments.map!(a => astapply!((a) {
291 			alias T = typeof(a);
292 			static if (is(T : Identifier)) {
293 				assert(pass.acquireThis() is null);
294 				
295 				return visit(a).apply!((val) {
296 					static if (is(typeof(val) : Expression)) {
297 						return TemplateArgument(evaluate(val));
298 					} else {
299 						return TemplateArgument(val);
300 					}
301 				})();
302 			} else static if (is(T : AstType)) {
303 				import d.semantic.type;
304 				return TemplateArgument(TypeVisitor(pass.pass).visit(a));
305 			} else {
306 				import d.semantic.expression;
307 				auto e = ExpressionVisitor(pass.pass).visit(a);
308 				return TemplateArgument(evaluate(e));
309 			}
310 		})(a)).array();
311 		
312 		CompileError ce;
313 		Symbol instantiated;
314 		
315 		auto iloc = i.location;
316 		auto instance = finalize(i.identifier.location, visit(i.identifier))
317 			.apply!(delegate TemplateInstance(identified) {
318 				static if (is(typeof(identified) : Symbol)) {
319 					// If we are within a pattern, we are not looking to instanciate.
320 					// XXX: Arguably, we'd like the TemplateInstancier to figure out if
321 					// this is a pattern instead of using this hack.
322 					if (inPattern) {
323 						instantiated = identified;
324 						return null;
325 					}
326 					
327 					if (auto s = cast(OverloadSet) identified) {
328 						return TemplateInstancier(pass.pass)
329 							.instanciate(iloc, s, args, fargs);
330 					}
331 					
332 					if (auto t = cast(Template) identified) {
333 						return TemplateInstancier(pass.pass)
334 							.instanciate(iloc, t, args, fargs);
335 					}
336 				}
337 				
338 				ce = getError(
339 					identified,
340 					iloc,
341 					"Unexpected " ~ typeid(identified).toString(),
342 				);
343 				
344 				return null;
345 			})();
346 		
347 		if (inPattern && instantiated) {
348 			return Identifiable(Pattern(instantiated, args).getType());
349 		}
350 		
351 		if (instance is null) {
352 			assert(ce, "No error reported :(");
353 			return Identifiable(ce.symbol);
354 		}
355 		
356 		return Identifiable(instance);
357 	}
358 	
359 	Identifiable resolveBracket(I)(Location location, Identifier base, I index) {
360 		// XXX: dafuq alias this :/
361 		return pass.build(base).apply!(i => resolveBracket(location, i, index))();
362 	}
363 	
364 	Identifiable resolveBracket(B)(
365 		Location location,
366 		B base,
367 		Identifier index,
368 	) if (!is(B : Identifier)) {
369 		// We don't want to use the same this for base and index.
370 		auto oldThisExpr = acquireThis();
371 		scope(exit) setThis(oldThisExpr);
372 		
373 		// XXX: dafuq alias this :/
374 		return pass.build(index).apply!(i => resolveBracket(location, base, i))();
375 	}
376 	
377 	Identifiable resolveBracket(
378 		Location location,
379 		Expression base,
380 		Expression index,
381 	) {
382 		import d.semantic.expression;
383 		auto e = ExpressionVisitor(pass.pass).getIndex(location, base, index);
384 		return Identifiable(e);
385 	}
386 	
387 	Identifiable resolveBracket(
388 		Location location,
389 		Type base,
390 		Expression index,
391 	) {
392 		import d.semantic.caster, d.semantic.expression;
393 		auto size = evalIntegral(buildImplicitCast(
394 			pass.pass,
395 			index.location,
396 			pass.object.getSizeT().type,
397 			index,
398 		));
399 		
400 		assert(
401 			size <= uint.max,
402 			"Array larger than uint.max are not supported"
403 		);
404 		
405 		return Identifiable(base.getArray(cast(uint) size));
406 	}
407 	
408 	Identifiable resolveBracket(Location location, Type base, Type index) {
409 		assert(0, "Maps not implemented");
410 	}
411 	
412 	Identifiable resolveBracket(Location location, Expression base, Type index) {
413 		assert(0, "Wat wat wat ?");
414 	}
415 	
416 	Identifiable resolveBracket(S1, S2)(
417 		Location location,
418 		S1 base,
419 		S2 index,
420 	) if (
421 		(is(S1 : Symbol) || is(S2 : Symbol)) &&
422 		!(is(S1 : Identifier) || is(S2 : Identifier))
423 	) {
424 		assert(0, "Wat wat wat ?");
425 	}
426 }
427 
428 public auto isError(Identifiable i) {
429 	return i.apply!((identified) {
430 		alias T = typeof(identified);
431 		static if (is(T : Symbol)) {
432 			return typeid(identified) is typeid(ErrorSymbol);
433 		} else static if (is(T : Expression)) {
434 			return typeid(identified) is typeid(ErrorExpression);
435 		} else static if (is(T : Type)) {
436 			return identified.kind == TypeKind.Error;
437 		} else {
438 			static assert(0, "Dafuq ?");
439 		}
440 	})();
441 }
442 
443 // Conflict with Interface in object.di
444 alias Interface = d.ir.symbol.Interface;
445 
446 alias SymbolPostProcessor = IdentifierPostProcessor!false;
447 alias AliasPostProcessor = IdentifierPostProcessor!true;
448 
449 struct IdentifierPostProcessor(bool asAlias) {
450 	IdentifierPass pass;
451 	alias pass this;
452 	
453 	Location location;
454 	
455 	this(IdentifierPass pass, Location location) {
456 		this.pass = pass;
457 		this.location = location;
458 	}
459 	
460 	Identifiable visit(Identifiable i) {
461 		return i.apply!(ii => visit(ii))();
462 	}
463 	
464 	Identifiable visit(Expression e) {
465 		return Identifiable(wrap(location, e));
466 	}
467 	
468 	Identifiable visit(Type t) {
469 		return Identifiable(t);
470 	}
471 	
472 	Identifiable visit(Symbol s) {
473 		return this.dispatch(s);
474 	}
475 	
476 	Identifiable visit(ValueSymbol vs) {
477 		return this.dispatch(vs);
478 	}
479 	
480 	Identifiable visit(Variable v) {
481 		if (asAlias && !thisExpr) {
482 			return Identifiable(v);
483 		}
484 		
485 		scheduler.require(v, Step.Signed);
486 		return visit(new VariableExpression(location, v));
487 	}
488 	
489 	Identifiable visit(Field f) {
490 		scheduler.require(f, Step.Signed);
491 		return Identifiable(build!FieldExpression(
492 			location,
493 			getThis(location),
494 			f,
495 		));
496 	}
497 	
498 	Identifiable buildFun(Function f) {
499 		scheduler.require(f, Step.Signed);
500 		if (thisExpr || f.hasThis) {
501 			import d.semantic.expression;
502 			return Identifiable(ExpressionVisitor(pass.pass).getFrom(
503 				location,
504 				getThis(location),
505 				f,
506 			));
507 		}
508 		
509 		static if (asAlias) {
510 			return Identifiable(f);
511 		} else {
512 			import d.semantic.expression;
513 			return Identifiable(
514 				ExpressionVisitor(pass.pass).getFrom(location, f),
515 			);
516 		}
517 	}
518 	
519 	Identifiable visit(Function f) {
520 		return buildFun(f);
521 	}
522 	
523 	Identifiable visit(Method m) {
524 		return buildFun(m);
525 	}
526 	
527 	Identifiable visit(OverloadSet s) {
528 		if (s.set.length == 1) {
529 			return visit(s.set[0]);
530 		}
531 		
532 		if (thisExpr is null) {
533 			return Identifiable(s);
534 		}
535 		
536 		auto dthis = getThis(location);
537 		
538 		Expression[] exprs;
539 		foreach(sym; s.set) {
540 			auto f = cast(Function) sym;
541 			assert(f, "Only function are implemented");
542 			
543 			import d.semantic.expression;
544 			auto e = ExpressionVisitor(pass.pass).getFrom(location, dthis, f);
545 			if (auto ee = cast(ErrorExpression) e) {
546 				continue;
547 			}
548 			
549 			exprs ~= e;
550 		}
551 		
552 		switch(exprs.length) {
553 			case 0 :
554 				return Identifiable(new CompileError(
555 					location,
556 					"No valid candidate in overload set",
557 				).symbol);
558 			
559 			case 1 :
560 				return Identifiable(exprs[0]);
561 			
562 			default :
563 				return Identifiable(new PolysemousExpression(
564 					location,
565 					exprs,
566 				));
567 		}
568 	}
569 	
570 	Identifiable visit(ValueAlias a) {
571 		if (asAlias && !thisExpr) {
572 			return Identifiable(a);
573 		}
574 		
575 		scheduler.require(a, Step.Signed);
576 		return visit(a.value);
577 	}
578 	
579 	Identifiable visit(SymbolAlias s) {
580 		scheduler.require(s, Step.Populated);
581 		return visit(s.symbol);
582 	}
583 	
584 	private auto getSymbolType(S)(S s) {
585 		static if (asAlias) {
586 			return Identifiable(s);
587 		} else {
588 			return Identifiable(Type.get(s));
589 		}
590 	}
591 	
592 	Identifiable visit(TypeAlias a) {
593 		scheduler.require(a);
594 		return getSymbolType(a);
595 	}
596 	
597 	Identifiable visit(Struct s) {
598 		return getSymbolType(s);
599 	}
600 	
601 	Identifiable visit(Union u) {
602 		return getSymbolType(u);
603 	}
604 	
605 	Identifiable visit(Class c) {
606 		return getSymbolType(c);
607 	}
608 
609 	Identifiable visit(Interface i) {
610 		return getSymbolType(i);
611 	}
612 
613 	Identifiable visit(Enum e) {
614 		return getSymbolType(e);
615 	}
616 	
617 	Identifiable visit(Template t) {
618 		return Identifiable(t);
619 	}
620 	
621 	Identifiable visit(TemplateInstance ti) {
622 		static if (!asAlias) {
623 			scheduler.require(ti, Step.Populated);
624 			
625 			// Try the eponymous trick.
626 			Template t = ti.getTemplate();
627 			if (auto s = ti.resolve(location, t.name)) {
628 				return visit(s);
629 			}
630 		}
631 
632 		return Identifiable(ti);
633 	}
634 	
635 	Identifiable visit(Module m) {
636 		return Identifiable(m);
637 	}
638 	
639 	Identifiable visit(TypeTemplateParameter t) {
640 		return getSymbolType(t);
641 	}
642 	
643 	Identifiable visit(ValueTemplateParameter v) {
644 		return Identifiable(v);
645 	}
646 	
647 	Identifiable visit(AliasTemplateParameter a) {
648 		return Identifiable(a);
649 	}
650 	
651 	Identifiable visit(ErrorSymbol e) {
652 		return Identifiable(e);
653 	}
654 }
655 
656 /**
657  * Resolve symbol.identifier.
658  */
659 struct SymbolDotIdentifierResolver {
660 	IdentifierPass pass;
661 	alias pass this;
662 	
663 	Location location;
664 	Name name;
665 	
666 	this(IdentifierPass pass, Location location, Name name) {
667 		this.pass = pass;
668 		this.location = location;
669 		this.name = name;
670 	}
671 	
672 	Identifiable visit(Symbol s) {
673 		if (auto vs = cast(ValueSymbol) s) {
674 			return resolveIn(location, postProcess(location, vs), name);
675 		}
676 		
677 		return this.dispatch(s);
678 	}
679 	
680 	Identifiable visit(OverloadSet o) {
681 		auto i = postProcess(location, o);
682 		if (i == Identifiable(o)) {
683 			assert(0, "Error, infinite loop");
684 		}
685 		
686 		return resolveIn(location, i, name);
687 	}
688 	
689 	Identifiable visit(Module m) {
690 		scheduler.require(m, Step.Populated);
691 		if (auto s = m.resolve(location, name)) {
692 			return Identifiable(s);
693 		}
694 		
695 		return Identifiable(new CompileError(
696 			location,
697 			"Cannot resolve " ~ name.toString(context),
698 		).symbol);
699 	}
700 	
701 	Identifiable visit(TemplateInstance ti) {
702 		scheduler.require(ti, Step.Populated);
703 		if (auto s = ti.resolve(location, name)) {
704 			return Identifiable(s);
705 		}
706 		
707 		// This failed, let's try the eponymous trick.
708 		Template t = ti.getTemplate();
709 		if (auto s = ti.resolve(location, t.name)) {
710 			return resolveIn(location, s, name);
711 		}
712 		
713 		return Identifiable(new CompileError(
714 			location,
715 			"Cannot resolve " ~ name.toString(context),
716 		).symbol);
717 	}
718 	
719 	Identifiable visit(SymbolAlias s) {
720 		scheduler.require(s, Step.Populated);
721 		return visit(s.symbol);
722 	}
723 	
724 	Identifiable resolveAsType(S)(S s) {
725 		return TypeDotIdentifierResolver(pass, location, name).visit(s);
726 	}
727 	
728 	Identifiable visit(Struct s) {
729 		return resolveAsType(s);
730 	}
731 	
732 	Identifiable visit(Union u) {
733 		return resolveAsType(u);
734 	}
735 	
736 	Identifiable visit(Class c) {
737 		return resolveAsType(c);
738 	}
739 	
740 	Identifiable visit(Interface i) {
741 		return resolveAsType(i);
742 	}
743 	
744 	Identifiable visit(Enum e) {
745 		return resolveAsType(e);
746 	}
747 	
748 	Identifiable visit(TypeAlias a) {
749 		return resolveAsType(a);
750 	}
751 }
752 
753 /**
754  * Resolve expression.identifier.
755  */
756 struct ExpressionDotIdentifierResolver {
757 	IdentifierPass pass;
758 	alias pass this;
759 	
760 	Location location;
761 	Name name;
762 	
763 	this(IdentifierPass pass, Location location, Name name) {
764 		this.pass = pass;
765 		this.location = location;
766 		this.name = name;
767 	}
768 	
769 	Identifiable visit(Expression e) in {
770 		assert(thisExpr is null);
771 	} do {
772 		e = wrap(location, e);
773 		return visit(e, e);
774 	}
775 	
776 	Identifiable visit(Expression e, Expression base) in {
777 		assert(thisExpr is null);
778 	} do {
779 		auto t = e.type.getCanonical();
780 		if (t.isAggregate) {
781 			auto a = t.aggregate;
782 			
783 			scheduler.require(a, Step.Populated);
784 			if (auto sym = a.resolve(location, name)) {
785 					setThis(e);
786 					return Identifiable(sym);
787 			}
788 			
789 			if (auto c = cast(Class) a) {
790 				if (auto sym = lookupInBase(c)) {
791 					setThis(e);
792 					return Identifiable(sym);
793 				}
794 			}
795 			
796 			import d.semantic.aliasthis;
797 			import std.algorithm, std.array;
798 			auto results = AliasThisResolver!identifiableHandler(pass.pass)
799 				.resolve(e, a)
800 				.map!((c) {
801 					// Make sure we process all alias this on the same base.
802 					auto oldThisExpr = thisExpr;
803 					scope(exit) thisExpr = oldThisExpr;
804 					
805 					auto i = resolveIn(location, c, name);
806 					
807 					import std.typecons;
808 					return tuple(i, thisExpr);
809 				})
810 				.filter!((t) => !t[0].isError())
811 				.array();
812 			
813 			if (results.length == 1) {
814 				thisExpr = results[0][1];
815 				return results[0][0];
816 			}
817 			
818 			assert(results.length == 0, "WTF am I supposed to do here ?");
819 		}
820 		
821 		auto et = t;
822 		while (et.kind == TypeKind.Enum) {
823 			scheduler.require(et.denum, Step.Populated);
824 			if (auto sym = et.denum.resolve(location, name)) {
825 				setThis(e);
826 				return Identifiable(sym);
827 			}
828 			
829 			et = et.denum.type.getCanonical();
830 		}
831 		
832 		// array.ptr is a special case.
833 		if (et.kind == TypeKind.Array && name == BuiltinName!"ptr") {
834 			return Identifiable(new UnaryExpression(
835 				location,
836 				t.element.getPointer(),
837 				UnaryOp.AddressOf,
838 				new IndexExpression(
839 					location,
840 					t.element,
841 					e,
842 					new IntegerLiteral(location, 0, BuiltinType.Uint),
843 				),
844 			));
845 		}
846 		
847 		// UFCS
848 		if (auto ufcs = resolveUFCS(e)) {
849 			return Identifiable(ufcs);
850 		}
851 		
852 		if (t.kind != TypeKind.Pointer) {
853 			return resolveInType(base);
854 		}
855 		
856 		// Try to autodereference pointers.
857 		return visit(new UnaryExpression(
858 			e.location,
859 			t.element,
860 			UnaryOp.Dereference,
861 			e,
862 		), base);
863 	}
864 	
865 	Symbol lookupInBase(Class c) {
866 		if (c is c.base) {
867 			return null;
868 		}
869 		
870 		c = c.base;
871 		scheduler.require(c, Step.Populated);
872 		if (auto sym = c.resolve(location, name)) {
873 			return sym;
874 		}
875 		
876 		return lookupInBase(c);
877 	}
878 	
879 	Expression resolveUFCS(Expression e) {
880 		// FIXME: templates and IFTI should UFCS too.
881 		Expression tryUFCS(Function f) {
882 			// No UFCS on member methods.
883 			if (f.hasThis) {
884 				return null;
885 			}
886 			
887 			import d.semantic.expression;
888 			auto dg = ExpressionVisitor(pass.pass).getFrom(location, e, f);
889 			if (typeid(dg) is typeid(ErrorExpression)) {
890 				return null;
891 			}
892 			
893 			return dg;
894 		}
895 		
896 		auto findUFCS(Symbol[] syms) {
897 			import std.algorithm, std.array;
898 			return syms
899 				.map!(s => cast(Function) s)
900 				.filter!(f => f !is null)
901 				.map!(f => tryUFCS(f))
902 				.filter!(e => e !is null)
903 				.array();
904 		}
905 		
906 		// TODO: Cache this result maybe ?
907 		auto a = IdentifierVisitor(pass).resolve(location, name);
908 		if (auto os = cast(OverloadSet) a) {
909 			auto ufcs = findUFCS(os.set);
910 			if (ufcs.length > 0) {
911 				assert(ufcs.length == 1, "ambiguous ufcs");
912 				return ufcs[0];
913 			}
914 		} else if (auto f = cast(Function) a) {
915 			auto ufcs = tryUFCS(f);
916 			if (ufcs) {
917 				return ufcs;
918 			}
919 		}
920 		
921 		return null;
922 	}
923 	
924 	Identifiable resolveInType(Expression e) {
925 		setThis(e);
926 		return TypeDotIdentifierResolver(pass, location, name).visit(e.type);
927 	}
928 }
929 
930 /**
931  * Resolve type.identifier.
932  */
933 struct TypeDotIdentifierResolver {
934 	IdentifierPass pass;
935 	alias pass this;
936 	
937 	Location location;
938 	Name name;
939 	
940 	this(IdentifierPass pass, Location location, Name name) {
941 		this.pass = pass;
942 		this.location = location;
943 		this.name = name;
944 	}
945 	
946 	Identifiable bailout(Type t) {
947 		if (name == BuiltinName!"init") {
948 			import d.semantic.defaultinitializer;
949 			return Identifiable(InitBuilder(pass.pass, location).visit(t));
950 		} else if (name == BuiltinName!"sizeof") {
951 			import d.semantic.sizeof;
952 			return Identifiable(new IntegerLiteral(
953 				location,
954 				SizeofVisitor(pass.pass).visit(t),
955 				pass.object.getSizeT().type.builtin,
956 			));
957 		}
958 		
959 		return Identifiable(getError(
960 			t,
961 			location,
962 			name.toString(context)
963 				~ " can't be resolved in type "
964 				~ t.toString(context),
965 		).symbol);
966 	}
967 	
968 	Identifiable visit(Type t) {
969 		return t.accept(this);
970 	}
971 	
972 	Identifiable visit(BuiltinType t) {
973 		if (name == BuiltinName!"max") {
974 			if (t == BuiltinType.Bool) {
975 				return Identifiable(new BooleanLiteral(location, true));
976 			} else if (isIntegral(t)) {
977 				return Identifiable(new IntegerLiteral(location, getMax(t), t));
978 			} else if (isChar(t)) {
979 				auto c = new CharacterLiteral(location, getCharMax(t), t);
980 				return Identifiable(c);
981 			}
982 		} else if (name == BuiltinName!"min") {
983 			if (t == BuiltinType.Bool) {
984 				return Identifiable(new BooleanLiteral(location, false));
985 			} else if (isIntegral(t)) {
986 				return Identifiable(new IntegerLiteral(location, getMin(t), t));
987 			} else if (isChar(t)) {
988 				return Identifiable(new CharacterLiteral(location, '\0', t));
989 			}
990 		}
991 		
992 		return bailout(Type.get(t));
993 	}
994 	
995 	Identifiable visitPointerOf(Type t) {
996 		return bailout(t.getPointer());
997 	}
998 	
999 	Identifiable visitSliceOf(Type t) {
1000 		// Slice have magic fields.
1001 		// XXX: This would gain to be moved to object.d
1002 		if (name == BuiltinName!"length") {
1003 			// FIXME: pass explicit location.
1004 			auto location = Location.init;
1005 			auto s = new Field(
1006 				location,
1007 				0,
1008 				pass.object.getSizeT().type,
1009 				BuiltinName!"length",
1010 				null,
1011 			);
1012 			
1013 			s.step = Step.Processed;
1014 			return Identifiable(s);
1015 		}
1016 		
1017 		if (name == BuiltinName!"ptr") {
1018 			// FIXME: pass explicit location.
1019 			auto location = Location.init;
1020 			auto s = new Field(
1021 				location,
1022 				1,
1023 				t.getPointer(),
1024 				BuiltinName!"ptr",
1025 				null,
1026 			);
1027 			
1028 			s.step = Step.Processed;
1029 			return Identifiable(s);
1030 		}
1031 		
1032 		return bailout(t.getSlice());
1033 	}
1034 	
1035 	Identifiable visitArrayOf(uint size, Type t) {
1036 		if (name != BuiltinName!"length") {
1037 			return bailout(t.getArray(size));
1038 		}
1039 		
1040 		return Identifiable(new IntegerLiteral(
1041 			location,
1042 			size,
1043 			pass.object.getSizeT().type.builtin,
1044 		));
1045 	}
1046 	
1047 	Symbol resolveInAggregate(Aggregate a) {
1048 		scheduler.require(a, Step.Populated);
1049 		return a.resolve(location, name);
1050 	}
1051 	
1052 	Identifiable visit(Struct s) {
1053 		if (auto sym = resolveInAggregate(s)) {
1054 			return Identifiable(sym);
1055 		}
1056 		
1057 		return bailout(Type.get(s));
1058 	}
1059 	
1060 	Identifiable visit(Union u) {
1061 		if (auto sym = resolveInAggregate(u)) {
1062 			return Identifiable(sym);
1063 		}
1064 		
1065 		return bailout(Type.get(u));
1066 	}
1067 	
1068 	Identifiable visit(Class c) {
1069 		if (auto s = resolveInAggregate(c)) {
1070 			return Identifiable(s);
1071 		}
1072 		
1073 		if (c !is c.base) {
1074 			return visit(c.base);
1075 		}
1076 		
1077 		return bailout(Type.get(c));
1078 	}
1079 	
1080 	Identifiable visit(Interface i) {
1081 		assert(0, "Not Implemented.");
1082 	}
1083 	
1084 	Identifiable visit(Enum e) {
1085 		scheduler.require(e, Step.Populated);
1086 		if (auto s = e.resolve(location, name)) {
1087 			return Identifiable(s);
1088 		}
1089 		
1090 		return visit(e.type);
1091 	}
1092 	
1093 	Identifiable visit(TypeAlias a) {
1094 		scheduler.require(a, Step.Populated);
1095 		return visit(a.type);
1096 	}
1097 	
1098 	Identifiable visit(Function f) {
1099 		assert(0, "Not Implemented.");
1100 	}
1101 	
1102 	Identifiable visit(Type[] seq) {
1103 		assert(0, "Not Implemented.");
1104 	}
1105 	
1106 	Identifiable visit(FunctionType f) {
1107 		return bailout(f.getType());
1108 	}
1109 	
1110 	Identifiable visit(Pattern p) {
1111 		return Identifiable(new CompileError(
1112 			location,
1113 			"Cannot resolve identifier on pattern.",
1114 		).symbol);
1115 	}
1116 	
1117 	Identifiable visit(CompileError e) {
1118 		return Identifiable(e.symbol);
1119 	}
1120 }