diff --git a/src/statement.c b/src/statement.c index b5857af6ab5c..773fb442732a 100644 --- a/src/statement.c +++ b/src/statement.c @@ -1789,10 +1789,7 @@ Statement *ForeachStatement::semantic(Scope *sc) if (!rinit) // if application of [] failed rinit = aggr; VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); -// r->semantic(sc); -//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); Statement *init = new ExpStatement(loc, r); -//printf("init: %s\n", init->toChars()); // !__r.empty Expression *e = new VarExp(loc, r); @@ -1808,16 +1805,70 @@ Statement *ForeachStatement::semantic(Scope *sc) */ e = new VarExp(loc, r); Expression *einit = new DotIdExp(loc, e, idhead); -// einit = einit->semantic(sc); - Parameter *arg = arguments->tdata()[0]; - VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); - ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + Statement *makeargs; + if (dim == 1) + { + Parameter *arg = arguments->tdata()[0]; + VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); + ve->storage_class |= STCforeach; + ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + + DeclarationExp *de = new DeclarationExp(loc, ve); + makeargs = new ExpStatement(loc, de); + } + else + { + Identifier *id = Lexer::uniqueId("__front"); + ExpInitializer *ei = new ExpInitializer(loc, einit); + VarDeclaration *vd = new VarDeclaration(loc, NULL, id, ei); + vd->storage_class |= STCctfe | STCref | STCforeach; + + Expression *de = new DeclarationExp(loc, vd); + makeargs = new ExpStatement(loc, de); + + Expression *ve = new VarExp(loc, vd); + ve->type = shead->isDeclaration()->type; + if (ve->type->toBasetype()->ty == Tfunction) + ve->type = ve->type->toBasetype()->nextOf(); + if (!ve->type || ve->type->ty == Terror) + goto Lrangeerr; + + Expressions *exps = new Expressions(); + exps->push(ve); + int pos = 0; + while (exps->dim < dim) + { + pos = expandAliasThisTuples(exps, pos); + if (pos == -1) + break; + } + if (exps->dim > dim) + goto Lrangeerr; + + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = arguments->tdata()[i]; + Expression *exp = exps->tdata()[i]; + #if 0 + printf("[%d] arg = %s %s, exp = %s %s\n", i, + arg->type ? arg->type->toChars() : "?", arg->ident->toChars(), + exp->type->toChars(), exp->toChars()); + #endif + if (arg->type && !exp->implicitConvTo(arg->type)) + goto Lrangeerr; + if (!arg->type) + arg->type = exp->type; + + VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, exp)); + var->storage_class |= STCctfe | STCref | STCforeach; + DeclarationExp *de = new DeclarationExp(loc, var); + makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, de)); + } - DeclarationExp *de = new DeclarationExp(loc, ve); + } Statement *body = new CompoundStatement(loc, - new ExpStatement(loc, de), this->body); + makeargs, this->body); s = new ForStatement(loc, init, condition, increment, body); #if 0 @@ -1828,6 +1879,10 @@ Statement *ForeachStatement::semantic(Scope *sc) #endif s = s->semantic(sc); break; + + Lrangeerr: + error("cannot infer argument types"); + break; } #endif case Tdelegate: diff --git a/test/runnable/aliasthis.d b/test/runnable/aliasthis.d index 303f48a2a275..69043f2e8c7b 100644 --- a/test/runnable/aliasthis.d +++ b/test/runnable/aliasthis.d @@ -496,6 +496,81 @@ void test6434() } /**************************************/ +// 6366 + +void test6366() +{ + struct Zip + { + string str; + size_t i; + this(string s) + { + str = s; + } + @property const bool empty() + { + return i == str.length; + } + @property Tup!(size_t, char) front() + { + return typeof(return)(i, str[i]); + } + void popFront() + { + ++i; + } + } + + foreach (i, c; Zip("hello")) + { + switch (i) + { + case 0: assert(c == 'h'); break; + case 1: assert(c == 'e'); break; + case 2: assert(c == 'l'); break; + case 3: assert(c == 'l'); break; + case 4: assert(c == 'o'); break; + default:assert(0); + } + } + + auto range(F...)(F field) + { + static struct Range { + F field; + bool empty = false; + Tup!F front() { return typeof(return)(field); } + void popFront(){ empty = true; } + } + return Range(field); + } + + foreach (i, t; range(10, tup("str", [1,2]))){ + static assert(is(typeof(i) == int)); + static assert(is(typeof(t) == Tup!(string, int[]))); + assert(i == 10); + assert(t == tup("str", [1,2])); + } + auto r1 = range(10, "str", [1,2]); + auto r2 = range(tup(10, "str"), [1,2]); + auto r3 = range(10, tup("str", [1,2])); + auto r4 = range(tup(10, "str", [1,2])); + alias Seq!(r1, r2, r3, r4) ranges; + foreach (n, _; ranges) + { + foreach (i, s, a; ranges[n]){ + static assert(is(typeof(i) == int)); + static assert(is(typeof(s) == string)); + static assert(is(typeof(a) == int[])); + assert(i == 10); + assert(s == "str"); + assert(a == [1,2]); + } + } +} + +/**********************************************/ int main() { @@ -517,6 +592,7 @@ int main() test6369c(); test6369d(); test6434(); + test6366(); printf("Success\n"); return 0;