Skip to content

Commit

Permalink
Fix Issue 5973 - alias this is not considered with superclass lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
RazvanN7 committed Oct 16, 2018
1 parent 1bab5f3 commit 4a9ad74
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 51 deletions.
81 changes: 46 additions & 35 deletions src/dmd/aliasthis.d
Expand Up @@ -63,50 +63,61 @@ extern (C++) final class AliasThis : Dsymbol

Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
{
AggregateDeclaration ad = isAggregate(e.type);
if (ad && ad.aliasthis)
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
{
uint olderrors = gag ? global.startGagging() : 0;
Loc loc = e.loc;
Type tthis = (e.op == TOK.type ? e.type : null);
e = new DotIdExp(loc, e, ad.aliasthis.ident);
e = e.expressionSemantic(sc);
if (tthis && ad.aliasthis.needThis())
if (ad.aliasthis)
{
if (e.op == TOK.variable)
uint olderrors = gag ? global.startGagging() : 0;
Loc loc = e.loc;
Type tthis = (e.op == TOK.type ? e.type : null);
e = new DotIdExp(loc, e, ad.aliasthis.ident);
e = e.expressionSemantic(sc);
if (tthis && ad.aliasthis.needThis())
{
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
if (e.op == TOK.variable)
{
// https://issues.dlang.org/show_bug.cgi?id=13009
// Support better match for the overloaded alias this.
bool hasOverloads;
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
{
if (!hasOverloads)
fd = f; // use exact match
e = new VarExp(loc, fd, hasOverloads);
e.type = f.type;
e = new CallExp(loc, e);
goto L1;
// https://issues.dlang.org/show_bug.cgi?id=13009
// Support better match for the overloaded alias this.
bool hasOverloads;
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
{
if (!hasOverloads)
fd = f; // use exact match
e = new VarExp(loc, fd, hasOverloads);
e.type = f.type;
e = new CallExp(loc, e);
goto L1;
}
}
}
/* non-@property function is not called inside typeof(),
* so resolve it ahead.
*/
{
int save = sc.intypeof;
sc.intypeof = 1; // bypass "need this" error check
e = resolveProperties(sc, e);
sc.intypeof = save;
}
L1:
e = new TypeExp(loc, new TypeTypeof(loc, e));
e = e.expressionSemantic(sc);
}
/* non-@property function is not called inside typeof(),
* so resolve it ahead.
*/
{
int save = sc.intypeof;
sc.intypeof = 1; // bypass "need this" error check
e = resolveProperties(sc, e);
sc.intypeof = save;
}
L1:
e = new TypeExp(loc, new TypeTypeof(loc, e));
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
if (gag && global.endGagging(olderrors))
e = null;
}

import dmd.dclass : ClassDeclaration;
auto cd = ad.isClassDeclaration();
if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
{
ad = cd.baseClass;
continue;
}
e = resolveProperties(sc, e);
if (gag && global.endGagging(olderrors))
e = null;
break;
}
return e;
}
30 changes: 20 additions & 10 deletions src/dmd/expressionsem.d
Expand Up @@ -2353,19 +2353,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor

if (hasThis(sc))
{
AggregateDeclaration ad = sc.getStructClassScope();
if (ad && ad.aliasthis)
for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
{
Expression e;
e = new ThisExp(exp.loc);
e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
e = new DotIdExp(exp.loc, e, exp.ident);
e = e.trySemantic(sc);
if (e)
if (ad.aliasthis)
{
result = e;
return;
Expression e;
e = new ThisExp(exp.loc);
e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
e = new DotIdExp(exp.loc, e, exp.ident);
e = e.trySemantic(sc);
if (e)
{
result = e;
return;
}
}

auto cd = ad.isClassDeclaration();
if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
{
ad = cd.baseClass;
continue;
}
break;
}
}

Expand Down
8 changes: 2 additions & 6 deletions src/dmd/typesem.d
Expand Up @@ -3436,16 +3436,12 @@ private extern(C++) final class DotExpVisitor : Visitor

/* See if we should forward to the alias this.
*/
if (sym.aliasthis)
auto alias_e = resolveAliasThis(sc, e, gagError);
if (alias_e && alias_e != e)
{
/* Rewrite e.ident as:
* e.aliasthis.ident
*/
auto alias_e = resolveAliasThis(sc, e, gagError);

if (!alias_e)
return returnExp(null);

auto die = new DotIdExp(e.loc, alias_e, ident);

auto errors = gagError ? 0 : global.startGagging();
Expand Down
41 changes: 41 additions & 0 deletions test/compilable/test5973.d
@@ -0,0 +1,41 @@
// https://issues.dlang.org/show_bug.cgi?id=5973

class A { int a = 1; }
class B { int b = 2; }
class C : A
{
B obj;
alias obj this;
this(){ obj = new B(); }
}
class X : C {}

class D
{
int i;
}

class E
{
D x;
alias x this;
}

class F : E
{
void test()
{
i = 5;
}
}

void main()
{
auto c = new C();
assert(c.a == 1); // lookup C -> A, OK
assert(c.b == 2); // lookup C => B, OK

auto x = new X();
assert(x.a == 1); // lookup X -> C -> A, OK
assert(x.b == 2); // lookup X -> C => B, NG (Line 17)
}

0 comments on commit 4a9ad74

Please sign in to comment.