Skip to content

Commit

Permalink
Merge pull request dlang#4742 from 9rnsr/fix14682
Browse files Browse the repository at this point in the history
[REG2.037] Issue 14682 - Incorrect interpretation of ~ []
  • Loading branch information
WalterBright authored and 9rnsr committed Jun 18, 2015
1 parent 6963c2b commit e23ff7c
Show file tree
Hide file tree
Showing 2 changed files with 171 additions and 26 deletions.
89 changes: 63 additions & 26 deletions src/expression.c
Expand Up @@ -12408,52 +12408,89 @@ Expression *CatExp::semantic(Scope *sc)
Type *tb1next = tb1->nextOf();
Type *tb2next = tb2->nextOf();

// Check for: array ~ array
if (tb1next && tb2next &&
(tb1next->implicitConvTo(tb2next) >= MATCHconst ||
tb2next->implicitConvTo(tb1next) >= MATCHconst)
tb2next->implicitConvTo(tb1next) >= MATCHconst ||
e1->op == TOKarrayliteral && e1->implicitConvTo(tb2) ||
e2->op == TOKarrayliteral && e2->implicitConvTo(tb1)
)
)
{
/* Here to avoid the case of:
/* Bugzilla 9248: Here to avoid the case of:
* void*[] a = [cast(void*)1];
* void*[] b = [cast(void*)2];
* a ~ b;
* becoming:
* a ~ [cast(void*)b];
*/

/* Bugzilla 14682: Also to avoid the case of:
* int[][] a;
* a ~ [];
* becoming:
* a ~ cast(int[])[];
*/
goto Lpeer;
}
else if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
e2->implicitConvTo(tb1next) >= MATCHconvert &&
tb2->ty != Tvoid)

// Check for: array ~ element
if ((tb1->ty == Tsarray || tb1->ty == Tarray) && tb2->ty != Tvoid)
{
if (e2->checkPostblit(sc, tb2))
return new ErrorExp();
e2 = e2->implicitCastTo(sc, tb1next);
type = tb1next->arrayOf();
if (tb2->ty == Tarray || tb2->ty == Tsarray)
if (e1->op == TOKarrayliteral && e1->implicitConvTo(tb2->arrayOf()))
{
// Make e2 into [e2]
e2 = new ArrayLiteralExp(e2->loc, e2);
e2->type = type;
if (e2->checkPostblit(sc, tb2))
return new ErrorExp();
e1 = e1->implicitCastTo(sc, tb2->arrayOf());
type = tb2->arrayOf();
goto L2elem;
}
if (e2->implicitConvTo(tb1next) >= MATCHconvert)
{
if (e2->checkPostblit(sc, tb2))
return new ErrorExp();
e2 = e2->implicitCastTo(sc, tb1next);
type = tb1next->arrayOf();
L2elem:
if (tb2->ty == Tarray || tb2->ty == Tsarray)
{
// Make e2 into [e2]
e2 = new ArrayLiteralExp(e2->loc, e2);
e2->type = type;
}
return this;
}
return this;
}
else if ((tb2->ty == Tsarray || tb2->ty == Tarray) &&
e1->implicitConvTo(tb2next) >= MATCHconvert &&
tb1->ty != Tvoid)
// Check for: element ~ array
if ((tb2->ty == Tsarray || tb2->ty == Tarray) && tb1->ty != Tvoid)
{
if (e1->checkPostblit(sc, tb1))
return new ErrorExp();
e1 = e1->implicitCastTo(sc, tb2next);
type = tb2next->arrayOf();
if (tb1->ty == Tarray || tb1->ty == Tsarray)
if (e2->op == TOKarrayliteral &&
e2->implicitConvTo(tb1->arrayOf()))
{
// Make e1 into [e1]
e1 = new ArrayLiteralExp(e1->loc, e1);
e1->type = type;
if (e1->checkPostblit(sc, tb1))
return new ErrorExp();
e2 = e2->implicitCastTo(sc, tb1->arrayOf());
type = tb1->arrayOf();
goto L1elem;
}
if (e1->implicitConvTo(tb2next) >= MATCHconvert)
{
if (e1->checkPostblit(sc, tb1))
return new ErrorExp();
e1 = e1->implicitCastTo(sc, tb2next);
type = tb2next->arrayOf();
L1elem:
if (tb1->ty == Tarray || tb1->ty == Tsarray)
{
// Make e1 into [e1]
e1 = new ArrayLiteralExp(e1->loc, e1);
e1->type = type;
}
return this;
}
return this;
}

Lpeer:
if ((tb1->ty == Tsarray || tb1->ty == Tarray) &&
(tb2->ty == Tsarray || tb2->ty == Tarray) &&
(tb1next->mod || tb2next->mod) &&
Expand Down
108 changes: 108 additions & 0 deletions test/runnable/test42.d
Expand Up @@ -5412,6 +5412,7 @@ void test9171()
}

/***************************************************/
// 9248

void test9248()
{
Expand All @@ -5421,6 +5422,111 @@ void test9248()
assert(c == [cast(void*)1, cast(void*)2]);
}

/***************************************************/
// 14682

void test14682a()
{
// operands
int[] a1;
int[][] a2;
int[][][] a3;
int[][][][] a4;

// results
int[] r1w = []; assert(r1w.length == 0);
int[][] r2w = []; assert(r2w.length == 0);
int[][][] r3w = []; assert(r3w.length == 0);
int[][][][] r4w = []; assert(r4w.length == 0);
// ----
int[][] r2x = [[]]; assert(r2x.length == 1 && r2x[0].length == 0);
int[][][] r3x = [[]]; assert(r3x.length == 1 && r3x[0].length == 0);
int[][][][] r4x = [[]]; assert(r4x.length == 1 && r4x[0].length == 0);
// ----
int[][][] r3y = [[[]]]; assert(r3y.length == 1 && r3y[0].length == 1 && r3y[0][0].length == 0);
int[][][][] r4y = [[[]]]; assert(r4y.length == 1 && r4y[0].length == 1 && r4y[0][0].length == 0);
// ----
int[][][][] r4z = [[[[]]]]; assert(r4z.length == 1 && r4z[0].length == 1 && r4z[0][0].length == 1 && r4z[0][0][0].length == 0);

// ArrayLiteralExp conforms to the type of LHS.
{ auto x = a1 ~ [] ; static assert(is(typeof(x) == typeof(a1))); assert(x == r1w); } // no ambiguity
{ auto x = a2 ~ [] ; static assert(is(typeof(x) == typeof(a2))); assert(x == r2w); } // fix <- ambiguity
{ auto x = a3 ~ [] ; static assert(is(typeof(x) == typeof(a3))); assert(x == r3w); } // fix <- ambiguity
{ auto x = a4 ~ [] ; static assert(is(typeof(x) == typeof(a4))); assert(x == r4w); } // fix <- ambiguity
// ----
//{ auto x = a1 ~ [[]] ; } // (see test14682b)
{ auto x = a2 ~ [[]] ; static assert(is(typeof(x) == typeof(a2))); assert(x == r2x); } // no ambiguity
{ auto x = a3 ~ [[]] ; static assert(is(typeof(x) == typeof(a3))); assert(x == r3x); } // fix <- ambiguity
{ auto x = a4 ~ [[]] ; static assert(is(typeof(x) == typeof(a4))); assert(x == r4x); } // fix <- ambiguity
// ----
static assert(!__traits(compiles, { auto x = a1 ~ [[[]]] ; }));
//{ auto x = a2 ~ [[[]]] ; } // (see test14682b)
{ auto x = a3 ~ [[[]]] ; static assert(is(typeof(x) == typeof(a3))); assert(x == r3y); } // no ambiguity
{ auto x = a4 ~ [[[]]] ; static assert(is(typeof(x) == typeof(a4))); assert(x == r4y); } // fix <- ambiguity
// ----
static assert(!__traits(compiles, { auto x = a1 ~ [[[[]]]]; }));
static assert(!__traits(compiles, { auto x = a2 ~ [[[[]]]]; }));
//{ auto x = a3 ~ [[[[]]]]; } // (see test14682b)
{ auto x = a4 ~ [[[[]]]]; static assert(is(typeof(x) == typeof(a4))); assert(x == r4z); } // no ambiguity

// ArrayLiteralExp conforms to the type of RHS.
{ auto x = [] ~ a1; static assert(is(typeof(x) == typeof(a1))); assert(x == r1w); } // no ambiguity
{ auto x = [] ~ a2; static assert(is(typeof(x) == typeof(a2))); assert(x == r2w); } // fix <- ambiguity
{ auto x = [] ~ a3; static assert(is(typeof(x) == typeof(a3))); assert(x == r3w); } // fix <- ambiguity
{ auto x = [] ~ a4; static assert(is(typeof(x) == typeof(a4))); assert(x == r4w); } // fix <- ambiguity
// ----
//{ auto x = [[]] ~ a1; } // (see test14682b)
{ auto x = [[]] ~ a2; static assert(is(typeof(x) == typeof(a2))); assert(x == r2x); } // no ambiguity
{ auto x = [[]] ~ a3; static assert(is(typeof(x) == typeof(a3))); assert(x == r3x); } // fix <- ambiguity
{ auto x = [[]] ~ a4; static assert(is(typeof(x) == typeof(a4))); assert(x == r4x); } // fix <- ambiguity
// ----
static assert(!__traits(compiles, { auto x = [[[]]] ~ a1; }));
//{ auto x = [[[]]] ~ a2; } // (see test14682b)
{ auto x = [[[]]] ~ a3; static assert(is(typeof(x) == typeof(a3))); assert(x == r3y); } // no ambiguity
{ auto x = [[[]]] ~ a4; static assert(is(typeof(x) == typeof(a4))); assert(x == r4y); } // fix <- ambiguity
// ----
static assert(!__traits(compiles, { auto x = [[[[]]]] ~ a1; }));
static assert(!__traits(compiles, { auto x = [[[[]]]] ~ a2; }));
//{ auto x = [[[[]]]] ~ a3; } // (see test14682b)
{ auto x = [[[[]]]] ~ a4; static assert(is(typeof(x) == typeof(a4))); assert(x == r4z); } // no ambiguity
}

void test14682b()
{
// operands
int[] a1;
int[][] a2;
int[][][] a3;
int[][][][] a4;

// results
int[][] r2a = [[], [] ]; assert(r2a.length == 2 && r2a[0].length == 0 && r2a[1].length == 0);
//int[][][] r3a = [[], [[]] ]; // should work, but doesn't
//int[][][][] r4a = [[], [[[]]]]; // should work, but doesn't
int[][][] r3a; { r3a.length = 2; r3a[0] = []; r3a[1] = [[]] ; }
assert(r3a.length == 2 && r3a[0].length == 0 && r3a[1].length == 1 && r3a[1][0].length == 0);
int[][][][] r4a; { r4a.length = 2; r4a[0] = []; r4a[1] = [[[]]]; }
assert(r4a.length == 2 && r4a[0].length == 0 && r4a[1].length == 1 && r4a[1][0].length == 1 && r4a[1][0][0].length == 0);
// ----
int[][] r2b = [ [] , []]; assert(r2b.length == 2 && r2b[1].length == 0 && r2b[0].length == 0);
//int[][][] r3b = [ [[]] , []]; // should work, but doesn't
//int[][][][] r4b = [[[[]]], []]; // should work, but doesn't
int[][][] r3b; { r3b.length = 2; r3b[0] = [[]] ; r3b[1] = []; }
assert(r3b.length == 2 && r3b[1].length == 0 && r3b[0].length == 1 && r3b[0][0].length == 0);
int[][][][] r4b; { r4b.length = 2; r4b[0] = [[[]]]; r4b[1] = []; }
assert(r4b.length == 2 && r4b[1].length == 0 && r4b[0].length == 1 && r4b[0][0].length == 1 && r4b[0][0][0].length == 0);

// ArrayLiteralExp conforms to the typeof(LHS)->arrayOf().
{ auto x = a1 ~ [[]] ; static assert(is(typeof(x) == typeof(a1)[])); assert(x == r2a); } // fix
{ auto x = a2 ~ [[[]]] ; static assert(is(typeof(x) == typeof(a2)[])); assert(x == r3a); } // fix
{ auto x = a3 ~ [[[[]]]]; static assert(is(typeof(x) == typeof(a3)[])); assert(x == r4a); } // fix

// ArrayLiteralExp conforms to the typeof(RHS)->arrayOf().
{ auto x = [[]] ~ a1; static assert(is(typeof(x) == typeof(a1)[])); assert(x == r2b); } // fix
{ auto x = [[[]]] ~ a2; static assert(is(typeof(x) == typeof(a2)[])); assert(x == r3b); } // fix
{ auto x = [[[[]]]] ~ a3; static assert(is(typeof(x) == typeof(a3)[])); assert(x == r4b); } // fix
}

/***************************************************/
// 9739

Expand Down Expand Up @@ -6151,6 +6257,8 @@ int main()
test8796();
test9171();
test9248();
test14682a();
test14682b();
test9739();
testdbl_to_ulong();
testdbl_to_uint();
Expand Down

0 comments on commit e23ff7c

Please sign in to comment.