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:
// 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.
// 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
}
}
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
}
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
}
// 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]
}
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
}
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
}
}
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
}
}
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
}
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 {
}
} 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
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 :=")
}
}
// 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
}
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
}
}
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
}
// 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
}
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
}
// 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
}
// 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
}
}
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
}
// 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
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
}
// 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
}
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}
}
}
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
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
}
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
}
// 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
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 {
}
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
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
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
}
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
}
}
}
}
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 {
}
}
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)
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
}
}
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.
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
}
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
}
if name != "_" {
pkg.name = name
} else {
- check.errorf(file.Name.Pos(), "invalid package name _")
+ check.errorf(file.Name.Pos(), _BlankPkgName, "invalid package name _")
}
fallthrough
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
}
}
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)
}
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
}
// 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
}
// 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
}
}
// 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
}
// 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"
// 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
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()
}
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
}
--- /dev/null
+// 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
+)
--- /dev/null
+// 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)
+ }
+}
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...)
}
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 {
// 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
}
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
}
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
//
//
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
}
// 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
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
}
} 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
}
// 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:
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
}
// 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
}
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
}
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
}
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
}
// 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
}
// 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
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
}
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
}
// 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
}
// 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
}
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
}
// 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
}
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:
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
}
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)
// 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]
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
// 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
}
}
// 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)
// 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)
// 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)
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
}
}
}
// 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
}
}
}
if !valid {
- check.invalidOp(x.pos(), "cannot index %s", x)
+ check.invalidOp(x.pos(), _NonIndexableOperand, "cannot index %s", x)
goto Error
}
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
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}
}
if !valid {
- check.invalidOp(x.pos(), "cannot slice %s", x)
+ check.invalidOp(x.pos(), _NonSliceableOperand, "cannot slice %s", x)
goto Error
}
// 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
}
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
}
}
}
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)
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
}
}
} 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) {
// 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
}
}
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
}
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
}
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
}
}
// 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())
}
// ----------------------------------------------------------------------------
// 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)
}
}
}
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 {
if jumpsOverVarDecl(jmp) {
check.softErrorf(
jmp.Label.Pos(),
+ _JumpOverDecl,
"goto %s jumps over variable declaration at line %d",
name,
check.fset.Position(varDeclPos).Line,
}
}
if !valid {
- check.errorf(s.Label.Pos(), "invalid break label %s", name)
+ check.errorf(s.Label.Pos(), _MisplacedLabel, "invalid break label %s", name)
return
}
}
}
if !valid {
- check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+ check.errorf(s.Label.Pos(), _MisplacedLabel, "invalid continue label %s", name)
return
}
// 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()
// 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
*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
// 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
}
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)
}
}
// 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
}
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)
// 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
}
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
}
}
// 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)
}
}
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)
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)
}
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)
}
}
}
// 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)
}
}
}
func TestSelf(t *testing.T) {
fset := token.NewFileSet()
- files, err := pkgFiles(fset, ".")
+ files, err := pkgFiles(fset, ".", 0)
if err != nil {
t.Fatal(err)
}
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)
}
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
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
}
}
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
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 {
}
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
}
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.
// (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
}
}
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
}
}
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
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
}
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
}
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)
// 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
}
}
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...)
}
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)
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
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:
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
}
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
}
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)
}
}
}
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
}
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.
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
}
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
}
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
check.stmt(inner, s.Body)
default:
- check.error(s.Pos(), "invalid statement")
+ check.invalidAST(s.Pos(), "invalid statement")
}
}
I6 interface{ I5 }
// maps
- M0 map[M0 /* ERROR invalid map key */ ]M0
+ M0 map[M0 /* ERROR incomparable map key */ ]M0
// channels
C0 chan C0
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
// 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
_ = 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
_ = 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
_ = 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
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
}
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:
}
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
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]
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
}
}
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:
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:
// 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)
}
})
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]
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:
}
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]
}
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
}
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
}
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
}
}
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
}
// 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
}
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
}
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
}
})
}
// 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
}