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
11 #include "root/dsystem.h"
14 #include "expression.h"
15 #include "statement.h"
18 #include "declaration.h"
19 #include "aggregate.h"
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
);
30 /********************************************
31 * Convert from expression to delegate that returns the expression,
35 * typeof(expr) delegate() { return expr; }
37 Expression
*toDelegate(Expression
*e
, Type
* t
, Scope
*sc
)
39 //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars());
42 TypeFunction
*tf
= new TypeFunction(NULL
, t
, 0, LINKd
);
45 FuncLiteralDeclaration
*fld
=
46 new FuncLiteralDeclaration(loc
, loc
, tf
, TOKdelegate
, NULL
);
49 sc
->parent
= fld
; // set current function to be the delegate
50 lambdaSetParent(e
, sc
);
51 bool r
= lambdaCheckForNestedRef(e
, sc
);
55 return new ErrorExp();
59 s
= new ExpStatement(loc
, e
);
61 s
= new ReturnStatement(loc
, e
);
64 e
= new FuncExp(loc
, fld
);
69 /******************************************
70 * Patch the parent of declarations to be the new function literal.
72 void lambdaSetParent(Expression
*e
, Scope
*sc
)
74 class LambdaSetParent
: public StoppableVisitor
78 LambdaSetParent(Scope
*sc
) : sc(sc
) {}
80 void visit(Expression
*)
84 void visit(DeclarationExp
*e
)
86 e
->declaration
->parent
= sc
->parent
;
89 void visit(IndexExp
*e
)
93 //printf("lengthVar\n");
94 e
->lengthVar
->parent
= sc
->parent
;
98 void visit(SliceExp
*e
)
102 //printf("lengthVar\n");
103 e
->lengthVar
->parent
= sc
->parent
;
108 LambdaSetParent
lsp(sc
);
109 walkPostorder(e
, &lsp
);
112 /*******************************************
113 * Look for references to variables in a scope enclosing the new function literal.
114 * Returns true if error occurs.
116 bool lambdaCheckForNestedRef(Expression
*e
, Scope
*sc
)
118 class LambdaCheckForNestedRef
: public StoppableVisitor
124 LambdaCheckForNestedRef(Scope
*sc
)
125 : sc(sc
), result(false)
129 void visit(Expression
*)
133 void visit(SymOffExp
*e
)
135 VarDeclaration
*v
= e
->var
->isVarDeclaration();
137 result
= v
->checkNestedReference(sc
, Loc());
140 void visit(VarExp
*e
)
142 VarDeclaration
*v
= e
->var
->isVarDeclaration();
144 result
= v
->checkNestedReference(sc
, Loc());
147 void visit(ThisExp
*e
)
150 result
= e
->var
->checkNestedReference(sc
, Loc());
153 void visit(DeclarationExp
*e
)
155 VarDeclaration
*v
= e
->declaration
->isVarDeclaration();
158 result
= v
->checkNestedReference(sc
, Loc());
162 /* Some expressions cause the frontend to create a temporary.
163 * For example, structs with cpctors replace the original
165 * __cpcttmp = __cpcttmp.cpctor(e);
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.
171 if (v
->_init
&& v
->_init
->isExpInitializer())
173 Expression
*ie
= initializerToExpression(v
->_init
);
174 result
= lambdaCheckForNestedRef(ie
, sc
);
180 LambdaCheckForNestedRef
v(sc
);
181 walkPostorder(e
, &v
);
185 bool checkNestedRef(Dsymbol
*s
, Dsymbol
*p
)
192 if (FuncDeclaration
*fd
= s
->isFuncDeclaration())
194 if (!fd
->isThis() && !fd
->isNested())
197 // Bugzilla 15332: change to delegate if fd is actually nested.
198 if (FuncLiteralDeclaration
*fld
= fd
->isFuncLiteralDeclaration())
199 fld
->tok
= TOKdelegate
;
201 if (AggregateDeclaration
*ad
= s
->isAggregateDeclaration())
203 if (ad
->storage_class
& STCstatic
)