// Compiler implementation of the D programming language // Copyright (c) 1999-2011 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include #include #include "mars.h" #include "expression.h" #include "statement.h" #include "mtype.h" #include "utf.h" #include "declaration.h" #include "aggregate.h" #include "scope.h" #if IN_LLVM #include "init.h" #endif /******************************************** * Convert from expression to delegate that returns the expression, * i.e. convert: * expr * to: * t delegate() { return expr; } */ int lambdaSetParent(Expression *e, void *param); int lambdaCheckForNestedRef(Expression *e, void *param); Expression *Expression::toDelegate(Scope *sc, Type *t) { //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); Type *tw = t->semantic(loc, sc); Type *tc = t->substWildTo(MODconst)->semantic(loc, sc); TypeFunction *tf = new TypeFunction(NULL, tc, 0, LINKd); (tf = (TypeFunction *)tf->semantic(loc, sc))->next = tw; // hack for bug7757 FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); Expression *e; sc = sc->push(); sc->parent = fld; // set current function to be the delegate e = this; e->apply(&lambdaSetParent, sc); e->apply(&lambdaCheckForNestedRef, sc); sc = sc->pop(); Statement *s; if (t->ty == Tvoid) s = new ExpStatement(loc, e); else s = new ReturnStatement(loc, e); fld->fbody = s; e = new FuncExp(loc, fld); e = e->semantic(sc); return e; } /****************************************** * Patch the parent of declarations to be the new function literal. */ int lambdaSetParent(Expression *e, void *param) { Scope *sc = (Scope *)param; /* We could use virtual functions instead of a switch, * but it doesn't seem worth the bother. */ switch (e->op) { case TOKdeclaration: { DeclarationExp *de = (DeclarationExp *)e; de->declaration->parent = sc->parent; break; } case TOKindex: { IndexExp *de = (IndexExp *)e; if (de->lengthVar) { //printf("lengthVar\n"); de->lengthVar->parent = sc->parent; } break; } case TOKslice: { SliceExp *se = (SliceExp *)e; if (se->lengthVar) { //printf("lengthVar\n"); se->lengthVar->parent = sc->parent; } break; } default: break; } return 0; } /******************************************* * Look for references to variables in a scope enclosing the new function literal. */ int lambdaCheckForNestedRef(Expression *e, void *param) { Scope *sc = (Scope *)param; /* We could use virtual functions instead of a switch, * but it doesn't seem worth the bother. */ switch (e->op) { #if IN_LLVM // We also need to consider the initializers of VarDeclarations in // DeclarationExps, such as generated for postblit invocation for // function parameters. // // Without this check, e.g. the nested reference to a in the delegate // create for the lazy argument is not picked up in the following case: // --- // struct HasPostblit { this(this) {} } // struct Foo { HasPostblit _data; } // void receiver(Foo) {} // void lazyFunc(E)(lazy E e) { e(); } // void test() { Foo a; lazyFunc(receiver(a)); } // --- case TOKdeclaration: { DeclarationExp *de = (DeclarationExp *)e; if (VarDeclaration *vd = de->declaration->isVarDeclaration()) { if (vd->init) { if (ExpInitializer* ei = vd->init->isExpInitializer()) { ei->exp->apply(&lambdaCheckForNestedRef, sc); } // TODO: Other classes of initializers? } } break; } #endif case TOKsymoff: { SymOffExp *se = (SymOffExp *)e; VarDeclaration *v = se->var->isVarDeclaration(); if (v) v->checkNestedReference(sc, 0); break; } case TOKvar: { VarExp *ve = (VarExp *)e; VarDeclaration *v = ve->var->isVarDeclaration(); if (v) v->checkNestedReference(sc, 0); break; } case TOKthis: case TOKsuper: { ThisExp *te = (ThisExp *)e; VarDeclaration *v = te->var->isVarDeclaration(); if (v) v->checkNestedReference(sc, 0); break; } default: break; } return 0; }