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 }