go/test/range3.go
Cuong Manh Le 778880b008 cmd/compile: fix typecheck range over negative integer
Before range over integer, types2 leaves constant expression in RHS of
non-constant shift untyped, so idealType do the validation to ensure
that constant value must be an int >= 0.

With range over int, the range expression can also be left untyped, and
can be an negative integer, causing the validation false.

Fixing this by relaxing the validation in idealType, and moving the
check to Unified IR reader.

Fixes #63378

Change-Id: I43042536c09afd98d52c5981adff5dbc5e7d882a
Reviewed-on: https://go-review.googlesource.com/c/go/+/532835
Auto-Submit: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Keith Randall <khr@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
2023-10-09 18:09:34 +00:00

400 lines
5.7 KiB
Go

// run -goexperiment range
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Test the 'for range' construct.
package main
// test range over integers
func testint1() {
bad := false
j := 0
for i := range int(4) {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
}
if j != 4 {
println("wrong count ranging over 4:", j)
bad = true
}
if bad {
panic("testint1")
}
}
func testint2() {
bad := false
j := 0
for i := range 4 {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
}
if j != 4 {
println("wrong count ranging over 4:", j)
bad = true
}
if bad {
panic("testint2")
}
}
func testint3() {
bad := false
type MyInt int
j := MyInt(0)
for i := range MyInt(4) {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
}
if j != 4 {
println("wrong count ranging over 4:", j)
bad = true
}
if bad {
panic("testint3")
}
}
// Issue #63378.
func testint4() {
for i := range -1 {
_ = i
panic("must not be executed")
}
}
// test range over functions
var gj int
func yield4x(yield func() bool) {
_ = yield() && yield() && yield() && yield()
}
func yield4(yield func(int) bool) {
_ = yield(1) && yield(2) && yield(3) && yield(4)
}
func yield3(yield func(int) bool) {
_ = yield(1) && yield(2) && yield(3)
}
func yield2(yield func(int) bool) {
_ = yield(1) && yield(2)
}
func testfunc0() {
j := 0
for range yield4x {
j++
}
if j != 4 {
println("wrong count ranging over yield4x:", j)
panic("testfunc0")
}
j = 0
for _ = range yield4 {
j++
}
if j != 4 {
println("wrong count ranging over yield4:", j)
panic("testfunc0")
}
}
func testfunc1() {
bad := false
j := 1
for i := range yield4 {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
}
if j != 5 {
println("wrong count ranging over f:", j)
bad = true
}
if bad {
panic("testfunc1")
}
}
func testfunc2() {
bad := false
j := 1
var i int
for i = range yield4 {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
}
if j != 5 {
println("wrong count ranging over f:", j)
bad = true
}
if i != 4 {
println("wrong final i ranging over f:", i)
bad = true
}
if bad {
panic("testfunc2")
}
}
func testfunc3() {
bad := false
j := 1
var i int
for i = range yield4 {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
if i == 2 {
break
}
continue
}
if j != 3 {
println("wrong count ranging over f:", j)
bad = true
}
if i != 2 {
println("wrong final i ranging over f:", i)
bad = true
}
if bad {
panic("testfunc3")
}
}
func testfunc4() {
bad := false
j := 1
var i int
func() {
for i = range yield4 {
if i != j {
println("range var", i, "want", j)
bad = true
}
j++
if i == 2 {
return
}
}
}()
if j != 3 {
println("wrong count ranging over f:", j)
bad = true
}
if i != 2 {
println("wrong final i ranging over f:", i)
bad = true
}
if bad {
panic("testfunc3")
}
}
func func5() (int, int) {
for i := range yield4 {
return 10, i
}
panic("still here")
}
func testfunc5() {
x, y := func5()
if x != 10 || y != 1 {
println("wrong results", x, y, "want", 10, 1)
panic("testfunc5")
}
}
func func6() (z, w int) {
for i := range yield4 {
z = 10
w = i
return
}
panic("still here")
}
func testfunc6() {
x, y := func6()
if x != 10 || y != 1 {
println("wrong results", x, y, "want", 10, 1)
panic("testfunc6")
}
}
var saved []int
func save(x int) {
saved = append(saved, x)
}
func printslice(s []int) {
print("[")
for i, x := range s {
if i > 0 {
print(", ")
}
print(x)
}
print("]")
}
func eqslice(s, t []int) bool {
if len(s) != len(t) {
return false
}
for i, x := range s {
if x != t[i] {
return false
}
}
return true
}
func func7() {
defer save(-1)
for i := range yield4 {
defer save(i)
}
defer save(5)
}
func checkslice(name string, saved, want []int) {
if !eqslice(saved, want) {
print("wrong results ")
printslice(saved)
print(" want ")
printslice(want)
print("\n")
panic(name)
}
}
func testfunc7() {
saved = nil
func7()
want := []int{5, 4, 3, 2, 1, -1}
checkslice("testfunc7", saved, want)
}
func func8() {
defer save(-1)
for i := range yield2 {
for j := range yield3 {
defer save(i*10 + j)
}
defer save(i)
}
defer save(-2)
for i := range yield4 {
defer save(i)
}
defer save(-3)
}
func testfunc8() {
saved = nil
func8()
want := []int{-3, 4, 3, 2, 1, -2, 2, 23, 22, 21, 1, 13, 12, 11, -1}
checkslice("testfunc8", saved, want)
}
func func9() {
n := 0
for _ = range yield2 {
for _ = range yield3 {
n++
defer save(n)
}
}
}
func testfunc9() {
saved = nil
func9()
want := []int{6, 5, 4, 3, 2, 1}
checkslice("testfunc9", saved, want)
}
// test that range evaluates the index and value expressions
// exactly once per iteration.
var ncalls = 0
func getvar(p *int) *int {
ncalls++
return p
}
func iter2(list ...int) func(func(int, int) bool) {
return func(yield func(int, int) bool) {
for i, x := range list {
if !yield(i, x) {
return
}
}
}
}
func testcalls() {
var i, v int
ncalls = 0
si := 0
sv := 0
for *getvar(&i), *getvar(&v) = range iter2(1, 2) {
si += i
sv += v
}
if ncalls != 4 {
println("wrong number of calls:", ncalls, "!= 4")
panic("fail")
}
if si != 1 || sv != 3 {
println("wrong sum in testcalls", si, sv)
panic("fail")
}
}
func main() {
testint1()
testint2()
testint3()
testint4()
testfunc0()
testfunc1()
testfunc2()
testfunc3()
testfunc4()
testfunc5()
testfunc6()
testfunc7()
testfunc8()
testfunc9()
testcalls()
}