Skip to content

Commit

Permalink
Merge pull request #3417 from 9rnsr/fix12508
Browse files Browse the repository at this point in the history
Issue 12508 - Codegen bug for interface type covariant return with lambda type inference
  • Loading branch information
WalterBright committed Apr 11, 2014
2 parents 2cbfb58 + 7d65ec8 commit 527ea20
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 2 deletions.
14 changes: 12 additions & 2 deletions src/cast.c
Expand Up @@ -118,6 +118,16 @@ Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
{
//printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e->type, e->type ? e->type->toChars() : NULL, t->toChars());
visit((Expression *)inferType(e, t));

if (result->op == TOKfunction)
{
Type *tn = t->nextOf();
if (tn->ty == Tfunction)
{
// Bugzilla 12508: Tweak function body for covariant returns.
e->fd->modifyReturns(sc, tn->nextOf());
}
}
}

void visit(ArrayLiteralExp *e)
Expand Down Expand Up @@ -2070,7 +2080,7 @@ Expression *castTo(Expression *e, Scope *sc, Type *t)

void visit(FuncExp *e)
{
//printf("FuncExp::castTo type = %s, t = %s\n", type->toChars(), t->toChars());
//printf("FuncExp::castTo type = %s, t = %s\n", e->type->toChars(), t->toChars());
result = inferType(e, t, 1);
if (result)
{
Expand Down Expand Up @@ -2246,7 +2256,7 @@ Expression *inferType(Expression *e, Type *t, int flag, Scope *sc, TemplateParam
return;
}

//printf("FuncExp::interType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", fe->to->toChars());
//printf("FuncExp::interType('%s'), to=%s\n", fe->type ? fe->type->toChars() : "null", t->toChars());

if (!fe->type) // semantic is not yet done
{
Expand Down
2 changes: 2 additions & 0 deletions src/declaration.h
Expand Up @@ -727,6 +727,8 @@ class FuncLiteralDeclaration : public FuncDeclaration
bool addPreInvariant();
bool addPostInvariant();

void modifyReturns(Scope *sc, Type *tret);

FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
const char *kind();
const char *toPrettyChars();
Expand Down
40 changes: 40 additions & 0 deletions src/func.c
Expand Up @@ -4321,6 +4321,46 @@ bool FuncLiteralDeclaration::addPostInvariant()
return false;
}

/*******************************
* Modify all expression type of return statements to tret.
*
* On function literals, return type may be modified based on the context type
* after its semantic3 is done, in FuncExp::implicitCastTo.
*
* A function() dg = (){ return new B(); } // OK if is(B : A) == true
*
* If B to A conversion is convariant that requires offseet adjusting,
* all return statements should be adjusted to return expressions typed A.
*/
void FuncLiteralDeclaration::modifyReturns(Scope *sc, Type *tret)
{
class RetWalker : public StatementRewriteWalker
{
public:
Scope *sc;
Type *tret;
FuncLiteralDeclaration *fld;

void visit(ReturnStatement *s)
{
Expression *exp = s->exp;
if (exp && !exp->type->equals(tret))
{
s->exp = exp->castTo(sc, tret);
}
}
};

if (semanticRun < PASSsemantic3done)
return;

RetWalker w;
w.sc = sc;
w.tret = tret;
w.fld = this;
fbody->accept(&w);
}

const char *FuncLiteralDeclaration::kind()
{
// GCC requires the (char*) casts
Expand Down
38 changes: 38 additions & 0 deletions test/runnable/funclit.d
Expand Up @@ -980,6 +980,43 @@ void test11661()
void function() fp = {}; // OK <- NG
}

/***************************************************/
// 12508

interface A12508(T)
{
T getT();
}

class C12508 : A12508!double
{
double getT() { return 1; }
}

void f12508(A12508!double delegate() dg)
{
auto a = dg();
assert(a !is null);
assert(a.getT() == 1.0); // fails!
}

void t12508(T)(A12508!T delegate() dg)
{
auto a = dg();
assert(a !is null);
assert(a.getT() == 1.0); // fails!
}

ref alias Dg12508 = A12508!double delegate();
void t12508(T)(Dg12508 dg) {}

void test12508()
{
f12508({ return new C12508(); });
t12508({ return new C12508(); });
static assert(!__traits(compiles, x12508({ return new C12508(); })));
}

/***************************************************/

int main()
Expand Down Expand Up @@ -1030,6 +1067,7 @@ int main()
test10288();
test10336();
test11661();
test12508();

printf("Success\n");
return 0;
Expand Down

0 comments on commit 527ea20

Please sign in to comment.