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 }