Expression *VarExp::doInline(InlineDoState *ids) { //printf("VarExp::doInline(%s)\n", toChars()); for (size_t i = 0; i < ids->from.dim; i++) { if (var == ids->from[i]) { VarExp *ve = (VarExp *)copy(); ve->var = (Declaration *)ids->to[i]; return ve; } } if (ids->fd && var == ids->fd->vthis) { VarExp *ve = new VarExp(loc, ids->vthis); ve->type = type; return ve; } /* Inlining context pointer access for nested referenced variables. * For example: * auto fun() { * int i = 40; * auto foo() { * int g = 2; * struct Result { * auto bar() { return i + g; } * } * return Result(); * } * return foo(); * } * auto t = fun(); * 'i' and 'g' are nested referenced variables in Result.bar(), so: * auto x = t.bar(); * should be inlined to: * auto x = *(t.vthis.vthis + i->voffset) + *(t.vthis + g->voffset) */ VarDeclaration *v = var->isVarDeclaration(); if (v && v->nestedrefs.dim && ids->vthis) { Dsymbol *s = ids->fd; FuncDeclaration *fdv = v->toParent()->isFuncDeclaration(); assert(fdv); Expression *ve = new VarExp(loc, ids->vthis); ve->type = ids->vthis->type; while (s != fdv) { FuncDeclaration *f = s->isFuncDeclaration(); if (AggregateDeclaration *ad = s->isThis()) { assert(ad->vthis); ve = new DotVarExp(loc, ve, ad->vthis); ve->type = ad->vthis->type; s = ad->toParent2(); } else if (f && f->isNested()) { assert(f->vthis); if (f->hasNestedFrameRefs()) { ve = new DotVarExp(loc, ve, f->vthis); ve->type = f->vthis->type; } s = f->toParent2(); } else assert(0); assert(s); } ve = new DotVarExp(loc, ve, v); ve->type = v->type; //printf("\t==> ve = %s, type = %s\n", ve->toChars(), ve->type->toChars()); return ve; } return this; }