mirror of
https://github.com/golang/go
synced 2024-11-21 19:14:44 -07:00
gc: implement new len spec, range bug fix, optimization
Fixes #885. R=ken2 CC=golang-dev https://golang.org/cl/1680048
This commit is contained in:
parent
f4429181df
commit
81c3e8cabc
@ -24,6 +24,8 @@ typecheckrange(Node *n)
|
|||||||
typecheck(&n->right, Erv);
|
typecheck(&n->right, Erv);
|
||||||
if((t = n->right->type) == T)
|
if((t = n->right->type) == T)
|
||||||
goto out;
|
goto out;
|
||||||
|
if(isptr[t->etype] && isfixedarray(t->type))
|
||||||
|
t = t->type;
|
||||||
n->type = t;
|
n->type = t;
|
||||||
|
|
||||||
switch(t->etype) {
|
switch(t->etype) {
|
||||||
@ -104,9 +106,6 @@ walkrange(Node *n)
|
|||||||
a = nod(OCONV, n->right, N);
|
a = nod(OCONV, n->right, N);
|
||||||
a->type = types[TSTRING];
|
a->type = types[TSTRING];
|
||||||
}
|
}
|
||||||
ha = nod(OXXX, N, N);
|
|
||||||
tempname(ha, a->type);
|
|
||||||
init = list(init, nod(OAS, ha, a));
|
|
||||||
|
|
||||||
v1 = n->list->n;
|
v1 = n->list->n;
|
||||||
hv1 = N;
|
hv1 = N;
|
||||||
@ -116,6 +115,16 @@ walkrange(Node *n)
|
|||||||
v2 = n->list->next->n;
|
v2 = n->list->next->n;
|
||||||
hv2 = N;
|
hv2 = N;
|
||||||
|
|
||||||
|
if(v2 == N && t->etype == TARRAY) {
|
||||||
|
// will have just one reference to argument.
|
||||||
|
// no need to make a potentially expensive copy.
|
||||||
|
ha = a;
|
||||||
|
} else {
|
||||||
|
ha = nod(OXXX, N, N);
|
||||||
|
tempname(ha, a->type);
|
||||||
|
init = list(init, nod(OAS, ha, a));
|
||||||
|
}
|
||||||
|
|
||||||
switch(t->etype) {
|
switch(t->etype) {
|
||||||
default:
|
default:
|
||||||
fatal("walkrange");
|
fatal("walkrange");
|
||||||
@ -131,7 +140,7 @@ walkrange(Node *n)
|
|||||||
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
|
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
|
||||||
if(v2) {
|
if(v2) {
|
||||||
hp = nod(OXXX, N, N);
|
hp = nod(OXXX, N, N);
|
||||||
tempname(hp, ptrto(a->type->type));
|
tempname(hp, ptrto(n->type->type));
|
||||||
tmp = nod(OINDEX, ha, nodintconst(0));
|
tmp = nod(OINDEX, ha, nodintconst(0));
|
||||||
tmp->etype = 1; // no bounds check
|
tmp->etype = 1; // no bounds check
|
||||||
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
|
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
|
||||||
|
@ -802,7 +802,7 @@ reswitch:
|
|||||||
nodconst(n, types[TINT], l->val.u.sval->len);
|
nodconst(n, types[TINT], l->val.u.sval->len);
|
||||||
break;
|
break;
|
||||||
case TARRAY:
|
case TARRAY:
|
||||||
if(t->bound >= 0)
|
if(t->bound >= 0 && l->op == ONAME)
|
||||||
nodconst(n, types[TINT], t->bound);
|
nodconst(n, types[TINT], t->bound);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -594,8 +594,6 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
case OMINUS:
|
case OMINUS:
|
||||||
case OPLUS:
|
case OPLUS:
|
||||||
case OCOM:
|
case OCOM:
|
||||||
case OLEN:
|
|
||||||
case OCAP:
|
|
||||||
case OREAL:
|
case OREAL:
|
||||||
case OIMAG:
|
case OIMAG:
|
||||||
case ODOT:
|
case ODOT:
|
||||||
@ -606,6 +604,22 @@ walkexpr(Node **np, NodeList **init)
|
|||||||
walkexpr(&n->left, init);
|
walkexpr(&n->left, init);
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
||||||
|
case OLEN:
|
||||||
|
case OCAP:
|
||||||
|
walkexpr(&n->left, init);
|
||||||
|
|
||||||
|
// replace len(*[10]int) with 10.
|
||||||
|
// delayed until now to preserve side effects.
|
||||||
|
t = n->left->type;
|
||||||
|
if(isptr[t->etype])
|
||||||
|
t = t->type;
|
||||||
|
if(isfixedarray(t)) {
|
||||||
|
safeexpr(n->left, init);
|
||||||
|
nodconst(n, n->type, t->bound);
|
||||||
|
n->typecheck = 1;
|
||||||
|
}
|
||||||
|
goto ret;
|
||||||
|
|
||||||
case OLSH:
|
case OLSH:
|
||||||
case ORSH:
|
case ORSH:
|
||||||
case OAND:
|
case OAND:
|
||||||
|
199
test/range.go
199
test/range.go
@ -32,18 +32,59 @@ func testchan() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// test that range over array only evaluates
|
// test that range over slice only evaluates
|
||||||
// the expression after "range" once.
|
// the expression after "range" once.
|
||||||
|
|
||||||
var nmake = 0
|
var nmake = 0
|
||||||
|
|
||||||
func makearray() []int {
|
func makeslice() []int {
|
||||||
nmake++
|
nmake++
|
||||||
return []int{1, 2, 3, 4, 5}
|
return []int{1, 2, 3, 4, 5}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testslice() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for _, v := range makeslice() {
|
||||||
|
s += v
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makeslice", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 15 {
|
||||||
|
println("wrong sum ranging over makeslice")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testslice1() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for i := range makeslice() {
|
||||||
|
s += i
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makeslice", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 10 {
|
||||||
|
println("wrong sum ranging over makeslice")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that range over array only evaluates
|
||||||
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
func makearray() [5]int {
|
||||||
|
nmake++
|
||||||
|
return [5]int{1, 2, 3, 4, 5}
|
||||||
|
}
|
||||||
|
|
||||||
func testarray() {
|
func testarray() {
|
||||||
s := 0
|
s := 0
|
||||||
|
nmake = 0
|
||||||
for _, v := range makearray() {
|
for _, v := range makearray() {
|
||||||
s += v
|
s += v
|
||||||
}
|
}
|
||||||
@ -57,6 +98,151 @@ func testarray() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testarray1() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for i := range makearray() {
|
||||||
|
s += i
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makearray", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 10 {
|
||||||
|
println("wrong sum ranging over makearray")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func makearrayptr() *[5]int {
|
||||||
|
nmake++
|
||||||
|
return &[5]int{1, 2, 3, 4, 5}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testarrayptr() {
|
||||||
|
nmake = 0
|
||||||
|
x := len(makearrayptr())
|
||||||
|
if x != 5 || nmake != 1 {
|
||||||
|
println("len called makearrayptr", nmake, "times and got len", x)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
nmake = 0
|
||||||
|
x = cap(makearrayptr())
|
||||||
|
if x != 5 || nmake != 1 {
|
||||||
|
println("cap called makearrayptr", nmake, "times and got len", x)
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for _, v := range makearrayptr() {
|
||||||
|
s += v
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makearrayptr", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 15 {
|
||||||
|
println("wrong sum ranging over makearrayptr")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testarrayptr1() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for i := range makearrayptr() {
|
||||||
|
s += i
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makearrayptr", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 10 {
|
||||||
|
println("wrong sum ranging over makearrayptr")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that range over string only evaluates
|
||||||
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
func makestring() string {
|
||||||
|
nmake++
|
||||||
|
return "abcd☺"
|
||||||
|
}
|
||||||
|
|
||||||
|
func teststring() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for _, v := range makestring() {
|
||||||
|
s += v
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makestring", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 'a'+'b'+'c'+'d'+'☺' {
|
||||||
|
println("wrong sum ranging over makestring")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func teststring1() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for i := range makestring() {
|
||||||
|
s += i
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makestring", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 10 {
|
||||||
|
println("wrong sum ranging over makestring")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that range over map only evaluates
|
||||||
|
// the expression after "range" once.
|
||||||
|
|
||||||
|
func makemap() map[int]int {
|
||||||
|
nmake++
|
||||||
|
return map[int]int{0:'a', 1:'b', 2:'c', 3:'d', 4:'☺'}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testmap() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for _, v := range makemap() {
|
||||||
|
s += v
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makemap", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 'a'+'b'+'c'+'d'+'☺' {
|
||||||
|
println("wrong sum ranging over makemap")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testmap1() {
|
||||||
|
s := 0
|
||||||
|
nmake = 0
|
||||||
|
for i := range makemap() {
|
||||||
|
s += i
|
||||||
|
}
|
||||||
|
if nmake != 1 {
|
||||||
|
println("range called makemap", nmake, "times")
|
||||||
|
panic("fail")
|
||||||
|
}
|
||||||
|
if s != 10 {
|
||||||
|
println("wrong sum ranging over makemap")
|
||||||
|
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.
|
||||||
|
|
||||||
@ -98,5 +284,14 @@ func testcalls() {
|
|||||||
func main() {
|
func main() {
|
||||||
testchan()
|
testchan()
|
||||||
testarray()
|
testarray()
|
||||||
|
testarray1()
|
||||||
|
testarrayptr()
|
||||||
|
testarrayptr1()
|
||||||
|
testslice()
|
||||||
|
testslice1()
|
||||||
|
teststring()
|
||||||
|
teststring1()
|
||||||
|
testmap()
|
||||||
|
testmap1()
|
||||||
testcalls()
|
testcalls()
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user