1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _aliasthis.d) 9 */ 10 11 module ddmd.aliasthis; 12 13 import core.stdc.stdio; 14 import ddmd.aggregate; 15 import ddmd.declaration; 16 import ddmd.dscope; 17 import ddmd.dsymbol; 18 import ddmd.errors; 19 import ddmd.expression; 20 import ddmd.globals; 21 import ddmd.identifier; 22 import ddmd.mtype; 23 import ddmd.opover; 24 import ddmd.tokens; 25 import ddmd.visitor; 26 27 /*********************************************************** 28 * alias ident this; 29 */ 30 extern (C++) final class AliasThis : Dsymbol 31 { 32 Identifier ident; 33 34 extern (D) this(Loc loc, Identifier ident) 35 { 36 super(null); // it's anonymous (no identifier) 37 this.loc = loc; 38 this.ident = ident; 39 } 40 41 override Dsymbol syntaxCopy(Dsymbol s) 42 { 43 assert(!s); 44 /* Since there is no semantic information stored here, 45 * we don't need to copy it. 46 */ 47 return this; 48 } 49 50 override void semantic(Scope* sc) 51 { 52 Dsymbol p = sc.parent.pastMixin(); 53 AggregateDeclaration ad = p.isAggregateDeclaration(); 54 if (!ad) 55 { 56 .error(loc, "alias this can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); 57 return; 58 } 59 60 assert(ad.members); 61 Dsymbol s = ad.search(loc, ident); 62 if (!s) 63 { 64 s = sc.search(loc, ident, null); 65 if (s) 66 .error(loc, "%s is not a member of %s", s.toChars(), ad.toChars()); 67 else 68 .error(loc, "undefined identifier %s", ident.toChars()); 69 return; 70 } 71 if (ad.aliasthis && s != ad.aliasthis) 72 { 73 .error(loc, "there can be only one alias this"); 74 return; 75 } 76 77 /* disable the alias this conversion so the implicit conversion check 78 * doesn't use it. 79 */ 80 ad.aliasthis = null; 81 82 Dsymbol sx = s; 83 if (sx.isAliasDeclaration()) 84 sx = sx.toAlias(); 85 Declaration d = sx.isDeclaration(); 86 if (d && !d.isTupleDeclaration()) 87 { 88 Type t = d.type; 89 assert(t); 90 if (ad.type.implicitConvTo(t) > MATCHnomatch) 91 { 92 .error(loc, "alias this is not reachable as %s already converts to %s", ad.toChars(), t.toChars()); 93 } 94 } 95 96 ad.aliasthis = s; 97 } 98 99 override const(char)* kind() const 100 { 101 return "alias this"; 102 } 103 104 AliasThis isAliasThis() 105 { 106 return this; 107 } 108 109 override void accept(Visitor v) 110 { 111 v.visit(this); 112 } 113 } 114 115 extern (C++) Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false) 116 { 117 AggregateDeclaration ad = isAggregate(e.type); 118 if (ad && ad.aliasthis) 119 { 120 uint olderrors = gag ? global.startGagging() : 0; 121 Loc loc = e.loc; 122 Type tthis = (e.op == TOKtype ? e.type : null); 123 e = new DotIdExp(loc, e, ad.aliasthis.ident); 124 e = e.semantic(sc); 125 if (tthis && ad.aliasthis.needThis()) 126 { 127 if (e.op == TOKvar) 128 { 129 if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) 130 { 131 // Bugzilla 13009: Support better match for the overloaded alias this. 132 bool hasOverloads; 133 if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) 134 { 135 if (!hasOverloads) 136 fd = f; // use exact match 137 e = new VarExp(loc, fd, hasOverloads); 138 e.type = f.type; 139 e = new CallExp(loc, e); 140 goto L1; 141 } 142 } 143 } 144 /* non-@property function is not called inside typeof(), 145 * so resolve it ahead. 146 */ 147 { 148 int save = sc.intypeof; 149 sc.intypeof = 1; // bypass "need this" error check 150 e = resolveProperties(sc, e); 151 sc.intypeof = save; 152 } 153 L1: 154 e = new TypeExp(loc, new TypeTypeof(loc, e)); 155 e = e.semantic(sc); 156 } 157 e = resolveProperties(sc, e); 158 if (gag && global.endGagging(olderrors)) 159 e = null; 160 } 161 return e; 162 }