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