Skip to content

Commit

Permalink
Merge pull request #4152 from 9rnsr/fix13756
Browse files Browse the repository at this point in the history
Issue 13756 - [AA] Allow ref const index on foreach AA iteration
  • Loading branch information
yebblies committed Nov 20, 2014
2 parents 5c087d7 + 7a0d2e5 commit e1e1368
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 13 deletions.
2 changes: 2 additions & 0 deletions src/opover.c
Expand Up @@ -1644,6 +1644,8 @@ bool inferApplyArgTypes(ForeachStatement *fes, Scope *sc, Dsymbol *&sapply)
{
arg->type = taa->index; // key type
arg->type = arg->type->addStorageClass(arg->storageClass);
if (arg->storageClass & STCref) // key must not be mutated via ref
arg->type = arg->type->addMod(MODconst);
}
arg = (*fes->arguments)[1];
}
Expand Down
33 changes: 20 additions & 13 deletions src/statement.c
Expand Up @@ -2326,35 +2326,41 @@ Statement *ForeachStatement::semantic(Scope *sc)
{
// Check types
Parameter *arg = (*arguments)[0];
bool isRef = (arg->storageClass & STCref) != 0;
Type *ta = arg->type;
if (dim == 2)
{
if (arg->storageClass & STCref)
{
error("foreach: index cannot be ref");
goto Lerror2;
}
if (!taa->index->implicitConvTo(arg->type))
Type *ti = (isRef ? taa->index->addMod(MODconst) : taa->index);
if (isRef ? !ti->constConv(ta) : !ti->implicitConvTo(ta))
{
error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars());
error("foreach: index must be type %s, not %s", ti->toChars(), ta->toChars());
goto Lerror2;
}
arg = (*arguments)[1];
isRef = (arg->storageClass & STCref) != 0;
ta = arg->type;
}
if ((!arg->type->equals(taa->nextOf()) && (arg->storageClass & STCref)) ||
!taa->nextOf()->implicitConvTo(arg->type))
Type *tn = taa->nextOf();
if (isRef ? !tn->constConv(ta) : !tn->implicitConvTo(ta))
{
error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars());
error("foreach: value must be type %s, not %s", tn->toChars(), ta->toChars());
goto Lerror2;
}

/* Call:
* extern(C) int _aaApply(void*, in size_t, int delegate(void*))
* _aaApply(aggr, keysize, flde)
*
* extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*))
* _aaApply2(aggr, keysize, flde)
*/
static const char *name[2] = { "_aaApply", "_aaApply2" };
static FuncDeclaration *fdapply[2] = { NULL, NULL };
static TypeDelegate *fldeTy[2] = { NULL, NULL };

unsigned char i = dim == 2;
if (!fdapply[i]) {
unsigned char i = (dim == 2 ? 1 : 0);
if (!fdapply[i])
{
args = new Parameters;
args->push(new Parameter(0, Type::tvoid->pointerTo(), NULL, NULL));
args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL));
Expand All @@ -2373,7 +2379,8 @@ Statement *ForeachStatement::semantic(Scope *sc)
size_t keysize = (size_t)taa->index->size();
keysize = (keysize + ((size_t)Target::ptrsize-1)) & ~((size_t)Target::ptrsize-1);
// paint delegate argument to the type runtime expects
if (!fldeTy[i]->equals(flde->type)) {
if (!fldeTy[i]->equals(flde->type))
{
flde = new CastExp(loc, flde, flde->type);
flde->type = fldeTy[i];
}
Expand Down
14 changes: 14 additions & 0 deletions test/fail_compilation/fail13756.d
@@ -0,0 +1,14 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail13756.d(11): Error: foreach: index must be type const(int), not int
---
*/

void maiin()
{
int[int] aa = [1:2];
foreach (ref int k, v; aa)
{
}
}
70 changes: 70 additions & 0 deletions test/runnable/foreach5.d
Expand Up @@ -962,6 +962,75 @@ void test12932() @nogc
assert(sum == 6);
}

/***************************************/
// 13756

void test13756()
{
int[int] org = [1:2], aa;

aa = org.dup;
foreach (v; aa)
{
static assert(is(typeof(v) == int));
v = 20;
}
assert(aa == [1:2]);

aa = org.dup;
foreach (ref v; aa)
{
static assert(is(typeof(v) == int));
v = 20;
}
assert(aa == [1:20]);

aa = org.dup;
foreach (k, v; aa)
{
static assert(is(typeof(k) == int));
static assert(is(typeof(v) == int));
k = 10;
v = 20;
}
assert(aa == [1:2]);

aa = org.dup;
foreach (k, ref v; aa)
{
static assert(is(typeof(k) == int));
static assert(is(typeof(v) == int));
k = 10;
v = 20;
}
assert(aa == [1:20]);

aa = org.dup;
foreach (ref k, v; aa) // NG -> OK
{
static assert(is(typeof(k) == const int));
static assert(is(typeof(v) == int));
static assert(!__traits(compiles, k = 10));
v = 20;
}
assert(aa == [1:2]);

aa = org.dup;
foreach (ref k, ref v; aa) // NG -> OK
{
static assert(is(typeof(k) == const int));
static assert(is(typeof(v) == int));
static assert(!__traits(compiles, k = 10));
v = 20;
}
assert(aa == [1:20]);

foreach (ref const k, v; aa) // NG -> OK, same with 'ref k'
{
static assert(is(typeof(k) == const int));
}
}

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

int main()
Expand Down Expand Up @@ -991,6 +1060,7 @@ int main()
test12103();
test12739();
test12932();
test13756();

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

0 comments on commit e1e1368

Please sign in to comment.