// A generic (non-instantiated) function value cannot be assigned to a variable.
if sig, _ := under(x.typ).(*Signature); sig != nil && sig.TypeParams().Len() > 0 {
- check.errorf(x, _Todo, "cannot use generic function %s without instantiation in %s", x, context)
+ check.errorf(x, _WrongTypeArgCount, "cannot use generic function %s without instantiation in %s", x, context)
}
// spec: "If a left-hand side is the blank identifier, any typed or
return false
}
if key != nil && !Identical(map_.key, key) {
- check.invalidArg(x, _Todo, "maps of %s must have identical key types", x)
+ check.invalidArg(x, _InvalidDelete, "maps of %s must have identical key types", x)
return false
}
key = map_.key
// The operand x must be the evaluation of inst.X and its type must be a signature.
func (check *Checker) funcInst(x *operand, ix *typeparams.IndexExpr) {
if !check.allowVersion(check.pkg, 1, 18) {
- check.softErrorf(inNode(ix.Orig, ix.Lbrack), _Todo, "function instantiation requires go1.18 or later")
+ check.softErrorf(inNode(ix.Orig, ix.Lbrack), _UnsupportedFeature, "function instantiation requires go1.18 or later")
}
targs := check.typeList(ix.Indices)
sig := x.typ.(*Signature)
got, want := len(targs), sig.TypeParams().Len()
if got > want {
- check.errorf(ix.Indices[got-1], _Todo, "got %d type arguments but want %d", got, want)
+ check.errorf(ix.Indices[got-1], _WrongTypeArgCount, "got %d type arguments but want %d", got, want)
x.mode = invalid
x.expr = ix.Orig
return
if i < len(posList) {
pos = posList[i]
}
- check.softErrorf(atPos(pos), _Todo, err.Error())
+ check.softErrorf(atPos(pos), _InvalidTypeArg, err.Error())
} else {
check.mono.recordInstance(check.pkg, pos, tparams, targs, posList)
}
}
if t, _ := under(T).(*Interface); t != nil {
if !t.IsMethodSet() {
- check.errorf(call, _Todo, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
+ check.errorf(call, _MisplacedConstraintIface, "cannot use interface %s in conversion (contains specific type constraints or is comparable)", T)
break
}
}
// check number of type arguments (got) vs number of type parameters (want)
got, want := len(targs), sig.TypeParams().Len()
if got > want {
- check.errorf(ix.Indices[want], _Todo, "got %d type arguments but want %d", got, want)
+ check.errorf(ix.Indices[want], _WrongTypeArgCount, "got %d type arguments but want %d", got, want)
check.use(call.Args...)
x.mode = invalid
x.expr = call
switch call.Fun.(type) {
case *ast.IndexExpr, *ast.IndexListExpr:
ix := typeparams.UnpackIndexExpr(call.Fun)
- check.softErrorf(inNode(call.Fun, ix.Lbrack), _Todo, "function instantiation requires go1.18 or later")
+ check.softErrorf(inNode(call.Fun, ix.Lbrack), _UnsupportedFeature, "function instantiation requires go1.18 or later")
default:
- check.softErrorf(inNode(call, call.Lparen), _Todo, "implicit function instantiation requires go1.18 or later")
+ check.softErrorf(inNode(call, call.Lparen), _UnsupportedFeature, "implicit function instantiation requires go1.18 or later")
}
}
// TODO(gri) provide position information for targs so we can feed
check.validType(obj.typ, nil)
// If typ is local, an error was already reported where typ is specified/defined.
if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
- check.errorf(tdecl.Type, _Todo, "using type constraint %s requires go1.18 or later", rhs)
+ check.errorf(tdecl.Type, _UnsupportedFeature, "using type constraint %s requires go1.18 or later", rhs)
}
}).describef(obj, "validType(%s)", obj.Name())
if alias && tdecl.TypeParams.NumFields() != 0 {
// The parser will ensure this but we may still get an invalid AST.
// Complain and continue as regular type definition.
- check.error(atPos(tdecl.Assign), _Todo, "generic type cannot be alias")
+ check.error(atPos(tdecl.Assign), _BadDecl, "generic type cannot be alias")
alias = false
}
// type (underlying not fully resolved yet) it cannot become a type parameter due
// to this very restriction.
if tpar, _ := named.underlying.(*TypeParam); tpar != nil {
- check.error(tdecl.Type, _Todo, "cannot use a type parameter as RHS in type declaration")
+ check.error(tdecl.Type, _MisplacedTypeParam, "cannot use a type parameter as RHS in type declaration")
named.underlying = Typ[Invalid]
}
}
check.later(func() {
for i, bound := range bounds {
if _, ok := under(bound).(*TypeParam); ok {
- check.error(posns[i], _Todo, "cannot use a type parameter as constraint")
+ check.error(posns[i], _MisplacedTypeParam, "cannot use a type parameter as constraint")
}
}
for _, tpar := range tparams {
obj.color_ = saved
if fdecl.Type.TypeParams.NumFields() > 0 && fdecl.Body == nil {
- check.softErrorf(fdecl.Name, _Todo, "parameterized function is missing function body")
+ check.softErrorf(fdecl.Name, _BadDecl, "parameterized function is missing function body")
}
// function body must be type-checked after global declarations
// var _ = unsafe.Slice(&x, uint64(1) << 63)
_InvalidUnsafeSlice
+ // All codes below were added in Go 1.18.
+
+ // _UnsupportedFeature occurs when a language feature is used that is not
+ // supported at this Go version.
+ _UnsupportedFeature
+
+ // _WrongTypeArgCount occurs when a type or function is instantiated with an
+ // incorrent number of type arguments, including when a generic type or
+ // function is used without instantiation.
+ //
+ // Errors inolving failed type inference are assigned other error codes.
+ //
+ // Example:
+ // type T[p any] int
+ //
+ // var _ T[int, string]
+ //
+ // Example:
+ // func f[T any]() {}
+ //
+ // var x = f
+ _WrongTypeArgCount
+
+ // _CannotInferTypeArgs occurs when type or function type argument inference
+ // fails to infer all type arguments.
+ //
+ // Example:
+ // func f[T any]() {}
+ //
+ // func _() {
+ // f()
+ // }
+ //
+ // Example:
+ // type N[P, Q any] struct{}
+ //
+ // var _ N[int]
+ _CannotInferTypeArgs
+
+ // _InvalidTypeArg occurs when a type argument does not satisfy its
+ // corresponding type parameter constraints.
+ //
+ // Example:
+ // type T[P ~int] struct{}
+ //
+ // var _ T[string]
+ _InvalidTypeArg // arguments? InferenceFailed
+
// _InvalidInstanceCycle occurs when an invalid cycle is detected
// within the instantiation graph.
//
// func f[T any]() { f[*T]() }
_InvalidInstanceCycle
+ // _InvalidUnion occurs when an embedded union or approximation element is
+ // not valid.
+ //
+ // Example:
+ // type _ interface {
+ // ~int | interface{ m() }
+ // }
+ _InvalidUnion
+
+ // _MisplacedConstraintIface occurs when a constraint-type interface is used
+ // outside of constraint position.
+ //
+ // Example:
+ // type I interface { ~int }
+ //
+ // var _ I
+ _MisplacedConstraintIface
+
+ // _InvalidMethodTypeParams occurs when methods have type parameters.
+ //
+ // Example:
+ // type T int
+ //
+ // func (T) m[P any]() {}
+ _InvalidMethodTypeParams
+
+ // _MisplacedTypeParam occurs when a type parameter is used in a place where
+ // it is not permitted.
+ //
+ // Example:
+ // type T[P any] P
+ //
+ // Example:
+ // type T[P any] struct{ *P }
+ _MisplacedTypeParam
+
// _Todo is a placeholder for error codes that have not been decided.
// TODO(rFindley) remove this error code after deciding on errors for generics code.
_Todo
}
}
doc := spec.Doc.Text()
- if !strings.HasPrefix(doc, name) {
- t.Errorf("doc for %q does not start with identifier", name)
+ if doc == "" {
+ t.Errorf("%q is undocumented", name)
+ } else if !strings.HasPrefix(doc, name) {
+ t.Errorf("doc for %q does not start with the error code name", name)
}
lowerComment := strings.ToLower(strings.TrimPrefix(doc, name))
for _, bad := range forbiddenInComment {
return false
}
if elem != nil && !Identical(ch.elem, elem) {
- check.invalidOp(x, _Todo, "channels of %s must have the same element type", x)
+ check.invalidOp(x, _InvalidReceive, "channels of %s must have the same element type", x)
return false
}
elem = ch.elem
}
}
if what != "" {
- check.errorf(x.expr, _Todo, "cannot use generic %s %s without instantiation", what, x.expr)
+ check.errorf(x.expr, _WrongTypeArgCount, "cannot use generic %s %s without instantiation", what, x.expr)
x.mode = invalid
x.typ = Typ[Invalid]
}
// Prevent crash if the struct referred to is not yet set up.
// See analogous comment for *Array.
if utyp.fields == nil {
- check.error(e, _Todo, "illegal cycle in type declaration")
+ check.error(e, _InvalidDeclCycle, "illegal cycle in type declaration")
goto Error
}
if len(e.Elts) == 0 {
return false
}
if base != nil && !Identical(p.base, base) {
- check.invalidOp(x, _Todo, "pointers of %s must have identical base types", x)
+ check.invalidOp(x, _InvalidIndirection, "pointers of %s must have identical base types", x)
return false
}
base = p.base
}
}
if allFailed {
- check.errorf(arg, _Todo, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
+ check.errorf(arg, _CannotInferTypeArgs, "%s %s of %s does not match %s (cannot infer %s)", kind, targ, arg.expr, tpar, typeParamsString(tparams))
return
}
}
smap := makeSubstMap(tparams, targs)
// TODO(rFindley): pass a positioner here, rather than arg.Pos().
inferred := check.subst(arg.Pos(), tpar, smap, nil)
+ // _CannotInferTypeArgs indicates a failure of inference, though the actual
+ // error may be better attributed to a user-provided type argument (hence
+ // _InvalidTypeArg). We can't differentiate these cases, so fall back on
+ // the more general _CannotInferTypeArgs.
if inferred != tpar {
- check.errorf(arg, _Todo, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
+ check.errorf(arg, _CannotInferTypeArgs, "%s %s of %s does not match inferred type %s for %s", kind, targ, arg.expr, inferred, tpar)
} else {
- check.errorf(arg, _Todo, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
+ check.errorf(arg, _CannotInferTypeArgs, "%s %s of %s does not match %s", kind, targ, arg.expr, tpar)
}
}
// At least one type argument couldn't be inferred.
assert(index >= 0 && targs[index] == nil)
tpar := tparams[index]
- check.errorf(posn, _Todo, "cannot infer %s (%v)", tpar.obj.name, tpar.obj.pos)
+ check.errorf(posn, _CannotInferTypeArgs, "cannot infer %s (%v)", tpar.obj.name, tpar.obj.pos)
return nil
}
if !u.unify(tpar, sbound) {
// TODO(gri) improve error message by providing the type arguments
// which we know already
- check.errorf(tpar.obj, _Todo, "%s does not match %s", tpar, sbound)
+ check.errorf(tpar.obj, _InvalidTypeArg, "%s does not match %s", tpar, sbound)
return nil, 0
}
}
if ntargs != ntparams {
// TODO(gri) provide better error message
if check != nil {
- check.errorf(atPos(pos), _Todo, "got %d arguments but %d type parameters", ntargs, ntparams)
+ check.errorf(atPos(pos), _WrongTypeArgCount, "got %d arguments but %d type parameters", ntargs, ntparams)
return false
}
panic(fmt.Sprintf("%v: got %d arguments but %d type parameters", pos, ntargs, ntparams))
if ftyp, _ := f.Type.(*ast.FuncType); ftyp != nil && ftyp.TypeParams != nil {
at = ftyp.TypeParams
}
- check.errorf(at, _Todo, "methods cannot have type parameters")
+ check.errorf(at, _InvalidMethodTypeParams, "methods cannot have type parameters")
}
// use named receiver type if available (for better error messages)
}
case typeDecl:
if d.spec.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, 1, 18) {
- check.softErrorf(d.spec.TypeParams.List[0], _Todo, "type parameters require go1.18 or later")
+ check.softErrorf(d.spec.TypeParams.List[0], _UnsupportedFeature, "type parameters require go1.18 or later")
}
obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
check.recordDef(d.decl.Name, obj)
}
if d.decl.Type.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError {
- check.softErrorf(d.decl.Type.TypeParams.List[0], _Todo, "type parameters require go1.18 or later")
+ check.softErrorf(d.decl.Type.TypeParams.List[0], _UnsupportedFeature, "type parameters require go1.18 or later")
}
info := &declInfo{file: fileScope, fdecl: d.decl}
// Methods are not package-level objects but we still track them in the
case nil:
check.invalidAST(ix.Orig, "parameterized receiver contains nil parameters")
default:
- check.errorf(arg, _Todo, "receiver type parameter %s must be an identifier", arg)
+ check.errorf(arg, _BadDecl, "receiver type parameter %s must be an identifier", arg)
}
if par == nil {
par = &ast.Ident{NamePos: arg.Pos(), Name: "_"}
// (A separate check is needed when type-checking interface method signatures because
// they don't have a receiver specification.)
if recvPar != nil {
- check.errorf(ftyp.TypeParams, _Todo, "methods cannot have type parameters")
+ check.errorf(ftyp.TypeParams, _InvalidMethodTypeParams, "methods cannot have type parameters")
}
}
// The receiver type may be an instantiated type referred to
// by an alias (which cannot have receiver parameters for now).
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
- check.errorf(atPos(recv.pos), _Todo, "cannot define methods on instantiated type %s", recv.typ)
+ check.errorf(atPos(recv.pos), _InvalidRecv, "cannot define methods on instantiated type %s", recv.typ)
break
}
// spec: "The type denoted by T is called the receiver base type; it must not
return false
}
if elem != nil && !Identical(uch.elem, elem) {
- check.invalidOp(inNode(s, s.Arrow), _Todo, "channels of %s must have the same element type", &ch)
+ check.invalidOp(inNode(s, s.Arrow), _InvalidSend, "channels of %s must have the same element type", &ch)
return false
}
elem = uch.elem
pos := f.Type.Pos()
name := embeddedFieldIdent(f.Type)
if name == nil {
- // TODO(rFindley): using invalidAST here causes test failures (all
- // errors should have codes). Clean this up.
- check.errorf(f.Type, _Todo, "invalid AST: embedded field type %s has no name", f.Type)
+ check.invalidAST(f.Type, "embedded field type %s has no name", f.Type)
name = ast.NewIdent("_")
name.NamePos = pos
addInvalid(name, pos)
case *Pointer:
check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer")
case *TypeParam:
- check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a (pointer to a) type parameter")
+ // This error code here is inconsistent with other error codes for
+ // invalid embedding, because this restriction may be relaxed in the
+ // future, and so it did not warrant a new error code.
+ check.error(embeddedPos, _MisplacedTypeParam, "embedded field type cannot be a (pointer to a) type parameter")
case *Interface:
if isPtr {
check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
tset := computeInterfaceTypeSet(check, pos, u)
// If typ is local, an error was already reported where typ is specified/defined.
if check != nil && check.isImportedConstraint(typ) && !check.allowVersion(check.pkg, 1, 18) {
- check.errorf(atPos(pos), _Todo, "embedding constraint interface %s requires go1.18 or later", typ)
+ check.errorf(atPos(pos), _UnsupportedFeature, "embedding constraint interface %s requires go1.18 or later", typ)
continue
}
if tset.comparable {
terms = tset.terms
case *Union:
if check != nil && !check.allowVersion(check.pkg, 1, 18) {
- check.errorf(atPos(pos), _Todo, "embedding interface element %s requires go1.18 or later", u)
+ check.errorf(atPos(pos), _InvalidIfaceEmbed, "embedding interface element %s requires go1.18 or later", u)
continue
}
tset := computeUnionTypeSet(check, pos, u)
allTerms = allTerms.union(terms)
if len(allTerms) > maxTermCount {
if check != nil {
- check.errorf(atPos(pos), _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
+ check.errorf(atPos(pos), _InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
}
utyp.tset = &invalidTypeSet
return utyp.tset
tset := computeInterfaceTypeSet(check, e.Pos(), t) // TODO(gri) is this the correct position?
if !tset.IsMethodSet() {
if tset.comparable {
- check.softErrorf(e, _Todo, "interface is (or embeds) comparable")
+ check.softErrorf(e, _MisplacedConstraintIface, "interface is (or embeds) comparable")
} else {
- check.softErrorf(e, _Todo, "interface contains type constraints")
+ check.softErrorf(e, _MisplacedConstraintIface, "interface contains type constraints")
}
}
}
typ := check.typInternal(e, def)
assert(isTyped(typ))
if isGeneric(typ) {
- check.errorf(e, _Todo, "cannot use generic type %s without instantiation", typ)
+ check.errorf(e, _WrongTypeArgCount, "cannot use generic type %s without instantiation", typ)
typ = Typ[Invalid]
}
check.recordTypeAndValue(e, typexpr, typ, nil)
case *ast.IndexExpr, *ast.IndexListExpr:
ix := typeparams.UnpackIndexExpr(e)
if !check.allowVersion(check.pkg, 1, 18) {
- check.softErrorf(inNode(e, ix.Lbrack), _Todo, "type instantiation requires go1.18 or later")
+ check.softErrorf(inNode(e, ix.Lbrack), _UnsupportedFeature, "type instantiation requires go1.18 or later")
}
return check.instantiatedType(ix.X, ix.Indices, def)
if i < len(posList) {
pos = posList[i]
}
- check.softErrorf(atPos(pos), _Todo, err.Error())
+ check.softErrorf(atPos(pos), _InvalidTypeArg, err.Error())
} else {
check.mono.recordInstance(check.pkg, x.Pos(), inst.tparams.list(), inst.targs.list(), posList)
}
return typ
}
if len(terms) >= maxTermCount {
- check.errorf(x, _Todo, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
+ check.errorf(x, _InvalidUnion, "cannot handle more than %d union terms (implementation limitation)", maxTermCount)
return Typ[Invalid]
}
terms = append(terms, NewTerm(tilde, typ))
f, _ := u.(*Interface)
if t.tilde {
if f != nil {
- check.errorf(tlist[i], _Todo, "invalid use of ~ (%s is an interface)", t.typ)
+ check.errorf(tlist[i], _InvalidUnion, "invalid use of ~ (%s is an interface)", t.typ)
continue // don't report another error for t
}
if !Identical(u, t.typ) {
- check.errorf(tlist[i], _Todo, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
+ check.errorf(tlist[i], _InvalidUnion, "invalid use of ~ (underlying type of %s is %s)", t.typ, u)
continue // don't report another error for t
}
}
// in the beginning. Embedded interfaces with tilde are excluded above. If we reach
// here, we must have at least two terms in the union.
if f != nil && !f.typeSet().IsTypeSet() {
- check.errorf(tlist[i], _Todo, "cannot use %s in union (interface contains methods)", t)
+ check.errorf(tlist[i], _InvalidUnion, "cannot use %s in union (interface contains methods)", t)
continue // don't report another error for t
}
// Report overlapping (non-disjoint) terms such as
// a|a, a|~a, ~a|~a, and ~a|A (where under(A) == a).
if j := overlappingTerm(terms[:i], t); j >= 0 {
- check.softErrorf(tlist[i], _Todo, "overlapping terms %s and %s", t, terms[j])
+ check.softErrorf(tlist[i], _InvalidUnion, "overlapping terms %s and %s", t, terms[j])
}
}
})
// check to later and could return Typ[Invalid] instead.
check.later(func() {
if _, ok := under(typ).(*TypeParam); ok {
- check.error(x, _Todo, "cannot embed a type parameter")
+ check.error(x, _MisplacedTypeParam, "cannot embed a type parameter")
}
})
return