From 579c61d653de0000e117b12a5fe268d6253193f8 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 10 Oct 2013 11:05:46 -0700 Subject: [PATCH] go.tools/go/types: more robust handling of ... errors with built-ins Catch ... errors earlier and in case of error, type-check all arguments anyway for better type reporting and fewer "declared but not used" errors. R=adonovan CC=golang-dev https://golang.org/cl/14600043 --- go/types/builtins.go | 17 +++++++++-------- go/types/call.go | 17 +++++++++++------ go/types/testdata/builtins.src | 2 -- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/go/types/builtins.go b/go/types/builtins.go index 4ffafe3a..cc70e2c2 100644 --- a/go/types/builtins.go +++ b/go/types/builtins.go @@ -19,6 +19,14 @@ import ( // false, and *x is undefined. // func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) { + // append is the only built-in that permits the use of ... for the last argument + 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) + return + } + // determine actual arguments var arg getter nargs := len(call.Args) @@ -34,14 +42,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b } } case _Make, _New, _Offsetof, _Trace: - // arguments requires special handling - } - - // append is the only built-in that permits the use of ... for the last argument - bin := predeclaredFuncs[id] - if call.Ellipsis.IsValid() && id != _Append { - check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) - return + // arguments require special handling } // check argument count diff --git a/go/types/call.go b/go/types/call.go index 7dd7bd4d..f665b2cc 100644 --- a/go/types/call.go +++ b/go/types/call.go @@ -16,12 +16,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind { switch x.mode { case invalid: - // We don't have a valid call or conversion but we have a list of arguments. - // Typecheck them independently for better partial type information in - // the presence of type errors. - for _, arg := range e.Args { - check.expr(x, arg) - } + check.use(e.Args) x.mode = invalid x.expr = e return statement @@ -85,6 +80,16 @@ 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 +// (and variables are "used") in the presence of other errors. +func (check *checker) use(list []ast.Expr) { + var x operand + for _, e := range list { + check.rawExpr(&x, e, nil) + } +} + // TODO(gri) use unpack for assignment checking as well. // A getter sets x as the i'th operand, where 0 <= i < n and n is the total diff --git a/go/types/testdata/builtins.src b/go/types/testdata/builtins.src index ce75d0ed..12898051 100644 --- a/go/types/testdata/builtins.src +++ b/go/types/testdata/builtins.src @@ -629,7 +629,6 @@ func Offsetof1() { _ = unsafe.Offsetof(y2 /* ERROR method value */ .m) var s []byte - _ = s _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ ) } @@ -731,7 +730,6 @@ func trace1() { // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar") var s []byte - _ = s trace(s... /* ERROR invalid use of \.\.\. */ ) }