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:
parent
cf1e27bbda
commit
4acd602bea
|
@ -8,6 +8,7 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/go/exact"
|
"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
|
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)
|
l := len(lhs)
|
||||||
r := len(rhs)
|
r := len(rhs)
|
||||||
assert(l > 0)
|
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 {
|
if !returnPos.IsValid() && x.mode == valueok && l == 2 {
|
||||||
// comma-ok expression
|
// comma-ok expression (not permitted with return statements)
|
||||||
x.mode = value
|
x.mode = value
|
||||||
t1 := check.initVar(lhs[0], &x)
|
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);
|
// lhs variables may be function result parameters (return statement);
|
||||||
// use rhs position for properly located error messages
|
// 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)
|
check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
|
||||||
invalidateVars(lhs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (check *checker) assignVars(lhs, rhs []ast.Expr) {
|
func (check *checker) assignVars(lhs, rhs []ast.Expr) {
|
||||||
|
@ -318,7 +326,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
|
||||||
vars[i] = obj
|
vars[i] = obj
|
||||||
}
|
}
|
||||||
|
|
||||||
check.initVars(vars, rhs, true)
|
check.initVars(vars, rhs, token.NoPos)
|
||||||
|
|
||||||
// declare variables
|
// declare variables
|
||||||
n := scope.Len()
|
n := scope.Len()
|
||||||
|
|
|
@ -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
|
// the index/size must be of integer type
|
||||||
if !isInteger(x.typ) {
|
if !isInteger(x.typ) {
|
||||||
check.invalidArg(x.pos(), "%s must be integer", &x)
|
check.invalidArg(x.pos(), "index %s must be integer", &x)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// a constant index/size i must be 0 <= i < length
|
// a constant index/size i must be 0 <= i < length
|
||||||
if x.mode == constant {
|
if x.mode == constant {
|
||||||
if exact.Sign(x.val) < 0 {
|
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
|
return
|
||||||
}
|
}
|
||||||
i, ok = exact.Int64Val(x.val)
|
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, ok := check.index(kv.Key, length); ok {
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
index = i
|
index = i
|
||||||
}
|
|
||||||
validIndex = true
|
validIndex = true
|
||||||
|
} else {
|
||||||
|
check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
eval = kv.Value
|
eval = kv.Value
|
||||||
} else if length >= 0 && index >= length {
|
} else if length >= 0 && index >= length {
|
||||||
|
|
|
@ -473,7 +473,7 @@ func (check *checker) varDecl(obj *Var, typ, init ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if m, _ := init.(*multiExpr); m != nil {
|
if m, _ := init.(*multiExpr); m != nil {
|
||||||
check.initVars(m.lhs, m.rhs, true)
|
check.initVars(m.lhs, m.rhs, token.NoPos)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -112,12 +112,10 @@ func TestStdfixed(t *testing.T) {
|
||||||
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
|
"bug136.go", "bug179.go", "bug344.go", // TODO(gri) implement missing label checks
|
||||||
"bug251.go", // TODO(gri) incorrect cycle checks for interface types
|
"bug251.go", // TODO(gri) incorrect cycle checks for interface types
|
||||||
"bug165.go", // TODO(gri) isComparable not working for incomplete struct type
|
"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
|
"bug200.go", // TODO(gri) complete duplicate checking in expr switches
|
||||||
"bug223.go", "bug413.go", "bug459.go", // TODO(gri) complete initialization checks
|
"bug223.go", "bug413.go", "bug459.go", // TODO(gri) complete initialization checks
|
||||||
"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
|
"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
|
||||||
"bug250.go", // TODO(gri) fix recursive interfaces
|
"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
|
"bug373.go", // TODO(gri) implement use checks
|
||||||
"bug376.go", // TODO(gri) built-ins must be called (no built-in function expressions)
|
"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)
|
"issue3924.go", // TODO(gri) && and || produce bool result (not untyped bool)
|
||||||
|
|
|
@ -230,7 +230,7 @@ func (check *checker) stmt(s ast.Stmt, fallthroughOk bool) {
|
||||||
lhs[i] = res
|
lhs[i] = res
|
||||||
}
|
}
|
||||||
if len(s.Results) > 0 || !named {
|
if len(s.Results) > 0 || !named {
|
||||||
check.initVars(lhs, s.Results, false)
|
check.initVars(lhs, s.Results, s.Return)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if len(s.Results) > 0 {
|
} else if len(s.Results) > 0 {
|
||||||
|
|
|
@ -178,6 +178,14 @@ func array_literals() {
|
||||||
_ = A1{2.1 /* ERROR "overflows" */ }
|
_ = A1{2.1 /* ERROR "overflows" */ }
|
||||||
_ = A1{"foo" /* ERROR "cannot convert" */ }
|
_ = 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{}
|
a0 := [...]int{}
|
||||||
assert(len(a0) == 0)
|
assert(len(a0) == 0)
|
||||||
|
|
||||||
|
@ -226,14 +234,22 @@ func slice_literals() {
|
||||||
_ = S0{"foo" /* ERROR "cannot convert" */ }
|
_ = S0{"foo" /* ERROR "cannot convert" */ }
|
||||||
|
|
||||||
// indices must be resolved correctly
|
// indices must be resolved correctly
|
||||||
// (for details, see comment in go/parser/parser.go, method parseElement)
|
const index1 = 1
|
||||||
index1 := 1
|
|
||||||
_ = S0{index1: 1}
|
_ = S0{index1: 1}
|
||||||
_ = S0{index2: 2}
|
_ = S0{index2: 2}
|
||||||
_ = S0{index3 /* ERROR "undeclared name" */ : 3}
|
_ = 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() {
|
func map_literals() {
|
||||||
type M0 map[string]int
|
type M0 map[string]int
|
||||||
|
@ -247,14 +263,14 @@ func map_literals() {
|
||||||
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
|
_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
|
||||||
|
|
||||||
// map keys must be resolved correctly
|
// map keys must be resolved correctly
|
||||||
// (for details, see comment in go/parser/parser.go, method parseElement)
|
|
||||||
key1 := "foo"
|
key1 := "foo"
|
||||||
_ = M0{key1: 1}
|
_ = M0{key1: 1}
|
||||||
_ = M0{key2: 2}
|
_ = M0{key2: 2}
|
||||||
_ = M0{key3 /* ERROR "undeclared name" */ : 2}
|
_ = M0{key3 /* ERROR "undeclared name" */ : 2}
|
||||||
|
|
||||||
|
var value int
|
||||||
_ = M1{true: 1, false: 0}
|
_ = M1{true: 1, false: 0}
|
||||||
_ = M2{nil: 0, &index2: 1}
|
_ = M2{nil: 0, &value: 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
var key2 string = "bar"
|
var key2 string = "bar"
|
||||||
|
|
|
@ -6,7 +6,35 @@
|
||||||
|
|
||||||
package stmt0
|
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, f, c, s := false, 1, 1.0, 1i, "foo"
|
||||||
b = i /* ERROR "cannot assign" */
|
b = i /* ERROR "cannot assign" */
|
||||||
i = f /* ERROR "cannot assign" */
|
i = f /* ERROR "cannot assign" */
|
||||||
|
@ -49,7 +77,7 @@ func assignments() {
|
||||||
// test cases for issue 5500
|
// test cases for issue 5500
|
||||||
_ = func() (int, bool) {
|
_ = func() (int, bool) {
|
||||||
var m map[int]int
|
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){}
|
g := func(int, bool){}
|
||||||
|
|
Loading…
Reference in New Issue