diff --git a/src/expression.c b/src/expression.c index 06bbe1386a72..29075ec07edc 100644 --- a/src/expression.c +++ b/src/expression.c @@ -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) && diff --git a/test/runnable/test42.d b/test/runnable/test42.d index 42ea960cc640..08d64dfc2202 100644 --- a/test/runnable/test42.d +++ b/test/runnable/test42.d @@ -5412,6 +5412,7 @@ void test9171() } /***************************************************/ +// 9248 void test9248() { @@ -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 @@ -6151,6 +6257,8 @@ int main() test8796(); test9171(); test9248(); + test14682a(); + test14682b(); test9739(); testdbl_to_ulong(); testdbl_to_uint();