From f78a770f469fcc60d450e1b9fcd03fbc9ffb010d Mon Sep 17 00:00:00 2001 From: k-hara Date: Wed, 16 Oct 2013 17:51:38 +0900 Subject: [PATCH] fix Issue 10684 - Refused array op with array literal Accept array literals as the operand of array-ops. --- Since, array-ops had required explicit slice to the array literal operands, eg. `a[] = [1,2][] + c[];` By the commit: https://github.com/9rnsr/dmd/commit/f703c5c6551affddd9213f759657a2b3e391b935 now the redundant slice operators at the right side of an array literal is entirely removed - `[1,2,3][][]` is rewritten to `[1,2,3]`. Although it has broke existing code using array-ops, I still cannot think the optimization was incorrect. On the other hand, I could not find the description about the necessity of explicit slice on array literal from the language spec. http://dlang.org/arrays.html#array-operations It looked to me that is just an implementation-specific restriction. So, I implemented this as the easiest way to fix the issue. --- src/arrayop.c | 33 +++++++++++++++++++++++++++++++++ src/expression.h | 3 +++ test/runnable/arrayop.d | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+) diff --git a/src/arrayop.c b/src/arrayop.c index 7187a63d87b8..9151c84c416f 100644 --- a/src/arrayop.c +++ b/src/arrayop.c @@ -309,6 +309,13 @@ bool isArrayOpValid(Expression *e) { if (e->op == TOKslice) return true; + if (e->op == TOKarrayliteral) + { + Type *t = e->type->toBasetype(); + while (t->ty == Tarray || t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + return (t->ty != Tvoid); + } Type *tb = e->type->toBasetype(); if ( (tb->ty == Tarray) || (tb->ty == Tsarray) ) @@ -451,6 +458,12 @@ void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) Expression::buildArrayIdent(buf, arguments); } +void ArrayLiteralExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Slice"); + arguments->shift(this); +} + void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) { buf->writestring("Slice"); @@ -558,6 +571,19 @@ Expression *CastExp::buildArrayLoop(Parameters *fparams) return Expression::buildArrayLoop(fparams); } +Expression *ArrayLiteralExp::buildArrayLoop(Parameters *fparams) +{ + Identifier *id = Identifier::generateId("p", fparams->dim); + Parameter *param = new Parameter(STCconst, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(Loc(), id); + Expressions *arguments = new Expressions(); + Expression *index = new IdentifierExp(Loc(), Id::p); + arguments->push(index); + e = new ArrayExp(Loc(), e, arguments); + return e; +} + Expression *SliceExp::buildArrayLoop(Parameters *fparams) { Identifier *id = Identifier::generateId("p", fparams->dim); @@ -671,6 +697,13 @@ int Expression::isArrayOperand() //printf("Expression::isArrayOperand() %s\n", toChars()); if (op == TOKslice) return 1; + if (op == TOKarrayliteral) + { + Type *t = type->toBasetype(); + while (t->ty == Tarray || t->ty == Tsarray) + t = t->nextOf()->toBasetype(); + return (t->ty != Tvoid); + } if (type->toBasetype()->ty == Tarray) { switch (op) diff --git a/src/expression.h b/src/expression.h index adb4354300d5..7455e2b2ac3e 100644 --- a/src/expression.h +++ b/src/expression.h @@ -486,6 +486,9 @@ class ArrayLiteralExp : public Expression Expression *inferType(Type *t, int flag = 0, Scope *sc = NULL, TemplateParameters *tparams = NULL); dt_t **toDt(dt_t **pdt); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + Expression *doInline(InlineDoState *ids); Expression *inlineScan(InlineScanState *iss); }; diff --git a/test/runnable/arrayop.d b/test/runnable/arrayop.d index d2d52b3b2cdd..98f9d8e83296 100644 --- a/test/runnable/arrayop.d +++ b/test/runnable/arrayop.d @@ -664,6 +664,38 @@ void test10433() foo(v, v); } +/************************************************************************/ +// 10684 + +void test10684a() +{ + int[] a = [0, 0]; + a[] += [10, 20][]; +} + +void test10684b() +{ + int[] a = [1, 2, 3]; + int[] b = [4, 5, 6]; + + // Allow array literal as the operand of array oeration + a[] += [1, 2, 3]; + assert(a == [2, 4, 6]); + + a[] *= b[] + [1, 1, 1]; + assert(a == [2*(4+1), 4*(5+1), 6*(6+1)]); + + a[] = [9, 8, 7] - [1, 2, 3]; + assert(a == [8, 6, 4]); + + a[] = [2, 4, 6] / 2; + assert(a == [1,2,3]); + + // Disallow: [1,2,3] is not an lvalue + static assert(!__traits(compiles, { [1,2,3] = a[] * 2; })); + static assert(!__traits(compiles, { [1,2,3] += a[] * b[]; })); +} + /************************************************************************/ int main() @@ -678,6 +710,8 @@ int main() test8651(); test9656(); test10433(); + test10684a(); + test10684b(); printf("Success\n"); return 0;