1 module d.semantic.caster;
2 
3 import d.semantic.semantic;
4 import d.semantic.typepromotion;
5 
6 import d.ir.expression;
7 import d.ir.symbol;
8 import d.ir.type;
9 
10 import source.location;
11 
12 import source.exception;
13 
14 Expression buildImplicitCast(
15 	SemanticPass pass,
16 	Location location,
17 	Type to,
18 	Expression e,
19 ) {
20 	return buildCast!false(pass, location, to, e);
21 }
22 
23 Expression buildExplicitCast(
24 	SemanticPass pass,
25 	Location location,
26 	Type to,
27 	Expression e,
28 ) {
29 	return buildCast!true(pass, location, to, e);
30 }
31 
32 CastKind implicitCastFrom(SemanticPass pass, Type from, Type to) {
33 	return ImplicitCaster(pass, to).castFrom(from);
34 }
35 
36 CastKind explicitCastFrom(SemanticPass pass, Type from, Type to) {
37 	return ExplicitCaster(pass, to).castFrom(from);
38 }
39 
40 private:
41 
42 // Conflict with Interface in object.di
43 alias Interface = d.ir.symbol.Interface;
44 
45 Expression buildCast(bool isExplicit)(
46 	SemanticPass pass,
47 	Location location,
48 	Type to,
49 	Expression e,
50 ) in {
51 	assert(e, "Expression must not be null");
52 } do {
53 	// If the expression is polysemous, we try the several meaning and
54 	// exclude the ones that make no sense.
55 	if (auto asPolysemous = cast(PolysemousExpression) e) {
56 		Expression casted;
57 		foreach(candidate; asPolysemous.expressions) {
58 			candidate = buildCast!isExplicit(pass, location, to, candidate);
59 			
60 			import d.ir.error;
61 			if (cast(ErrorExpression) candidate) {
62 				continue;
63 			}
64 			
65 			if (casted) {
66 				return new CompileError(location, "Ambiguous").expression;
67 			}
68 			
69 			casted = candidate;
70 		}
71 		
72 		if (casted) {
73 			return casted;
74 		}
75 		
76 		import d.ir.error;
77 		return new CompileError(location, "No match found").expression;
78 	}
79 	
80 	// When casting an array literal, we try to push down the
81 	// cast to each element of the literal.
82 	if (auto al = cast(ArrayLiteral) e) {
83 		switch (to.kind) with(TypeKind) {
84 			case Array:
85 				if (al.values.length != to.size) {
86 					import d.ir.error;
87 					return new CompileError(
88 						al.location,
89 						"Incorrect element count",
90 					).expression;
91 				}
92 				
93 				goto case;
94 				
95 			case Slice:
96 				import std.algorithm, std.array;
97 				auto et = to.element;
98 				auto values = al.values
99 					.map!(v => buildCast!isExplicit(pass, location, et, v))
100 					.array();
101 				return build!ArrayLiteral(e.location, to, values);
102 			
103 			default:
104 				break;
105 		}
106 	}
107 	
108 	auto kind = Caster!(isExplicit, delegate CastKind(c, t) {
109 		alias T = typeof(t);
110 		static if (is(T : Aggregate)) {
111 			static struct AliasThisResult {
112 				Expression expr;
113 				CastKind level;
114 			}
115 			
116 			auto level = CastKind.Invalid;
117 			enum InvalidResult = AliasThisResult(null, CastKind.Invalid);
118 			
119 			import d.semantic.aliasthis;
120 			import std.algorithm;
121 			auto results = AliasThisResolver!((identified) {
122 				alias T = typeof(identified);
123 				static if (is(T : Expression)) {
124 					auto oldE = e;
125 					scope(exit) e = oldE;
126 					e = identified;
127 					
128 					auto cLevel = c.castFrom(identified.type, to);
129 					if (cLevel == CastKind.Invalid || cLevel < level) {
130 						return InvalidResult;
131 					}
132 					
133 					level = cLevel;
134 					return AliasThisResult(identified, cLevel);
135 				} else {
136 					return InvalidResult;
137 				}
138 			})(pass).resolve(e, t).filter!(r => r.level == level);
139 			
140 			if (level == CastKind.Invalid) {
141 				return CastKind.Invalid;
142 			}
143 			
144 			Expression candidate;
145 			foreach(r; results) {
146 				if (candidate !is null) {
147 					return CastKind.Invalid;
148 				}
149 				
150 				candidate = r.expr;
151 			}
152 			
153 			assert(candidate, "if no candidate are found, level should be Invalid");
154 			
155 			e = candidate;
156 			return level;
157 		} else static if (is(T : BuiltinType)) {
158 			auto to = c.to;
159 			if (to.kind != TypeKind.Builtin || !canConvertToIntegral(to.builtin)) {
160 				return CastKind.Invalid;
161 			}
162 			
163 			assert(getSize(to.builtin) < getSize(t));
164 			
165 			import d.semantic.vrp;
166 			return ValueRangePropagator!uint(pass).canFit(e, to)
167 				? CastKind.Trunc
168 				: CastKind.Invalid;
169 		} else {
170 			return CastKind.Invalid;
171 		}
172 	})(pass, to).castFrom(e.type);
173 	
174 	switch(kind) with(CastKind) {
175 		case Exact:
176 			// FIXME: Because we don't cast type qualifier the proper
177 			// way, we need to make sure they match.
178 			e.type = e.type.qualify(to.qualifier);
179 			return e;
180 		
181 		default:
182 			return new CastExpression(location, kind, to, e);
183 		
184 		case Invalid:
185 			if (to.kind == TypeKind.Error) {
186 				return to.error.expression;
187 			}
188 			
189 			import d.ir.error;
190 			if (auto ee = cast(ErrorExpression) e) {
191 				return ee;
192 			}
193 			
194 			return new CompileError(
195 				location,
196 				"Can't cast " ~ e.type.toString(pass.context)
197 					~ " to " ~ to.toString(pass.context),
198 			).expression;
199 	}
200 }
201 
202 alias ExplicitCaster = Caster!true;
203 alias ImplicitCaster = Caster!false;
204 
205 struct Caster(bool isExplicit, alias bailoutOverride = null) {
206 	// XXX: Used only to get to super class, should probably go away.
207 	private SemanticPass pass;
208 	alias pass this;
209 	
210 	Type to;
211 	
212 	this(SemanticPass pass, Type to) {
213 		this.pass = pass;
214 		this.to = to;
215 	}
216 	
217 	enum hasBailoutOverride = !is(typeof(bailoutOverride) : typeof(null));
218 	
219 	CastKind bailout(T)(T t) {
220 		static if (hasBailoutOverride) {
221 			return bailoutOverride(this, t);
222 		} else {
223 			return CastKind.Invalid;
224 		}
225 	}
226 	
227 	CastKind bailoutDefault(T)(T t) {
228 		return CastKind.Invalid;
229 	}
230 	
231 	CastKind castFrom(ParamType from, ParamType to) {
232 		if (from.isRef != to.isRef) {
233 			return CastKind.Invalid;
234 		}
235 		
236 		auto k = castFrom(from.getType(), to.getType());
237 		if (from.isRef && k < CastKind.Qual) {
238 			return CastKind.Invalid;
239 		}
240 		
241 		return k;
242 	}
243 	
244 	// FIXME: handle qualifiers.
245 	CastKind castFrom(Type from) {
246 		from = from.getCanonical();
247 		to = to.getCanonical();
248 		
249 		if (from == to) {
250 			return CastKind.Exact;
251 		}
252 		
253 		return from.accept(this);
254 	}
255 	
256 	CastKind castFrom(Type from, Type to) {
257 		this.to = to;
258 		return castFrom(from);
259 	}
260 	
261 	CastKind visit(BuiltinType t) {
262 		if (isExplicit && to.kind == TypeKind.Enum) {
263 			to = to.getCanonicalAndPeelEnum();
264 			auto k = visit(t);
265 			return (k == CastKind.Exact)
266 				? CastKind.Bit
267 				: k;
268 		}
269 		
270 		// Can cast typeof(null) to class, pointer and function.
271 		if (t == BuiltinType.Null && to.hasPointerABI()) {
272 			return CastKind.Bit;
273 		}
274 		
275 		// Can explicitely cast integral to pointer.
276 		if (isExplicit && (to.kind == TypeKind.Pointer && canConvertToIntegral(t))) {
277 			return CastKind.IntToPtr;
278 		}
279 		
280 		if (to.kind != TypeKind.Builtin) {
281 			return CastKind.Invalid;
282 		}
283 		
284 		auto bt = to.builtin;
285 		if (t == bt) {
286 			return CastKind.Exact;
287 		}
288 		
289 		final switch(t) with(BuiltinType) {
290 			case None :
291 			case Void :
292 				return CastKind.Invalid;
293 			
294 			case Bool :
295 				if (isIntegral(bt)) {
296 					return CastKind.UPad;
297 				}
298 				
299 				return CastKind.Invalid;
300 			
301 			case Char :
302 				t = integralOfChar(t);
303 				goto case Ubyte;
304 			
305 			case Wchar :
306 				t = integralOfChar(t);
307 				goto case Ushort;
308 			
309 			case Dchar :
310 				t = integralOfChar(t);
311 				goto case Uint;
312 			
313 			case Byte, Ubyte, Short, Ushort, Int, Uint, Long, Ulong, Cent, Ucent :
314 				if (isExplicit && bt == Bool) {
315 					return CastKind.IntToBool;
316 				}
317 				
318 				if (!isIntegral(bt)) {
319 					return CastKind.Invalid;
320 				}
321 				
322 				auto ut = unsigned(t);
323 				bt = unsigned(bt);
324 				if (ut == bt) {
325 					return CastKind.Bit;
326 				} else if (ut < bt) {
327 					return isSigned(t)
328 						? CastKind.SPad
329 						: CastKind.UPad;
330 				} else static if (isExplicit) {
331 					return CastKind.Trunc;
332 				} else {
333 					return bailout(t);
334 				}
335 			
336 			case Float, Double, Real :
337 				assert(0, "Floating point casts are not implemented");
338 			
339 			case Null :
340 				return CastKind.Invalid;
341 		}
342 	}
343 	
344 	CastKind visitPointerOf(Type t) {
345 		// You can explicitely cast pointer to class, function.
346 		if (isExplicit && to.kind != TypeKind.Pointer && to.hasPointerABI()) {
347 			return CastKind.Bit;
348 		}
349 		
350 		// It is also possible to cast to integral explicitely.
351 		if (isExplicit && to.kind == TypeKind.Builtin) {
352 			if (canConvertToIntegral(to.builtin)) {
353 				return CastKind.PtrToInt;
354 			}
355 		}
356 		
357 		if (to.kind != TypeKind.Pointer) {
358 			return CastKind.Invalid;
359 		}
360 		
361 		auto e = to.element.getCanonical();
362 		
363 		// Cast to void* is kind of special.
364 		if (e.kind == TypeKind.Builtin && e.builtin == BuiltinType.Void) {
365 			return (isExplicit || canConvert(t.qualifier, e.qualifier))
366 				? CastKind.Bit
367 				: CastKind.Invalid;
368 		}
369 		
370 		auto subCast = castFrom(t, e);
371 		switch(subCast) with(CastKind) {
372 			case Qual:
373 				if (canConvert(t.qualifier, e.qualifier)) {
374 					return Qual;
375 				}
376 				
377 				goto default;
378 			
379 			case Exact:
380 				return Qual;
381 			
382 			static if (isExplicit) {
383 				default:
384 					return Bit;
385 			} else {
386 				case Bit :
387 					if (canConvert(t.qualifier, e.qualifier)) {
388 						return subCast;
389 					}
390 					
391 					goto default;
392 				
393 				default:
394 					return Invalid;
395 			}
396 		}
397 	}
398 	
399 	CastKind visitSliceOf(Type t) {
400 		if (to.kind != TypeKind.Slice) {
401 			return CastKind.Invalid;
402 		}
403 		
404 		auto e = to.element.getCanonical();
405 		
406 		auto subCast = castFrom(t, e);
407 		switch(subCast) with(CastKind) {
408 			case Qual:
409 				if (canConvert(t.qualifier, e.qualifier)) {
410 					return Qual;
411 				}
412 				
413 				goto default;
414 			
415 			case Exact:
416 				return Qual;
417 			
418 			static if (isExplicit) {
419 				default:
420 					return Bit;
421 			} else {
422 				case Bit:
423 					if (canConvert(t.qualifier, e.qualifier)) {
424 						return subCast;
425 					}
426 					
427 					goto default;
428 				
429 				default:
430 					return Invalid;
431 			}
432 		}
433 	}
434 	
435 	CastKind visitArrayOf(uint size, Type t) {
436 		if (to.kind != TypeKind.Array) {
437 			return CastKind.Invalid;
438 		}
439 		
440 		if (size != to.size) {
441 			return CastKind.Invalid;
442 		}
443 		
444 		auto e = to.element.getCanonical();
445 		
446 		auto subCast = castFrom(t, e);
447 		switch(subCast) with(CastKind) {
448 			case Qual:
449 				if (canConvert(t.qualifier, e.qualifier)) {
450 					return Qual;
451 				}
452 				
453 				goto default;
454 			
455 			case Exact:
456 				return Exact;
457 			
458 			static if (isExplicit) {
459 				default:
460 					return Bit;
461 			} else {
462 				case Bit:
463 					if (canConvert(t.qualifier, e.qualifier)) {
464 						return subCast;
465 					}
466 					
467 					goto default;
468 				
469 				default:
470 					return Invalid;
471 			}
472 		}
473 	}
474 	
475 	CastKind visit(Struct s) {
476 		if (to.kind == TypeKind.Struct) {
477 			if (to.dstruct is s) {
478 				return CastKind.Exact;
479 			}
480 		}
481 		
482 		return bailout(s);
483 	}
484 	
485 	private auto castClass(Class from, Class to) {
486 		if (from is to) {
487 			return CastKind.Exact;
488 		}
489 		
490 		auto upcast = from;
491 		
492 		// Stop at object.
493 		while(upcast !is upcast.base) {
494 			// Automagically promote to base type.
495 			upcast = upcast.base;
496 			
497 			if (upcast is to) {
498 				return CastKind.Bit;
499 			}
500 		}
501 		
502 		static if (isExplicit) {
503 			auto downcast = to;
504 			
505 			// Stop at object.
506 			while(downcast !is downcast.base) {
507 				// Automagically promote to base type.
508 				downcast = downcast.base;
509 				
510 				if (downcast is from) {
511 					return CastKind.Down;
512 				}
513 			}
514 		}
515 		
516 		return CastKind.Invalid;
517 	}
518 	
519 	CastKind visit(Class c) {
520 		if (isExplicit && to.kind == TypeKind.Pointer) {
521 			auto et = to.element.getCanonical();
522 			if (et.kind == TypeKind.Builtin &&
523 				et.builtin == BuiltinType.Void) {
524 				return CastKind.Bit;
525 			}
526 		}
527 		
528 		if (to.kind == TypeKind.Class) {
529 			scheduler.require(c, Step.Signed);
530 			auto kind = castClass(c, to.dclass);
531 			if (kind > CastKind.Invalid) {
532 				return kind;
533 			}
534 		}
535 		
536 		return bailout(c);
537 	}
538 	
539 	CastKind visit(Enum e) {
540 		if (to.kind == TypeKind.Enum) {
541 			if (e is to.denum) {
542 				return CastKind.Exact;
543 			}
544 		}
545 		
546 		// Automagically promote to base type.
547 		return castFrom(e.type);
548 	}
549 	
550 	CastKind visit(TypeAlias a) {
551 		return castFrom(a.type);
552 	}
553 	
554 	CastKind visit(Interface i) {
555 		return CastKind.Invalid;
556 	}
557 	
558 	CastKind visit(Union u) {
559 		return (to.kind == TypeKind.Union && to.dunion is u)
560 			? CastKind.Exact
561 			: CastKind.Invalid;
562 	}
563 	
564 	CastKind visit(Function f) {
565 		assert(0, "Cast to context type do not make any sense.");
566 	}
567 	
568 	CastKind visit(Type[] seq) {
569 		assert(0, "Cast to sequence type do not make any sense.");
570 	}
571 	
572 	CastKind visit(FunctionType f) {
573 		if (to.kind == TypeKind.Pointer && f.contexts.length == 0) {
574 			auto e = to.element.getCanonical();
575 			static if (isExplicit) {
576 				return CastKind.Bit;
577 			} else if (e.kind == TypeKind.Builtin && e.builtin == BuiltinType.Void) {
578 				// FIXME: qualifier.
579 				return CastKind.Bit;
580 			} else {
581 				return CastKind.Invalid;
582 			}
583 		}
584 		
585 		if (to.kind != TypeKind.Function) {
586 			return CastKind.Invalid;
587 		}
588 		
589 		auto tf = to.asFunctionType();
590 		
591 		if (f.contexts.length != tf.contexts.length) {
592 			return CastKind.Invalid;
593 		}
594 		
595 		enum onFail = isExplicit ? CastKind.Bit : CastKind.Invalid;
596 		
597 		if (f.parameters.length != tf.parameters.length) {
598 			return onFail;
599 		}
600 		
601 		if (f.isVariadic != tf.isVariadic) {
602 			return onFail;
603 		}
604 		
605 		if (f.linkage != tf.linkage) {
606 			return onFail;
607 		}
608 		
609 		auto k = castFrom(f.returnType, tf.returnType);
610 		if (k < CastKind.Bit) {
611 			return onFail;
612 		}
613 		
614 		import std.range;
615 		foreach(fromc, toc; lockstep(f.contexts, tf.contexts)) {
616 			// ref context decay to void*
617 			if (fromc.isRef && !toc.isRef &&
618 				toc.kind == TypeKind.Pointer) {
619 				
620 				auto e = toc.getType().element;
621 				if (e.kind == TypeKind.Builtin &&
622 					e.builtin == BuiltinType.Void) {
623 				
624 					k = CastKind.Bit;
625 					continue;
626 				}
627 			}
628 			
629 			// Contexts are covariant.
630 			auto kc = castFrom(fromc, toc);
631 			if (kc < CastKind.Bit) {
632 				return onFail;
633 			}
634 			
635 			import std.algorithm;
636 			k = min(k, kc);
637 		}
638 		
639 		foreach(fromp, top; lockstep(f.parameters, tf.parameters)) {
640 			// Parameters are contrevariant.
641 			auto kp = castFrom(top, fromp);
642 			if (kp < CastKind.Bit) {
643 				return onFail;
644 			}
645 			
646 			import std.algorithm;
647 			k = min(k, kp);
648 		}
649 		
650 		return (k < CastKind.Exact) ? CastKind.Bit : CastKind.Exact;
651 	}
652 	
653 	CastKind visit(Pattern p) {
654 		assert(0, "Pattern cannot be casted.");
655 	}
656 	
657 	import d.ir.error;
658 	CastKind visit(CompileError e) {
659 		return CastKind.Invalid;
660 	}
661 }