1 module d.semantic.expression; 2 3 import d.semantic.caster; 4 import d.semantic.semantic; 5 6 import d.ast.expression; 7 import d.ast.type; 8 9 import d.ir.error; 10 import d.ir.expression; 11 import d.ir.symbol; 12 import d.ir.type; 13 14 import source.location; 15 16 import source.exception; 17 18 alias TernaryExpression = d.ir.expression.TernaryExpression; 19 alias ArrayLiteral = d.ir.expression.ArrayLiteral; 20 alias CallExpression = d.ir.expression.CallExpression; 21 alias NewExpression = d.ir.expression.NewExpression; 22 23 struct ExpressionVisitor { 24 private SemanticPass pass; 25 alias pass this; 26 27 this(SemanticPass pass) { 28 this.pass = pass; 29 } 30 31 Expression visit(AstExpression e) { 32 return this.dispatch!((e) { 33 throw new CompileException( 34 e.location, typeid(e).toString() ~ " is not supported"); 35 })(e); 36 } 37 38 Expression visit(ParenExpression e) { 39 return visit(e.expr); 40 } 41 42 Expression visit(BooleanLiteral e) { 43 return e; 44 } 45 46 Expression visit(IntegerLiteral e) { 47 return e; 48 } 49 50 Expression visit(FloatLiteral e) { 51 return e; 52 } 53 54 Expression visit(CharacterLiteral e) { 55 return e; 56 } 57 58 Expression visit(NullLiteral e) { 59 return e; 60 } 61 62 Expression visit(StringLiteral e) { 63 return e; 64 } 65 66 private: 67 ErrorExpression getError(Expression base, Location location, string msg) { 68 return .getError(base, location, msg).expression; 69 } 70 71 ErrorExpression getError(Expression base, string msg) { 72 return getError(base, base.location, msg); 73 } 74 75 ErrorExpression getError(Symbol base, Location location, string msg) { 76 return .getError(base, location, msg).expression; 77 } 78 79 ErrorExpression getError(Type t, Location location, string msg) { 80 return .getError(t, location, msg).expression; 81 } 82 83 Expression getTemporary(Expression value) { 84 if (auto e = cast(ErrorExpression) value) { 85 return e; 86 } 87 88 auto loc = value.location; 89 90 import source.name; 91 auto v = new Variable(loc, value.type, BuiltinName!"", value); 92 v.step = Step.Processed; 93 94 return new VariableExpression(loc, v); 95 } 96 97 Expression getLvalue(Expression value) { 98 if (auto e = cast(ErrorExpression) value) { 99 return e; 100 } 101 102 import source.name; 103 auto v = new Variable(value.location, 104 value.type.getParamType(ParamKind.Ref), 105 BuiltinName!"", value); 106 107 v.step = Step.Processed; 108 return new VariableExpression(value.location, v); 109 } 110 111 auto buildAssign(Location location, Expression lhs, Expression rhs) { 112 if (!lhs.isLvalue) { 113 return getError(lhs, "Expected an lvalue"); 114 } 115 116 auto type = lhs.type; 117 rhs = buildImplicitCast(pass, rhs.location, type, rhs); 118 return 119 build!BinaryExpression(location, type, BinaryOp.Assign, lhs, rhs); 120 } 121 122 Expression buildBinary(Location location, AstBinaryOp op, Expression lhs, 123 Expression rhs) { 124 if (op.isAssign()) { 125 lhs = getLvalue(lhs); 126 rhs = getTemporary(rhs); 127 128 auto type = lhs.type; 129 auto llhs = build!BinaryExpression(location, type, BinaryOp.Comma, 130 rhs, lhs); 131 132 return buildAssign(location, lhs, buildExplicitCast( 133 pass, location, type, 134 buildBinary(location, op.getBaseOp(), llhs, rhs))); 135 } 136 137 Type type; 138 BinaryOp bop; 139 ICmpOp icmpop; 140 final switch (op) with (AstBinaryOp) { 141 case Comma: 142 return build!BinaryExpression(location, rhs.type, 143 BinaryOp.Comma, lhs, rhs); 144 145 case Assign: 146 return buildAssign(location, lhs, rhs); 147 148 case Add, Sub: 149 auto c = lhs.type.getCanonical(); 150 if (c.kind == TypeKind.Pointer) { 151 // FIXME: check that rhs is an integer. 152 if (op == Sub) { 153 rhs = build!UnaryExpression(rhs.location, rhs.type, 154 UnaryOp.Minus, rhs); 155 } 156 157 auto i = 158 build!IndexExpression(location, c.element, lhs, rhs); 159 return build!UnaryExpression(location, lhs.type, 160 UnaryOp.AddressOf, i); 161 } 162 163 goto case; 164 165 case Mul, Pow: 166 bop = cast(BinaryOp) op; 167 goto PromotedBinaryOp; 168 169 case Div, Rem: 170 import d.semantic.typepromotion; 171 type = getPromotedType(pass, location, lhs.type, rhs.type); 172 173 auto bt = type.builtin; 174 auto signed = isIntegral(bt) && isSigned(bt); 175 176 // FIXME: We need some wrapper asserting + unitest for these. 177 bop = 178 cast(BinaryOp) (((op - Div) * 2) + BinaryOp.UDiv + signed); 179 goto CastBinaryOp; 180 181 case Or, And, Xor: 182 case LeftShift, UnsignedRightShift: 183 // FIXME: We need some wrapper asserting + unitest for these. 184 bop = cast(BinaryOp) (op - Or + BinaryOp.Or); 185 goto PromotedBinaryOp; 186 187 PromotedBinaryOp: 188 import d.semantic.typepromotion; 189 type = getPromotedType(pass, location, lhs.type, rhs.type); 190 191 goto CastBinaryOp; 192 193 case SignedRightShift: 194 import d.semantic.typepromotion; 195 type = getPromotedType(pass, location, lhs.type, rhs.type); 196 197 auto bt = type.builtin; 198 bop = (isIntegral(bt) && isSigned(bt)) 199 ? BinaryOp.SignedRightShift 200 : BinaryOp.UnsignedRightShift; 201 202 goto CastBinaryOp; 203 204 case LogicalOr, LogicalAnd: 205 type = Type.get(BuiltinType.Bool); 206 207 // FIXME: We need some wrapper asserting + unitest for these. 208 bop = cast(BinaryOp) (op - LogicalOr + BinaryOp.LogicalOr); 209 210 lhs = buildExplicitCast(pass, lhs.location, type, lhs); 211 rhs = buildExplicitCast(pass, rhs.location, type, rhs); 212 213 goto BuildBinaryOp; 214 215 CastBinaryOp: 216 lhs = buildImplicitCast(pass, lhs.location, type, lhs); 217 rhs = buildImplicitCast(pass, rhs.location, type, rhs); 218 219 goto BuildBinaryOp; 220 221 BuildBinaryOp: 222 return build!BinaryExpression(location, type, bop, lhs, rhs); 223 224 case Concat: 225 type = lhs.type; 226 if (type.getCanonical().kind != TypeKind.Slice) { 227 return getError(lhs, "Expected a slice"); 228 } 229 230 rhs = buildImplicitCast( 231 pass, rhs.location, 232 (rhs.type.getCanonical().kind == TypeKind.Slice) 233 ? type 234 : type.element, 235 rhs); 236 237 return callOverloadSet(location, pass.object.getArrayConcat(), 238 [lhs, rhs]); 239 240 case AddAssign, SubAssign: 241 case MulAssign, PowAssign: 242 case DivAssign, RemAssign: 243 case OrAssign, AndAssign, XorAssign: 244 case LeftShiftAssign: 245 case UnsignedRightShiftAssign: 246 case SignedRightShiftAssign: 247 case LogicalOrAssign: 248 case LogicalAndAssign: 249 case ConcatAssign: 250 assert(0, "Assign op should not reach this point"); 251 252 case Equal, Identical: 253 icmpop = ICmpOp.Equal; 254 goto HandleICmp; 255 256 case NotEqual, NotIdentical: 257 icmpop = ICmpOp.NotEqual; 258 goto HandleICmp; 259 260 case Greater: 261 icmpop = ICmpOp.Greater; 262 goto HandleICmp; 263 264 case GreaterEqual: 265 icmpop = ICmpOp.GreaterEqual; 266 goto HandleICmp; 267 268 case Less: 269 icmpop = ICmpOp.Less; 270 goto HandleICmp; 271 272 case LessEqual: 273 icmpop = ICmpOp.LessEqual; 274 goto HandleICmp; 275 276 HandleICmp: 277 import d.semantic.typepromotion; 278 type = getPromotedType(pass, location, lhs.type, rhs.type); 279 280 lhs = buildImplicitCast(pass, lhs.location, type, lhs); 281 rhs = buildImplicitCast(pass, rhs.location, type, rhs); 282 283 return build!ICmpExpression(location, icmpop, lhs, rhs); 284 285 case In: 286 case NotIn: 287 assert(0, "in and !in are not implemented."); 288 289 case LessGreater: 290 case LessEqualGreater: 291 case UnorderedLess: 292 case UnorderedLessEqual: 293 case UnorderedGreater: 294 case UnorderedGreaterEqual: 295 case Unordered: 296 case UnorderedEqual: 297 assert(0, "Unorderd comparisons are not implemented."); 298 } 299 } 300 301 public: 302 Expression visit(AstBinaryExpression e) { 303 return buildBinary(e.location, e.op, visit(e.lhs), visit(e.rhs)); 304 } 305 306 Expression visit(AstTernaryExpression e) { 307 auto condition = buildExplicitCast(pass, e.condition.location, 308 Type.get(BuiltinType.Bool), 309 visit(e.condition)); 310 311 auto lhs = visit(e.lhs); 312 auto rhs = visit(e.rhs); 313 314 import d.semantic.typepromotion; 315 auto t = getPromotedType(pass, e.location, lhs.type, rhs.type); 316 317 lhs = buildExplicitCast(pass, lhs.location, t, lhs); 318 rhs = buildExplicitCast(pass, rhs.location, t, rhs); 319 320 return build!TernaryExpression(e.location, t, condition, lhs, rhs); 321 } 322 323 private Expression handleAddressOf(Expression expr) { 324 // For fucked up reasons, &funcname is a special case. 325 if (auto se = cast(FunctionExpression) expr) { 326 return expr; 327 } else if (auto pe = cast(PolysemousExpression) expr) { 328 import std.algorithm, std.array; 329 pe.expressions = 330 pe.expressions.map!(e => handleAddressOf(e)).array(); 331 return pe; 332 } 333 334 return build!UnaryExpression(expr.location, expr.type.getPointer(), 335 UnaryOp.AddressOf, expr); 336 } 337 338 Expression visit(AstUnaryExpression e) { 339 auto expr = visit(e.expr); 340 auto op = e.op; 341 342 Type type; 343 final switch (op) with (UnaryOp) { 344 case AddressOf: 345 return handleAddressOf(expr); 346 347 // It could have been so simple :( 348 /+ 349 type = expr.type.getPointer(); 350 break; 351 +/ 352 353 case Dereference: 354 auto c = expr.type.getCanonical(); 355 if (c.kind == TypeKind.Pointer) { 356 type = c.element; 357 break; 358 } 359 360 return getError(expr, e.location, 361 "Only pointers can be dereferenced"); 362 363 case PreInc, PreDec: 364 case PostInc, PostDec: 365 // FIXME: check that type is integer or pointer. 366 type = expr.type; 367 break; 368 369 case Plus: 370 case Minus: 371 case Complement: 372 // FIXME: check that type is integer. 373 type = expr.type; 374 break; 375 376 case Not: 377 type = Type.get(BuiltinType.Bool); 378 expr = buildExplicitCast(pass, expr.location, type, expr); 379 break; 380 } 381 382 return build!UnaryExpression(e.location, type, op, expr); 383 } 384 385 Expression visit(AstCastExpression e) { 386 import d.semantic.type; 387 return buildExplicitCast( 388 pass, e.location, TypeVisitor(pass).visit(e.type), visit(e.expr)); 389 } 390 391 Expression visit(AstArrayLiteral e) { 392 import std.algorithm, std.array; 393 auto values = e.values.map!(v => visit(v)).array(); 394 395 // The type of the first element determine the type of the array. 396 auto type = 397 values.length > 0 ? values[0].type : Type.get(BuiltinType.Void); 398 399 // Cast all the value to the proper type. 400 values = values.map!(v => buildImplicitCast(pass, v.location, type, v)) 401 .array(); 402 403 return build!ArrayLiteral(e.location, type.getSlice(), values); 404 } 405 406 Expression buildArgument(Expression arg, ParamType pt) { 407 if (pt.isRef && !canConvert(arg.type.qualifier, pt.qualifier)) { 408 return getError(arg, "Can't pass argument (" 409 ~ arg.type.toString(context) ~ ") by ref to " 410 ~ pt.toString(context)); 411 } 412 413 arg = buildImplicitCast(pass, arg.location, pt.getType(), arg); 414 415 // Test if we can pass by ref. 416 if (pt.isRef && !arg.isLvalue) { 417 return getError(arg, "Argument isn't a lvalue"); 418 } 419 420 return arg; 421 } 422 423 enum MatchLevel { 424 Not, 425 TypeConvert, 426 QualifierConvert, 427 Exact, 428 } 429 430 // TODO: deduplicate. 431 private auto matchArgument(Expression arg, ParamType param) { 432 if (param.isRef && !canConvert(arg.type.qualifier, param.qualifier)) { 433 return MatchLevel.Not; 434 } 435 436 auto flavor = implicitCastFrom(pass, arg.type, param.getType()); 437 438 // test if we can pass by ref. 439 if (param.isRef && !(flavor >= CastKind.Bit && arg.isLvalue)) { 440 return MatchLevel.Not; 441 } 442 443 return matchLevel(flavor); 444 } 445 446 // TODO: deduplicate. 447 private auto matchArgument(ParamType type, ParamType param) { 448 if (param.isRef && !canConvert(type.qualifier, param.qualifier)) { 449 return MatchLevel.Not; 450 } 451 452 auto flavor = implicitCastFrom(pass, type.getType(), param.getType()); 453 454 // test if we can pass by ref. 455 if (param.isRef && !(flavor >= CastKind.Bit && type.isRef)) { 456 return MatchLevel.Not; 457 } 458 459 return matchLevel(flavor); 460 } 461 462 private auto matchLevel(CastKind flavor) { 463 final switch (flavor) with (CastKind) { 464 case Invalid: 465 return MatchLevel.Not; 466 467 case IntToPtr, PtrToInt, Down, IntToBool, Trunc: 468 assert(0, "Not an implicit cast !"); 469 470 case UPad, SPad, Bit: 471 return MatchLevel.TypeConvert; 472 473 case Qual: 474 return MatchLevel.QualifierConvert; 475 476 case Exact: 477 return MatchLevel.Exact; 478 } 479 } 480 481 private Expression getContext(Location location, Function f) in { 482 assert(f.step >= Step.Signed); 483 } do { 484 import d.semantic.closure; 485 auto ctx = ContextFinder(pass).visit(f); 486 return build!ContextExpression(location, ctx); 487 } 488 489 Expression getFrom(Location location, Function f) { 490 scheduler.require(f, Step.Signed); 491 492 Expression[] ctxs; 493 ctxs.reserve(f.hasThis + f.hasContext); 494 if (f.hasContext) { 495 ctxs ~= getContext(location, f); 496 } 497 498 if (f.hasThis) { 499 ctxs ~= getThis(location); 500 } 501 502 return getFromImpl(location, f, ctxs); 503 } 504 505 Expression getFrom(Location location, Expression thisExpr, Function f) { 506 scheduler.require(f, Step.Signed); 507 508 Expression[] ctxs; 509 ctxs.reserve(f.hasContext + 1); 510 511 if (f.hasContext) { 512 ctxs ~= getContext(location, f); 513 } 514 515 ctxs ~= thisExpr; 516 return getFromImpl(location, f, ctxs); 517 } 518 519 private Expression getFromImpl(Location location, Function f, 520 Expression[] ctxs) in { 521 assert(f.step >= Step.Signed); 522 assert(ctxs.length >= f.hasContext + f.hasThis); 523 } do { 524 foreach (i, ref c; ctxs) { 525 c = buildArgument(c, f.type.parameters[i]); 526 } 527 528 auto e = (ctxs.length == 0) 529 ? new FunctionExpression(location, f) 530 : build!DelegateExpression(location, ctxs, f); 531 532 // If this is not a property, things are straigforward. 533 if (!f.isProperty) { 534 return e; 535 } 536 537 assert(!f.hasContext); 538 if (f.params.length != ctxs.length - f.hasContext) { 539 return getError(e, "Invalid number of argument for @property " 540 ~ f.name.toString(context)); 541 } 542 543 Expression[] args; 544 return build!CallExpression(location, f.type.returnType.getType(), e, 545 args); 546 } 547 548 Expression visit(AstCallExpression c) { 549 import std.algorithm, std.array; 550 auto args = c.args.map!(a => visit(a)).array(); 551 552 // FIXME: Have a ThisCallExpression. 553 auto te = cast(ThisExpression) c.callee; 554 if (te is null) { 555 return handleCall(c.location, visit(c.callee), args); 556 } 557 558 // FIXME: check if we are in a constructor. 559 auto t = thisType.getType().getCanonical(); 560 if (!t.isAggregate()) { 561 assert(0, "ctor on non aggregate not implemented"); 562 } 563 564 auto loc = c.callee.location; 565 auto thisExpr = getThis(loc); 566 567 auto ctor = findCtor(c.location, loc, thisExpr, args); 568 auto thisKind = ctor.type.asFunctionType().contexts[0].paramKind; 569 auto call = callCallable(c.location, ctor, args); 570 571 final switch (thisKind) with (ParamKind) { 572 case Regular: 573 // Value type, by value. 574 return build!BinaryExpression(c.location, thisExpr.type, 575 BinaryOp.Assign, thisExpr, call); 576 577 case Final: 578 // Classes. 579 return call; 580 581 case Ref: 582 // Value type, by ref. 583 return build!BinaryExpression(c.location, thisExpr.type, 584 BinaryOp.Comma, call, thisExpr); 585 } 586 } 587 588 Expression visit(IdentifierCallExpression c) { 589 import std.algorithm, std.array; 590 auto args = c.args.map!(a => visit(a)).array(); 591 592 // XXX: Why are doing this here ? 593 // Shouldn't this be done in the identifier module ? 594 Expression postProcess(T)(T identified) { 595 static if (is(T : Expression)) { 596 return handleCall(c.location, identified, args); 597 } else { 598 static if (is(T : Symbol)) { 599 if (auto s = cast(OverloadSet) identified) { 600 return callOverloadSet(c.location, s, args); 601 } 602 603 if (auto t = cast(Template) identified) { 604 auto callee = handleIFTI(c.location, t, args); 605 return callCallable(c.location, callee, args); 606 } 607 } 608 609 static if (is(T : Type)) { 610 return callType(c.location, c.callee.location, identified, 611 args); 612 } else { 613 return getError( 614 identified, c.location, 615 c.callee.toString(pass.context) ~ " isn't callable"); 616 } 617 } 618 } 619 620 import d.ast.identifier, d.semantic.identifier; 621 if (auto tidi = cast(TemplateInstantiation) c.callee) { 622 // XXX: For some reason this need to be passed a lambda. 623 return IdentifierResolver(pass).build(tidi, args) 624 .apply!(i => postProcess(i))(); 625 } 626 627 // XXX: For some reason this need to be passed a lambda. 628 return IdentifierResolver(pass).build(c.callee) 629 .apply!((i => postProcess(i)))(); 630 } 631 632 Expression visit(TypeCallExpression e) { 633 import d.semantic.type; 634 auto t = TypeVisitor(pass).visit(e.type); 635 636 import std.algorithm, std.array; 637 auto args = e.args.map!(a => visit(a)).array(); 638 639 return callType(e.location, e.location, t, args); 640 } 641 642 private Expression callType(Location location, Location calleeLoc, 643 Type callee, Expression[] args) { 644 auto t = callee.getCanonical(); 645 switch (t.kind) with (TypeKind) { 646 case Builtin: 647 if (args.length == 1) { 648 return buildImplicitCast(pass, location, t, args[0]); 649 } 650 651 return getError(t, location, "Expected one argument"); 652 653 case Struct: 654 auto s = t.dstruct; 655 scheduler.require(s, Step.Signed); 656 657 import d.semantic.defaultinitializer; 658 auto di = InstanceBuilder(pass, calleeLoc).visit(s); 659 if (s.isSmall) { 660 return callCtor(location, calleeLoc, di, args); 661 } 662 663 auto thisExpr = getTemporary(di); 664 return build!BinaryExpression( 665 location, t, BinaryOp.Comma, 666 callCtor(location, calleeLoc, thisExpr, args), thisExpr); 667 668 default: 669 return getError(t, location, "Cannot build this type"); 670 } 671 } 672 673 private Expression callCtor(Location location, Location calleeLoc, 674 Expression thisExpr, Expression[] args) in { 675 assert(thisExpr.type.isAggregate()); 676 } do { 677 auto ctor = findCtor(location, calleeLoc, thisExpr, args); 678 return callCallable(location, ctor, args); 679 } 680 681 // XXX: factorize with NewExpression 682 private Expression findCtor(Location location, Location calleeLoc, 683 Expression thisExpr, Expression[] args) in { 684 assert(thisExpr.type.isAggregate(), 685 thisExpr.toString(context) ~ " is not an aggregate"); 686 } do { 687 auto agg = thisExpr.type.aggregate; 688 689 import source.name, d.semantic.identifier; 690 return IdentifierResolver(pass) 691 .resolveIn(location, agg, BuiltinName!"__ctor") 692 .apply!(delegate Expression(i) { 693 alias T = typeof(i); 694 static if (is(T : Symbol)) { 695 if (auto f = cast(Function) i) { 696 return getFrom(calleeLoc, thisExpr, f); 697 } 698 699 if (auto s = cast(OverloadSet) i) { 700 // FIXME: overload resolution doesn't do alias this 701 // or vrp trunc, so we need a workaround here. 702 if (s.set.length == 1) { 703 if (auto f = cast(Function) s.set[0]) { 704 return getFrom(calleeLoc, thisExpr, f); 705 } 706 } 707 708 import std.algorithm, std.array; 709 return chooseOverload( 710 location, s.set.map!(delegate Expression(s) { 711 if (auto f = cast(Function) s) { 712 return getFrom(calleeLoc, thisExpr, f); 713 } 714 715 // XXX: Template ??!?!!? 716 assert(0, "Not a constructor"); 717 }).array(), args); 718 } 719 } 720 721 return getError( 722 i, location, 723 agg.name.toString(pass.context) ~ " isn't callable"); 724 })(); 725 } 726 727 private 728 Expression handleIFTI(Location location, Template t, Expression[] args) { 729 import d.semantic.dtemplate; 730 TemplateArgument[] targs; 731 targs.length = t.parameters.length; 732 733 auto i = TemplateInstancier(pass).instanciate(location, t, [], args); 734 scheduler.require(i); 735 736 import d.semantic.identifier; 737 return IdentifierResolver(pass).buildIn(location, i, t.name) 738 .apply!(delegate Expression(identified) { 739 alias T = typeof(identified); 740 static if (is(T : Expression)) { 741 return identified; 742 } else { 743 return getError( 744 identified, location, 745 t.name.toString(pass.context) ~ " isn't callable"); 746 } 747 })(); 748 } 749 750 private Expression callOverloadSet(Location location, OverloadSet s, 751 Expression[] args) { 752 import std.algorithm, std.array; 753 return callCallable(location, chooseOverload(location, s.set.map!((s) { 754 pass.scheduler.require(s, Step.Signed); 755 if (auto f = cast(Function) s) { 756 return getFrom(location, f); 757 } else if (auto t = cast(Template) s) { 758 return handleIFTI(location, t, args); 759 } 760 761 throw new CompileException( 762 s.location, 763 typeid(s).toString() ~ " is not supported in overload set"); 764 }).array(), args), args); 765 } 766 767 private static bool checkArgumentCount(bool isVariadic, size_t argCount, 768 size_t paramCount) { 769 return isVariadic ? argCount >= paramCount : argCount == paramCount; 770 } 771 772 // XXX: Take a range instead of an array. 773 private 774 Expression chooseOverload(Location location, Expression[] candidates, 775 Expression[] args) { 776 import std.algorithm, std.range; 777 auto cds = 778 candidates.map!(e => findCallable(location, e, args)).filter!((e) { 779 auto t = e.type.getCanonical(); 780 assert( 781 t.kind == TypeKind.Function, 782 e.type.toString(pass.context) ~ " is not a function type"); 783 784 auto ft = t.asFunctionType(); 785 return checkArgumentCount(ft.isVariadic, args.length, 786 ft.parameters.length); 787 }); 788 789 auto level = MatchLevel.Not; 790 Expression match; 791 CandidateLoop: foreach (candidate; cds) { 792 auto t = candidate.type.getCanonical(); 793 assert(t.kind == TypeKind.Function, 794 "We should have filtered function at this point."); 795 796 auto funType = t.asFunctionType(); 797 798 auto candidateLevel = MatchLevel.Exact; 799 foreach (arg, param; lockstep(args, funType.parameters)) { 800 auto argLevel = matchArgument(arg, param); 801 802 // If we don't match high enough. 803 if (argLevel < level) { 804 continue CandidateLoop; 805 } 806 807 final switch (argLevel) with (MatchLevel) { 808 case Not: 809 // This function don't match, go to next one. 810 continue CandidateLoop; 811 812 case TypeConvert, QualifierConvert: 813 candidateLevel = min(candidateLevel, argLevel); 814 continue; 815 816 case Exact: 817 // Go to next argument 818 continue; 819 } 820 } 821 822 if (candidateLevel > level) { 823 level = candidateLevel; 824 match = candidate; 825 } else if (candidateLevel == level) { 826 // Check for specialisation. 827 auto mt = match.type.getCanonical(); 828 assert(mt.kind == TypeKind.Function, 829 "We should have filtered function at this point."); 830 831 auto prange = lockstep(funType.parameters, 832 mt.asFunctionType().parameters); 833 834 bool candidateFail; 835 bool matchFail; 836 foreach (param, matchParam; prange) { 837 if (matchArgument(param, matchParam) == MatchLevel.Not) { 838 candidateFail = true; 839 } 840 841 if (matchArgument(matchParam, param) == MatchLevel.Not) { 842 matchFail = true; 843 } 844 } 845 846 if (matchFail == candidateFail) { 847 return getError(candidate, location, 848 "ambiguous function call."); 849 } 850 851 if (matchFail) { 852 match = candidate; 853 } 854 } 855 } 856 857 if (!match) { 858 return new CompileError(location, "No candidate for function call") 859 .expression; 860 } 861 862 return match; 863 } 864 865 private Expression findCallable(Location location, Expression callee, 866 Expression[] args) { 867 if (auto asPolysemous = cast(PolysemousExpression) callee) { 868 return chooseOverload(location, asPolysemous.expressions, args); 869 } 870 871 auto type = callee.type.getCanonical(); 872 if (type.kind == TypeKind.Function) { 873 return callee; 874 } 875 876 import std.algorithm, std.array; 877 import d.semantic.aliasthis; 878 auto ar = AliasThisResolver!((identified) { 879 alias T = typeof(identified); 880 static if (is(T : Expression)) { 881 return findCallable(location, identified, args); 882 } else { 883 return cast(Expression) null; 884 } 885 })(pass); 886 887 auto results = ar.resolve(callee) 888 .filter!(e => e !is null && typeid(e) !is typeid(ErrorExpression)) 889 .array(); 890 891 if (results.length == 1) { 892 return results[0]; 893 } 894 895 return getError(callee, location, 896 "You must call function or delegates, not " 897 ~ callee.type.toString(context)); 898 } 899 900 private Expression handleCall(Location location, Expression callee, 901 Expression[] args) { 902 return 903 callCallable(location, findCallable(location, callee, args), args); 904 } 905 906 // XXX: This assume that calable is the right one, 907 // but not all call sites do the check. 908 private Expression callCallable(Location location, Expression callee, 909 Expression[] args) in { 910 auto k = callee.type.getCanonical().kind; 911 assert(k == TypeKind.Function || k == TypeKind.Error, 912 callee.toString(context)); 913 } do { 914 auto t = callee.type.getCanonical(); 915 if (t.kind == TypeKind.Error) { 916 return callee; 917 } 918 919 auto f = t.asFunctionType(); 920 921 auto paramTypes = f.parameters; 922 auto returnType = f.returnType; 923 924 // If we don't have enough parameters, try to find default 925 // values in the function declaration. 926 if (args.length < paramTypes.length) { 927 Function fun; 928 if (auto fe = cast(FunctionExpression) callee) { 929 fun = fe.fun; 930 } else if (auto dge = cast(DelegateExpression) callee) { 931 fun = dge.method; 932 } else { 933 // Can't find the function, error. 934 return getError(callee, location, "Insuffiscient parameters"); 935 } 936 937 auto start = args.length + f.contexts.length; 938 auto stop = paramTypes.length + f.contexts.length; 939 auto params = fun.params[start .. stop]; 940 foreach (p; params) { 941 if (p.value is null) { 942 return 943 getError(callee, location, "Insuffiscient parameters"); 944 } 945 946 args ~= p.value; 947 } 948 } else if (args.length > paramTypes.length && !f.isVariadic) { 949 return getError(callee, location, "Too much parameters"); 950 } 951 952 import std.range; 953 foreach (ref arg, pt; lockstep(args, paramTypes)) { 954 arg = buildArgument(arg, pt); 955 } 956 957 // If this is an intrinsic, create an intrinsic expression 958 if (auto fe = cast(FunctionExpression) callee) { 959 if (auto i = fe.fun.intrinsicID) { 960 return build!IntrinsicExpression(location, returnType.getType(), 961 i, args); 962 } 963 } 964 965 return 966 build!CallExpression(location, returnType.getType(), callee, args); 967 } 968 969 // XXX: factorize with findCtor 970 Expression visit(AstNewExpression e) { 971 import std.algorithm, std.array; 972 auto args = e.args.map!(a => visit(a)).array(); 973 974 import d.semantic.type; 975 auto type = TypeVisitor(pass).visit(e.type); 976 977 import d.semantic.defaultinitializer; 978 auto di = NewBuilder(pass, e.location).visit(type); 979 auto hackForDg = (&di)[0 .. 1]; 980 981 import source.name, d.semantic.identifier; 982 auto ctor = IdentifierResolver(pass) 983 .resolveIn(e.location, type, BuiltinName!"__ctor") 984 .apply!(delegate Function(identified) { 985 static if (is(typeof(identified) : Symbol)) { 986 if (auto f = cast(Function) identified) { 987 pass.scheduler.require(f, Step.Signed); 988 return f; 989 } 990 991 if (auto s = cast(OverloadSet) identified) { 992 auto m = chooseOverload( 993 e.location, s.set.map!(delegate Expression(s) { 994 if (auto f = cast(Function) s) { 995 return new DelegateExpression(e.location, 996 hackForDg, f); 997 } 998 999 assert(0, "not a constructor"); 1000 }).array(), args); 1001 1002 // XXX: find a clean way to achieve this. 1003 return (cast(DelegateExpression) m).method; 1004 } 1005 } 1006 1007 assert(0, "Gimme some construtor !"); 1008 })(); 1009 1010 // First parameter is compiler magic. 1011 auto parameters = ctor.type.parameters[1 .. $]; 1012 1013 import std.range; 1014 assert(args.length >= parameters.length); 1015 foreach (ref arg, pt; lockstep(args, parameters)) { 1016 arg = buildArgument(arg, pt); 1017 } 1018 1019 if (type.getCanonical().kind != TypeKind.Class) { 1020 type = type.getPointer(); 1021 } 1022 1023 return build!NewExpression(e.location, type, di, ctor, args); 1024 } 1025 1026 Expression getThis(Location location) { 1027 import source.name, d.semantic.identifier; 1028 auto thisExpr = IdentifierResolver(pass) 1029 .build(location, BuiltinName!"this") 1030 .apply!(delegate Expression(identified) { 1031 static if (is(typeof(identified) : Expression)) { 1032 return identified; 1033 } else { 1034 return new CompileError( 1035 location, "Cannot find a suitable this pointer") 1036 .expression; 1037 } 1038 })(); 1039 1040 return buildImplicitCast(pass, location, thisType.getType(), thisExpr); 1041 } 1042 1043 Expression visit(ThisExpression e) { 1044 return getThis(e.location); 1045 } 1046 1047 Expression getIndex(Location location, Expression indexed, 1048 Expression index) { 1049 auto t = indexed.type.getCanonical(); 1050 if (!t.hasElement) { 1051 return getError(indexed, location, 1052 "Can't index " ~ indexed.type.toString(context)); 1053 } 1054 1055 index = buildImplicitCast(pass, location, pass.object.getSizeT().type, 1056 index); 1057 1058 // Make sure we create a temporary for rvalue indices. 1059 // XXX: Should this be done in the backend ? 1060 if (t.kind == TypeKind.Array && !indexed.isLvalue) { 1061 indexed = getTemporary(indexed); 1062 } 1063 1064 return build!IndexExpression(location, t.element, indexed, index); 1065 } 1066 1067 Expression visit(AstIndexExpression e) { 1068 auto indexed = visit(e.indexed); 1069 1070 import std.algorithm, std.array; 1071 auto arguments = e.arguments.map!(e => visit(e)).array(); 1072 assert(arguments.length == 1, 1073 "Multiple argument index are not supported"); 1074 1075 return getIndex(e.location, indexed, arguments[0]); 1076 } 1077 1078 Expression visit(AstSliceExpression e) { 1079 // TODO: check if it is valid. 1080 auto sliced = visit(e.sliced); 1081 1082 auto t = sliced.type.getCanonical(); 1083 if (!t.hasElement) { 1084 return getError(sliced, e.location, 1085 "Can't slice " ~ t.toString(context)); 1086 } 1087 1088 assert(e.first.length == 1 && e.second.length == 1); 1089 1090 auto first = visit(e.first[0]); 1091 auto second = visit(e.second[0]); 1092 1093 return build!SliceExpression(e.location, t.element.getSlice(), sliced, 1094 first, second); 1095 } 1096 1097 private Expression handleTypeid(Location location, Expression e) { 1098 auto c = e.type.getCanonical(); 1099 if (c.kind == TypeKind.Class) { 1100 auto classInfo = pass.object.getClassInfo(); 1101 return 1102 build!DynamicTypeidExpression(location, Type.get(classInfo), e); 1103 } 1104 1105 return getTypeInfo(location, e.type); 1106 } 1107 1108 auto getTypeInfo(Location location, Type t) { 1109 t = t.getCanonical(); 1110 if (t.kind == TypeKind.Class) { 1111 return getClassInfo(location, t.dclass); 1112 } 1113 1114 alias StaticTypeidExpression = d.ir.expression.StaticTypeidExpression; 1115 return build!StaticTypeidExpression( 1116 location, Type.get(pass.object.getTypeInfo()), t); 1117 } 1118 1119 auto getClassInfo(Location location, Class c) { 1120 alias StaticTypeidExpression = d.ir.expression.StaticTypeidExpression; 1121 return build!StaticTypeidExpression( 1122 location, Type.get(pass.object.getClassInfo()), Type.get(c)); 1123 } 1124 1125 Expression visit(AstTypeidExpression e) { 1126 return handleTypeid(e.location, visit(e.argument)); 1127 } 1128 1129 Expression visit(AstStaticTypeidExpression e) { 1130 import d.semantic.type; 1131 return getTypeInfo(e.location, TypeVisitor(pass).visit(e.argument)); 1132 } 1133 1134 Expression visit(IdentifierTypeidExpression e) { 1135 import d.semantic.identifier; 1136 return IdentifierResolver(pass).build(e.argument) 1137 .apply!(delegate Expression(identified) { 1138 alias T = typeof(identified); 1139 static if (is(T : Type)) { 1140 return getTypeInfo(e.location, identified); 1141 } else static if (is(T : Expression)) { 1142 return handleTypeid(e.location, identified); 1143 } else { 1144 return getError(identified, e.location, 1145 "Can't get typeid of " 1146 ~ e.argument.toString(pass.context)); 1147 } 1148 })(); 1149 } 1150 1151 Expression visit(IdentifierExpression e) { 1152 import d.semantic.identifier; 1153 return IdentifierResolver(pass).build(e.identifier) 1154 .apply!(delegate Expression(identified) { 1155 alias T = typeof(identified); 1156 static if (is(T : Expression)) { 1157 return identified; 1158 } else { 1159 static if (is(T : Symbol)) { 1160 if (auto s = cast(OverloadSet) identified) { 1161 return buildPolysemous(e.location, s); 1162 } 1163 } 1164 1165 return getError(identified, e.location, 1166 e.identifier.toString(pass.context) 1167 ~ " isn't an expression"); 1168 } 1169 })(); 1170 } 1171 1172 private Expression buildPolysemous(Location location, OverloadSet s) { 1173 import std.algorithm, std.array; 1174 import d.semantic.identifier; 1175 auto exprs = s.set.map!(s => IdentifierResolver(pass) 1176 .postProcess(location, s).apply!(delegate Expression(identified) { 1177 alias T = typeof(identified); 1178 static if (is(T : Expression)) { 1179 return identified; 1180 } else static if (is(T : Type)) { 1181 assert(0, "Type can't be overloaded"); 1182 } else { 1183 // TODO: handle templates. 1184 throw new CompileException( 1185 identified.location, typeid(identified).toString() 1186 ~ " is not supported in overload set"); 1187 } 1188 })()).array(); 1189 return new PolysemousExpression(location, exprs); 1190 } 1191 1192 import d.ast.declaration, d.ast.statement; 1193 private auto handleDgs(Location location, string prefix, ParamDecl[] params, 1194 bool isVariadic, BlockStatement fbody) { 1195 // FIXME: can still collide with mixins, 1196 // but that should rare enough for now. 1197 import std.conv; 1198 auto offset = location.getFullLocation(context).getStartOffset(); 1199 auto name = context.getName(prefix ~ offset.to!string()); 1200 1201 auto d = new FunctionDeclaration( 1202 location, defaultStorageClass, 1203 AstType.getAuto().getParamType(ParamKind.Regular), name, params, 1204 isVariadic, fbody); 1205 1206 auto f = 1207 new Function(location, currentScope, FunctionType.init, name, []); 1208 1209 f.hasContext = true; 1210 1211 import d.semantic.symbol; 1212 SymbolAnalyzer(pass).analyze(d, f); 1213 scheduler.require(f); 1214 1215 return getFrom(location, f); 1216 } 1217 1218 Expression visit(DelegateLiteral e) { 1219 return handleDgs(e.location, "__dg", e.params, e.isVariadic, e.fbody); 1220 } 1221 1222 Expression visit(Lambda e) { 1223 auto v = e.value; 1224 return handleDgs( 1225 e.location, 1226 "__lambda", 1227 e.params, 1228 false, 1229 new BlockStatement(v.location, [new ReturnStatement(v.location, v)]) 1230 ); 1231 } 1232 1233 import d.ast.conditional; 1234 Expression visit(Mixin!AstExpression e) { 1235 import d.semantic.evaluator; 1236 auto str = evalString(visit(e.value)); 1237 auto pos = context.registerMixin(e.location, str ~ "\0"); 1238 1239 import source.dlexer; 1240 auto trange = lex(pos, context); 1241 1242 import d.parser.base, d.parser.expression; 1243 trange.match(TokenType.Begin); 1244 return visit(trange.parseExpression()); 1245 } 1246 }