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