From 4acd602bea6db37389ee5f39bce01267c0fdcfbd Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 17 Sep 2013 10:26:06 -0700 Subject: [PATCH] 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 --- go/types/assignments.go | 18 +++++++++++++----- go/types/expr.go | 8 +++++--- go/types/resolver.go | 2 +- go/types/stdlib_test.go | 2 -- go/types/stmt.go | 2 +- go/types/testdata/expr3.src | 26 +++++++++++++++++++++----- go/types/testdata/stmt0.src | 32 ++++++++++++++++++++++++++++++-- 7 files changed, 71 insertions(+), 19 deletions(-) diff --git a/go/types/assignments.go b/go/types/assignments.go index 569d46fe..2f44dede 100644 --- a/go/types/assignments.go +++ b/go/types/assignments.go @@ -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() diff --git a/go/types/expr.go b/go/types/expr.go index e71b2d96..8a8151fc 100644 --- a/go/types/expr.go +++ b/go/types/expr.go @@ -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 { diff --git a/go/types/resolver.go b/go/types/resolver.go index 2832ae03..0c0ea5cc 100644 --- a/go/types/resolver.go +++ b/go/types/resolver.go @@ -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 } diff --git a/go/types/stdlib_test.go b/go/types/stdlib_test.go index b84d00d0..e971d08d 100644 --- a/go/types/stdlib_test.go +++ b/go/types/stdlib_test.go @@ -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) diff --git a/go/types/stmt.go b/go/types/stmt.go index b0415c01..8b097801 100644 --- a/go/types/stmt.go +++ b/go/types/stmt.go @@ -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 { diff --git a/go/types/testdata/expr3.src b/go/types/testdata/expr3.src index 4eca42b2..a91c7ea7 100644 --- a/go/types/testdata/expr3.src +++ b/go/types/testdata/expr3.src @@ -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" diff --git a/go/types/testdata/stmt0.src b/go/types/testdata/stmt0.src index 24b54b97..5317fc85 100644 --- a/go/types/testdata/stmt0.src +++ b/go/types/testdata/stmt0.src @@ -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){}