Skip to content

Commit

Permalink
Merge pull request #1781 from jpf91/fix9777
Browse files Browse the repository at this point in the history
Fix issue 9777 Wrong code when calling final interface methods
  • Loading branch information
WalterBright committed Mar 22, 2013
2 parents 60733bc + f35c753 commit 1375dee
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ struct ClassDeclaration : AggregateDeclaration

virtual int isBaseInfoComplete();
Dsymbol *search(Loc, Identifier *ident, int flags);
Dsymbol *searchBase(Loc, Identifier *ident);
ClassDeclaration *searchBase(Loc, Identifier *ident);
#if DMDV2
int isFuncHidden(FuncDeclaration *fd);
#endif
Expand Down
6 changes: 3 additions & 3 deletions src/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -979,17 +979,17 @@ Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags)
return s;
}

Dsymbol *ClassDeclaration::searchBase(Loc loc, Identifier *ident)
ClassDeclaration *ClassDeclaration::searchBase(Loc loc, Identifier *ident)
{
// Search bases classes in depth-first, left to right order

for (size_t i = 0; i < baseclasses->dim; i++)
{
BaseClass *b = (*baseclasses)[i];
Dsymbol *cdb = b->type->isClassHandle();
ClassDeclaration *cdb = b->type->isClassHandle();
if (cdb->ident->equals(ident))
return cdb;
cdb = ((ClassDeclaration *)cdb)->searchBase(loc, ident);
cdb = cdb->searchBase(loc, ident);
if (cdb)
return cdb;
}
Expand Down
21 changes: 17 additions & 4 deletions src/mtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -8487,13 +8487,26 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident)
// See if it's 'this' class or a base class
if (e->op != TOKtype)
{
Dsymbol *cbase = sym->ident == ident ?
sym : sym->searchBase(e->loc, ident);
if (cbase)
if (sym->ident == ident)
{
e = new DotTypeExp(0, e, cbase);
e = new DotTypeExp(0, e, sym);
return e;
}

ClassDeclaration *cbase = sym->searchBase(e->loc, ident);
if (cbase)
{
if (InterfaceDeclaration *ifbase = cbase->isInterfaceDeclaration())
{
e = new CastExp(0, e, ifbase->type);
return e;
}
else
{
e = new DotTypeExp(0, e, cbase);
return e;
}
}
}

if (ident == Id::classinfo)
Expand Down
61 changes: 57 additions & 4 deletions test/runnable/xtest46.d
Original file line number Diff line number Diff line change
Expand Up @@ -4300,25 +4300,78 @@ static assert(typeof(cfunc6596).stringof == "extern (C) int()");

interface Timer
{
final int run() { printf("Timer.run()\n"); return 1; };
final int run() { printf("Timer.run()\n"); fun(); return 1; };
int fun();
}

interface Application
{
final int run() { printf("Application.run()\n"); return 2; };
final int run() { printf("Application.run()\n"); fun(); return 2; };
int fun();
}

class TimedApp : Timer, Application
{
int funCalls;
override int fun()
{
printf("TimedApp.fun()\n");
funCalls++;
return 2;
}
}

class SubTimedApp : TimedApp
{
int subFunCalls;

override int fun()
{
printf("SubTimedApp.fun()\n");
subFunCalls++;
return 1;
}
}

void test4647()
{
auto app = new TimedApp;
assert(app.Timer.run() == 1); // error, no Timer property
//Test access to TimedApps base interfaces
auto app = new TimedApp();
assert((cast(Application)app).run() == 2);
assert((cast(Timer)app).run() == 1);
assert(app.Timer.run() == 1); // error, no Timer property
assert(app.Application.run() == 2); // error, no Application property
assert(app.run() == 1); // This would call Timer.run() if the two calls
// above were commented out
assert(app.funCalls == 5);

assert(app.TimedApp.fun() == 2);
assert(app.funCalls == 6);

//Test direct access to SubTimedApp interfaces
auto app2 = new SubTimedApp();
assert((cast(Application)app2).run() == 2);
assert((cast(Timer)app2).run() == 1);
assert(app2.Application.run() == 2);
assert(app2.Timer.run() == 1);
assert(app2.funCalls == 0);
assert(app2.subFunCalls == 4);

assert(app2.fun() == 1);
assert(app2.SubTimedApp.fun() == 1);
assert(app2.funCalls == 0);
assert(app2.subFunCalls == 6);

//Test access to SubTimedApp interfaces via TimedApp
auto app3 = new SubTimedApp();
(cast(Timer)cast(TimedApp)app3).run();
app3.TimedApp.Timer.run();
assert((cast(Application)cast(TimedApp)app3).run() == 2);
assert((cast(Timer)cast(TimedApp)app3).run() == 1);
assert(app3.TimedApp.Application.run() == 2);
assert(app3.TimedApp.Timer.run() == 1);
assert(app3.funCalls == 0);
assert(app3.subFunCalls == 6);
}

/***************************************************/
Expand Down

0 comments on commit 1375dee

Please sign in to comment.