diff --git a/go/types/assignments.go b/go/types/assignments.go index 4d041b853c4..0af71d563b8 100644 --- a/go/types/assignments.go +++ b/go/types/assignments.go @@ -210,12 +210,13 @@ func (check *checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) l := len(lhs) get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid()) if l != r { - // invalidate lhs + // invalidate lhs and use rhs for _, obj := range lhs { if obj.typ == nil { obj.typ = Typ[Invalid] } } + check.use(rhs...) if returnPos.IsValid() { check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r) return @@ -246,6 +247,7 @@ func (check *checker) assignVars(lhs, rhs []ast.Expr) { get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2) if l != r { check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r) + check.use(rhs...) return } diff --git a/go/types/builtins.go b/go/types/builtins.go index 3f3254250b9..ebe8302498b 100644 --- a/go/types/builtins.go +++ b/go/types/builtins.go @@ -23,7 +23,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b bin := predeclaredFuncs[id] if call.Ellipsis.IsValid() && id != _Append { check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) - check.use(call.Args) + check.use(call.Args...) return } @@ -481,7 +481,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b selx, _ := unparen(arg0).(*ast.SelectorExpr) if selx == nil { check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0) - check.rawExpr(x, arg0, nil) // evaluate to avoid spurious "declared but not used" errors + check.use(arg0) return } check.expr(x, selx.X) diff --git a/go/types/call.go b/go/types/call.go index 7bcf216d981..74f888721e2 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -16,7 +16,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind { switch x.mode { case invalid: - check.use(e.Args) + check.use(e.Args...) x.mode = invalid x.expr = e return statement @@ -82,12 +82,12 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind { } } -// use type-checks each list element. -// Useful to make sure a list of expressions is evaluated +// use type-checks each argument. +// Useful to make sure expressions are evaluated // (and variables are "used") in the presence of other errors. -func (check *checker) use(list []ast.Expr) { +func (check *checker) use(arg ...ast.Expr) { var x operand - for _, e := range list { + for _, e := range arg { check.rawExpr(&x, e, nil) } } diff --git a/go/types/resolver.go b/go/types/resolver.go index f674befc103..6dea18b4fdb 100644 --- a/go/types/resolver.go +++ b/go/types/resolver.go @@ -57,9 +57,11 @@ func (check *checker) arityMatch(s, init *ast.ValueSpec) { // init exprs from s n := s.Values[l] check.errorf(n.Pos(), "extra init expr %s", n) + // TODO(gri) avoid declared but not used error here } else { // init exprs "inherited" check.errorf(s.Pos(), "extra init expr at %s", init.Pos()) + // TODO(gri) avoid declared but not used error here } case l > r && (init != nil || r != 1): n := s.Names[r] diff --git a/go/types/stmt.go b/go/types/stmt.go index 90505184aa8..92fd730e092 100644 --- a/go/types/stmt.go +++ b/go/types/stmt.go @@ -341,6 +341,7 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) { } } else if len(s.Results) > 0 { check.error(s.Results[0].Pos(), "no result values expected") + check.use(s.Results...) } case *ast.BranchStmt: diff --git a/go/types/testdata/vardecl.src b/go/types/testdata/vardecl.src index c597914b958..329f4ffe26e 100644 --- a/go/types/testdata/vardecl.src +++ b/go/types/testdata/vardecl.src @@ -5,6 +5,7 @@ package vardecl // Prerequisites. +import "math" func f() {} func g() (x, y int) { return } var m map[string]int @@ -147,6 +148,26 @@ func (r T) _(a, b, c int) (u, v, w int) { return } +// Invalid (unused) expressions must not lead to spurious "declared but not used errors" +func _() { + var a, b, c int + var x, y int + x, y = a /* ERROR assignment count mismatch */ , b, c + _ = x + _ = y +} + +func _() { + var x int + return x /* ERROR no result values expected */ + return math /* ERROR no result values expected */ .Sin(0) +} + +func _() int { + var x, y int + return /* ERROR wrong number of return values */ x, y +} + // Short variable declarations must declare at least one new non-blank variable. func _() { _ := /* ERROR no new variables */ 0