Commit 8d504c4e authored by Russ Cox's avatar Russ Cox

cmd/gc: implement 'for range x {'

Fixes #6102.

LGTM=gri
R=ken, r, gri
CC=golang-codereviews
https://golang.org/cl/113120043
parent 26d0f75f
...@@ -495,7 +495,7 @@ esc(EscState *e, Node *n, Node *up) ...@@ -495,7 +495,7 @@ esc(EscState *e, Node *n, Node *up)
case ORANGE: case ORANGE:
// Everything but fixed array is a dereference. // Everything but fixed array is a dereference.
if(isfixedarray(n->type) && n->list->next) if(isfixedarray(n->type) && n->list && n->list->next)
escassign(e, n->list->next->n, n->right); escassign(e, n->list->next->n, n->right);
break; break;
......
...@@ -880,7 +880,11 @@ stmtfmt(Fmt *f, Node *n) ...@@ -880,7 +880,11 @@ stmtfmt(Fmt *f, Node *n)
fmtstrcpy(f, "for loop"); fmtstrcpy(f, "for loop");
break; break;
} }
if(n->list == nil) {
fmtprint(f, "for range %N { %H }", n->right, n->nbody);
break;
}
fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody); fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
break; break;
......
...@@ -613,6 +613,11 @@ range_stmt: ...@@ -613,6 +613,11 @@ range_stmt:
$$->colas = 1; $$->colas = 1;
colasdefn($1, $$); colasdefn($1, $$);
} }
| LRANGE expr
{
$$ = nod(ORANGE, N, $2);
$$->etype = 0; // := flag
}
for_header: for_header:
osimple_stmt ';' osimple_stmt ';' osimple_stmt osimple_stmt ';' osimple_stmt ';' osimple_stmt
......
...@@ -67,9 +67,11 @@ typecheckrange(Node *n) ...@@ -67,9 +67,11 @@ typecheckrange(Node *n)
yyerror("too many variables in range"); yyerror("too many variables in range");
} }
v1 = n->list->n; v1 = N;
if(n->list)
v1 = n->list->n;
v2 = N; v2 = N;
if(n->list->next) if(n->list && n->list->next)
v2 = n->list->next->n; v2 = n->list->next->n;
// this is not only a optimization but also a requirement in the spec. // this is not only a optimization but also a requirement in the spec.
...@@ -77,14 +79,17 @@ typecheckrange(Node *n) ...@@ -77,14 +79,17 @@ typecheckrange(Node *n)
// clause is equivalent to the same clause with only the first variable // clause is equivalent to the same clause with only the first variable
// present." // present."
if(isblank(v2)) { if(isblank(v2)) {
n->list = list1(v1); if(v1 != N)
n->list = list1(v1);
v2 = N; v2 = N;
} }
if(v1->defn == n) if(v1) {
v1->type = t1; if(v1->defn == n)
else if(v1->type != T && assignop(t1, v1->type, &why) == 0) v1->type = t1;
yyerror("cannot assign type %T to %lN in range%s", t1, v1, why); else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
}
if(v2) { if(v2) {
if(v2->defn == n) if(v2->defn == n)
v2->type = t2; v2->type = t2;
...@@ -123,9 +128,11 @@ walkrange(Node *n) ...@@ -123,9 +128,11 @@ walkrange(Node *n)
a = n->right; a = n->right;
lno = setlineno(a); lno = setlineno(a);
v1 = n->list->n; v1 = N;
if(n->list)
v1 = n->list->n;
v2 = N; v2 = N;
if(n->list->next && !isblank(n->list->next->n)) if(n->list && n->list->next && !isblank(n->list->next->n))
v2 = n->list->next->n; v2 = n->list->next->n;
// n->list has no meaning anymore, clear it // n->list has no meaning anymore, clear it
// to avoid erroneous processing by racewalk. // to avoid erroneous processing by racewalk.
...@@ -154,7 +161,9 @@ walkrange(Node *n) ...@@ -154,7 +161,9 @@ walkrange(Node *n)
n->ntest = nod(OLT, hv1, hn); n->ntest = nod(OLT, hv1, hn);
n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1))); n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
if(v2 == N) if(v1 == N)
body = nil;
else if(v2 == N)
body = list1(nod(OAS, v1, hv1)); body = list1(nod(OAS, v1, hv1));
else { else {
a = nod(OAS2, N, N); a = nod(OAS2, N, N);
...@@ -205,16 +214,18 @@ walkrange(Node *n) ...@@ -205,16 +214,18 @@ walkrange(Node *n)
key = nod(ODOT, hit, keyname); key = nod(ODOT, hit, keyname);
key = nod(OIND, key, N); key = nod(OIND, key, N);
if(v2 == N) { if(v1 == N)
a = nod(OAS, v1, key); body = nil;
else if(v2 == N) {
body = list1(nod(OAS, v1, key));
} else { } else {
val = nod(ODOT, hit, valname); val = nod(ODOT, hit, valname);
val = nod(OIND, val, N); val = nod(OIND, val, N);
a = nod(OAS2, N, N); a = nod(OAS2, N, N);
a->list = list(list1(v1), v2); a->list = list(list1(v1), v2);
a->rlist = list(list1(key), val); a->rlist = list(list1(key), val);
body = list1(a);
} }
body = list1(a);
break; break;
case TCHAN: case TCHAN:
...@@ -223,6 +234,7 @@ walkrange(Node *n) ...@@ -223,6 +234,7 @@ walkrange(Node *n)
n->ntest = N; n->ntest = N;
hv1 = temp(t->type); hv1 = temp(t->type);
hv1->typecheck = 1;
if(haspointers(t->type)) if(haspointers(t->type))
init = list(init, nod(OAS, hv1, N)); init = list(init, nod(OAS, hv1, N));
hb = temp(types[TBOOL]); hb = temp(types[TBOOL]);
...@@ -233,7 +245,10 @@ walkrange(Node *n) ...@@ -233,7 +245,10 @@ walkrange(Node *n)
a->list = list(list1(hv1), hb); a->list = list(list1(hv1), hb);
a->rlist = list1(nod(ORECV, ha, N)); a->rlist = list1(nod(ORECV, ha, N));
n->ntest->ninit = list1(a); n->ntest->ninit = list1(a);
body = list1(nod(OAS, v1, hv1)); if(v1 == N)
body = nil;
else
body = list1(nod(OAS, v1, hv1));
break; break;
case TSTRING: case TSTRING:
...@@ -257,7 +272,10 @@ walkrange(Node *n) ...@@ -257,7 +272,10 @@ walkrange(Node *n)
n->ntest = nod(ONE, hv1, nodintconst(0)); n->ntest = nod(ONE, hv1, nodintconst(0));
n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a); n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
body = list1(nod(OAS, v1, ohv1));
body = nil;
if(v1 != N)
body = list1(nod(OAS, v1, ohv1));
if(v2 != N) if(v2 != N)
body = list(body, nod(OAS, v2, hv2)); body = list(body, nod(OAS, v2, hv2));
break; break;
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -20,16 +20,16 @@ static struct { ...@@ -20,16 +20,16 @@ static struct {
{32, ';', {32, ';',
"missing import path; require quoted string"}, "missing import path; require quoted string"},
{378, ';', {380, ';',
"missing { after if clause"}, "missing { after if clause"},
{399, ';', {401, ';',
"missing { after switch clause"}, "missing { after switch clause"},
{238, ';', {239, ';',
"missing { after for clause"}, "missing { after for clause"},
{476, LBODY, {478, LBODY,
"missing { after for clause"}, "missing { after for clause"},
{22, '{', {22, '{',
...@@ -47,33 +47,33 @@ static struct { ...@@ -47,33 +47,33 @@ static struct {
{37, ',', {37, ',',
"unexpected comma in channel type"}, "unexpected comma in channel type"},
{439, LELSE, {441, LELSE,
"unexpected semicolon or newline before else"}, "unexpected semicolon or newline before else"},
{258, ',', {259, ',',
"name list not allowed in interface type"}, "name list not allowed in interface type"},
{238, LVAR, {239, LVAR,
"var declaration not allowed in for initializer"}, "var declaration not allowed in for initializer"},
{65, '{', {65, '{',
"unexpected { at end of statement"}, "unexpected { at end of statement"},
{377, '{', {379, '{',
"unexpected { at end of statement"}, "unexpected { at end of statement"},
{126, ';', {126, ';',
"argument to go/defer must be function call"}, "argument to go/defer must be function call"},
{426, ';', {428, ';',
"need trailing comma before newline in composite literal"}, "need trailing comma before newline in composite literal"},
{437, ';', {439, ';',
"need trailing comma before newline in composite literal"}, "need trailing comma before newline in composite literal"},
{113, LNAME, {113, LNAME,
"nested func not allowed"}, "nested func not allowed"},
{645, ';', {647, ';',
"else must be followed by if or statement block"} "else must be followed by if or statement block"}
}; };
...@@ -123,7 +123,7 @@ func pallmall(cols []int) { ...@@ -123,7 +123,7 @@ func pallmall(cols []int) {
fmt.Println(msg) fmt.Println(msg)
tot := 0 tot := 0
// wait for all results // wait for all results
for _ = range cols { for range cols {
result := <-ended result := <-ended
tot += result.met tot += result.met
fmt.Printf("%v%v\n", result.met, spell(result.same, true)) fmt.Printf("%v%v\n", result.met, spell(result.same, true))
......
...@@ -56,6 +56,9 @@ func main() { ...@@ -56,6 +56,9 @@ func main() {
for _ = range cs {// ERROR "receive" for _ = range cs {// ERROR "receive"
} }
for range cs {// ERROR "receive"
}
close(c) close(c)
close(cs) close(cs)
close(cr) // ERROR "receive" close(cr) // ERROR "receive"
......
...@@ -18,4 +18,6 @@ func main() { ...@@ -18,4 +18,6 @@ func main() {
} }
for _ = range t { for _ = range t {
} }
for range t {
}
} }
...@@ -14,6 +14,8 @@ type matrix struct { ...@@ -14,6 +14,8 @@ type matrix struct {
func (a matrix) equal() bool { func (a matrix) equal() bool {
for _ = range a.e { for _ = range a.e {
} }
for range a.e {
}
return true return true
} }
......
...@@ -32,6 +32,13 @@ func testchan() { ...@@ -32,6 +32,13 @@ func testchan() {
println("Wanted lowercase alphabet; got", s) println("Wanted lowercase alphabet; got", s)
panic("fail") panic("fail")
} }
n := 0
for range seq('a', 'z') {
n++
}
if n != 26 {
println("testchan wrong count", n, "want 26")
}
} }
// test that range over slice only evaluates // test that range over slice only evaluates
...@@ -87,6 +94,22 @@ func testslice1() { ...@@ -87,6 +94,22 @@ func testslice1() {
} }
} }
func testslice2() {
n := 0
nmake = 0
for range makeslice() {
n++
}
if nmake != 1 {
println("range called makeslice", nmake, "times")
panic("fail")
}
if n != 5 {
println("wrong count ranging over makeslice", n)
panic("fail")
}
}
// test that range over array only evaluates // test that range over array only evaluates
// the expression after "range" once. // the expression after "range" once.
...@@ -127,6 +150,22 @@ func testarray1() { ...@@ -127,6 +150,22 @@ func testarray1() {
} }
} }
func testarray2() {
n := 0
nmake = 0
for range makearray() {
n++
}
if nmake != 1 {
println("range called makearray", nmake, "times")
panic("fail")
}
if n != 5 {
println("wrong count ranging over makearray", n)
panic("fail")
}
}
func makearrayptr() *[5]int { func makearrayptr() *[5]int {
nmake++ nmake++
return &[5]int{1, 2, 3, 4, 5} return &[5]int{1, 2, 3, 4, 5}
...@@ -176,6 +215,22 @@ func testarrayptr1() { ...@@ -176,6 +215,22 @@ func testarrayptr1() {
} }
} }
func testarrayptr2() {
n := 0
nmake = 0
for range makearrayptr() {
n++
}
if nmake != 1 {
println("range called makearrayptr", nmake, "times")
panic("fail")
}
if n != 5 {
println("wrong count ranging over makearrayptr", n)
panic("fail")
}
}
// test that range over string only evaluates // test that range over string only evaluates
// the expression after "range" once. // the expression after "range" once.
...@@ -216,6 +271,22 @@ func teststring1() { ...@@ -216,6 +271,22 @@ func teststring1() {
} }
} }
func teststring2() {
n := 0
nmake = 0
for range makestring() {
n++
}
if nmake != 1 {
println("range called makestring", nmake, "times")
panic("fail")
}
if n != 5 {
println("wrong count ranging over makestring", n)
panic("fail")
}
}
// test that range over map only evaluates // test that range over map only evaluates
// the expression after "range" once. // the expression after "range" once.
...@@ -256,6 +327,22 @@ func testmap1() { ...@@ -256,6 +327,22 @@ func testmap1() {
} }
} }
func testmap2() {
n := 0
nmake = 0
for range makemap() {
n++
}
if nmake != 1 {
println("range called makemap", nmake, "times")
panic("fail")
}
if n != 5 {
println("wrong count ranging over makemap", n)
panic("fail")
}
}
// test that range evaluates the index and value expressions // test that range evaluates the index and value expressions
// exactly once per iteration. // exactly once per iteration.
...@@ -298,13 +385,18 @@ func main() { ...@@ -298,13 +385,18 @@ func main() {
testchan() testchan()
testarray() testarray()
testarray1() testarray1()
testarray2()
testarrayptr() testarrayptr()
testarrayptr1() testarrayptr1()
testarrayptr2()
testslice() testslice()
testslice1() testslice1()
testslice2()
teststring() teststring()
teststring1() teststring1()
teststring2()
testmap() testmap()
testmap1() testmap1()
testmap2()
testcalls() testcalls()
} }
...@@ -97,6 +97,8 @@ func (m intMap) Len() int { return len(m) } ...@@ -97,6 +97,8 @@ func (m intMap) Len() int { return len(m) }
func (m intMap) RangeAll() { func (m intMap) RangeAll() {
for _ = range m { for _ = range m {
} }
for range m {
}
} }
func stressMaps() { func stressMaps() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment