1 
2 /* Compiler implementation of the D programming language
3  * Copyright (C) 2009-2019 by The D Language Foundation, All Rights Reserved
4  * written by Walter Bright
5  * http://www.digitalmars.com
6  * Distributed under the Boost Software License, Version 1.0.
7  * http://www.boost.org/LICENSE_1_0.txt
8  * https://github.com/D-Programming-Language/dmd/blob/master/src/aliasthis.c
9  */
10 
11 #include "root/dsystem.h"
12 
13 #include "mars.h"
14 #include "identifier.h"
15 #include "aliasthis.h"
16 #include "scope.h"
17 #include "aggregate.h"
18 #include "dsymbol.h"
19 #include "mtype.h"
20 #include "declaration.h"
21 #include "tokens.h"
22 
23 Expression *semantic(Expression *e, Scope *sc);
24 
resolveAliasThis(Scope * sc,Expression * e,bool gag)25 Expression *resolveAliasThis(Scope *sc, Expression *e, bool gag)
26 {
27     AggregateDeclaration *ad = isAggregate(e->type);
28 
29     if (ad && ad->aliasthis)
30     {
31         unsigned olderrors = gag ? global.startGagging() : 0;
32 
33         Loc loc = e->loc;
34         Type *tthis = (e->op == TOKtype ? e->type : NULL);
35         e = new DotIdExp(loc, e, ad->aliasthis->ident);
36         e = semantic(e, sc);
37         if (tthis && ad->aliasthis->needThis())
38         {
39             if (e->op == TOKvar)
40             {
41                 if (FuncDeclaration *fd = ((VarExp *)e)->var->isFuncDeclaration())
42                 {
43                     // Bugzilla 13009: Support better match for the overloaded alias this.
44                     bool hasOverloads = false;
45                     if (FuncDeclaration *f = fd->overloadModMatch(loc, tthis, hasOverloads))
46                     {
47                         if (!hasOverloads)
48                             fd = f;     // use exact match
49                         e = new VarExp(loc, fd, hasOverloads);
50                         e->type = f->type;
51                         e = new CallExp(loc, e);
52                         goto L1;
53                     }
54                 }
55             }
56             /* non-@property function is not called inside typeof(),
57              * so resolve it ahead.
58              */
59             {
60             int save = sc->intypeof;
61             sc->intypeof = 1;   // bypass "need this" error check
62             e = resolveProperties(sc, e);
63             sc->intypeof = save;
64             }
65 
66         L1:
67             e = new TypeExp(loc, new TypeTypeof(loc, e));
68             e = semantic(e, sc);
69         }
70         e = resolveProperties(sc, e);
71 
72         if (gag && global.endGagging(olderrors))
73             e = NULL;
74     }
75 
76     return e;
77 }
78 
AliasThis(Loc loc,Identifier * ident)79 AliasThis::AliasThis(Loc loc, Identifier *ident)
80     : Dsymbol(NULL)             // it's anonymous (no identifier)
81 {
82     this->loc = loc;
83     this->ident = ident;
84 }
85 
syntaxCopy(Dsymbol * s)86 Dsymbol *AliasThis::syntaxCopy(Dsymbol *s)
87 {
88     assert(!s);
89     return new AliasThis(loc, ident);
90 }
91 
semantic(Scope * sc)92 void AliasThis::semantic(Scope *sc)
93 {
94     if (semanticRun != PASSinit)
95         return;
96 
97     if (_scope)
98     {
99         sc = _scope;
100         _scope = NULL;
101     }
102 
103     if (!sc)
104         return;
105 
106     semanticRun = PASSsemantic;
107 
108     Dsymbol *p = sc->parent->pastMixin();
109     AggregateDeclaration *ad = p->isAggregateDeclaration();
110     if (!ad)
111     {
112         ::error(loc, "alias this can only be a member of aggregate, not %s %s",
113             p->kind(), p->toChars());
114         return;
115     }
116 
117     assert(ad->members);
118     Dsymbol *s = ad->search(loc, ident);
119     if (!s)
120     {
121         s = sc->search(loc, ident, NULL);
122         if (s)
123             ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars());
124         else
125             ::error(loc, "undefined identifier %s", ident->toChars());
126         return;
127     }
128     else if (ad->aliasthis && s != ad->aliasthis)
129     {
130         ::error(loc, "there can be only one alias this");
131         return;
132     }
133 
134     if (ad->type->ty == Tstruct && ((TypeStruct *)ad->type)->sym != ad)
135     {
136         AggregateDeclaration *ad2 = ((TypeStruct *)ad->type)->sym;
137         assert(ad2->type == Type::terror);
138         ad->aliasthis = ad2->aliasthis;
139         return;
140     }
141 
142     /* disable the alias this conversion so the implicit conversion check
143      * doesn't use it.
144      */
145     ad->aliasthis = NULL;
146 
147     Dsymbol *sx = s;
148     if (sx->isAliasDeclaration())
149         sx = sx->toAlias();
150     Declaration *d = sx->isDeclaration();
151     if (d && !d->isTupleDeclaration())
152     {
153         Type *t = d->type;
154         assert(t);
155         if (ad->type->implicitConvTo(t) > MATCHnomatch)
156         {
157             ::error(loc, "alias this is not reachable as %s already converts to %s", ad->toChars(), t->toChars());
158         }
159     }
160 
161     ad->aliasthis = s;
162     semanticRun = PASSsemanticdone;
163 }
164 
kind()165 const char *AliasThis::kind() const
166 {
167     return "alias this";
168 }
169