1
0
mirror of https://github.com/golang/go synced 2024-11-19 00:44:40 -07:00

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
This commit is contained in:
Robert Griesemer 2013-10-10 11:05:46 -07:00
parent f54303d6cb
commit 579c61d653
3 changed files with 20 additions and 16 deletions

View File

@ -19,6 +19,14 @@ import (
// false, and *x is undefined. // false, and *x is undefined.
// //
func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) { 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 // determine actual arguments
var arg getter var arg getter
nargs := len(call.Args) 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: case _Make, _New, _Offsetof, _Trace:
// arguments requires special handling // arguments require 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
} }
// check argument count // check argument count

View File

@ -16,12 +16,7 @@ func (check *checker) call(x *operand, e *ast.CallExpr) exprKind {
switch x.mode { switch x.mode {
case invalid: case invalid:
// We don't have a valid call or conversion but we have a list of arguments. check.use(e.Args)
// Typecheck them independently for better partial type information in
// the presence of type errors.
for _, arg := range e.Args {
check.expr(x, arg)
}
x.mode = invalid x.mode = invalid
x.expr = e x.expr = e
return statement 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. // 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 // A getter sets x as the i'th operand, where 0 <= i < n and n is the total

View File

@ -629,7 +629,6 @@ func Offsetof1() {
_ = unsafe.Offsetof(y2 /* ERROR method value */ .m) _ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
var s []byte var s []byte
_ = s
_ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ ) _ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
} }
@ -731,7 +730,6 @@ func trace1() {
// _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar") // _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
var s []byte var s []byte
_ = s
trace(s... /* ERROR invalid use of \.\.\. */ ) trace(s... /* ERROR invalid use of \.\.\. */ )
} }