Showing with 58 additions and 48 deletions.
  1. +13 −5 src/aliasthis.d
  2. +14 −16 src/func.d
  3. +31 −27 test/runnable/aliasthis.d
18 changes: 13 additions & 5 deletions src/aliasthis.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

module ddmd.aliasthis;

import core.stdc.stdio;
import ddmd.aggregate;
import ddmd.declaration;
import ddmd.dscope;
Expand Down Expand Up @@ -57,6 +58,7 @@ public:
.error(loc, "alias this can only be a member of aggregate, not %s %s", p.kind(), p.toChars());
return;
}

assert(ad.members);
Dsymbol s = ad.search(loc, ident);
if (!s)
Expand All @@ -73,17 +75,20 @@ public:
.error(loc, "there can be only one alias this");
return;
}

if (ad.type.ty == Tstruct && (cast(TypeStruct)ad.type).sym != ad)
{
AggregateDeclaration ad2 = (cast(TypeStruct)ad.type).sym;
assert(ad2.type == Type.terror);
ad.aliasthis = ad2.aliasthis;
return;
}

/* disable the alias this conversion so the implicit conversion check
* doesn't use it.
*/
ad.aliasthis = null;

Dsymbol sx = s;
if (sx.isAliasDeclaration())
sx = sx.toAlias();
Expand All @@ -97,6 +102,7 @@ public:
.error(loc, "alias this is not reachable as %s already converts to %s", ad.toChars(), t.toChars());
}
}

ad.aliasthis = s;
}

Expand Down Expand Up @@ -130,14 +136,16 @@ extern (C++) Expression resolveAliasThis(Scope* sc, Expression e, bool gag = fal
{
if (e.op == TOKvar)
{
if (FuncDeclaration f = (cast(VarExp)e).var.isFuncDeclaration())
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
{
// Bugzilla 13009: Support better match for the overloaded alias this.
Type t;
f = f.overloadModMatch(loc, tthis, t);
if (f && t)
bool hasOverloads;
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
{
e = new VarExp(loc, f, 0); // use better match
if (!hasOverloads)
fd = f; // use exact match
e = new VarExp(loc, fd, hasOverloads);
e.type = f.type;
e = new CallExp(loc, e);
goto L1;
}
Expand Down
30 changes: 14 additions & 16 deletions src/func.d
Original file line number Diff line number Diff line change
Expand Up @@ -2543,20 +2543,20 @@ public:
* There's four result types.
*
* 1. If the 'tthis' matches only one candidate, it's an "exact match".
* Returns the function and 't' is set to its type.
* Returns the function and 'hasOverloads' is set to false.
* eg. If 'tthis" is mutable and there's only one mutable method.
* 2. If there's two or more match candidates, but a candidate function will be
* a "better match".
* Returns NULL but 't' is set to the candidate type.
* Returns the better match function but 'hasOverloads' is set to true.
* eg. If 'tthis' is mutable, and there's both mutable and const methods,
* the mutable method will be a better match.
* 3. If there's two or more match candidates, but there's no better match,
* Returns NULL and 't' is set to NULL to represent "ambiguous match".
* Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
* eg. If 'tthis' is mutable, and there's two or more mutable methods.
* 4. If there's no candidates, it's "no match" and returns NULL with error report.
* 4. If there's no candidates, it's "no match" and returns null with error report.
* e.g. If 'tthis' is const but there's no const methods.
*/
final FuncDeclaration overloadModMatch(Loc loc, Type tthis, ref Type t)
final FuncDeclaration overloadModMatch(Loc loc, Type tthis, ref bool hasOverloads)
{
//printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
Match m;
Expand Down Expand Up @@ -2604,6 +2604,7 @@ public:

LlastIsBetter:
//printf("\tlastbetter\n");
m.count++; // count up
return 0;

LcurrIsBetter:
Expand All @@ -2620,29 +2621,26 @@ public:
return 0;
});

if (m.count == 1) // exact match
if (m.count == 1) // exact match
{
t = m.lastf.type;
hasOverloads = false;
}
else if (m.count > 1)
else if (m.count > 1) // better or ambiguous match
{
if (!m.nextf) // better match
t = m.lastf.type;
else // ambiguous match
t = null;
m.lastf = null;
hasOverloads = true;
}
else // no match
else // no match
{
t = null;
hasOverloads = true;
auto tf = cast(TypeFunction)this.type;
assert(tthis);
assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
{
OutBuffer thisBuf, funcBuf;
MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
.error(loc, "%smethod %s is not callable using a %sobject", funcBuf.peekString(), this.toPrettyChars(), thisBuf.peekString());
.error(loc, "%smethod %s is not callable using a %sobject",
funcBuf.peekString(), this.toPrettyChars(), thisBuf.peekString());
}
}
return m.lastf;
Expand Down
58 changes: 31 additions & 27 deletions test/runnable/aliasthis.d
Original file line number Diff line number Diff line change
Expand Up @@ -1808,46 +1808,50 @@ struct T13009
void put(char c) {}
}

struct S13009
struct S13009(bool rev)
{
T13009 t;

@property
T13009 getT()
static if (!rev)
{
return t;
@property T13009 getT() { return t; }
@property inout(T13009) getT() inout { return t; }
}

@property
inout(T13009) getT() inout
else
{
return t;
@property inout(T13009) getT() inout { return t; }
@property T13009 getT() { return t; }
}

alias getT this;
}

void test13009()
{
alias MS = S13009;
alias CS = const(S13009);
alias WS = inout( S13009);
alias WCS = inout(const S13009);
alias SMS = shared( S13009);
alias SCS = shared( const S13009);
alias SWS = shared(inout S13009);
alias SWCS = shared(inout const S13009);
alias IS = immutable(S13009);

alias MSput = MS .put;
alias CSput = CS .put;
alias WSput = WS .put;
alias WCSput = WCS.put;
static assert(!__traits(compiles, { alias SMSput = SMS .put; }));
static assert(!__traits(compiles, { alias SCSput = SCS .put; }));
static assert(!__traits(compiles, { alias SWSput = SWS .put; }));
static assert(!__traits(compiles, { alias SWCSput = SWCS.put; }));
alias ISput = IS .put;
foreach (bool rev; Seq!(false, true))
{
alias S = S13009!rev;

alias MS = S;
alias CS = const(S);
alias WS = inout( S);
alias WCS = inout(const S);
alias SMS = shared( S);
alias SCS = shared( const S);
alias SWS = shared(inout S);
alias SWCS = shared(inout const S);
alias IS = immutable(S);

alias MSput = MS .put;
alias CSput = CS .put;
alias WSput = WS .put;
alias WCSput = WCS.put;
static assert(!__traits(compiles, { alias SMSput = SMS .put; }));
static assert(!__traits(compiles, { alias SCSput = SCS .put; }));
static assert(!__traits(compiles, { alias SWSput = SWS .put; }));
static assert(!__traits(compiles, { alias SWCSput = SWCS.put; }));
alias ISput = IS .put;
}
}

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