aboutsummaryrefslogtreecommitdiff
path: root/src/go
diff options
context:
space:
mode:
authorRob Findley <rfindley@google.com>2020-10-19 11:51:17 -0400
committerRobert Findley <rfindley@google.com>2020-10-30 14:13:03 +0000
commit733c4af41d2e89d18cfb039e0107336a4c1ec220 (patch)
treedd690132c110447b802de7b1b08c89635df192ca /src/go
parentf7e26467b4e7ee0bb3219c26e71292ff4aac7da9 (diff)
downloadgo-733c4af41d2e89d18cfb039e0107336a4c1ec220.tar.gz
go-733c4af41d2e89d18cfb039e0107336a4c1ec220.zip
go/types: add internal error codes
Tools using go/types sometimes need to implement special handling for certain errors produced by the type-checker. They can offer suggested fixes, expand the error position to surrounding syntax, highlight related syntax (for example in the case of a declaration cycle), link to additional documentation, group errors by category, or correlate errors with signals produced by other static analysis tools. All these require a notion of error identity. Tools need to be able to reliably determine the nature of an error without re-implementing type checking logic or parsing error messages. This CL is a first-pass at adding such an identifier to types.Error: a (for the moment unexported) field containing one of many declared errorCode constants. A wide variety of error code constants are defined, and assigned to type checker errors according to their 'functional equivalence', meaning that they should be ideally be stable under refactoring. With few exceptions, each error code is documented with an example that produces it. This is enforced by tests. When error codes are exported they will represent quite a large API surface. For this reason, as well as the likelihood that error codes will change at the start, both the code field and the codes themselves are initially unexported. gopls will read these fields using reflection during this experimental phase. Others can obviously do the same, provided they accept the lack of forward compatibility. For #42290 Change-Id: I15e3c2bffd2046c20297b1857057d421f633098a Reviewed-on: https://go-review.googlesource.com/c/go/+/264179 Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org> Trust: Robert Griesemer <gri@golang.org> Trust: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/go')
-rw-r--r--src/go/types/api.go10
-rw-r--r--src/go/types/assignments.go37
-rw-r--r--src/go/types/builtins.go88
-rw-r--r--src/go/types/call.go36
-rw-r--r--src/go/types/check.go4
-rw-r--r--src/go/types/check_test.go11
-rw-r--r--src/go/types/conversions.go4
-rw-r--r--src/go/types/decl.go18
-rw-r--r--src/go/types/errorcodes.go1361
-rw-r--r--src/go/types/errorcodes_test.go197
-rw-r--r--src/go/types/errors.go40
-rw-r--r--src/go/types/expr.go127
-rw-r--r--src/go/types/initorder.go6
-rw-r--r--src/go/types/labels.go14
-rw-r--r--src/go/types/operand.go24
-rw-r--r--src/go/types/resolver.go35
-rw-r--r--src/go/types/self_test.go8
-rw-r--r--src/go/types/stmt.go77
-rw-r--r--src/go/types/testdata/cycles.src8
-rw-r--r--src/go/types/testdata/expr3.src20
-rw-r--r--src/go/types/typexpr.go58
21 files changed, 1906 insertions, 277 deletions
diff --git a/src/go/types/api.go b/src/go/types/api.go
index 1abcd9d951..abe1f9f862 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -43,6 +43,13 @@ type Error struct {
Pos token.Pos // error position
Msg string // error message
Soft bool // if set, error is "soft"
+
+ // go116code is a future API, unexported as the set of error codes is large
+ // and likely to change significantly during experimentation. Tools wishing
+ // to preview this feature may read go116code using reflection (see
+ // errorcodes_test.go), but beware that there is no guarantee of future
+ // compatibility.
+ go116code errorCode
}
// Error returns an error string formatted as follows:
@@ -370,7 +377,8 @@ func AssertableTo(V *Interface, T Type) bool {
// AssignableTo reports whether a value of type V is assignable to a variable of type T.
func AssignableTo(V, T Type) bool {
x := operand{mode: value, typ: V}
- return x.assignableTo(nil, T, nil) // check not needed for non-constant x
+ ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x
+ return ok
}
// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
index 4e8ec278fc..c099d11c25 100644
--- a/src/go/types/assignments.go
+++ b/src/go/types/assignments.go
@@ -38,7 +38,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
// complex, or string constant."
if T == nil || IsInterface(T) {
if T == nil && x.typ == Typ[UntypedNil] {
- check.errorf(x.pos(), "use of untyped nil in %s", context)
+ check.errorf(x.pos(), _UntypedNil, "use of untyped nil in %s", context)
x.mode = invalid
return
}
@@ -46,13 +46,13 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
}
if err := check.canConvertUntyped(x, target); err != nil {
var internalErr Error
- var msg string
+ msg := err.Error()
+ code := _IncompatibleAssign
if errors.As(err, &internalErr) {
msg = internalErr.Msg
- } else {
- msg = err.Error()
+ code = internalErr.go116code
}
- check.errorf(x.pos(), "cannot use %s as %s value in %s: %v", x, target, context, msg)
+ check.errorf(x.pos(), code, "cannot use %s as %s value in %s: %v", x, target, context, msg)
x.mode = invalid
return
}
@@ -66,11 +66,12 @@ func (check *Checker) assignment(x *operand, T Type, context string) {
return
}
- if reason := ""; !x.assignableTo(check, T, &reason) {
+ reason := ""
+ if ok, code := x.assignableTo(check, T, &reason); !ok {
if reason != "" {
- check.errorf(x.pos(), "cannot use %s as %s value in %s: %s", x, T, context, reason)
+ check.errorf(x.pos(), code, "cannot use %s as %s value in %s: %s", x, T, context, reason)
} else {
- check.errorf(x.pos(), "cannot use %s as %s value in %s", x, T, context)
+ check.errorf(x.pos(), code, "cannot use %s as %s value in %s", x, T, context)
}
x.mode = invalid
}
@@ -86,7 +87,7 @@ func (check *Checker) initConst(lhs *Const, x *operand) {
// rhs must be a constant
if x.mode != constant_ {
- check.errorf(x.pos(), "%s is not constant", x)
+ check.errorf(x.pos(), _InvalidConstInit, "%s is not constant", x)
if lhs.typ == nil {
lhs.typ = Typ[Invalid]
}
@@ -121,7 +122,7 @@ func (check *Checker) initVar(lhs *Var, x *operand, context string) Type {
if isUntyped(typ) {
// convert untyped types to default types
if typ == Typ[UntypedNil] {
- check.errorf(x.pos(), "use of untyped nil in %s", context)
+ check.errorf(x.pos(), _UntypedNil, "use of untyped nil in %s", context)
lhs.typ = Typ[Invalid]
return nil
}
@@ -195,11 +196,11 @@ func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
var op operand
check.expr(&op, sel.X)
if op.mode == mapindex {
- check.errorf(z.pos(), "cannot assign to struct field %s in map", ExprString(z.expr))
+ check.errorf(z.pos(), _UnaddressableFieldAssign, "cannot assign to struct field %s in map", ExprString(z.expr))
return nil
}
}
- check.errorf(z.pos(), "cannot assign to %s", &z)
+ check.errorf(z.pos(), _UnassignableOperand, "cannot assign to %s", &z)
return nil
}
@@ -228,10 +229,10 @@ func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos)
}
check.useGetter(get, r)
if returnPos.IsValid() {
- check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
+ check.errorf(returnPos, _WrongResultCount, "wrong number of return values (want %d, got %d)", l, r)
return
}
- check.errorf(rhs[0].Pos(), "cannot initialize %d variables with %d values", l, r)
+ check.errorf(rhs[0].Pos(), _WrongAssignCount, "cannot initialize %d variables with %d values", l, r)
return
}
@@ -266,7 +267,7 @@ func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
}
if l != r {
check.useGetter(get, r)
- check.errorf(rhs[0].Pos(), "cannot assign %d values to %d variables", r, l)
+ check.errorf(rhs[0].Pos(), _WrongAssignCount, "cannot assign %d values to %d variables", r, l)
return
}
@@ -307,7 +308,7 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
if alt, _ := alt.(*Var); alt != nil {
obj = alt
} else {
- check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+ check.errorf(lhs.Pos(), _UnassignableOperand, "cannot assign to %s", lhs)
}
check.recordUse(ident, alt)
} else {
@@ -320,7 +321,7 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
}
} else {
check.useLHS(lhs)
- check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+ check.invalidAST(lhs.Pos(), "cannot declare %s", lhs)
}
if obj == nil {
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
@@ -344,6 +345,6 @@ func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
check.declare(scope, nil, obj, scopePos) // recordObject already called
}
} else {
- check.softErrorf(pos, "no new variables on left side of :=")
+ check.softErrorf(pos, _NoNewVar, "no new variables on left side of :=")
}
}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
index a445ebf1c6..960d1f28bc 100644
--- a/src/go/types/builtins.go
+++ b/src/go/types/builtins.go
@@ -21,7 +21,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// 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.invalidOp(call.Ellipsis, _InvalidDotDotDot, "invalid use of ... with built-in %s", bin.name)
check.use(call.Args...)
return
}
@@ -68,7 +68,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
msg = "too many"
}
if msg != "" {
- check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+ check.invalidOp(call.Rparen, _WrongArgCount, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
return
}
}
@@ -85,7 +85,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
if s, _ := S.Underlying().(*Slice); s != nil {
T = s.elem
} else {
- check.invalidArg(x.pos(), "%s is not a slice", x)
+ check.invalidArg(x.pos(), _InvalidAppend, "%s is not a slice", x)
return
}
@@ -95,23 +95,25 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// spec: "As a special case, append also accepts a first argument assignable
// to type []byte with a second argument of string type followed by ... .
// This form appends the bytes of the string.
- if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check, NewSlice(universeByte), nil) {
- arg(x, 1)
- if x.mode == invalid {
- return
- }
- if isString(x.typ) {
- if check.Types != nil {
- sig := makeSig(S, S, x.typ)
- sig.variadic = true
- check.recordBuiltinType(call.Fun, sig)
+ if nargs == 2 && call.Ellipsis.IsValid() {
+ if ok, _ := x.assignableTo(check, NewSlice(universeByte), nil); ok {
+ arg(x, 1)
+ if x.mode == invalid {
+ return
}
- x.mode = value
- x.typ = S
- break
+ if isString(x.typ) {
+ if check.Types != nil {
+ sig := makeSig(S, S, x.typ)
+ sig.variadic = true
+ check.recordBuiltinType(call.Fun, sig)
+ }
+ x.mode = value
+ x.typ = S
+ break
+ }
+ alist = append(alist, *x)
+ // fallthrough
}
- alist = append(alist, *x)
- // fallthrough
}
// check general case by creating custom signature
@@ -175,7 +177,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
if mode == invalid && typ != Typ[Invalid] {
- check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+ code := _InvalidCap
+ if id == _Len {
+ code = _InvalidLen
+ }
+ check.invalidArg(x.pos(), code, "%s for %s", x, bin.name)
return
}
@@ -190,11 +196,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// close(c)
c, _ := x.typ.Underlying().(*Chan)
if c == nil {
- check.invalidArg(x.pos(), "%s is not a channel", x)
+ check.invalidArg(x.pos(), _InvalidClose, "%s is not a channel", x)
return
}
if c.dir == RecvOnly {
- check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+ check.invalidArg(x.pos(), _InvalidClose, "%s must not be a receive-only channel", x)
return
}
@@ -258,13 +264,13 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// both argument types must be identical
if !check.identical(x.typ, y.typ) {
- check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+ check.invalidArg(x.pos(), _InvalidComplex, "mismatched types %s and %s", x.typ, y.typ)
return
}
// the argument types must be of floating-point type
if !isFloat(x.typ) {
- check.invalidArg(x.pos(), "arguments have type %s, expected floating-point", x.typ)
+ check.invalidArg(x.pos(), _InvalidComplex, "arguments have type %s, expected floating-point", x.typ)
return
}
@@ -318,12 +324,12 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
if dst == nil || src == nil {
- check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+ check.invalidArg(x.pos(), _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
return
}
if !check.identical(dst, src) {
- check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+ check.invalidArg(x.pos(), _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
return
}
@@ -337,7 +343,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// delete(m, k)
m, _ := x.typ.Underlying().(*Map)
if m == nil {
- check.invalidArg(x.pos(), "%s is not a map", x)
+ check.invalidArg(x.pos(), _InvalidDelete, "%s is not a map", x)
return
}
arg(x, 1) // k
@@ -345,8 +351,8 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
return
}
- if !x.assignableTo(check, m.key, nil) {
- check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+ if ok, code := x.assignableTo(check, m.key, nil); !ok {
+ check.invalidArg(x.pos(), code, "%s is not assignable to %s", x, m.key)
return
}
@@ -382,7 +388,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// the argument must be of complex type
if !isComplex(x.typ) {
- check.invalidArg(x.pos(), "argument has type %s, expected complex type", x.typ)
+ code := _InvalidImag
+ if id == _Real {
+ code = _InvalidReal
+ }
+ check.invalidArg(x.pos(), code, "argument has type %s, expected complex type", x.typ)
return
}
@@ -434,11 +444,11 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
case *Map, *Chan:
min = 1
default:
- check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+ check.invalidArg(arg0.Pos(), _InvalidMake, "cannot make %s; type must be slice, map, or channel", arg0)
return
}
if nargs < min || min+1 < nargs {
- check.errorf(call.Pos(), "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
+ check.errorf(call.Pos(), _WrongArgCount, "%v expects %d or %d arguments; found %d", call, min, min+1, nargs)
return
}
types := []Type{T}
@@ -451,7 +461,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
}
}
if len(sizes) == 2 && sizes[0] > sizes[1] {
- check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+ check.invalidArg(call.Args[1].Pos(), _SwappedMakeArgs, "length and capacity swapped")
// safe to continue
}
x.mode = value
@@ -549,7 +559,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
arg0 := call.Args[0]
selx, _ := unparen(arg0).(*ast.SelectorExpr)
if selx == nil {
- check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+ check.invalidArg(arg0.Pos(), _BadOffsetofSyntax, "%s is not a selector expression", arg0)
check.use(arg0)
return
}
@@ -564,18 +574,18 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
obj, index, indirect := check.lookupFieldOrMethod(base, false, check.pkg, sel)
switch obj.(type) {
case nil:
- check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+ check.invalidArg(x.pos(), _MissingFieldOrMethod, "%s has no single field %s", base, sel)
return
case *Func:
// TODO(gri) Using derefStructPtr may result in methods being found
// that don't actually exist. An error either way, but the error
// message is confusing. See: https://play.golang.org/p/al75v23kUy ,
// but go/types reports: "invalid argument: x.m is a method value".
- check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+ check.invalidArg(arg0.Pos(), _InvalidOffsetof, "%s is a method value", arg0)
return
}
if indirect {
- check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+ check.invalidArg(x.pos(), _InvalidOffsetof, "field %s is embedded via a pointer in %s", sel, base)
return
}
@@ -605,15 +615,15 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
// The result of assert is the value of pred if there is no error.
// Note: assert is only available in self-test mode.
if x.mode != constant_ || !isBoolean(x.typ) {
- check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+ check.invalidArg(x.pos(), _Test, "%s is not a boolean constant", x)
return
}
if x.val.Kind() != constant.Bool {
- check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+ check.errorf(x.pos(), _Test, "internal error: value of %s should be a boolean constant", x)
return
}
if !constant.BoolVal(x.val) {
- check.errorf(call.Pos(), "%v failed", call)
+ check.errorf(call.Pos(), _Test, "%v failed", call)
// compile-time assertion failure - safe to continue
}
// result is constant - no need to record signature
diff --git a/src/go/types/call.go b/src/go/types/call.go
index be4cfdf9eb..fd0cfe3b28 100644
--- a/src/go/types/call.go
+++ b/src/go/types/call.go
@@ -29,7 +29,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
x.mode = invalid
switch n := len(e.Args); n {
case 0:
- check.errorf(e.Rparen, "missing argument in conversion to %s", T)
+ check.errorf(e.Rparen, _WrongArgCount, "missing argument in conversion to %s", T)
case 1:
check.expr(x, e.Args[0])
if x.mode != invalid {
@@ -37,7 +37,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
}
default:
check.use(e.Args...)
- check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+ check.errorf(e.Args[n-1].Pos(), _WrongArgCount, "too many arguments in conversion to %s", T)
}
x.expr = e
return conversion
@@ -60,7 +60,7 @@ func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
sig, _ := x.typ.Underlying().(*Signature)
if sig == nil {
- check.invalidOp(x.pos(), "cannot call non-function %s", x)
+ check.invalidOp(x.pos(), _InvalidCall, "cannot call non-function %s", x)
x.mode = invalid
x.expr = e
return statement
@@ -231,13 +231,13 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
if call.Ellipsis.IsValid() {
// last argument is of the form x...
if !sig.variadic {
- check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+ check.errorf(call.Ellipsis, _NonVariadicDotDotDot, "cannot use ... in call to non-variadic %s", call.Fun)
check.useGetter(arg, n)
return
}
if len(call.Args) == 1 && n > 1 {
// f()... is not permitted if f() is multi-valued
- check.errorf(call.Ellipsis, "cannot use ... with %d-valued %s", n, call.Args[0])
+ check.errorf(call.Ellipsis, _InvalidDotDotDotOperand, "cannot use ... with %d-valued %s", n, call.Args[0])
check.useGetter(arg, n)
return
}
@@ -263,7 +263,7 @@ func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature,
n++
}
if n < sig.params.Len() {
- check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun)
+ check.errorf(call.Rparen, _WrongArgCount, "too few arguments in call to %s", call.Fun)
// ok to continue
}
}
@@ -291,18 +291,18 @@ func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token
}
}
default:
- check.errorf(x.pos(), "too many arguments")
+ check.errorf(x.pos(), _WrongArgCount, "too many arguments")
return
}
if ellipsis.IsValid() {
- // argument is of the form x... and x is single-valued
if i != n-1 {
- check.errorf(ellipsis, "can only use ... with matching parameter")
+ check.errorf(ellipsis, _MisplacedDotDotDot, "can only use ... with matching parameter")
return
}
+ // argument is of the form x... and x is single-valued
if _, ok := x.typ.Underlying().(*Slice); !ok && x.typ != Typ[UntypedNil] { // see issue #18268
- check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
+ check.errorf(x.pos(), _InvalidDotDotDotOperand, "cannot use %s as parameter of type %s", x, typ)
return
}
} else if sig.variadic && i >= n-1 {
@@ -365,7 +365,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
}
}
if exp == nil {
- check.errorf(e.Sel.Pos(), "%s not declared by package C", sel)
+ check.errorf(e.Sel.Pos(), _UndeclaredImportedName, "%s not declared by package C", sel)
goto Error
}
check.objDecl(exp, nil)
@@ -373,12 +373,12 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
exp = pkg.scope.Lookup(sel)
if exp == nil {
if !pkg.fake {
- check.errorf(e.Sel.Pos(), "%s not declared by package %s", sel, pkg.name)
+ check.errorf(e.Sel.Pos(), _UndeclaredImportedName, "%s not declared by package %s", sel, pkg.name)
}
goto Error
}
if !exp.Exported() {
- check.errorf(e.Sel.Pos(), "%s not exported by package %s", sel, pkg.name)
+ check.errorf(e.Sel.Pos(), _UnexportedName, "%s not exported by package %s", sel, pkg.name)
// ok to continue
}
}
@@ -431,9 +431,9 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
switch {
case index != nil:
// TODO(gri) should provide actual type where the conflict happens
- check.errorf(e.Sel.Pos(), "ambiguous selector %s.%s", x.expr, sel)
+ check.errorf(e.Sel.Pos(), _AmbiguousSelector, "ambiguous selector %s.%s", x.expr, sel)
case indirect:
- check.errorf(e.Sel.Pos(), "cannot call pointer method %s on %s", sel, x.typ)
+ check.errorf(e.Sel.Pos(), _InvalidMethodExpr, "cannot call pointer method %s on %s", sel, x.typ)
default:
// Check if capitalization of sel matters and provide better error
// message in that case.
@@ -445,11 +445,11 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
changeCase = string(unicode.ToUpper(r)) + sel[1:]
}
if obj, _, _ = check.lookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, changeCase); obj != nil {
- check.errorf(e.Sel.Pos(), "%s.%s undefined (type %s has no field or method %s, but does have %s)", x.expr, sel, x.typ, sel, changeCase)
+ check.errorf(e.Sel.Pos(), _MissingFieldOrMethod, "%s.%s undefined (type %s has no field or method %s, but does have %s)", x.expr, sel, x.typ, sel, changeCase)
break
}
}
- check.errorf(e.Sel.Pos(), "%s.%s undefined (type %s has no field or method %s)", x.expr, sel, x.typ, sel)
+ check.errorf(e.Sel.Pos(), _MissingFieldOrMethod, "%s.%s undefined (type %s has no field or method %s)", x.expr, sel, x.typ, sel)
}
goto Error
}
@@ -464,7 +464,7 @@ func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
m, _ := obj.(*Func)
if m == nil {
// TODO(gri) should check if capitalization of sel matters and provide better error message in that case
- check.errorf(e.Sel.Pos(), "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
+ check.errorf(e.Sel.Pos(), _MissingFieldOrMethod, "%s.%s undefined (type %s has no method %s)", x.expr, sel, x.typ, sel)
goto Error
}
diff --git a/src/go/types/check.go b/src/go/types/check.go
index 007babdf9d..407faa034f 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -217,7 +217,7 @@ func (check *Checker) initFiles(files []*ast.File) {
if name != "_" {
pkg.name = name
} else {
- check.errorf(file.Name.Pos(), "invalid package name _")
+ check.errorf(file.Name.Pos(), _BlankPkgName, "invalid package name _")
}
fallthrough
@@ -225,7 +225,7 @@ func (check *Checker) initFiles(files []*ast.File) {
check.files = append(check.files, file)
default:
- check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+ check.errorf(file.Package, _MismatchedPkgName, "package %s; expected %s", name, pkg.name)
// ignore this file
}
}
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
index e01c3de13b..37b287a20d 100644
--- a/src/go/types/check_test.go
+++ b/src/go/types/check_test.go
@@ -279,6 +279,17 @@ func checkFiles(t *testing.T, testfiles []string) {
return
}
+ for _, err := range errlist {
+ err, ok := err.(Error)
+ if !ok {
+ continue
+ }
+ code := readCode(err)
+ if code == 0 {
+ t.Errorf("missing error code: %v", err)
+ }
+ }
+
// match and eliminate errors;
// we are expecting the following errors
errmap := errMap(t, pkgName, files)
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
index 4a6bddb24c..4f47140aa2 100644
--- a/src/go/types/conversions.go
+++ b/src/go/types/conversions.go
@@ -38,7 +38,7 @@ func (check *Checker) conversion(x *operand, T Type) {
}
if !ok {
- check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+ check.errorf(x.pos(), _InvalidConversion, "cannot convert %s to %s", x, T)
x.mode = invalid
return
}
@@ -81,7 +81,7 @@ func (check *Checker) conversion(x *operand, T Type) {
// exported API call, i.e., when all methods have been type-checked.
func (x *operand) convertibleTo(check *Checker, T Type) bool {
// "x is assignable to T"
- if x.assignableTo(check, T, nil) {
+ if ok, _ := x.assignableTo(check, T, nil); ok {
return true
}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
index a022ec5678..416878d20d 100644
--- a/src/go/types/decl.go
+++ b/src/go/types/decl.go
@@ -15,7 +15,7 @@ func (check *Checker) reportAltDecl(obj Object) {
// We use "other" rather than "previous" here because
// the first declaration seen may not be textually
// earlier in the source.
- check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+ check.errorf(pos, _DuplicateDecl, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
}
}
@@ -26,7 +26,7 @@ func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token
// binding."
if obj.Name() != "_" {
if alt := scope.Insert(obj); alt != nil {
- check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+ check.errorf(obj.Pos(), _DuplicateDecl, "%s redeclared in this block", obj.Name())
check.reportAltDecl(alt)
return
}
@@ -357,16 +357,16 @@ func (check *Checker) cycleError(cycle []Object) {
// cycle? That would be more consistent with other error messages.
i := firstInSrc(cycle)
obj := cycle[i]
- check.errorf(obj.Pos(), "illegal cycle in declaration of %s", obj.Name())
+ check.errorf(obj.Pos(), _InvalidDeclCycle, "illegal cycle in declaration of %s", obj.Name())
for range cycle {
- check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+ check.errorf(obj.Pos(), _InvalidDeclCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented
i++
if i >= len(cycle) {
i = 0
}
obj = cycle[i]
}
- check.errorf(obj.Pos(), "\t%s", obj.Name())
+ check.errorf(obj.Pos(), _InvalidDeclCycle, "\t%s", obj.Name())
}
// firstInSrc reports the index of the object with the "smallest"
@@ -468,7 +468,7 @@ func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
// don't report an error if the type is an invalid C (defined) type
// (issue #22090)
if t.Underlying() != Typ[Invalid] {
- check.errorf(typ.Pos(), "invalid constant type %s", t)
+ check.errorf(typ.Pos(), _InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
return
@@ -694,9 +694,9 @@ func (check *Checker) addMethodDecls(obj *TypeName) {
if alt := mset.insert(m); alt != nil {
switch alt.(type) {
case *Var:
- check.errorf(m.pos, "field and method with the same name %s", m.name)
+ check.errorf(m.pos, _DuplicateFieldAndMethod, "field and method with the same name %s", m.name)
case *Func:
- check.errorf(m.pos, "method %s already declared for %s", m.name, obj)
+ check.errorf(m.pos, _DuplicateMethod, "method %s already declared for %s", m.name, obj)
default:
unreachable()
}
@@ -721,7 +721,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
fdecl := decl.fdecl
check.funcType(sig, fdecl.Recv, fdecl.Type)
if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
- check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
+ check.errorf(fdecl.Pos(), _InvalidInitSig, "func init must have no arguments and no return values")
// ok to continue
}
diff --git a/src/go/types/errorcodes.go b/src/go/types/errorcodes.go
new file mode 100644
index 0000000000..56c2995cff
--- /dev/null
+++ b/src/go/types/errorcodes.go
@@ -0,0 +1,1361 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types
+
+type errorCode int
+
+// This file defines the error codes that can be produced during type-checking.
+// Collectively, these codes provide an identifier that may be used to
+// implement special handling for certain types of errors.
+//
+// Error codes should be fine-grained enough that the exact nature of the error
+// can be easily determined, but coarse enough that they are not an
+// implementation detail of the type checking algorithm. As a rule-of-thumb,
+// errors should be considered equivalent if there is a theoretical refactoring
+// of the type checker in which they are emitted in exactly one place. For
+// example, the type checker emits different error messages for "too many
+// arguments" and "too few arguments", but one can imagine an alternative type
+// checker where this check instead just emits a single "wrong number of
+// arguments", so these errors should have the same code.
+//
+// Error code names should be as brief as possible while retaining accuracy and
+// distinctiveness. In most cases names should start with an adjective
+// describing the nature of the error (e.g. "invalid", "unused", "misplaced"),
+// and end with a noun identifying the relevant language object. For example,
+// "_DuplicateDecl" or "_InvalidSliceExpr". For brevity, naming follows the
+// convention that "bad" implies a problem with syntax, and "invalid" implies a
+// problem with types.
+
+const (
+ _ errorCode = iota
+
+ // _Test is reserved for errors that only apply while in self-test mode.
+ _Test
+
+ /* package names */
+
+ // _BlankPkgName occurs when a package name is the blank identifier "_".
+ //
+ // Per the spec:
+ // "The PackageName must not be the blank identifier."
+ _BlankPkgName
+
+ // _MismatchedPkgName occurs when a file's package name doesn't match the
+ // package name already established by other files.
+ _MismatchedPkgName
+
+ /* initialization */
+
+ // _DuplicateDecl occurs when an identifier is declared multiple times.
+ //
+ // Example:
+ // var x = 1
+ // var x = 2
+ _DuplicateDecl
+
+ // _InvalidInitCycle occurs when an invalid cycle is detected within the
+ // initialization graph.
+ //
+ // Example:
+ // var x int = f()
+ //
+ // func f() int { return x }
+ _InvalidInitCycle
+
+ // _InvalidDeclCycle occurs when a declaration cycle is not valid.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // type T struct {
+ // a [n]int
+ // }
+ //
+ // var n = unsafe.Sizeof(T{})
+ _InvalidDeclCycle
+
+ /* consts */
+
+ // _TruncatedFloat occurs when a float constant is truncated to an integer
+ // value.
+ //
+ // Example:
+ // var _ int = 98.6
+ _TruncatedFloat
+
+ // _NumericOverflow occurs when a numeric constant overflows its target type.
+ //
+ // Example:
+ // var x int8 = 1000
+ _NumericOverflow
+
+ // _InvalidConstInit occurs when a const declaration has a non-constant
+ // initializer.
+ //
+ // Example:
+ // var x int
+ // const _ = x
+ _InvalidConstInit
+
+ // _InvalidConstVal occurs when a const value cannot be converted to its
+ // target type.
+ //
+ // Example:
+ // var x string = 1
+ _InvalidConstVal
+
+ // _InvalidConstType occurs when the underlying type in a const declaration
+ // is not a valid constant type.
+ //
+ // Example:
+ // const c *int = 4
+ _InvalidConstType
+
+ /* operators */
+
+ /* operators > general */
+
+ // _UndefinedOp occurs when an operator is not defined for the type(s) used
+ // in an operation.
+ //
+ // Example:
+ // var c = "a" - "b"
+ _UndefinedOp
+
+ // _MismatchedTypes occurs when operand types are incompatible in a binary
+ // operation.
+ //
+ // Example:
+ // var a = "hello"
+ // var b = 1
+ // var c = a - b
+ _MismatchedTypes
+
+ /* operators > shift */
+
+ // _InvalidShiftCount occurs when the right-hand side of a shift operation is
+ // either non-integer, negative, or too large.
+ //
+ // Example:
+ // var (
+ // x string
+ // y int = 1 << x
+ // )
+ _InvalidShiftCount
+
+ // _InvalidShiftOperand occurs when the shifted operand is not an integer.
+ //
+ // Example:
+ // var s = "hello"
+ // var x = s << 2
+ _InvalidShiftOperand
+
+ /* operators > chan */
+
+ // _InvalidReceive occurs when there is a channel receive from a value that
+ // is either not a channel, or is a send-only channel.
+ //
+ // Example:
+ // func f() {
+ // var x = 1
+ // <-x
+ // }
+ _InvalidReceive
+
+ // _InvalidSend occurs when there is a channel send to a value that is not a
+ // channel, or is a receive-only channel.
+ //
+ // Example:
+ // func f() {
+ // var x = 1
+ // x <- "hello!"
+ // }
+ _InvalidSend
+
+ /* operators > & */
+
+ // _UnaddressableOperand occurs when the & operator is applied to an
+ // unaddressable expression.
+ //
+ // Example:
+ // var x = &1
+ _UnaddressableOperand
+
+ /* operators > * */
+
+ // _InvalidIndirection occurs when a non-pointer value is indirected via the
+ // '*' operator.
+ //
+ // Example:
+ // var x int
+ // var y = *x
+ _InvalidIndirection
+
+ /* operators > index */
+
+ // _NonIndexableOperand occurs when an index operation is applied to a value
+ // that cannot be indexed.
+ //
+ // Example:
+ // var x = 1
+ // var y = x[1]
+ _NonIndexableOperand
+
+ // _InvalidIndex occurs when an index argument is not of integer type,
+ // negative, or out-of-bounds.
+ //
+ // Example:
+ // var s = [...]int{1,2,3}
+ // var x = s[5]
+ //
+ // Example:
+ // var s = []int{1,2,3}
+ // var _ = s[-1]
+ //
+ // Example:
+ // var s = []int{1,2,3}
+ // var i string
+ // var _ = s[i]
+ _InvalidIndex
+
+ // _InvalidSliceExpr occurs when a three-index slice expression (a[x:y:z]) is
+ // applied to a string.
+ //
+ // Example:
+ // var s = "hello"
+ // var x = s[1:2:3]
+ _InvalidSliceExpr
+
+ // _SwappedSliceIndices occurs when constant indices in a slice expression
+ // are decreasing in value.
+ //
+ // Example:
+ // var _ = []int{1,2,3}[2:1]
+ _SwappedSliceIndices
+
+ /* operators > slice */
+
+ // _NonSliceableOperand occurs when a slice operation is applied to a value
+ // whose type is not sliceable, or is unaddressable.
+ //
+ // Example:
+ // var x = [...]int{1, 2, 3}[:1]
+ //
+ // Example:
+ // var x = 1
+ // var y = 1[:1]
+ _NonSliceableOperand
+
+ /* operators > division */
+
+ // _DivByZero occurs when a division operation is provable at compile
+ // time to be a division by zero.
+ //
+ // Example:
+ // const divisor = 0
+ // var x int = 1/divisor
+ _DivByZero
+
+ /* operators > inc/dec */
+
+ // _NonNumericIncDec occurs when an increment or decrement operator is
+ // applied to a non-numeric value.
+ //
+ // Example:
+ // func f() {
+ // var c = "c"
+ // c++
+ // }
+ _NonNumericIncDec
+
+ /* offsetof */
+
+ // _BadOffsetofSyntax occurs when unsafe.Offsetof is called with an argument
+ // that is not a selector expression.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // var x int
+ // var _ = unsafe.Offsetof(x)
+ _BadOffsetofSyntax
+
+ // _InvalidOffsetof occurs when unsafe.Offsetof is called with a method
+ // selector, rather than a field selector, or when the field is embedded via
+ // a pointer.
+ //
+ // Per the spec:
+ //
+ // "If f is an embedded field, it must be reachable without pointer
+ // indirections through fields of the struct. "
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // type T struct { f int }
+ // type S struct { *T }
+ // var s S
+ // var _ = unsafe.Offsetof(s.f)
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // type S struct{}
+ //
+ // func (S) m() {}
+ //
+ // var s S
+ // var _ = unsafe.Offsetof(s.m)
+ _InvalidOffsetof
+
+ // _UnaddressableFieldAssign occurs when trying to assign to a struct field
+ // in a map value.
+ //
+ // Example:
+ // func f() {
+ // m := make(map[string]struct{i int})
+ // m["foo"].i = 42
+ // }
+ _UnaddressableFieldAssign
+
+ /* Labels */
+
+ // _UndeclaredLabel occurs when an undeclared label is jumped to.
+ //
+ // Example:
+ // func f() {
+ // goto L
+ // }
+ _UndeclaredLabel
+
+ // _DuplicateLabel occurs when a label is declared more than once.
+ //
+ // Example:
+ // func f() int {
+ // L:
+ // L:
+ // return 1
+ // }
+ _DuplicateLabel
+
+ // _UnusedLabel occurs when a label is declared but not used.
+ //
+ // Example:
+ // func f() {
+ // L:
+ // }
+ _UnusedLabel
+
+ // _MisplacedLabel occurs when a break or continue label is not on a for,
+ // switch, or select statement.
+ //
+ // Example:
+ // func f() {
+ // L:
+ // a := []int{1,2,3}
+ // for _, e := range a {
+ // if e > 10 {
+ // break L
+ // }
+ // println(a)
+ // }
+ // }
+ _MisplacedLabel
+
+ // _JumpOverDecl occurs when a label jumps over a variable declaration.
+ //
+ // Example:
+ // func f() int {
+ // goto L
+ // x := 2
+ // L:
+ // x++
+ // return x
+ // }
+ _JumpOverDecl
+
+ // _JumpIntoBlock occurs when a forward jump goes to a label inside a nested
+ // block.
+ //
+ // Example:
+ // func f(x int) {
+ // goto L
+ // if x > 0 {
+ // L:
+ // print("inside block")
+ // }
+ // }
+ _JumpIntoBlock
+
+ /* type declarations */
+
+ // _DuplicateFieldAndMethod occurs when an identifier appears as both a field
+ // and method name.
+ //
+ // Example:
+ // type T struct {
+ // m int
+ // }
+ //
+ // func (T) m() {}
+ _DuplicateFieldAndMethod
+
+ // _DuplicateMethod occurs when two methods on the same receiver type have
+ // the same name.
+ //
+ // Example:
+ // type T struct {}
+ // func (T) m() {}
+ // func (T) m(i int) int { return i }
+ _DuplicateMethod
+
+ // _InvalidArrayLen occurs when an array length is not a constant value.
+ //
+ // Example:
+ // var n = 3
+ // var _ = [n]int{}
+ _InvalidArrayLen
+
+ // _BlankIfaceMethod occurs when a method name is '_'.
+ //
+ // Per the spec:
+ // "The name of each explicitly specified method must be unique and not
+ // blank."
+ //
+ // Example:
+ // type T interface {
+ // _(int)
+ // }
+ _BlankIfaceMethod
+
+ // _NotAType occurs when the identifier used as the underlying type in a type
+ // declaration or the right-hand side of a type alias does not denote a type.
+ //
+ // Example:
+ // var S = 2
+ //
+ // type T S
+ _NotAType
+
+ // _IncomparableMapKey occurs when a map key type does not support the == and
+ // != operators.
+ //
+ // Per the spec:
+ // "The comparison operators == and != must be fully defined for operands of
+ // the key type; thus the key type must not be a function, map, or slice."
+ //
+ // Example:
+ // var x map[T]int
+ //
+ // type T []int
+ _IncomparableMapKey
+
+ // _InvalidIfaceEmbed occurs when a non-interface type is embedded in an
+ // interface.
+ //
+ // Example:
+ // type T struct {}
+ //
+ // func (T) m()
+ //
+ // type I interface {
+ // T
+ // }
+ _InvalidIfaceEmbed
+
+ // _InvalidPtrEmbed occurs when an embedded field is of the pointer form *T,
+ // and T itself is itself a pointer, an unsafe.Pointer, or an interface.
+ //
+ // Per the spec:
+ // "An embedded field must be specified as a type name T or as a pointer to
+ // a non-interface type name *T, and T itself may not be a pointer type."
+ //
+ // Example:
+ // type T *int
+ //
+ // type S struct {
+ // *T
+ // }
+ _InvalidPtrEmbed
+
+ // _InvalidTypeCycle occurs when a cycle in type definitions results in a
+ // type that is not well-defined.
+ //
+ // Example:
+ // import "unsafe"
+ //
+ // type T [unsafe.Sizeof(T{})]int
+ _InvalidTypeCycle
+
+ /* function declarations */
+
+ // _MissingInitBody occurs when an init function is missing its body.
+ //
+ // Example:
+ // func init()
+ _MissingInitBody
+
+ // _BadRecv occurs when a method declaration does not have exactly one
+ // receiver parameter.
+ //
+ // Example:
+ // func () _() {}
+ _BadRecv
+
+ // _InvalidRecv occurs when a receiver type expression is not of the form T
+ // or *T, or T is a pointer type.
+ //
+ // Example:
+ // type T struct {}
+ //
+ // func (**T) m() {}
+ _InvalidRecv
+
+ // _MissingReturn occurs when a function with results is missing a return
+ // statement.
+ //
+ // Example:
+ // func f() int {}
+ _MissingReturn
+
+ // _WrongResultCount occurs when a return statement returns an incorrect
+ // number of values.
+ //
+ // Example:
+ // func ReturnOne() int {
+ // return 1, 2
+ // }
+ _WrongResultCount
+
+ // _OutOfScopeResult occurs when the name of a value implicitly returned by
+ // an empty return statement is shadowed in a nested scope.
+ //
+ // Example:
+ // func factor(n int) (i int) {
+ // for i := 2; i < n; i++ {
+ // if n%i == 0 {
+ // return
+ // }
+ // }
+ // return 0
+ // }
+ _OutOfScopeResult
+
+ // _InvalidInitDecl occurs when init is declared as anything other than a
+ // function.
+ //
+ // Example:
+ // var init = 1
+ _InvalidInitDecl
+
+ // _InvalidMainDecl occurs when main is declared as anything other than a
+ // function, in a main package.
+ _InvalidMainDecl
+
+ // _InvalidInitSig occurs when an init function declares parameters or
+ // results.
+ //
+ // Example:
+ // func init() int { return 1 }
+ _InvalidInitSig
+
+ /* imports */
+
+ // _BadImportPath occurs when an import path is not valid.
+ _BadImportPath
+
+ // _BrokenImport occurs when importing a package fails.
+ //
+ // Example:
+ // import "amissingpackage"
+ _BrokenImport
+
+ // _UnusedImport occurs when an import is unused.
+ //
+ // Example:
+ // import "fmt"
+ //
+ // func main() {}
+ _UnusedImport
+
+ // _ImportCRenamed occurs when the special import "C" is renamed. "C" is a
+ // pseudo-package, and must not be renamed.
+ //
+ // Example:
+ // import _ "C"
+ _ImportCRenamed
+
+ // _UndeclaredImportedName occurs when a package-qualified identifier is
+ // undeclared by the imported package.
+ //
+ // Example:
+ // import "go/types"
+ //
+ // var _ = types.NotAnActualIdentifier
+ _UndeclaredImportedName
+
+ // _UnexportedName occurs when a selector refers to an unexported identifier
+ // of an imported package.
+ //
+ // Example:
+ // import "reflect"
+ //
+ // type _ reflect.flag
+ _UnexportedName
+
+ // _InvalidPkgUse occurs when a package identifier is used outside of a
+ // selector expression.
+ //
+ // Example:
+ // import "fmt"
+ //
+ // var _ = fmt
+ _InvalidPkgUse
+
+ /* assignment */
+
+ // _WrongAssignCount occurs when the number of values on the right-hand side
+ // of an assignment or or initialization expression does not match the number
+ // of variables on the left-hand side.
+ //
+ // Example:
+ // var x = 1, 2
+ _WrongAssignCount
+
+ // _UntypedNil occurs when the predeclared (untyped) value nil is used to
+ // initialize a variable declared without an explicit type.
+ //
+ // Example:
+ // var x = nil
+ _UntypedNil
+
+ // _TooManyValues occurs when a function returns too many values for the
+ // expression context in which it is used.
+ //
+ // Example:
+ // func ReturnTwo() (int, int) {
+ // return 1, 2
+ // }
+ //
+ // var x = ReturnTwo()
+ _TooManyValues
+
+ // _MultiValAssignOp occurs when an assignment operation (+=, *=, etc) does
+ // not have single-valued left-hand or right-hand side.
+ //
+ // Per the spec:
+ // "In assignment operations, both the left- and right-hand expression lists
+ // must contain exactly one single-valued expression"
+ //
+ // Example:
+ // func f() int {
+ // x, y := 1, 2
+ // x, y += 1
+ // return x + y
+ // }
+ _MultiValAssignOp
+
+ // _InvalidIfaceAssign occurs when a value of type T is used as an
+ // interface, but T does not implement a method of the expected interface.
+ //
+ // Example:
+ // type I interface {
+ // f()
+ // }
+ //
+ // type T int
+ //
+ // var x I = T(1)
+ _InvalidIfaceAssign
+
+ // _InvalidChanAssign occurs when a chan assignment is invalid.
+ //
+ // Per the spec, a value x is assignable to a channel type T if:
+ // "x is a bidirectional channel value, T is a channel type, x's type V and
+ // T have identical element types, and at least one of V or T is not a
+ // defined type."
+ //
+ // Example:
+ // type T1 chan int
+ // type T2 chan int
+ //
+ // var x T1
+ // // Invalid assignment because both types are named
+ // var _ T2 = x
+ _InvalidChanAssign
+
+ // _IncompatibleAssign occurs when the type of the right-hand side expression
+ // in an assignment cannot be assigned to the type of the variable being
+ // assigned.
+ //
+ // Example:
+ // var x []int
+ // var _ int = x
+ _IncompatibleAssign
+
+ /* assertions */
+
+ // _InvalidAssert occurs when a type assertion is applied to a
+ // value that is not of interface type.
+ //
+ // Example:
+ // var x = 1
+ // var _ = x.(float64)
+ _InvalidAssert
+
+ // _ImpossibleAssert occurs for a type assertion x.(T) when the value x of
+ // interface cannot have dynamic type T, due to a missing or mismatching
+ // method on T.
+ //
+ // Example:
+ // type T int
+ //
+ // func (t *T) m() int { return int(*t) }
+ //
+ // type I interface { m() int }
+ //
+ // var x I
+ // var _ = x.(T)
+ _ImpossibleAssert
+
+ /* conversions */
+
+ // _InvalidConversion occurs when the argument type cannot be converted to the
+ // target.
+ //
+ // See https://golang.org/ref/spec#Conversions for the rules of
+ // convertibility.
+ //
+ // Example:
+ // var x float64
+ // var _ = string(x)
+ _InvalidConversion
+
+ // _UnassignableOperand occurs when the left-hand side of an assignment is
+ // not assignable.
+ //
+ // Example:
+ // func f() {
+ // const c = 1
+ // c = 2
+ // }
+ _UnassignableOperand
+
+ // _InvalidPostDecl occurs when there is a declaration in a for-loop post
+ // statement.
+ //
+ // Example:
+ // func f() {
+ // for i := 0; i < 10; j := 0 {}
+ // }
+ _InvalidPostDecl
+
+ // _UnusedVar occurs when a variable is declared but unused.
+ //
+ // Example:
+ // func f() {
+ // x := 1
+ // }
+ _UnusedVar
+
+ // _NoNewVar occurs when a short variable declaration (':=') does not declare
+ // new variables.
+ //
+ // Example:
+ // func f() {
+ // x := 1
+ // x := 2
+ // }
+ _NoNewVar
+
+ /* dot dot dot */
+
+ // _NonVariadicDotDotDot occurs when a "..." is used on the final argument to
+ // a non-variadic function.
+ //
+ // Example:
+ // func printArgs(s []string) {
+ // for _, a := range s {
+ // println(a)
+ // }
+ // }
+ //
+ // func f() {
+ // s := []string{"a", "b", "c"}
+ // printArgs(s...)
+ // }
+ _NonVariadicDotDotDot
+
+ // _MisplacedDotDotDot occurs when a "..." is used somewhere other than the
+ // final argument to a function call.
+ //
+ // Example:
+ // func printArgs(args ...int) {
+ // for _, a := range args {
+ // println(a)
+ // }
+ // }
+ //
+ // func f() {
+ // a := []int{1,2,3}
+ // printArgs(0, a...)
+ // }
+ _MisplacedDotDotDot
+
+ // _InvalidDotDotDotOperand occurs when a "..." operator is applied to a
+ // single-valued operand.
+ //
+ // Example:
+ // func printArgs(args ...int) {
+ // for _, a := range args {
+ // println(a)
+ // }
+ // }
+ //
+ // func f() {
+ // a := 1
+ // printArgs(a...)
+ // }
+ //
+ // Example:
+ // func args() (int, int) {
+ // return 1, 2
+ // }
+ //
+ // func printArgs(args ...int) {
+ // for _, a := range args {
+ // println(a)
+ // }
+ // }
+ //
+ // func g() {
+ // printArgs(args()...)
+ // }
+ _InvalidDotDotDotOperand
+
+ /* selectors */
+
+ // _MissingFieldOrMethod occurs when a selector references a field or method
+ // that does not exist.
+ //
+ // Example:
+ // type T struct {}
+ //
+ // var x = T{}.f
+ _MissingFieldOrMethod
+
+ // _AmbiguousSelector occurs when a selector is ambiguous.
+ //
+ // Example:
+ // type E1 struct { i int }
+ // type E2 struct { i int }
+ // type T struct { E1; E2 }
+ //
+ // var x T
+ // var _ = x.i
+ _AmbiguousSelector
+
+ /* calls */
+
+ // _InvalidMethodExpr occurs when a pointer method is called but the argument
+ // is not addressable.
+ //
+ // Example:
+ // type T struct {}
+ //
+ // func (*T) m() int { return 1 }
+ //
+ // var _ = T.m(T{})
+ _InvalidMethodExpr
+
+ // _InvalidCall occurs when an expression is called that is not of function
+ // type.
+ //
+ // Example:
+ // var x = "x"
+ // var y = x()
+ _InvalidCall
+
+ // _WrongArgCount occurs when too few or too many arguments are passed by a
+ // function call.
+ //
+ // Example:
+ // func f(i int) {}
+ // var x = f()
+ _WrongArgCount
+
+ /* suspended calls */
+
+ // _InvalidDefer occurs when a deferred expression is not a function call,
+ // for example if the expression is a type conversion.
+ //
+ // Example:
+ // func f(i int) int {
+ // defer int32(i)
+ // return i
+ // }
+ _InvalidDefer
+
+ // _InvalidGo occurs when a go expression is not a function call, for example
+ // if the expression is a type conversion.
+ //
+ // Example:
+ // func f(i int) int {
+ // go int32(i)
+ // return i
+ // }
+ _InvalidGo
+
+ // _UnusedResults occurs when a restricted expression-only built-in function
+ // is suspended via go or defer. Such a suspension discards the results of
+ // these side-effect free built-in functions, and therefore is ineffectual.
+ //
+ // Example:
+ // func f(a []int) int {
+ // defer len(a)
+ // return i
+ // }
+ _UnusedResults
+
+ /* built-in functions */
+
+ // _UncalledBuiltin occurs when a built-in function is used as a
+ // function-valued expression, instead of being called.
+ //
+ // Per the spec:
+ // "The built-in functions do not have standard Go types, so they can only
+ // appear in call expressions; they cannot be used as function values."
+ //
+ // Example:
+ // var _ = copy
+ _UncalledBuiltin
+
+ // _InvalidDotDotDot occurs when a "..." is used in a non-variadic built-in
+ // function.
+ //
+ // Example:
+ // var s = []int{1, 2, 3}
+ // var l = len(s...)
+ _InvalidDotDotDot
+
+ /* built-ins > copy */
+
+ // _InvalidCopy occurs when the arguments are not of slice type or do not
+ // have compatible type.
+ //
+ // See https://golang.org/ref/spec#Appending_and_copying_slices for more
+ // information on the type requirements for the copy built-in.
+ //
+ // Example:
+ // func f() {
+ // var x []int
+ // y := []int64{1,2,3}
+ // copy(x, y)
+ // }
+ _InvalidCopy
+
+ /* built-ins > cap/len */
+
+ // _InvalidCap occurs when an argument to the cap built-in function is not of
+ // supported type.
+ //
+ // See https://golang.org/ref/spec#Length_and_capacity for information on
+ // which underlying types are supported as arguments to cap and len.
+ //
+ // Example:
+ // var s = 2
+ // var x = cap(s)
+ _InvalidCap
+
+ // _InvalidLen occurs when an argument to the len built-in function is not of
+ // supported type.
+ //
+ // See https://golang.org/ref/spec#Length_and_capacity for information on
+ // which underlying types are supported as arguments to cap and len.
+ //
+ // Example:
+ // var s = 2
+ // var x = len(s)
+ _InvalidLen
+
+ /* built-ins > close */
+
+ // _InvalidClose occurs when close(...) is called with an argument that is
+ // not of channel type, or that is a receive-only channel.
+ //
+ // Example:
+ // func f() {
+ // var x int
+ // close(x)
+ // }
+ _InvalidClose
+
+ /* built-ins > make */
+
+ // _SwappedMakeArgs occurs when make is called with three arguments, and its
+ // length argument is larger than its capacity argument.
+ //
+ // Example:
+ // var x = make([]int, 3, 2)
+ _SwappedMakeArgs
+
+ // _InvalidMake occurs when make is called with an unsupported type argument.
+ //
+ // See https://golang.org/ref/spec#Making_slices_maps_and_channels for
+ // information on the types that may be created using make.
+ //
+ // Example:
+ // var x = make(int)
+ _InvalidMake
+
+ /* built-ins > delete */
+
+ // _InvalidDelete occurs when the delete built-in function is called with a
+ // first argument that is not a map.
+ //
+ // Example:
+ // func f() {
+ // m := "hello"
+ // delete(m, "e")
+ // }
+ _InvalidDelete
+
+ /* built-ins > complex/imag/real */
+
+ // _InvalidImag occurs when the imag built-in function is called with an
+ // argument that does not have complex type.
+ //
+ // Example:
+ // var _ = imag(int(1))
+ _InvalidImag
+
+ // _InvalidReal occurs when the real built-in function is called with an
+ // argument that does not have complex type.
+ //
+ // Example:
+ // var _ = real(int(1))
+ _InvalidReal
+
+ // _InvalidComplex occurs when the complex built-in function is called with
+ // arguments with incompatible types.
+ //
+ // Example:
+ // var _ = complex(float32(1), float64(2))
+ _InvalidComplex
+
+ /* built-ins > append */
+
+ // _InvalidAppend occurs when append is called with a first argument that is
+ // not a slice.
+ //
+ // Example:
+ // var _ = append(1, 2)
+ _InvalidAppend
+
+ /* literals */
+
+ // _InvalidLitIndex occurs when the key in a key-value element of a slice or
+ // array literal is not an integer constant.
+ //
+ // Example:
+ // var i = 0
+ // var x = []string{i: "world"}
+ _InvalidLitIndex
+
+ // _OversizeArrayLit occurs when an array literal exceeds its length.
+ //
+ // Example:
+ // var _ = [2]int{1,2,3}
+ _OversizeArrayLit
+
+ // _DuplicateLitKey occurs when an index is duplicated in a slice, array, or
+ // map literal.
+ //
+ // Example:
+ // var _ = []int{0:1, 0:2}
+ //
+ // Example:
+ // var _ = map[string]int{"a": 1, "a": 2}
+ _DuplicateLitKey
+
+ // _BadDotDotDotSyntax occurs when a "..." occurs in a context where it is
+ // not valid.
+ //
+ // Example:
+ // var _ = map[int][...]int{0: {}}
+ _BadDotDotDotSyntax
+
+ // _MissingLitKey occurs when a map literal is missing a key expression.
+ //
+ // Example:
+ // var _ = map[string]int{1}
+ _MissingLitKey
+
+ // _InvalidStructLit occurs when a positional struct literal has an incorrect
+ // number of values.
+ //
+ // Example:
+ // var _ = struct{i, j int}{1,2,3}
+ _InvalidStructLit
+
+ // _UntypedLit occurs when a composite literal omits a required type
+ // identifier.
+ //
+ // Example:
+ // type outer struct{
+ // inner struct { i int }
+ // }
+ //
+ // var _ = outer{inner: {1}}
+ _UntypedLit
+
+ // _MixedStructLit occurs when a struct literal contains a mix of positional
+ // and named elements.
+ //
+ // Example:
+ // var _ = struct{i, j int}{i: 1, 2}
+ _MixedStructLit
+
+ // _InvalidLitField occurs when a field name is not a valid identifier.
+ //
+ // Example:
+ // var _ = struct{i int}{1: 1}
+ _InvalidLitField
+
+ // _MissingLitField occurs when a struct literal refers to a field that does
+ // not exist on the struct type.
+ //
+ // Example:
+ // var _ = struct{i int}{j: 2}
+ _MissingLitField
+
+ // _DuplicateLitField occurs when a struct literal contains duplicated
+ // fields.
+ //
+ // Example:
+ // var _ = struct{i int}{i: 1, i: 2}
+ _DuplicateLitField
+
+ // _UnexportedLitField occurs when a positional struct literal implicitly
+ // assigns an unexported field of an imported type.
+ _UnexportedLitField
+
+ /* control flow */
+
+ // _MisplacedBreak occurs when a break statement is not within a for, switch,
+ // or select statement of the innermost function definition.
+ //
+ // Example:
+ // func f() {
+ // break
+ // }
+ _MisplacedBreak
+
+ // _MisplacedContinue occurs when a continue statement is not within a for
+ // loop of the innermost function definition.
+ //
+ // Example:
+ // func sumeven(n int) int {
+ // proceed := func() {
+ // continue
+ // }
+ // sum := 0
+ // for i := 1; i <= n; i++ {
+ // if i % 2 != 0 {
+ // proceed()
+ // }
+ // sum += i
+ // }
+ // return sum
+ // }
+ _MisplacedContinue
+
+ // _MisplacedFallthrough occurs when a fallthrough statement is not within an
+ // expression switch.
+ //
+ // Example:
+ // func typename(i interface{}) string {
+ // switch i.(type) {
+ // case int64:
+ // fallthrough
+ // case int:
+ // return "int"
+ // }
+ // return "unsupported"
+ // }
+ _MisplacedFallthrough
+
+ // _DuplicateCase occurs when a type or expression switch has duplicate
+ // cases.
+ //
+ // Example:
+ // func printInt(i int) {
+ // switch i {
+ // case 1:
+ // println("one")
+ // case 1:
+ // println("One")
+ // }
+ // }
+ _DuplicateCase
+
+ // _DuplicateDefault occurs when a type or expression switch has multiple
+ // default clauses.
+ //
+ // Example:
+ // func printInt(i int) {
+ // switch i {
+ // case 1:
+ // println("one")
+ // default:
+ // println("One")
+ // default:
+ // println("1")
+ // }
+ // }
+ _DuplicateDefault
+
+ // _BadTypeKeyword occurs when a .(type) expression is used anywhere other
+ // than a type switch.
+ //
+ // Example:
+ // type I interface {
+ // m()
+ // }
+ // var t I
+ // var _ = t.(type)
+ _BadTypeKeyword
+
+ // _InvalidCond occurs when an if condition is not a boolean expression.
+ //
+ // Example:
+ // func checkReturn(i int) {
+ // if i {
+ // panic("non-zero return")
+ // }
+ // }
+ _InvalidCond
+
+ // _InvalidChanRange occurs when a send-only channel used in a range
+ // expression.
+ //
+ // Example:
+ // func sum(c chan<- int) {
+ // s := 0
+ // for i := range c {
+ // s += i
+ // }
+ // }
+ _InvalidChanRange
+
+ // _InvalidIterVar occurs when two iteration variables are used while ranging
+ // over a channel.
+ //
+ // Example:
+ // func f(c chan int) {
+ // for k, v := range c {
+ // println(k, v)
+ // }
+ // }
+ _InvalidIterVar
+
+ // _InvalidRangeExpr occurs when the type of a range expression is not array,
+ // slice, string, map, or channel.
+ //
+ // Example:
+ // func f(i int) {
+ // for j := range i {
+ // println(j)
+ // }
+ // }
+ _InvalidRangeExpr
+
+ // _InvalidSelectCase occurs when a select case is not a channel send or
+ // receive.
+ //
+ // Example:
+ // func checkChan(c <-chan int) bool {
+ // select {
+ // case c:
+ // return true
+ // default:
+ // return false
+ // }
+ // }
+ _InvalidSelectCase
+
+ // _InvalidTypeSwitch occurs when .(type) is used on an expression that is
+ // not of interface type.
+ //
+ // Example:
+ // func f(i int) {
+ // switch x := i.(type) {}
+ // }
+ _InvalidTypeSwitch
+
+ // _InvalidLit occurs when a composite literal expression does not match its
+ // type.
+ //
+ // Example:
+ // type P *struct{
+ // x int
+ // }
+ // var _ = P {}
+ _InvalidLit
+
+ /* miscellaneous codes */
+
+ // _NotAnExpr occurs when a type expression is used where a value expression
+ // is expected.
+ //
+ // Example:
+ // type T struct {}
+ //
+ // func f() {
+ // T
+ // }
+ _NotAnExpr
+
+ // _UnusedExpr occurs when a side-effect free expression is used as a
+ // statement. Such a statement has no effect.
+ //
+ // Example:
+ // func f(i int) {
+ // i*i
+ // }
+ _UnusedExpr
+
+ // _UndeclaredName occurs when an identifier is not declared in the current
+ // scope.
+ //
+ // Example:
+ // var x T
+ _UndeclaredName
+
+ // _InvalidBlank occurs when a blank identifier is used as a value or type.
+ //
+ // Per the spec:
+ // "The blank identifier may appear as an operand only on the left-hand side
+ // of an assignment."
+ //
+ // Example:
+ // var x = _
+ _InvalidBlank
+
+ // _InvalidIota occurs when the predeclared identifier iota is used outside
+ // of a constant declaration.
+ //
+ // Example:
+ // var x = iota
+ _InvalidIota
+
+ // _InvalidUntypedConversion occurs when an there is no valid implicit
+ // conversion from an untyped value satisfying the type constraints of the
+ // context in which it is used.
+ //
+ // Example:
+ // var _ = 1 + ""
+ _InvalidUntypedConversion
+)
diff --git a/src/go/types/errorcodes_test.go b/src/go/types/errorcodes_test.go
new file mode 100644
index 0000000000..5da1cdadfc
--- /dev/null
+++ b/src/go/types/errorcodes_test.go
@@ -0,0 +1,197 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package types_test
+
+import (
+ "fmt"
+ "go/ast"
+ "go/constant"
+ "go/importer"
+ "go/parser"
+ "go/token"
+ "reflect"
+ "strings"
+ "testing"
+
+ . "go/types"
+)
+
+func TestErrorCodeExamples(t *testing.T) {
+ walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
+ t.Run(name, func(t *testing.T) {
+ doc := spec.Doc.Text()
+ examples := strings.Split(doc, "Example:")
+ for i := 1; i < len(examples); i++ {
+ example := examples[i]
+ err := checkExample(t, example)
+ if err == nil {
+ t.Fatalf("no error in example #%d", i)
+ }
+ typerr, ok := err.(Error)
+ if !ok {
+ t.Fatalf("not a types.Error: %v", err)
+ }
+ if got := readCode(typerr); got != value {
+ t.Errorf("%s: example #%d returned code %d (%s), want %d", name, i, got, err, value)
+ }
+ }
+ })
+ })
+}
+
+func walkCodes(t *testing.T, f func(string, int, *ast.ValueSpec)) {
+ t.Helper()
+ fset := token.NewFileSet()
+ files, err := pkgFiles(fset, ".", parser.ParseComments) // from self_test.go
+ if err != nil {
+ t.Fatal(err)
+ }
+ conf := Config{Importer: importer.Default()}
+ info := &Info{
+ Types: make(map[ast.Expr]TypeAndValue),
+ Defs: make(map[*ast.Ident]Object),
+ Uses: make(map[*ast.Ident]Object),
+ }
+ _, err = conf.Check("types", fset, files, info)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, file := range files {
+ for _, decl := range file.Decls {
+ decl, ok := decl.(*ast.GenDecl)
+ if !ok || decl.Tok != token.CONST {
+ continue
+ }
+ for _, spec := range decl.Specs {
+ spec, ok := spec.(*ast.ValueSpec)
+ if !ok || len(spec.Names) == 0 {
+ continue
+ }
+ obj := info.ObjectOf(spec.Names[0])
+ if named, ok := obj.Type().(*Named); ok && named.Obj().Name() == "errorCode" {
+ if len(spec.Names) != 1 {
+ t.Fatalf("bad Code declaration for %q: got %d names, want exactly 1", spec.Names[0].Name, len(spec.Names))
+ }
+ codename := spec.Names[0].Name
+ value := int(constant.Val(obj.(*Const).Val()).(int64))
+ f(codename, value, spec)
+ }
+ }
+ }
+ }
+}
+
+func readCode(err Error) int {
+ v := reflect.ValueOf(err)
+ return int(v.FieldByName("go116code").Int())
+}
+
+func checkExample(t *testing.T, example string) error {
+ t.Helper()
+ fset := token.NewFileSet()
+ src := fmt.Sprintf("package p\n\n%s", example)
+ file, err := parser.ParseFile(fset, "example.go", src, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ conf := Config{
+ FakeImportC: true,
+ Importer: importer.Default(),
+ }
+ _, err = conf.Check("example", fset, []*ast.File{file}, nil)
+ return err
+}
+
+func TestErrorCodeStyle(t *testing.T) {
+ // The set of error codes is large and intended to be self-documenting, so
+ // this test enforces some style conventions.
+ forbiddenInIdent := []string{
+ // use invalid instead
+ "illegal",
+ // words with a common short-form
+ "argument",
+ "assertion",
+ "assignment",
+ "boolean",
+ "channel",
+ "condition",
+ "declaration",
+ "expression",
+ "function",
+ "initial", // use init for initializer, initialization, etc.
+ "integer",
+ "interface",
+ "iterat", // use iter for iterator, iteration, etc.
+ "literal",
+ "operation",
+ "package",
+ "pointer",
+ "receiver",
+ "signature",
+ "statement",
+ "variable",
+ }
+ forbiddenInComment := []string{
+ // lhs and rhs should be spelled-out.
+ "lhs", "rhs",
+ // builtin should be hyphenated.
+ "builtin",
+ // Use dot-dot-dot.
+ "ellipsis",
+ }
+ nameHist := make(map[int]int)
+ longestName := ""
+ maxValue := 0
+
+ walkCodes(t, func(name string, value int, spec *ast.ValueSpec) {
+ if name == "_" {
+ return
+ }
+ nameHist[len(name)]++
+ if value > maxValue {
+ maxValue = value
+ }
+ if len(name) > len(longestName) {
+ longestName = name
+ }
+ if token.IsExported(name) {
+ // This is an experimental API, and errorCode values should not be
+ // exported.
+ t.Errorf("%q is exported", name)
+ }
+ if name[0] != '_' || !token.IsExported(name[1:]) {
+ t.Errorf("%q should start with _, followed by an exported identifier", name)
+ }
+ lower := strings.ToLower(name)
+ for _, bad := range forbiddenInIdent {
+ if strings.Contains(lower, bad) {
+ t.Errorf("%q contains forbidden word %q", name, bad)
+ }
+ }
+ doc := spec.Doc.Text()
+ if !strings.HasPrefix(doc, name) {
+ t.Errorf("doc for %q does not start with identifier", name)
+ }
+ lowerComment := strings.ToLower(strings.TrimPrefix(doc, name))
+ for _, bad := range forbiddenInComment {
+ if strings.Contains(lowerComment, bad) {
+ t.Errorf("doc for %q contains forbidden word %q", name, bad)
+ }
+ }
+ })
+
+ if testing.Verbose() {
+ var totChars, totCount int
+ for chars, count := range nameHist {
+ totChars += chars * count
+ totCount += count
+ }
+ avg := float64(totChars) / float64(totCount)
+ fmt.Println()
+ fmt.Printf("%d error codes\n", totCount)
+ fmt.Printf("average length: %.2f chars\n", avg)
+ fmt.Printf("max length: %d (%s)\n", len(longestName), longestName)
+ }
+}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
index 88e41c5713..b721cb1279 100644
--- a/src/go/types/errors.go
+++ b/src/go/types/errors.go
@@ -110,41 +110,43 @@ func (check *Checker) err(err error) {
f(err)
}
-func (check *Checker) error(pos token.Pos, msg string) {
- check.err(Error{Fset: check.fset, Pos: pos, Msg: msg})
+func (check *Checker) error(pos token.Pos, code errorCode, msg string) {
+ check.err(Error{Fset: check.fset, Pos: pos, Msg: msg, go116code: code})
}
// newErrorf creates a new Error, but does not handle it.
-func (check *Checker) newErrorf(pos token.Pos, format string, args ...interface{}) error {
+func (check *Checker) newErrorf(pos token.Pos, code errorCode, format string, args ...interface{}) error {
return Error{
- Fset: check.fset,
- Pos: pos,
- Msg: check.sprintf(format, args...),
- Soft: false,
+ Fset: check.fset,
+ Pos: pos,
+ Msg: check.sprintf(format, args...),
+ Soft: false,
+ go116code: code,
}
}
-func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
- check.error(pos, check.sprintf(format, args...))
+func (check *Checker) errorf(pos token.Pos, code errorCode, format string, args ...interface{}) {
+ check.error(pos, code, check.sprintf(format, args...))
}
-func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
+func (check *Checker) softErrorf(pos token.Pos, code errorCode, format string, args ...interface{}) {
check.err(Error{
- Fset: check.fset,
- Pos: pos,
- Msg: check.sprintf(format, args...),
- Soft: true,
+ Fset: check.fset,
+ Pos: pos,
+ Msg: check.sprintf(format, args...),
+ Soft: true,
+ go116code: code,
})
}
func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid AST: "+format, args...)
+ check.errorf(pos, 0, "invalid AST: "+format, args...)
}
-func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid argument: "+format, args...)
+func (check *Checker) invalidArg(pos token.Pos, code errorCode, format string, args ...interface{}) {
+ check.errorf(pos, code, "invalid argument: "+format, args...)
}
-func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
- check.errorf(pos, "invalid operation: "+format, args...)
+func (check *Checker) invalidOp(pos token.Pos, code errorCode, format string, args ...interface{}) {
+ check.errorf(pos, code, "invalid operation: "+format, args...)
}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
index 94d98f0fbb..5f3415a59d 100644
--- a/src/go/types/expr.go
+++ b/src/go/types/expr.go
@@ -68,7 +68,7 @@ var unaryOpPredicates = opPredicates{
func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
if pred := m[op]; pred != nil {
if !pred(x.typ) {
- check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+ check.invalidOp(x.pos(), _UndefinedOp, "operator %s not defined for %s", op, x)
return false
}
} else {
@@ -85,7 +85,7 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
// spec: "As an exception to the addressability
// requirement x may also be a composite literal."
if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
- check.invalidOp(x.pos(), "cannot take address of %s", x)
+ check.invalidOp(x.pos(), _UnaddressableOperand, "cannot take address of %s", x)
x.mode = invalid
return
}
@@ -96,12 +96,12 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
case token.ARROW:
typ, ok := x.typ.Underlying().(*Chan)
if !ok {
- check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+ check.invalidOp(x.pos(), _InvalidReceive, "cannot receive from non-channel %s", x)
x.mode = invalid
return
}
if typ.dir == SendOnly {
- check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+ check.invalidOp(x.pos(), _InvalidReceive, "cannot receive from send-only channel %s", x)
x.mode = invalid
return
}
@@ -342,6 +342,7 @@ func (check *Checker) isRepresentable(x *operand, typ *Basic) error {
assert(x.mode == constant_)
if !representableConst(x.val, check, typ, &x.val) {
var msg string
+ var code errorCode
if isNumeric(x.typ) && isNumeric(typ) {
// numeric conversion : error msg
//
@@ -352,13 +353,16 @@ func (check *Checker) isRepresentable(x *operand, typ *Basic) error {
//
if !isInteger(x.typ) && isInteger(typ) {
msg = "%s truncated to %s"
+ code = _TruncatedFloat
} else {
msg = "%s overflows %s"
+ code = _NumericOverflow
}
} else {
msg = "cannot convert %s to %s"
+ code = _InvalidConstVal
}
- return check.newErrorf(x.pos(), msg, x, typ)
+ return check.newErrorf(x.pos(), code, msg, x, typ)
}
return nil
}
@@ -466,7 +470,7 @@ func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
// We already know from the shift check that it is representable
// as an integer if it is a constant.
if !isInteger(typ) {
- check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+ check.invalidOp(x.Pos(), _InvalidShiftOperand, "shifted operand %s (type %s) must be integer", x, typ)
return
}
// Even if we have an integer, if the value is a constant we
@@ -517,7 +521,7 @@ func (check *Checker) canConvertUntyped(x *operand, target Type) error {
check.updateExprType(x.expr, target, false)
}
} else if xkind != tkind {
- return check.newErrorf(x.pos(), "cannot convert %s to %s", x, target)
+ return check.newErrorf(x.pos(), _InvalidUntypedConversion, "cannot convert %s to %s", x, target)
}
return nil
}
@@ -531,7 +535,7 @@ func (check *Checker) canConvertUntyped(x *operand, target Type) error {
} else {
newTarget := check.implicitType(x, target)
if newTarget == nil {
- return check.newErrorf(x.pos(), "cannot convert %s to %s", x, target)
+ return check.newErrorf(x.pos(), _InvalidUntypedConversion, "cannot convert %s to %s", x, target)
}
target = newTarget
}
@@ -608,7 +612,10 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
// spec: "In any comparison, the first operand must be assignable
// to the type of the second operand, or vice versa."
err := ""
- if x.assignableTo(check, y.typ, nil) || y.assignableTo(check, x.typ, nil) {
+ var code errorCode
+ xok, _ := x.assignableTo(check, y.typ, nil)
+ yok, _ := y.assignableTo(check, x.typ, nil)
+ if xok || yok {
defined := false
switch op {
case token.EQL, token.NEQ:
@@ -626,13 +633,15 @@ func (check *Checker) comparison(x, y *operand, op token.Token) {
typ = y.typ
}
err = check.sprintf("operator %s not defined for %s", op, typ)
+ code = _UndefinedOp
}
} else {
err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+ code = _MismatchedTypes
}
if err != "" {
- check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+ check.errorf(x.pos(), code, "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
x.mode = invalid
return
}
@@ -669,7 +678,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
// as an integer. Nothing to do.
} else {
// shift has no chance
- check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+ check.invalidOp(x.pos(), _InvalidShiftOperand, "shifted operand %s must be integer", x)
x.mode = invalid
return
}
@@ -686,7 +695,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
return
}
default:
- check.invalidOp(y.pos(), "shift count %s must be integer", y)
+ check.invalidOp(y.pos(), _InvalidShiftCount, "shift count %s must be integer", y)
x.mode = invalid
return
}
@@ -699,7 +708,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
yval = constant.ToInt(y.val)
assert(yval.Kind() == constant.Int)
if constant.Sign(yval) < 0 {
- check.invalidOp(y.pos(), "negative shift count %s", y)
+ check.invalidOp(y.pos(), _InvalidShiftCount, "negative shift count %s", y)
x.mode = invalid
return
}
@@ -711,7 +720,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
const shiftBound = 1023 - 1 + 52 // so we can express smallestFloat64
s, ok := constant.Uint64Val(yval)
if !ok || s > shiftBound {
- check.invalidOp(y.pos(), "invalid shift count %s", y)
+ check.invalidOp(y.pos(), _InvalidShiftCount, "invalid shift count %s", y)
x.mode = invalid
return
}
@@ -768,7 +777,7 @@ func (check *Checker) shift(x, y *operand, e *ast.BinaryExpr, op token.Token) {
// non-constant shift - lhs must be an integer
if !isInteger(x.typ) {
- check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+ check.invalidOp(x.pos(), _InvalidShiftOperand, "shifted operand %s must be integer", x)
x.mode = invalid
return
}
@@ -832,7 +841,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
// only report an error if we have valid types
// (otherwise we had an error reported elsewhere already)
if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
- check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+ check.invalidOp(x.pos(), _MismatchedTypes, "mismatched types %s and %s", x.typ, y.typ)
}
x.mode = invalid
return
@@ -846,7 +855,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
if op == token.QUO || op == token.REM {
// check for zero divisor
if (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
- check.invalidOp(y.pos(), "division by zero")
+ check.invalidOp(y.pos(), _DivByZero, "division by zero")
x.mode = invalid
return
}
@@ -856,7 +865,7 @@ func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, o
re, im := constant.Real(y.val), constant.Imag(y.val)
re2, im2 := constant.BinaryOp(re, token.MUL, re), constant.BinaryOp(im, token.MUL, im)
if constant.Sign(re2) == 0 && constant.Sign(im2) == 0 {
- check.invalidOp(y.pos(), "division by zero")
+ check.invalidOp(y.pos(), _DivByZero, "division by zero")
x.mode = invalid
return
}
@@ -909,7 +918,7 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) {
// the index must be of integer type
if !isInteger(x.typ) {
- check.invalidArg(x.pos(), "index %s must be integer", &x)
+ check.invalidArg(x.pos(), _InvalidIndex, "index %s must be integer", &x)
return
}
@@ -919,13 +928,13 @@ func (check *Checker) index(index ast.Expr, max int64) (typ Type, val int64) {
// a constant index i must be in bounds
if constant.Sign(x.val) < 0 {
- check.invalidArg(x.pos(), "index %s must not be negative", &x)
+ check.invalidArg(x.pos(), _InvalidIndex, "index %s must not be negative", &x)
return
}
v, valid := constant.Int64Val(constant.ToInt(x.val))
if !valid || max >= 0 && v >= max {
- check.errorf(x.pos(), "index %s is out of bounds", &x)
+ check.errorf(x.pos(), _InvalidIndex, "index %s is out of bounds", &x)
return
}
@@ -951,12 +960,12 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64
index = i
validIndex = true
} else {
- check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+ check.errorf(e.Pos(), _InvalidLitIndex, "index %s must be integer constant", kv.Key)
}
}
eval = kv.Value
} else if length >= 0 && index >= length {
- check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+ check.errorf(e.Pos(), _OversizeArrayLit, "index %d is out of bounds (>= %d)", index, length)
} else {
validIndex = true
}
@@ -964,7 +973,7 @@ func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64
// if we have a valid index, check for duplicate entries
if validIndex {
if visited[index] {
- check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+ check.errorf(e.Pos(), _DuplicateLitKey, "duplicate index %d in array or slice literal", index)
}
visited[index] = true
}
@@ -1054,7 +1063,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *ast.Ellipsis:
// ellipses are handled explicitly where they are legal
// (array composite literals and parameter lists)
- check.error(e.Pos(), "invalid use of '...'")
+ check.error(e.Pos(), _BadDotDotDotSyntax, "invalid use of '...'")
goto Error
case *ast.BasicLit:
@@ -1113,7 +1122,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
default:
// TODO(gri) provide better error messages depending on context
- check.error(e.Pos(), "missing type in composite literal")
+ check.error(e.Pos(), _UntypedLit, "missing type in composite literal")
goto Error
}
@@ -1129,7 +1138,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
for _, e := range e.Elts {
kv, _ := e.(*ast.KeyValueExpr)
if kv == nil {
- check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+ check.error(e.Pos(), _MixedStructLit, "mixture of field:value and value elements in struct literal")
continue
}
key, _ := kv.Key.(*ast.Ident)
@@ -1137,12 +1146,12 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// so we don't drop information on the floor
check.expr(x, kv.Value)
if key == nil {
- check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+ check.errorf(kv.Pos(), _InvalidLitField, "invalid field name %s in struct literal", kv.Key)
continue
}
i := fieldIndex(utyp.fields, check.pkg, key.Name)
if i < 0 {
- check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+ check.errorf(kv.Pos(), _MissingLitField, "unknown field %s in struct literal", key.Name)
continue
}
fld := fields[i]
@@ -1151,7 +1160,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
check.assignment(x, etyp, "struct literal")
// 0 <= i < len(fields)
if visited[i] {
- check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+ check.errorf(kv.Pos(), _DuplicateLitField, "duplicate field name %s in struct literal", key.Name)
continue
}
visited[i] = true
@@ -1160,25 +1169,25 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// no element must have a key
for i, e := range e.Elts {
if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
- check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+ check.error(kv.Pos(), _MixedStructLit, "mixture of field:value and value elements in struct literal")
continue
}
check.expr(x, e)
if i >= len(fields) {
- check.error(x.pos(), "too many values in struct literal")
+ check.error(x.pos(), _InvalidStructLit, "too many values in struct literal")
break // cannot continue
}
// i < len(fields)
fld := fields[i]
if !fld.Exported() && fld.pkg != check.pkg {
- check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+ check.errorf(x.pos(), _UnexportedLitField, "implicit assignment to unexported field %s in %s literal", fld.name, typ)
continue
}
etyp := fld.typ
check.assignment(x, etyp, "struct literal")
}
if len(e.Elts) < len(fields) {
- check.error(e.Rbrace, "too few values in struct literal")
+ check.error(e.Rbrace, _InvalidStructLit, "too few values in struct literal")
// ok to continue
}
}
@@ -1188,7 +1197,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// This is a stop-gap solution. Should use Checker.objPath to report entire
// path starting with earliest declaration in the source. TODO(gri) fix this.
if utyp.elem == nil {
- check.error(e.Pos(), "illegal cycle in type declaration")
+ check.error(e.Pos(), _InvalidTypeCycle, "illegal cycle in type declaration")
goto Error
}
n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
@@ -1215,7 +1224,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// Prevent crash if the slice referred to is not yet set up.
// See analogous comment for *Array.
if utyp.elem == nil {
- check.error(e.Pos(), "illegal cycle in type declaration")
+ check.error(e.Pos(), _InvalidTypeCycle, "illegal cycle in type declaration")
goto Error
}
check.indexedElts(e.Elts, utyp.elem, -1)
@@ -1224,14 +1233,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// Prevent crash if the map referred to is not yet set up.
// See analogous comment for *Array.
if utyp.key == nil || utyp.elem == nil {
- check.error(e.Pos(), "illegal cycle in type declaration")
+ check.error(e.Pos(), _InvalidTypeCycle, "illegal cycle in type declaration")
goto Error
}
visited := make(map[interface{}][]Type, len(e.Elts))
for _, e := range e.Elts {
kv, _ := e.(*ast.KeyValueExpr)
if kv == nil {
- check.error(e.Pos(), "missing key in map literal")
+ check.error(e.Pos(), _MissingLitKey, "missing key in map literal")
continue
}
check.exprWithHint(x, kv.Key, utyp.key)
@@ -1256,7 +1265,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
visited[xkey] = nil
}
if duplicate {
- check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+ check.errorf(x.pos(), _DuplicateLitKey, "duplicate key %s in map literal", x.val)
continue
}
}
@@ -1278,7 +1287,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
// if utyp is invalid, an error was reported before
if utyp != Typ[Invalid] {
- check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+ check.errorf(e.Pos(), _InvalidLit, "invalid composite literal type %s", typ)
goto Error
}
}
@@ -1352,7 +1361,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
if !valid {
- check.invalidOp(x.pos(), "cannot index %s", x)
+ check.invalidOp(x.pos(), _NonIndexableOperand, "cannot index %s", x)
goto Error
}
@@ -1377,7 +1386,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
case *Basic:
if isString(typ) {
if e.Slice3 {
- check.invalidOp(x.pos(), "3-index slice of string")
+ check.invalidOp(x.pos(), _InvalidSliceExpr, "3-index slice of string")
goto Error
}
valid = true
@@ -1395,7 +1404,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
valid = true
length = typ.len
if x.mode != variable {
- check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+ check.invalidOp(x.pos(), _NonSliceableOperand, "cannot slice %s (value not addressable)", x)
goto Error
}
x.typ = &Slice{elem: typ.elem}
@@ -1413,7 +1422,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
if !valid {
- check.invalidOp(x.pos(), "cannot slice %s", x)
+ check.invalidOp(x.pos(), _NonSliceableOperand, "cannot slice %s", x)
goto Error
}
@@ -1421,7 +1430,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
// spec: "Only the first index may be omitted; it defaults to 0."
if e.Slice3 && (e.High == nil || e.Max == nil) {
- check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+ check.invalidAST(e.Rbrack, "2nd and 3rd index required in 3-index slice")
goto Error
}
@@ -1458,7 +1467,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
if x > 0 {
for _, y := range ind[i+1:] {
if y >= 0 && x > y {
- check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+ check.errorf(e.Rbrack, _SwappedSliceIndices, "swapped slice indices: %d > %d", x, y)
break L // only report one error, ok to continue
}
}
@@ -1472,12 +1481,14 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
}
xtyp, _ := x.typ.Underlying().(*Interface)
if xtyp == nil {
- check.invalidOp(x.pos(), "%s is not an interface", x)
+ check.invalidOp(x.pos(), _InvalidAssert, "%s is not an interface", x)
goto Error
}
// x.(type) expressions are handled explicitly in type switches
if e.Type == nil {
- check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+ // Don't use invalidAST because this can occur in the AST produced by
+ // go/parser.
+ check.error(e.Pos(), _BadTypeKeyword, "use of .(type) outside type switch")
goto Error
}
T := check.typ(e.Type)
@@ -1503,7 +1514,7 @@ func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
x.mode = variable
x.typ = typ.base
} else {
- check.invalidOp(x.pos(), "cannot indirect %s", x)
+ check.invalidOp(x.pos(), _InvalidIndirection, "cannot indirect %s", x)
goto Error
}
}
@@ -1597,7 +1608,7 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface,
} else {
msg = "missing method " + method.name
}
- check.errorf(pos, "%s cannot have dynamic type %s (%s)", x, T, msg)
+ check.errorf(pos, _ImpossibleAssert, "%s cannot have dynamic type %s (%s)", x, T, msg)
}
func (check *Checker) singleValue(x *operand) {
@@ -1605,7 +1616,7 @@ func (check *Checker) singleValue(x *operand) {
// tuple types are never named - no need for underlying type below
if t, ok := x.typ.(*Tuple); ok {
assert(t.Len() != 1)
- check.errorf(x.pos(), "%d-valued %s where single value is expected", t.Len(), x)
+ check.errorf(x.pos(), _TooManyValues, "%d-valued %s where single value is expected", t.Len(), x)
x.mode = invalid
}
}
@@ -1624,17 +1635,21 @@ func (check *Checker) expr(x *operand, e ast.Expr) {
func (check *Checker) multiExpr(x *operand, e ast.Expr) {
check.rawExpr(x, e, nil)
var msg string
+ var code errorCode
switch x.mode {
default:
return
case novalue:
msg = "%s used as value"
+ code = _TooManyValues
case builtin:
msg = "%s must be called"
+ code = _UncalledBuiltin
case typexpr:
msg = "%s is not an expression"
+ code = _NotAnExpr
}
- check.errorf(x.pos(), msg, x)
+ check.errorf(x.pos(), code, msg, x)
x.mode = invalid
}
@@ -1647,17 +1662,21 @@ func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
check.rawExpr(x, e, hint)
check.singleValue(x)
var msg string
+ var code errorCode
switch x.mode {
default:
return
case novalue:
msg = "%s used as value"
+ code = _TooManyValues
case builtin:
msg = "%s must be called"
+ code = _UncalledBuiltin
case typexpr:
msg = "%s is not an expression"
+ code = _NotAnExpr
}
- check.errorf(x.pos(), msg, x)
+ check.errorf(x.pos(), code, msg, x)
x.mode = invalid
}
@@ -1668,7 +1687,7 @@ func (check *Checker) exprOrType(x *operand, e ast.Expr) {
check.rawExpr(x, e, nil)
check.singleValue(x)
if x.mode == novalue {
- check.errorf(x.pos(), "%s used as value or type", x)
+ check.errorf(x.pos(), _NotAnExpr, "%s used as value or type", x)
x.mode = invalid
}
}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index 9d5e9165ad..f770d8b830 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -151,14 +151,14 @@ func findPath(objMap map[Object]*declInfo, from, to Object, seen map[Object]bool
// reportCycle reports an error for the given cycle.
func (check *Checker) reportCycle(cycle []Object) {
obj := cycle[0]
- check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+ check.errorf(obj.Pos(), _InvalidInitCycle, "initialization cycle for %s", obj.Name())
// subtle loop: print cycle[i] for i = 0, n-1, n-2, ... 1 for len(cycle) = n
for i := len(cycle) - 1; i >= 0; i-- {
- check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+ check.errorf(obj.Pos(), _InvalidInitCycle, "\t%s refers to", obj.Name()) // secondary error, \t indented
obj = cycle[i]
}
// print cycle[0] again to close the cycle
- check.errorf(obj.Pos(), "\t%s", obj.Name())
+ check.errorf(obj.Pos(), _InvalidInitCycle, "\t%s", obj.Name())
}
// ----------------------------------------------------------------------------
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
index 3b43b4ba05..5a577c45d4 100644
--- a/src/go/types/labels.go
+++ b/src/go/types/labels.go
@@ -22,20 +22,23 @@ func (check *Checker) labels(body *ast.BlockStmt) {
// for the respective gotos.
for _, jmp := range fwdJumps {
var msg string
+ var code errorCode
name := jmp.Label.Name
if alt := all.Lookup(name); alt != nil {
msg = "goto %s jumps into block"
alt.(*Label).used = true // avoid another error
+ code = _JumpIntoBlock
} else {
msg = "label %s not declared"
+ code = _UndeclaredLabel
}
- check.errorf(jmp.Label.Pos(), msg, name)
+ check.errorf(jmp.Label.Pos(), code, msg, name)
}
// spec: "It is illegal to define a label that is never used."
for _, obj := range all.elems {
if lbl := obj.(*Label); !lbl.used {
- check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+ check.softErrorf(lbl.pos, _UnusedLabel, "label %s declared but not used", lbl.name)
}
}
}
@@ -133,7 +136,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele
if name := s.Label.Name; name != "_" {
lbl := NewLabel(s.Label.Pos(), check.pkg, name)
if alt := all.Insert(lbl); alt != nil {
- check.softErrorf(lbl.pos, "label %s already declared", name)
+ check.softErrorf(lbl.pos, _DuplicateLabel, "label %s already declared", name)
check.reportAltDecl(alt)
// ok to continue
} else {
@@ -150,6 +153,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele
if jumpsOverVarDecl(jmp) {
check.softErrorf(
jmp.Label.Pos(),
+ _JumpOverDecl,
"goto %s jumps over variable declaration at line %d",
name,
check.fset.Position(varDeclPos).Line,
@@ -187,7 +191,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele
}
}
if !valid {
- check.errorf(s.Label.Pos(), "invalid break label %s", name)
+ check.errorf(s.Label.Pos(), _MisplacedLabel, "invalid break label %s", name)
return
}
@@ -202,7 +206,7 @@ func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.Labele
}
}
if !valid {
- check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+ check.errorf(s.Label.Pos(), _MisplacedLabel, "invalid continue label %s", name)
return
}
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
index 6fbfe09627..73b3be2655 100644
--- a/src/go/types/operand.go
+++ b/src/go/types/operand.go
@@ -210,16 +210,16 @@ func (x *operand) isNil() bool {
// detailed explanation of the failure (result != ""). The check parameter may
// be nil if assignableTo is invoked through an exported API call, i.e., when
// all methods have been type-checked.
-func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
+func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, errorCode) {
if x.mode == invalid || T == Typ[Invalid] {
- return true // avoid spurious errors
+ return true, 0 // avoid spurious errors
}
V := x.typ
// x's type is identical to T
if check.identical(V, T) {
- return true
+ return true, 0
}
Vu := V.Underlying()
@@ -228,16 +228,16 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
// x is an untyped value representable by a value of type T.
if isUntyped(Vu) {
if t, ok := Tu.(*Basic); ok && x.mode == constant_ {
- return representableConst(x.val, check, t, nil)
+ return representableConst(x.val, check, t, nil), _IncompatibleAssign
}
- return check.implicitType(x, Tu) != nil
+ return check.implicitType(x, Tu) != nil, _IncompatibleAssign
}
// Vu is typed
// x's type V and T have identical underlying types and at least one of V or
// T is not a named type.
if check.identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
- return true
+ return true, 0
}
// T is an interface type and x implements T
@@ -255,9 +255,9 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
*reason = "missing method " + m.Name()
}
}
- return false
+ return false, _InvalidIfaceAssign
}
- return true
+ return true, 0
}
// x is a bidirectional channel value, T is a channel
@@ -265,9 +265,13 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
// and at least one of V or T is not a named type
if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
if Tc, ok := Tu.(*Chan); ok && check.identical(Vc.elem, Tc.elem) {
- return !isNamed(V) || !isNamed(T)
+ if !isNamed(V) || !isNamed(T) {
+ return true, 0
+ } else {
+ return false, _InvalidChanAssign
+ }
}
}
- return false
+ return false, _IncompatibleAssign
}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index cce222cbc5..05d24ef22d 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -55,26 +55,27 @@ func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
r = len(init.Values)
}
+ const code = _WrongAssignCount
switch {
case init == nil && r == 0:
// var decl w/o init expr
if s.Type == nil {
- check.errorf(s.Pos(), "missing type or init expr")
+ check.errorf(s.Pos(), code, "missing type or init expr")
}
case l < r:
if l < len(s.Values) {
// init exprs from s
n := s.Values[l]
- check.errorf(n.Pos(), "extra init expr %s", n)
+ check.errorf(n.Pos(), code, "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", check.fset.Position(init.Pos()))
+ check.errorf(s.Pos(), code, "extra init expr at %s", check.fset.Position(init.Pos()))
// TODO(gri) avoid declared but not used error here
}
case l > r && (init != nil || r != 1):
n := s.Names[r]
- check.errorf(n.Pos(), "missing init expr for %s", n)
+ check.errorf(n.Pos(), code, "missing init expr for %s", n)
}
}
@@ -103,14 +104,14 @@ func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
// spec: "A package-scope or file-scope identifier with name init
// may only be declared to be a function with this (func()) signature."
if ident.Name == "init" {
- check.errorf(ident.Pos(), "cannot declare init - must be func")
+ check.errorf(ident.Pos(), _InvalidInitDecl, "cannot declare init - must be func")
return
}
// spec: "The main package must have package name main and declare
// a function main that takes no arguments and returns no value."
if ident.Name == "main" && check.pkg.name == "main" {
- check.errorf(ident.Pos(), "cannot declare main - must be func")
+ check.errorf(ident.Pos(), _InvalidMainDecl, "cannot declare main - must be func")
return
}
@@ -168,7 +169,7 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package {
imp = nil // create fake package below
}
if err != nil {
- check.errorf(pos, "could not import %s (%s)", path, err)
+ check.errorf(pos, _BrokenImport, "could not import %s (%s)", path, err)
if imp == nil {
// create a new fake package
// come up with a sensible package name (heuristic)
@@ -241,7 +242,7 @@ func (check *Checker) collectObjects() {
// import package
path, err := validatedImportPath(d.spec.Path.Value)
if err != nil {
- check.errorf(d.spec.Path.Pos(), "invalid import path (%s)", err)
+ check.errorf(d.spec.Path.Pos(), _BadImportPath, "invalid import path (%s)", err)
return
}
@@ -264,11 +265,11 @@ func (check *Checker) collectObjects() {
name = d.spec.Name.Name
if path == "C" {
// match cmd/compile (not prescribed by spec)
- check.errorf(d.spec.Name.Pos(), `cannot rename import "C"`)
+ check.errorf(d.spec.Name.Pos(), _ImportCRenamed, `cannot rename import "C"`)
return
}
if name == "init" {
- check.errorf(d.spec.Name.Pos(), "cannot declare init - must be func")
+ check.errorf(d.spec.Name.Pos(), _InvalidInitDecl, "cannot declare init - must be func")
return
}
}
@@ -299,7 +300,7 @@ func (check *Checker) collectObjects() {
// the object may be imported into more than one file scope
// concurrently. See issue #32154.)
if alt := fileScope.Insert(obj); alt != nil {
- check.errorf(d.spec.Name.Pos(), "%s redeclared in this block", obj.Name())
+ check.errorf(d.spec.Name.Pos(), _DuplicateDecl, "%s redeclared in this block", obj.Name())
check.reportAltDecl(alt)
}
}
@@ -372,7 +373,7 @@ func (check *Checker) collectObjects() {
check.recordDef(d.decl.Name, obj)
// init functions must have a body
if d.decl.Body == nil {
- check.softErrorf(obj.pos, "missing function body")
+ check.softErrorf(obj.pos, _MissingInitBody, "missing function body")
}
} else {
check.declare(pkg.scope, d.decl.Name, obj, token.NoPos)
@@ -402,10 +403,10 @@ func (check *Checker) collectObjects() {
for _, obj := range scope.elems {
if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
if pkg, ok := obj.(*PkgName); ok {
- check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+ check.errorf(alt.Pos(), _DuplicateDecl, "%s already declared through import of %s", alt.Name(), pkg.Imported())
check.reportAltDecl(pkg)
} else {
- check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+ check.errorf(alt.Pos(), _DuplicateDecl, "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
// TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
check.reportAltDecl(obj)
}
@@ -574,9 +575,9 @@ func (check *Checker) unusedImports() {
path := obj.imported.path
base := pkgName(path)
if obj.name == base {
- check.softErrorf(obj.pos, "%q imported but not used", path)
+ check.softErrorf(obj.pos, _UnusedImport, "%q imported but not used", path)
} else {
- check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+ check.softErrorf(obj.pos, _UnusedImport, "%q imported but not used as %s", path, obj.name)
}
}
}
@@ -586,7 +587,7 @@ func (check *Checker) unusedImports() {
// check use of dot-imported packages
for _, unusedDotImports := range check.unusedDotImports {
for pkg, pos := range unusedDotImports {
- check.softErrorf(pos, "%q imported but not used", pkg.path)
+ check.softErrorf(pos, _UnusedImport, "%q imported but not used", pkg.path)
}
}
}
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
index b5f6bfe532..262dc7b97a 100644
--- a/src/go/types/self_test.go
+++ b/src/go/types/self_test.go
@@ -19,7 +19,7 @@ import (
func TestSelf(t *testing.T) {
fset := token.NewFileSet()
- files, err := pkgFiles(fset, ".")
+ files, err := pkgFiles(fset, ".", 0)
if err != nil {
t.Fatal(err)
}
@@ -65,7 +65,7 @@ func BenchmarkCheck(b *testing.B) {
func runbench(b *testing.B, path string, ignoreFuncBodies, writeInfo bool) {
fset := token.NewFileSet()
- files, err := pkgFiles(fset, path)
+ files, err := pkgFiles(fset, path, 0)
if err != nil {
b.Fatal(err)
}
@@ -102,7 +102,7 @@ func runbench(b *testing.B, path string, ignoreFuncBodies, writeInfo bool) {
b.ReportMetric(float64(lines)*float64(b.N)/time.Since(start).Seconds(), "lines/s")
}
-func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+func pkgFiles(fset *token.FileSet, path string, mode parser.Mode) ([]*ast.File, error) {
filenames, err := pkgFilenames(path) // from stdlib_test.go
if err != nil {
return nil, err
@@ -110,7 +110,7 @@ func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
var files []*ast.File
for _, filename := range filenames {
- file, err := parser.ParseFile(fset, filename, nil, 0)
+ file, err := parser.ParseFile(fset, filename, nil, mode)
if err != nil {
return nil, err
}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
index c1593bbee9..cc98b07728 100644
--- a/src/go/types/stmt.go
+++ b/src/go/types/stmt.go
@@ -46,7 +46,7 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body
}
if sig.results.Len() > 0 && !check.isTerminating(body, "") {
- check.error(body.Rbrace, "missing return")
+ check.error(body.Rbrace, _MissingReturn, "missing return")
}
// spec: "Implementation restriction: A compiler may make it illegal to
@@ -65,7 +65,7 @@ func (check *Checker) usage(scope *Scope) {
return unused[i].pos < unused[j].pos
})
for _, v := range unused {
- check.softErrorf(v.pos, "%s declared but not used", v.name)
+ check.softErrorf(v.pos, _UnusedVar, "%s declared but not used", v.name)
}
for _, scope := range scope.children {
@@ -139,7 +139,7 @@ func (check *Checker) multipleDefaults(list []ast.Stmt) {
}
if d != nil {
if first != nil {
- check.errorf(d.Pos(), "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
+ check.errorf(d.Pos(), _DuplicateDefault, "multiple defaults (first at %s)", check.fset.Position(first.Pos()))
} else {
first = d
}
@@ -168,17 +168,23 @@ func assignOp(op token.Token) token.Token {
func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
var x operand
var msg string
+ var code errorCode
switch check.rawExpr(&x, call, nil) {
case conversion:
msg = "requires function call, not conversion"
+ code = _InvalidDefer
+ if keyword == "go" {
+ code = _InvalidGo
+ }
case expression:
msg = "discards result of"
+ code = _UnusedResults
case statement:
return
default:
unreachable()
}
- check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+ check.errorf(x.pos(), code, "%s %s %s", keyword, msg, &x)
}
// goVal returns the Go value for val, or nil.
@@ -250,8 +256,8 @@ L:
// (quadratic algorithm, but these lists tend to be very short)
for _, vt := range seen[val] {
if check.identical(v.typ, vt.typ) {
- check.errorf(v.pos(), "duplicate case %s in expression switch", &v)
- check.error(vt.pos, "\tprevious case") // secondary error, \t indented
+ check.errorf(v.pos(), _DuplicateCase, "duplicate case %s in expression switch", &v)
+ check.error(vt.pos, _DuplicateCase, "\tprevious case") // secondary error, \t indented
continue L
}
}
@@ -276,8 +282,8 @@ L:
if T != nil {
Ts = T.String()
}
- check.errorf(e.Pos(), "duplicate case %s in type switch", Ts)
- check.error(pos, "\tprevious case") // secondary error, \t indented
+ check.errorf(e.Pos(), _DuplicateCase, "duplicate case %s in type switch", Ts)
+ check.error(pos, _DuplicateCase, "\tprevious case") // secondary error, \t indented
continue L
}
}
@@ -324,18 +330,22 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
var x operand
kind := check.rawExpr(&x, s.X, nil)
var msg string
+ var code errorCode
switch x.mode {
default:
if kind == statement {
return
}
msg = "is not used"
+ code = _UnusedExpr
case builtin:
msg = "must be called"
+ code = _UncalledBuiltin
case typexpr:
msg = "is not an expression"
+ code = _NotAnExpr
}
- check.errorf(x.pos(), "%s %s", &x, msg)
+ check.errorf(x.pos(), code, "%s %s", &x, msg)
case *ast.SendStmt:
var ch, x operand
@@ -347,12 +357,12 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
tch, ok := ch.typ.Underlying().(*Chan)
if !ok {
- check.invalidOp(s.Arrow, "cannot send to non-chan type %s", ch.typ)
+ check.invalidOp(s.Arrow, _InvalidSend, "cannot send to non-chan type %s", ch.typ)
return
}
if tch.dir == RecvOnly {
- check.invalidOp(s.Arrow, "cannot send to receive-only type %s", tch)
+ check.invalidOp(s.Arrow, _InvalidSend, "cannot send to receive-only type %s", tch)
return
}
@@ -376,7 +386,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
return
}
if !isNumeric(x.typ) {
- check.invalidOp(s.X.Pos(), "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
+ check.invalidOp(s.X.Pos(), _NonNumericIncDec, "%s%s (non-numeric type %s)", s.X, s.Tok, x.typ)
return
}
@@ -404,7 +414,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
default:
// assignment operations
if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
- check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+ check.errorf(s.TokPos, _MultiValAssignOp, "assignment operation %s requires single-valued expressions", s.Tok)
return
}
op := assignOp(s.Tok)
@@ -437,8 +447,8 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
// with the same name as a result parameter is in scope at the place of the return."
for _, obj := range res.vars {
if alt := check.lookup(obj.name); alt != nil && alt != obj {
- check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
- check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+ check.errorf(s.Pos(), _OutOfScopeResult, "result parameter %s not in scope at return", obj.name)
+ check.errorf(alt.Pos(), _OutOfScopeResult, "\tinner declaration of %s", obj)
// ok to continue
}
}
@@ -447,7 +457,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.initVars(res.vars, s.Results, s.Return)
}
} else if len(s.Results) > 0 {
- check.error(s.Results[0].Pos(), "no result values expected")
+ check.error(s.Results[0].Pos(), _WrongResultCount, "no result values expected")
check.use(s.Results...)
}
@@ -459,19 +469,20 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
switch s.Tok {
case token.BREAK:
if ctxt&breakOk == 0 {
- check.error(s.Pos(), "break not in for, switch, or select statement")
+ check.error(s.Pos(), _MisplacedBreak, "break not in for, switch, or select statement")
}
case token.CONTINUE:
if ctxt&continueOk == 0 {
- check.error(s.Pos(), "continue not in for statement")
+ check.error(s.Pos(), _MisplacedContinue, "continue not in for statement")
}
case token.FALLTHROUGH:
if ctxt&fallthroughOk == 0 {
msg := "fallthrough statement out of place"
+ code := _MisplacedFallthrough
if ctxt&finalSwitchCase != 0 {
msg = "cannot fallthrough final case in switch"
}
- check.error(s.Pos(), msg)
+ check.error(s.Pos(), code, msg)
}
default:
check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
@@ -491,7 +502,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
var x operand
check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) {
- check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+ check.error(s.Cond.Pos(), _InvalidCond, "non-boolean condition in if statement")
}
check.stmt(inner, s.Body)
// The parser produces a correct AST but if it was modified
@@ -502,7 +513,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
case *ast.IfStmt, *ast.BlockStmt:
check.stmt(inner, s.Else)
default:
- check.error(s.Else.Pos(), "invalid else branch in if statement")
+ check.invalidAST(s.Else.Pos(), "invalid else branch in if statement")
}
case *ast.SwitchStmt:
@@ -581,7 +592,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
if lhs.Name == "_" {
// _ := x.(type) is an invalid short variable declaration
- check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+ check.softErrorf(lhs.Pos(), _NoNewVar, "no new variable on left side of :=")
lhs = nil // avoid declared but not used error below
} else {
check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
@@ -607,7 +618,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
xtyp, _ := x.typ.Underlying().(*Interface)
if xtyp == nil {
- check.errorf(x.pos(), "%s is not an interface", &x)
+ check.errorf(x.pos(), _InvalidTypeSwitch, "%s is not an interface", &x)
return
}
@@ -660,7 +671,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
v.used = true // avoid usage error when checking entire function
}
if !used {
- check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+ check.softErrorf(lhs.Pos(), _UnusedVar, "%s declared but not used", lhs.Name)
}
}
@@ -697,7 +708,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
if !valid {
- check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+ check.error(clause.Comm.Pos(), _InvalidSelectCase, "select case must be send or receive (possibly with assignment)")
continue
}
@@ -719,14 +730,14 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
var x operand
check.expr(&x, s.Cond)
if x.mode != invalid && !isBoolean(x.typ) {
- check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+ check.error(s.Cond.Pos(), _InvalidCond, "non-boolean condition in for statement")
}
}
check.simpleStmt(s.Post)
// spec: "The init statement may be a short variable
// declaration, but the post statement must not."
if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
- check.softErrorf(s.Pos(), "cannot declare in post statement")
+ check.softErrorf(s.Pos(), _InvalidPostDecl, "cannot declare in post statement")
// Don't call useLHS here because we want to use the lhs in
// this erroneous statement so that we don't get errors about
// these lhs variables being declared but not used.
@@ -770,18 +781,18 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
key = typ.elem
val = Typ[Invalid]
if typ.dir == SendOnly {
- check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
+ check.errorf(x.pos(), _InvalidChanRange, "cannot range over send-only channel %s", &x)
// ok to continue
}
if s.Value != nil {
- check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
+ check.errorf(s.Value.Pos(), _InvalidIterVar, "iteration over %s permits only one iteration variable", &x)
// ok to continue
}
}
}
if key == nil {
- check.errorf(x.pos(), "cannot range over %s", &x)
+ check.errorf(x.pos(), _InvalidRangeExpr, "cannot range over %s", &x)
// ok to continue
}
@@ -814,7 +825,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
vars = append(vars, obj)
}
} else {
- check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+ check.invalidAST(lhs.Pos(), "cannot declare %s", lhs)
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
}
@@ -841,7 +852,7 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
}
} else {
- check.error(s.TokPos, "no new variables on left side of :=")
+ check.error(s.TokPos, _NoNewVar, "no new variables on left side of :=")
}
} else {
// ordinary assignment
@@ -861,6 +872,6 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
check.stmt(inner, s.Body)
default:
- check.error(s.Pos(), "invalid statement")
+ check.invalidAST(s.Pos(), "invalid statement")
}
}
diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
index b2ee8ecd5f..218b4cad6a 100644
--- a/src/go/types/testdata/cycles.src
+++ b/src/go/types/testdata/cycles.src
@@ -65,7 +65,7 @@ type (
I6 interface{ I5 }
// maps
- M0 map[M0 /* ERROR invalid map key */ ]M0
+ M0 map[M0 /* ERROR incomparable map key */ ]M0
// channels
C0 chan C0
@@ -114,7 +114,7 @@ func _() {
i0 /* ERROR cycle */ interface{ i0 }
// maps
- m0 map[m0 /* ERROR invalid map key */ ]m0
+ m0 map[m0 /* ERROR incomparable map key */ ]m0
// channels
c0 chan c0
@@ -123,10 +123,10 @@ func _() {
// test cases for issue 6667
-type A [10]map[A /* ERROR invalid map key */ ]bool
+type A [10]map[A /* ERROR incomparable map key */ ]bool
type S struct {
- m map[S /* ERROR invalid map key */ ]bool
+ m map[S /* ERROR incomparable map key */ ]bool
}
// test cases for issue 7236
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
index 63af9fc867..4ecb1987bb 100644
--- a/src/go/types/testdata/expr3.src
+++ b/src/go/types/testdata/expr3.src
@@ -43,9 +43,9 @@ func indexes() {
_ = a[:10:10]
_ = a[:11 /* ERROR "index .* out of bounds" */ :10]
_ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
- _ = a[10:0:10] /* ERROR "invalid slice indices" */
- _ = a[0:10:0] /* ERROR "invalid slice indices" */
- _ = a[10:0:0] /* ERROR "invalid slice indices" */
+ _ = a[10:0:10] /* ERROR swapped slice indices" */
+ _ = a[0:10:0] /* ERROR "swapped slice indices" */
+ _ = a[10:0:0] /* ERROR "swapped slice indices" */
_ = &a /* ERROR "cannot take address" */ [:10]
pa := &a
@@ -61,9 +61,9 @@ func indexes() {
_ = pa[:10:10]
_ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
_ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
- _ = pa[10:0:10] /* ERROR "invalid slice indices" */
- _ = pa[0:10:0] /* ERROR "invalid slice indices" */
- _ = pa[10:0:0] /* ERROR "invalid slice indices" */
+ _ = pa[10:0:10] /* ERROR "swapped slice indices" */
+ _ = pa[0:10:0] /* ERROR "swapped slice indices" */
+ _ = pa[10:0:0] /* ERROR "swapped slice indices" */
_ = &pa /* ERROR "cannot take address" */ [:10]
var b [0]int
@@ -81,16 +81,16 @@ func indexes() {
_ = s[: - /* ERROR "negative" */ 1]
_ = s[0]
_ = s[1:2]
- _ = s[2:1] /* ERROR "invalid slice indices" */
+ _ = s[2:1] /* ERROR "swapped slice indices" */
_ = s[2:]
_ = s[: 1 /* ERROR "overflows" */ <<100]
_ = s[1 /* ERROR "overflows" */ <<100 :]
_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
_ = s[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
_ = s[:10:10]
- _ = s[10:0:10] /* ERROR "invalid slice indices" */
- _ = s[0:10:0] /* ERROR "invalid slice indices" */
- _ = s[10:0:0] /* ERROR "invalid slice indices" */
+ _ = s[10:0:10] /* ERROR "swapped slice indices" */
+ _ = s[0:10:0] /* ERROR "swapped slice indices" */
+ _ = s[10:0:0] /* ERROR "swapped slice indices" */
_ = &s /* ERROR "cannot take address" */ [:10]
var m map[string]int
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
index d5837c4f0e..b03870477d 100644
--- a/src/go/types/typexpr.go
+++ b/src/go/types/typexpr.go
@@ -28,9 +28,9 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
scope, obj := check.scope.LookupParent(e.Name, check.pos)
if obj == nil {
if e.Name == "_" {
- check.errorf(e.Pos(), "cannot use _ as value or type")
+ check.errorf(e.Pos(), _InvalidBlank, "cannot use _ as value or type")
} else {
- check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+ check.errorf(e.Pos(), _UndeclaredName, "undeclared name: %s", e.Name)
}
return
}
@@ -61,7 +61,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
switch obj := obj.(type) {
case *PkgName:
- check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+ check.errorf(e.Pos(), _InvalidPkgUse, "use of package %s not in selector", obj.name)
return
case *Const:
@@ -71,7 +71,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool)
}
if obj == universeIota {
if check.iota == nil {
- check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+ check.errorf(e.Pos(), _InvalidIota, "cannot use iota outside constant declaration")
return
}
x.val = check.iota
@@ -159,11 +159,11 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
var recv *Var
switch len(recvList) {
case 0:
- check.error(recvPar.Pos(), "method is missing receiver")
+ check.error(recvPar.Pos(), _BadRecv, "method is missing receiver")
recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
default:
// more than one receiver
- check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+ check.error(recvList[len(recvList)-1].Pos(), _BadRecv, "method must have exactly one receiver")
fallthrough // continue with first receiver
case 1:
recv = recvList[0]
@@ -194,7 +194,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
err = "basic or unnamed type"
}
if err != "" {
- check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+ check.errorf(recv.pos, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err)
// ok to continue
}
}
@@ -227,9 +227,9 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
case invalid:
// ignore - error reported before
case novalue:
- check.errorf(x.pos(), "%s used as type", &x)
+ check.errorf(x.pos(), _NotAType, "%s used as type", &x)
default:
- check.errorf(x.pos(), "%s is not a type", &x)
+ check.errorf(x.pos(), _NotAType, "%s is not a type", &x)
}
case *ast.SelectorExpr:
@@ -244,9 +244,9 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
case invalid:
// ignore - error reported before
case novalue:
- check.errorf(x.pos(), "%s used as type", &x)
+ check.errorf(x.pos(), _NotAType, "%s used as type", &x)
default:
- check.errorf(x.pos(), "%s is not a type", &x)
+ check.errorf(x.pos(), _NotAType, "%s is not a type", &x)
}
case *ast.ParenExpr:
@@ -306,7 +306,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
// it is safe to continue in any case (was issue 6667).
check.atEnd(func() {
if !Comparable(typ.key) {
- check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
+ check.errorf(e.Key.Pos(), _IncomparableMapKey, "incomparable map key type %s", typ.key)
}
})
@@ -334,7 +334,7 @@ func (check *Checker) typInternal(e ast.Expr, def *Named) Type {
return typ
default:
- check.errorf(e.Pos(), "%s is not a type", e)
+ check.errorf(e.Pos(), _NotAType, "%s is not a type", e)
}
typ := Typ[Invalid]
@@ -353,7 +353,7 @@ func (check *Checker) typOrNil(e ast.Expr) Type {
case invalid:
// ignore - error reported before
case novalue:
- check.errorf(x.pos(), "%s used as type", &x)
+ check.errorf(x.pos(), _NotAType, "%s used as type", &x)
case typexpr:
return x.typ
case value:
@@ -362,7 +362,7 @@ func (check *Checker) typOrNil(e ast.Expr) Type {
}
fallthrough
default:
- check.errorf(x.pos(), "%s is not a type", &x)
+ check.errorf(x.pos(), _NotAType, "%s is not a type", &x)
}
return Typ[Invalid]
}
@@ -375,7 +375,7 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
check.expr(&x, e)
if x.mode != constant_ {
if x.mode != invalid {
- check.errorf(x.pos(), "array length %s must be constant", &x)
+ check.errorf(x.pos(), _InvalidArrayLen, "array length %s must be constant", &x)
}
return -1
}
@@ -385,12 +385,12 @@ func (check *Checker) arrayLength(e ast.Expr) int64 {
if n, ok := constant.Int64Val(val); ok && n >= 0 {
return n
}
- check.errorf(x.pos(), "invalid array length %s", &x)
+ check.errorf(x.pos(), _InvalidArrayLen, "invalid array length %s", &x)
return -1
}
}
}
- check.errorf(x.pos(), "array length %s must be integer", &x)
+ check.errorf(x.pos(), _InvalidArrayLen, "array length %s must be integer", &x)
return -1
}
@@ -407,7 +407,7 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 {
variadic = true
} else {
- check.softErrorf(t.Pos(), "can only use ... with final parameter in list")
+ check.softErrorf(t.Pos(), _MisplacedDotDotDot, "can only use ... with final parameter in list")
// ignore ... and continue
}
}
@@ -454,7 +454,7 @@ func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicO
func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
if alt := oset.insert(obj); alt != nil {
- check.errorf(pos, "%s redeclared", obj.Name())
+ check.errorf(pos, _DuplicateDecl, "%s redeclared", obj.Name())
check.reportAltDecl(alt)
return false
}
@@ -469,7 +469,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
// and we don't care if a constructed AST has more.)
name := f.Names[0]
if name.Name == "_" {
- check.errorf(name.Pos(), "invalid method name _")
+ check.errorf(name.Pos(), _BlankIfaceMethod, "invalid method name _")
continue // ignore
}
@@ -501,7 +501,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
utyp := check.underlying(typ)
if _, ok := utyp.(*Interface); !ok {
if utyp != Typ[Invalid] {
- check.errorf(f.Type.Pos(), "%s is not an interface", typ)
+ check.errorf(f.Type.Pos(), _InvalidIfaceEmbed, "%s is not an interface", typ)
}
continue
}
@@ -575,14 +575,14 @@ func (check *Checker) completeInterface(ityp *Interface) {
methods = append(methods, m)
mpos[m] = pos
case explicit:
- check.errorf(pos, "duplicate method %s", m.name)
- check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+ check.errorf(pos, _DuplicateDecl, "duplicate method %s", m.name)
+ check.errorf(mpos[other.(*Func)], _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
default:
// check method signatures after all types are computed (issue #33656)
check.atEnd(func() {
if !check.identical(m.typ, other.Type()) {
- check.errorf(pos, "duplicate method %s", m.name)
- check.errorf(mpos[other.(*Func)], "\tother declaration of %s", m.name) // secondary error, \t indented
+ check.errorf(pos, _DuplicateDecl, "duplicate method %s", m.name)
+ check.errorf(mpos[other.(*Func)], _DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
}
})
}
@@ -723,19 +723,19 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
// unsafe.Pointer is treated like a regular pointer
if t.kind == UnsafePointer {
- check.errorf(pos, "embedded field type cannot be unsafe.Pointer")
+ check.errorf(pos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer")
addInvalid(name, pos)
continue
}
case *Pointer:
- check.errorf(pos, "embedded field type cannot be a pointer")
+ check.errorf(pos, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
addInvalid(name, pos)
continue
case *Interface:
if isPtr {
- check.errorf(pos, "embedded field type cannot be a pointer to an interface")
+ check.errorf(pos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
addInvalid(name, pos)
continue
}