mirror of
https://github.com/golang/go
synced 2024-11-21 13:44:45 -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);
|
||||
if((t = n->right->type) == T)
|
||||
goto out;
|
||||
if(isptr[t->etype] && isfixedarray(t->type))
|
||||
t = t->type;
|
||||
n->type = t;
|
||||
|
||||
switch(t->etype) {
|
||||
@ -104,9 +106,6 @@ walkrange(Node *n)
|
||||
a = nod(OCONV, n->right, N);
|
||||
a->type = types[TSTRING];
|
||||
}
|
||||
ha = nod(OXXX, N, N);
|
||||
tempname(ha, a->type);
|
||||
init = list(init, nod(OAS, ha, a));
|
||||
|
||||
v1 = n->list->n;
|
||||
hv1 = N;
|
||||
@ -116,6 +115,16 @@ walkrange(Node *n)
|
||||
v2 = n->list->next->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) {
|
||||
default:
|
||||
fatal("walkrange");
|
||||
@ -131,7 +140,7 @@ walkrange(Node *n)
|
||||
init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
|
||||
if(v2) {
|
||||
hp = nod(OXXX, N, N);
|
||||
tempname(hp, ptrto(a->type->type));
|
||||
tempname(hp, ptrto(n->type->type));
|
||||
tmp = nod(OINDEX, ha, nodintconst(0));
|
||||
tmp->etype = 1; // no bounds check
|
||||
init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
|
||||
|
@ -802,7 +802,7 @@ reswitch:
|
||||
nodconst(n, types[TINT], l->val.u.sval->len);
|
||||
break;
|
||||
case TARRAY:
|
||||
if(t->bound >= 0)
|
||||
if(t->bound >= 0 && l->op == ONAME)
|
||||
nodconst(n, types[TINT], t->bound);
|
||||
break;
|
||||
}
|
||||
|
@ -594,8 +594,6 @@ walkexpr(Node **np, NodeList **init)
|
||||
case OMINUS:
|
||||
case OPLUS:
|
||||
case OCOM:
|
||||
case OLEN:
|
||||
case OCAP:
|
||||
case OREAL:
|
||||
case OIMAG:
|
||||
case ODOT:
|
||||
@ -606,6 +604,22 @@ walkexpr(Node **np, NodeList **init)
|
||||
walkexpr(&n->left, init);
|
||||
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 ORSH:
|
||||
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.
|
||||
|
||||
var nmake = 0
|
||||
|
||||
func makearray() []int {
|
||||
func makeslice() []int {
|
||||
nmake++
|
||||
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() {
|
||||
s := 0
|
||||
nmake = 0
|
||||
for _, v := range makearray() {
|
||||
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
|
||||
// exactly once per iteration.
|
||||
|
||||
@ -98,5 +284,14 @@ func testcalls() {
|
||||
func main() {
|
||||
testchan()
|
||||
testarray()
|
||||
testarray1()
|
||||
testarrayptr()
|
||||
testarrayptr1()
|
||||
testslice()
|
||||
testslice1()
|
||||
teststring()
|
||||
teststring1()
|
||||
testmap()
|
||||
testmap1()
|
||||
testcalls()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user