go.tools/go/types: fix a couple of std lib test failures

1. handle return statements with zero (but expected) return values
2. indices provided for array or slice composite literals must be integer constants

Added additional test cases.

R=adonovan
CC=golang-dev
https://golang.org/cl/13734043
This commit is contained in:
Robert Griesemer 2013-09-17 10:26:06 -07:00
parent cf1e27bbda
commit 4acd602bea
7 changed files with 71 additions and 19 deletions

View File

@ -8,6 +8,7 @@ package types
import (
"go/ast"
"go/token"
"code.google.com/p/go.tools/go/exact"
)
@ -154,7 +155,9 @@ func (check *checker) assignVar(lhs ast.Expr, x *operand) Type {
return z.typ
}
func (check *checker) initVars(lhs []*Var, rhs []ast.Expr, allowCommaOk bool) {
// If returnPos is valid, initVars is called to type-check the assignment of
// return expressions, and returnPos is the position of the return statement.
func (check *checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
l := len(lhs)
r := len(rhs)
assert(l > 0)
@ -199,8 +202,8 @@ func (check *checker) initVars(lhs []*Var, rhs []ast.Expr, allowCommaOk bool) {
}
}
if allowCommaOk && x.mode == valueok && l == 2 {
// comma-ok expression
if !returnPos.IsValid() && x.mode == valueok && l == 2 {
// comma-ok expression (not permitted with return statements)
x.mode = value
t1 := check.initVar(lhs[0], &x)
@ -216,10 +219,15 @@ func (check *checker) initVars(lhs []*Var, rhs []ast.Expr, allowCommaOk bool) {
}
}
invalidateVars(lhs)
// lhs variables may be function result parameters (return statement);
// use rhs position for properly located error messages
if returnPos.IsValid() {
check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
return
}
check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
invalidateVars(lhs)
}
func (check *checker) assignVars(lhs, rhs []ast.Expr) {
@ -318,7 +326,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
vars[i] = obj
}
check.initVars(vars, rhs, true)
check.initVars(vars, rhs, token.NoPos)
// declare variables
n := scope.Len()

View File

@ -768,14 +768,14 @@ func (check *checker) index(arg ast.Expr, length int64) (i int64, ok bool) {
// the index/size must be of integer type
if !isInteger(x.typ) {
check.invalidArg(x.pos(), "%s must be integer", &x)
check.invalidArg(x.pos(), "index %s must be integer", &x)
return
}
// a constant index/size i must be 0 <= i < length
if x.mode == constant {
if exact.Sign(x.val) < 0 {
check.invalidArg(x.pos(), "%s must not be negative", &x)
check.invalidArg(x.pos(), "index %s must not be negative", &x)
return
}
i, ok = exact.Int64Val(x.val)
@ -806,8 +806,10 @@ func (check *checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64
if i, ok := check.index(kv.Key, length); ok {
if i >= 0 {
index = i
validIndex = true
} else {
check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
}
validIndex = true
}
eval = kv.Value
} else if length >= 0 && index >= length {

View File

@ -473,7 +473,7 @@ func (check *checker) varDecl(obj *Var, typ, init ast.Expr) {
}
if m, _ := init.(*multiExpr); m != nil {
check.initVars(m.lhs, m.rhs, true)
check.initVars(m.lhs, m.rhs, token.NoPos)
return
}

View File

@ -112,12 +112,10 @@ func TestStdfixed(t *testing.T) {
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
"bug251.go", // TODO(gri) incorrect cycle checks for interface types
"bug165.go", // TODO(gri) isComparable not working for incomplete struct type
"bug176.go", // TODO(gri) composite literal array index must be non-negative constant
"bug200.go", // TODO(gri) complete duplicate checking in expr switches
"bug223.go", "bug413.go", "bug459.go", // TODO(gri) complete initialization checks
"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
"bug250.go", // TODO(gri) fix recursive interfaces
"bug326.go", // TODO(gri) assignment doesn't guard against len(rhs) == 0
"bug373.go", // TODO(gri) implement use checks
"bug376.go", // TODO(gri) built-ins must be called (no built-in function expressions)
"issue3924.go", // TODO(gri) && and || produce bool result (not untyped bool)

View File

@ -230,7 +230,7 @@ func (check *checker) stmt(s ast.Stmt, fallthroughOk bool) {
lhs[i] = res
}
if len(s.Results) > 0 || !named {
check.initVars(lhs, s.Results, false)
check.initVars(lhs, s.Results, s.Return)
return
}
} else if len(s.Results) > 0 {

View File

@ -178,6 +178,14 @@ func array_literals() {
_ = A1{2.1 /* ERROR "overflows" */ }
_ = A1{"foo" /* ERROR "cannot convert" */ }
// indices must be integer constants
i := 1
const f = 2.1
const s = "foo"
_ = A1{i /* ERROR "index i must be integer constant" */ : 0}
_ = A1{f /* ERROR "cannot be .* represented" */ : 0}
_ = A1{s /* ERROR "cannot convert" */ : 0}
a0 := [...]int{}
assert(len(a0) == 0)
@ -226,14 +234,22 @@ func slice_literals() {
_ = S0{"foo" /* ERROR "cannot convert" */ }
// indices must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement)
index1 := 1
const index1 = 1
_ = S0{index1: 1}
_ = S0{index2: 2}
_ = S0{index3 /* ERROR "undeclared name" */ : 3}
// indices must be integer constants
i := 1
const f = 2.1
const s = "foo"
_ = S0{i /* ERROR "index i must be integer constant" */ : 0}
_ = S0{f /* ERROR "cannot be .* represented" */ : 0}
_ = S0{s /* ERROR "cannot convert" */ : 0}
}
var index2 int = 2
const index2 int = 2
func map_literals() {
type M0 map[string]int
@ -247,14 +263,14 @@ func map_literals() {
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
// map keys must be resolved correctly
// (for details, see comment in go/parser/parser.go, method parseElement)
key1 := "foo"
_ = M0{key1: 1}
_ = M0{key2: 2}
_ = M0{key3 /* ERROR "undeclared name" */ : 2}
var value int
_ = M1{true: 1, false: 0}
_ = M2{nil: 0, &index2: 1}
_ = M2{nil: 0, &value: 1}
}
var key2 string = "bar"

View File

@ -6,7 +6,35 @@
package stmt0
func assignments() {
func assignments0() (int, int) {
var a, b, c int
var ch chan int
f0 := func() {}
f1 := func() int { return 1 }
f2 := func() (int, int) { return 1, 2 }
f3 := func() (int, int, int) { return 1, 2, 3 }
a, b, c = 1, 2, 3
a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
a = f0 /* ERROR "used as value" */ ()
a = f1()
a = f2 /* ERROR "used as single value" */ ()
a, b = f2()
a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
a, b, c = f3()
a, b = f3 /* ERROR "assignment count mismatch" */ ()
a, b, c = <- /* ERROR "assignment count mismatch" */ ch
return /* ERROR "wrong number of return values" */
return /* ERROR "wrong number of return values" */ 1
return 1, 2
return /* ERROR "wrong number of return values" */ 1, 2, 3
}
func assignments1() {
b, i, f, c, s := false, 1, 1.0, 1i, "foo"
b = i /* ERROR "cannot assign" */
i = f /* ERROR "cannot assign" */
@ -49,7 +77,7 @@ func assignments() {
// test cases for issue 5500
_ = func() (int, bool) {
var m map[int]int
return m /* ERROR "assignment count mismatch" */ [0]
return /* ERROR "wrong number of return values" */ m[0]
}
g := func(int, bool){}