Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 13756 - [AA] Allow ref const index on foreach AA iteration #4152

Merged
merged 1 commit into from
Nov 20, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/opover.c
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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