Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
fix Issue 14626 - byValue doesn't work with inout AA
Browse files Browse the repository at this point in the history
Until 2.065, compiler had substituted all `inout` qualifiers in the `Key` and `Value` types to `const`, then those had passed to the template struct `AssociativeArray`.

https://github.com/D-Programming-Language/dmd/blob/v2.065.0/src/mtype.c#L4897

This change emulates that.
  • Loading branch information
9rnsr committed Jul 17, 2015
1 parent 73a6555 commit 6d57c68
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 8 deletions.
32 changes: 32 additions & 0 deletions src/core/internal/traits.d
Expand Up @@ -53,6 +53,38 @@ template Unqual(T)
}
}

// Substitute all `inout` qualifiers that appears in T to `const`
template substInout(T)
{
static if (is(T == immutable))
{
alias substInout = T;
}
else static if (is(T : shared const U, U) || is(T : const U, U))
{
// U is top-unqualified
mixin("alias substInout = "
~ (is(T == shared) ? "shared " : "")
~ (is(T == const) || is(T == inout) ? "const " : "") // substitute inout to const
~ "substInoutForm!U;");
}
else
static assert(0);
}

private template substInoutForm(T)
{
static if (is(T == struct) || is(T == class) || is(T == union) || is(T == interface))
{
alias substInoutForm = T; // prevent matching to the form of alias-this-ed type
}
else static if (is(T : V[K], K, V)) alias substInoutForm = substInout!V[substInout!K];
else static if (is(T : U[n], U, size_t n)) alias substInoutForm = substInout!U[n];
else static if (is(T : U[], U)) alias substInoutForm = substInout!U[];
else static if (is(T : U*, U)) alias substInoutForm = substInout!U*;
else alias substInoutForm = T;
}

/// used to declare an extern(D) function that is defined in a different module
template externDFunc(string fqn, T:FT*, FT) if(is(FT == function))
{
Expand Down
52 changes: 44 additions & 8 deletions src/object.d
Expand Up @@ -1825,13 +1825,15 @@ V[K] dup(T : V[K], K, V)(T* aa)

auto byKey(T : V[K], K, V)(T aa) pure nothrow @nogc
{
import core.internal.traits : substInout;

static struct Result
{
AARange r;

pure nothrow @nogc:
@property bool empty() { return _aaRangeEmpty(r); }
@property ref K front() { return *cast(K*)_aaRangeFrontKey(r); }
@property ref front() { return *cast(substInout!K*)_aaRangeFrontKey(r); }
void popFront() { _aaRangePopFront(r); }
@property Result save() { return this; }
}
Expand All @@ -1846,13 +1848,15 @@ auto byKey(T : V[K], K, V)(T* aa) pure nothrow @nogc

auto byValue(T : V[K], K, V)(T aa) pure nothrow @nogc
{
import core.internal.traits : substInout;

static struct Result
{
AARange r;

pure nothrow @nogc:
@property bool empty() { return _aaRangeEmpty(r); }
@property ref V front() { return *cast(V*)_aaRangeFrontValue(r); }
@property ref front() { return *cast(substInout!V*)_aaRangeFrontValue(r); }
void popFront() { _aaRangePopFront(r); }
@property Result save() { return this; }
}
Expand All @@ -1867,6 +1871,8 @@ auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc

auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc
{
import core.internal.traits : substInout;

static struct Result
{
AARange r;
Expand All @@ -1879,14 +1885,14 @@ auto byKeyValue(T : V[K], K, V)(T aa) pure nothrow @nogc
{
// We save the pointers here so that the Pair we return
// won't mutate when Result.popFront is called afterwards.
private K* keyp;
private V* valp;
private void* keyp;
private void* valp;

@property ref inout(K) key() inout { return *keyp; }
@property ref inout(V) value() inout { return *valp; }
@property ref key() inout { return *cast(substInout!K*)keyp; }
@property ref value() inout { return *cast(substInout!V*)valp; }
}
return Pair(cast(K*)_aaRangeFrontKey(r),
cast(V*)_aaRangeFrontValue(r));
return Pair(_aaRangeFrontKey(r),
_aaRangeFrontValue(r));
}
void popFront() { _aaRangePopFront(r); }
@property Result save() { return this; }
Expand Down Expand Up @@ -2228,6 +2234,36 @@ unittest
}
}

unittest
{
// test for bug 14626
static struct S
{
string[string] aa;
inout(string) key() inout { return aa.byKey().front; }
inout(string) val() inout { return aa.byValue().front; }
auto keyval() inout { return aa.byKeyValue().front; }
}

S s = S(["a":"b"]);
assert(s.key() == "a");
assert(s.val() == "b");
assert(s.keyval().key == "a");
assert(s.keyval().value == "b");

void testInoutKeyVal(inout(string) key)
{
inout(string)[typeof(key)] aa;

foreach (i; aa.byKey()) {}
foreach (i; aa.byValue()) {}
foreach (i; aa.byKeyValue()) {}
}

const int[int] caa;
static assert(is(typeof(caa.byValue().front) == const int));
}

private void _destructRecurse(S)(ref S s)
if (is(S == struct))
{
Expand Down

0 comments on commit 6d57c68

Please sign in to comment.