1
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-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/delegatize.c
9 */
10
11 #include "root/dsystem.h"
12
13 #include "mars.h"
14 #include "expression.h"
15 #include "statement.h"
16 #include "mtype.h"
17 #include "utf.h"
18 #include "declaration.h"
19 #include "aggregate.h"
20 #include "scope.h"
21 #include "init.h"
22 #include "tokens.h"
23
24
25 bool walkPostorder(Expression *e, StoppableVisitor *v);
26 void lambdaSetParent(Expression *e, Scope *sc);
27 bool lambdaCheckForNestedRef(Expression *e, Scope *sc);
28 Expression *semantic(Expression *e, Scope *sc);
29
30 /********************************************
31 * Convert from expression to delegate that returns the expression,
32 * i.e. convert:
33 * expr
34 * to:
35 * typeof(expr) delegate() { return expr; }
36 */
toDelegate(Expression * e,Type * t,Scope * sc)37 Expression *toDelegate(Expression *e, Type* t, Scope *sc)
38 {
39 //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
40 Loc loc = e->loc;
41
42 TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd);
43 if (t->hasWild())
44 tf->mod = MODwild;
45 FuncLiteralDeclaration *fld =
46 new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL);
47
48 sc = sc->push();
49 sc->parent = fld; // set current function to be the delegate
50 lambdaSetParent(e, sc);
51 bool r = lambdaCheckForNestedRef(e, sc);
52 sc = sc->pop();
53
54 if (r)
55 return new ErrorExp();
56
57 Statement *s;
58 if (t->ty == Tvoid)
59 s = new ExpStatement(loc, e);
60 else
61 s = new ReturnStatement(loc, e);
62 fld->fbody = s;
63
64 e = new FuncExp(loc, fld);
65 e = semantic(e, sc);
66 return e;
67 }
68
69 /******************************************
70 * Patch the parent of declarations to be the new function literal.
71 */
lambdaSetParent(Expression * e,Scope * sc)72 void lambdaSetParent(Expression *e, Scope *sc)
73 {
74 class LambdaSetParent : public StoppableVisitor
75 {
76 Scope *sc;
77 public:
78 LambdaSetParent(Scope *sc) : sc(sc) {}
79
80 void visit(Expression *)
81 {
82 }
83
84 void visit(DeclarationExp *e)
85 {
86 e->declaration->parent = sc->parent;
87 }
88
89 void visit(IndexExp *e)
90 {
91 if (e->lengthVar)
92 {
93 //printf("lengthVar\n");
94 e->lengthVar->parent = sc->parent;
95 }
96 }
97
98 void visit(SliceExp *e)
99 {
100 if (e->lengthVar)
101 {
102 //printf("lengthVar\n");
103 e->lengthVar->parent = sc->parent;
104 }
105 }
106 };
107
108 LambdaSetParent lsp(sc);
109 walkPostorder(e, &lsp);
110 }
111
112 /*******************************************
113 * Look for references to variables in a scope enclosing the new function literal.
114 * Returns true if error occurs.
115 */
lambdaCheckForNestedRef(Expression * e,Scope * sc)116 bool lambdaCheckForNestedRef(Expression *e, Scope *sc)
117 {
118 class LambdaCheckForNestedRef : public StoppableVisitor
119 {
120 public:
121 Scope *sc;
122 bool result;
123
124 LambdaCheckForNestedRef(Scope *sc)
125 : sc(sc), result(false)
126 {
127 }
128
129 void visit(Expression *)
130 {
131 }
132
133 void visit(SymOffExp *e)
134 {
135 VarDeclaration *v = e->var->isVarDeclaration();
136 if (v)
137 result = v->checkNestedReference(sc, Loc());
138 }
139
140 void visit(VarExp *e)
141 {
142 VarDeclaration *v = e->var->isVarDeclaration();
143 if (v)
144 result = v->checkNestedReference(sc, Loc());
145 }
146
147 void visit(ThisExp *e)
148 {
149 if (e->var)
150 result = e->var->checkNestedReference(sc, Loc());
151 }
152
153 void visit(DeclarationExp *e)
154 {
155 VarDeclaration *v = e->declaration->isVarDeclaration();
156 if (v)
157 {
158 result = v->checkNestedReference(sc, Loc());
159 if (result)
160 return;
161
162 /* Some expressions cause the frontend to create a temporary.
163 * For example, structs with cpctors replace the original
164 * expression e with:
165 * __cpcttmp = __cpcttmp.cpctor(e);
166 *
167 * In this instance, we need to ensure that the original
168 * expression e does not have any nested references by
169 * checking the declaration initializer too.
170 */
171 if (v->_init && v->_init->isExpInitializer())
172 {
173 Expression *ie = initializerToExpression(v->_init);
174 result = lambdaCheckForNestedRef(ie, sc);
175 }
176 }
177 }
178 };
179
180 LambdaCheckForNestedRef v(sc);
181 walkPostorder(e, &v);
182 return v.result;
183 }
184
checkNestedRef(Dsymbol * s,Dsymbol * p)185 bool checkNestedRef(Dsymbol *s, Dsymbol *p)
186 {
187 while (s)
188 {
189 if (s == p) // hit!
190 return false;
191
192 if (FuncDeclaration *fd = s->isFuncDeclaration())
193 {
194 if (!fd->isThis() && !fd->isNested())
195 break;
196
197 // Bugzilla 15332: change to delegate if fd is actually nested.
198 if (FuncLiteralDeclaration *fld = fd->isFuncLiteralDeclaration())
199 fld->tok = TOKdelegate;
200 }
201 if (AggregateDeclaration *ad = s->isAggregateDeclaration())
202 {
203 if (ad->storage_class & STCstatic)
204 break;
205 }
206 s = s->toParent2();
207 }
208 return true;
209 }
210