]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | |
2 | /* Compiler implementation of the D programming language | |
3 | * Copyright (C) 1999-2018 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 | ||
f9ab59ff | 11 | #include "root/dsystem.h" |
b4c522fa IB |
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 | */ | |
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 | */ | |
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 | */ | |
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 | ||
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 | } |