Skip to content

Commit

Permalink
Update for proper UFCS name lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
9rnsr committed Jun 7, 2015
1 parent 1c7c4f9 commit 5a8db43
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 39 deletions.
58 changes: 44 additions & 14 deletions src/dsymbol.c
Expand Up @@ -1400,6 +1400,16 @@ ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s)
this->sc = sc;
}

bool isMultiDimOpDollar(TemplateDeclaration *td)
{
for (; td; td = td->overnext)
{
if (td->parameters->dim && (*td->parameters)[0]->isTemplateValueParameter())
return true;
}
return false;
}

Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
{
//printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags);
Expand Down Expand Up @@ -1512,13 +1522,31 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
Dsymbol *s;
if (!sx)
{
// See module scope opDollar
Dsymbol *sm = sc->search(loc, Id::empty, NULL);
assert(sm);
Dsymbol *sa = sm->search(loc, Id::opDollar);
if (!sa) // no dollar exists -- search in higher scope
// See UFCS opDollar (same as searchUFCS)
s = NULL;
for (Scope *scx = sc; scx; scx = scx->enclosing)
{
if (!scx->scopesym)
continue;
s = scx->scopesym->search(loc, Id::opDollar);
if (s)
{
// overload set contains only module scope symbols.
if (s->isOverloadSet())
break;
// selective/renamed imports also be picked up
if (s->isAliasDeclaration() && ((AliasDeclaration *)s)->import)
break;
// See only module scope symbols for UFCS target.
Dsymbol *p = s->toParent2();
if (p && p->isModule())
break;
}
s = NULL;
}
if (!s) // no opDollar exists
return NULL;
s = sa->toAlias();
s = s->toAlias();
}
else
s = sx->toAlias();
Expand All @@ -1537,19 +1565,22 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
}

Expression *e = NULL;
TemplateDeclaration *td = s->isTemplateDeclaration();
// Check for multi-dimensional opDollar(dim) template.
if (td && td->parameters->dim &&
(*td->parameters)[0]->isTemplateValueParameter())
TemplateDeclaration *td;
if (FuncDeclaration *fd = s->isFuncDeclaration())
td = fd->findTemplateDeclRoot();
else
td = s->isTemplateDeclaration();

// Prefer multi-dimensional opDollar(size_t dim) template.
if (td && isMultiDimOpDollar(td))
{
Objects *tiargs = new Objects();
Expression *edim = new IntegerExp(Loc(), curdim, Type::tsize_t);
edim = edim->semantic(sc);
tiargs->push(edim);
if (!sx) // UFCS version
{
e = new IdentifierExp(loc, Id::empty);
e = new DotTemplateInstanceExp(loc, e, td->ident, tiargs);
e = new ScopeExp(loc, new TemplateInstance(loc, td, tiargs));
e = new CallExp(loc, e, ce);
//printf("1 e = %s\n", e->toChars());
}
Expand All @@ -1572,8 +1603,7 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags)
}
if (!sx) // UFCS version
{
e = new IdentifierExp(loc, Id::empty);
e = new DotIdExp(loc, e, s->ident);
e = new DsymbolExp(loc, s);
e = new CallExp(loc, e, ce);
//printf("2 e = %s\n", e->toChars());
}
Expand Down
1 change: 1 addition & 0 deletions src/magicport.json
Expand Up @@ -1926,6 +1926,7 @@
"function getNthSymbolDg",
"struct ScopeDsymbol",
"struct WithScopeSymbol",
"function isMultiDimOpDollar",
"struct ArrayScopeSymbol",
"struct OverloadSet",
"struct DsymbolTable"
Expand Down
3 changes: 3 additions & 0 deletions test/runnable/imports/opover7177a.d
@@ -0,0 +1,3 @@
module imports.opover7177a;

auto opDollar(R)(R r) { return r.length; }
3 changes: 3 additions & 0 deletions test/runnable/imports/opover7177b.d
@@ -0,0 +1,3 @@
module imports.opover7177b;

auto opDollar(size_t dim, R)(R r) { return r.length; }
64 changes: 39 additions & 25 deletions test/runnable/opover2.d
Expand Up @@ -1337,32 +1337,18 @@ void test19()
/**************************************/
// 7177

auto opDollar(R)(R r) { return r.length; }

void test7177()
{
struct A(E)
struct A
{
alias E = int;
E[] arr;

@property size_t length() const { return arr.length; }

E opIndex(size_t i) { return arr[i]; }

E opIndex(size_t i, int ofs) { return arr[i+ofs]; }

A opSlice(size_t b, size_t e)
{
return A(arr[b .. e]);
}
A opSlice(size_t b, size_t e) { return A(arr[b .. e]); }
}
auto a = A!int([1,2,3]);
assert(a[0] == 1);
assert(a[$-1] == 3);
auto b = a[2 .. $];
assert(b.length == 1);

// Even if 'length' found, e.length!(dim) will never be invoked.
struct X1
{
@property size_t length()() const { return 1; }
Expand All @@ -1371,21 +1357,49 @@ void test7177()
void opIndex(size_t i, size_t j) {}
void opSlice(size_t b, size_t e) {}
}
X1 x1;
x1.length = 1;
static assert( __traits(compiles, x1[$]));
static assert(!__traits(compiles, x1[$, $]));

struct X2
{
// Even if 'length' found, e.length!(dim) will never be invoked.
@property size_t length(size_t dim)() const { return 2; }
void opIndex(size_t i) {}
void opIndex(size_t i, size_t j) {}
void opSlice(size_t b, size_t e) {}
}
X2 x2;
static assert(!__traits(compiles, x2[$]));
static assert(!__traits(compiles, x2[$, $]));

{
import imports.opover7177a; // opDollar(R)(R r)

auto a = A([1,2,3]);
assert(a[0] == 1);
assert(a[$-1] == 3);
assert(a[2..$].length == 1);

X1 x1;
x1.length = 1;
static assert( __traits(compiles, x1[$]));
static assert(!__traits(compiles, x1[$, $]));

X2 x2;
static assert(!__traits(compiles, x2[$]));
static assert(!__traits(compiles, x2[$, $]));
}
{
import imports.opover7177b; // opDollar(size_t dim, R)(R r)

auto a = A([1,2,3]);
assert(a[0] == 1);
assert(a[$-1] == 3);
assert(a[2..$].length == 1);

X1 x1;
x1.length = 1;
static assert( __traits(compiles, x1[$]));
static assert( __traits(compiles, x1[$, $])); // opDollar!0, opDollar!1

X2 x2;
static assert(!__traits(compiles, x2[$]));
static assert(!__traits(compiles, x2[$, $]));
}
}

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

0 comments on commit 5a8db43

Please sign in to comment.