case _Clear:
// clear(m)
- if !check.allowVersion(check.pkg, call.Pos(), 1, 21) {
- check.versionErrorf(call.Fun, "go1.21", "clear")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 21, "clear") {
return
}
case _Add:
// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
- if !check.allowVersion(check.pkg, call.Pos(), 1, 17) {
- check.versionErrorf(call.Fun, "go1.17", "unsafe.Add")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 17, "unsafe.Add") {
return
}
case _Slice:
// unsafe.Slice(ptr *T, len IntegerType) []T
- if !check.allowVersion(check.pkg, call.Pos(), 1, 17) {
- check.versionErrorf(call.Fun, "go1.17", "unsafe.Slice")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 17, "unsafe.Slice") {
return
}
case _SliceData:
// unsafe.SliceData(slice []T) *T
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.versionErrorf(call.Fun, "go1.20", "unsafe.SliceData")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.SliceData") {
return
}
case _String:
// unsafe.String(ptr *byte, len IntegerType) string
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.versionErrorf(call.Fun, "go1.20", "unsafe.String")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.String") {
return
}
case _StringData:
// unsafe.StringData(str string) *byte
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.versionErrorf(call.Fun, "go1.20", "unsafe.StringData")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.StringData") {
return
}
// Note: trace is only available in self-test mode.
// (no argument evaluated yet)
if nargs == 0 {
- check.dump("%v: trace() without arguments", posFor(call))
+ check.dump("%v: trace() without arguments", atPos(call))
x.mode = novalue
break
}
x1 := x
for _, arg := range call.ArgList {
check.rawExpr(nil, x1, arg, nil, false) // permit trace for types, e.g.: new(trace(T))
- check.dump("%v: %s", posFor(x1), x1)
+ check.dump("%v: %s", atPos(x1), x1)
x1 = &t // use incoming x only for first argument
}
// trace is only available in test mode - no need to record signature
func (check *Checker) funcInst(tsig *Signature, pos syntax.Pos, x *operand, inst *syntax.IndexExpr) {
assert(tsig != nil || inst != nil)
- var versionErr bool // set if version error was reported
- var instErrPos poser // position for instantion error
+ var instErrPos poser
if inst != nil {
instErrPos = inst.Pos()
} else {
instErrPos = pos
}
- if !check.allowVersion(check.pkg, pos, 1, 18) {
- check.versionErrorf(instErrPos, "go1.18", "function instantiation")
- versionErr = true
- }
+ versionErr := !check.allowVersionf(check.pkg, instErrPos, 1, 18, "function instantiation")
// targs and xlist are the type arguments and corresponding type expressions, or nil.
var targs []Type
// of a synthetic function f where f's parameters are the parameters and results
// of x and where the arguments to the call of f are values of the parameter and
// result types of x.
- if !versionErr && !check.allowVersion(check.pkg, pos, 1, 21) {
+ if !versionErr && !check.allowVersion(check.pkg, instErrPos, 1, 21) {
if inst != nil {
check.versionErrorf(instErrPos, "go1.21", "partially instantiated function in assignment")
} else {
// is an error checking its arguments (for example, if an incorrect number
// of arguments is supplied).
if got == want && want > 0 {
- if !check.allowVersion(check.pkg, x.Pos(), 1, 18) {
- check.versionErrorf(inst.Pos(), "go1.18", "function instantiation")
- }
+ check.allowVersionf(check.pkg, inst, 1, 18, "function instantiation")
sig = check.instantiateSignature(inst.Pos(), sig, targs, xlist)
assert(sig.TypeParams().Len() == 0) // signature is not generic anymore
if n > 0 {
if !check.allowVersion(check.pkg, call.Pos(), 1, 18) {
if iexpr, _ := call.Fun.(*syntax.IndexExpr); iexpr != nil {
- check.versionErrorf(iexpr.Pos(), "go1.18", "function instantiation")
+ check.versionErrorf(iexpr, "go1.18", "function instantiation")
} else {
- check.versionErrorf(call.Pos(), "go1.18", "implicit function instantiation")
+ check.versionErrorf(call, "go1.18", "implicit function instantiation")
}
}
// rename type parameters to avoid problems with recursive calls
}
}
}
- if len(genericArgs) > 0 && !check.allowVersion(check.pkg, call.Pos(), 1, 21) {
- // at the moment we only support implicit instantiations of argument functions
- check.versionErrorf(args[genericArgs[0]].Pos(), "go1.21", "implicitly instantiated function as argument")
- }
+ // at the moment we only support implicit instantiations of argument functions
+ _ = len(genericArgs) > 0 && check.allowVersionf(check.pkg, args[genericArgs[0]], 1, 21, "implicitly instantiated function as argument")
// tparams holds the type parameters of the callee and generic function arguments, if any:
// the first n type parameters belong to the callee, followed by mi type parameters for each
x.typ = exp.typ
x.id = exp.id
default:
- check.dump("%v: unexpected object %v", posFor(e.Sel), exp)
+ check.dump("%v: unexpected object %v", atPos(e.Sel), exp)
unreachable()
}
x.expr = e
for x, info := range check.untyped {
if debug && isTyped(info.typ) {
- check.dump("%v: %s (type %s) is typed", posFor(x), x, info.typ)
+ check.dump("%v: %s (type %s) is typed", atPos(x), x, info.typ)
unreachable()
}
check.recordTypeAndValue(x, info.mode, info.typ, info.val)
switch a := Tu.(type) {
case *Array:
if Identical(s.Elem(), a.Elem()) {
- if check == nil || check.allowVersion(check.pkg, x.Pos(), 1, 20) {
+ if check == nil || check.allowVersion(check.pkg, x, 1, 20) {
return true
}
// check != nil
case *Pointer:
if a, _ := under(a.Elem()).(*Array); a != nil {
if Identical(s.Elem(), a.Elem()) {
- if check == nil || check.allowVersion(check.pkg, x.Pos(), 1, 17) {
+ if check == nil || check.allowVersion(check.pkg, x, 1, 17) {
return true
}
// check != nil
check.validType(t)
}
// If typ is local, an error was already reported where typ is specified/defined.
- if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, tdecl.Pos(), 1, 18) {
- check.versionErrorf(tdecl.Type, "go1.18", "using type constraint %s", rhs)
- }
+ _ = check.isImportedConstraint(rhs) && check.allowVersionf(check.pkg, tdecl.Type, 1, 18, "using type constraint %s", rhs)
}).describef(obj, "validType(%s)", obj.Name())
alias := tdecl.Alias
// alias declaration
if alias {
- if !check.allowVersion(check.pkg, tdecl.Pos(), 1, 9) {
- check.versionErrorf(tdecl, "go1.9", "type aliases")
- }
-
+ check.allowVersionf(check.pkg, tdecl, 1, 9, "type aliases")
check.brokenAlias(obj)
rhs = check.typ(tdecl.Type)
check.validAlias(obj, rhs)
// errorf adds formatted error information to err.
// It may be called multiple times to provide additional information.
func (err *error_) errorf(at poser, format string, args ...interface{}) {
- err.desc = append(err.desc, errorDesc{posFor(at), format, args})
+ err.desc = append(err.desc, errorDesc{atPos(at), format, args})
}
func sprintf(qf Qualifier, tpSubscripts bool, format string, args ...interface{}) string {
return
}
- pos := posFor(at)
+ pos := atPos(at)
// If we are encountering an error while evaluating an inherited
// constant initialization expression, pos is the position of in
check.err(at, UnsupportedFeature, msg, true)
}
-// posFor reports the left (= start) position of at.
-func posFor(at poser) syntax.Pos {
+// atPos reports the left (= start) position of at.
+func atPos(at poser) syntax.Pos {
switch x := at.(type) {
case *operand:
if x.expr != nil {
// The respective sub-expressions got their final types
// upon assignment or use.
if debug {
- check.dump("%v: found old type(%s): %s (new: %s)", posFor(x), x, old.typ, typ)
+ check.dump("%v: found old type(%s): %s (new: %s)", atPos(x), x, old.typ, typ)
unreachable()
}
return
// Check that RHS is otherwise at least of integer type.
switch {
case allInteger(y.typ):
- if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, x.Pos(), 1, 13) {
- check.versionErrorf(y, "go1.13", invalidOp+"signed shift count %s", y)
+ if !allUnsigned(y.typ) && !check.allowVersionf(check.pkg, y, 1, 13, invalidOp+"signed shift count %s", y) {
x.mode = invalid
return
}
// types, which are comparatively rare.
default:
- panic(fmt.Sprintf("%s: unknown expression type %T", posFor(e), e))
+ panic(fmt.Sprintf("%s: unknown expression type %T", atPos(e), e))
}
// everything went well
// so that ordinary, non-type parameter interfaces implement comparable.
if constraint && comparable(V, true /* spec comparability */, nil, nil) {
// V is comparable if we are at Go 1.20 or higher.
- if check == nil || check.allowVersion(check.pkg, pos, 1, 20) {
+ if check == nil || check.allowVersion(check.pkg, atPos(pos), 1, 20) { // atPos needed so that go/types generate passes
return true
}
if cause != nil {
for _, f := range iface.MethodList {
if f.Name == nil {
- addEmbedded(posFor(f.Type), parseUnion(check, f.Type))
+ addEmbedded(atPos(f.Type), parseUnion(check, f.Type))
continue
}
// f.Name != nil
}
case *syntax.TypeDecl:
- if len(s.TParamList) != 0 && !check.allowVersion(pkg, s.Pos(), 1, 18) {
- check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
- }
+ _ = len(s.TParamList) != 0 && check.allowVersionf(pkg, s.TParamList[0], 1, 18, "type parameter")
obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil)
check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s})
}
check.recordDef(s.Name, obj)
}
- if len(s.TParamList) != 0 && !check.allowVersion(pkg, s.Pos(), 1, 18) && !hasTParamError {
- check.versionErrorf(s.TParamList[0], "go1.18", "type parameter")
- }
+ _ = len(s.TParamList) != 0 && !hasTParamError && check.allowVersionf(pkg, s.TParamList[0], 1, 18, "type parameter")
info := &declInfo{file: fileScope, fdecl: s}
// Methods are not package-level objects but we still track them in the
// object map so that we can handle them like regular functions (if the
assert(!isTypeParam(typ))
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, pos, 1, 18) {
- check.versionErrorf(pos, "go1.18", "embedding constraint interface %s", typ)
+ if check != nil && check.isImportedConstraint(typ) && !check.allowVersionf(check.pkg, pos, 1, 18, "embedding constraint interface %s", typ) {
continue
}
comparable = tset.comparable
}
terms = tset.terms
case *Union:
- if check != nil && !check.allowVersion(check.pkg, pos, 1, 18) {
- check.versionErrorf(pos, "go1.18", "embedding interface element %s", u)
+ if check != nil && !check.allowVersionf(check.pkg, pos, 1, 18, "embedding interface element %s", u) {
continue
}
tset := computeUnionTypeSet(check, unionSets, pos, u)
if u == Typ[Invalid] {
continue
}
- if check != nil && !check.allowVersion(check.pkg, pos, 1, 18) {
- check.versionErrorf(pos, "go1.18", "embedding non-interface type %s", typ)
+ if check != nil && !check.allowVersionf(check.pkg, pos, 1, 18, "embedding non-interface type %s", typ) {
continue
}
terms = termlist{{false, typ}}
}
return
case universeAny, universeComparable:
- if !check.allowVersion(check.pkg, e.Pos(), 1, 18) {
- check.versionErrorf(e, "go1.18", "predeclared %s", e.Value)
+ if !check.allowVersionf(check.pkg, e, 1, 18, "predeclared %s", e.Value) {
return // avoid follow-on errors
}
}
}
case *syntax.IndexExpr:
- if !check.allowVersion(check.pkg, e.Pos(), 1, 18) {
- check.versionErrorf(e.Pos(), "go1.18", "type instantiation")
- }
+ check.allowVersionf(check.pkg, e, 1, 18, "type instantiation")
return check.instantiatedType(e.X, unpackExpr(e.Index), def)
case *syntax.ParenExpr:
import (
"cmd/compile/internal/syntax"
"errors"
+ "fmt"
"strings"
)
// allowVersion reports whether the given package
// is allowed to use version major.minor.
-func (check *Checker) allowVersion(pkg *Package, pos syntax.Pos, major, minor int) bool {
+func (check *Checker) allowVersion(pkg *Package, at poser, major, minor int) bool {
// We assume that imported packages have all been checked,
// so we only have to check for the local package.
if pkg != check.pkg {
// If the source file declares its Go version, use that to decide.
if check.posVers != nil {
- if v, ok := check.posVers[base(pos)]; ok && v.major >= 1 {
+ if v, ok := check.posVers[base(at.Pos())]; ok && v.major >= 1 {
return v.major > major || v.major == major && v.minor >= minor
}
}
return ma == 0 && mi == 0 || ma > major || ma == major && mi >= minor
}
+// allowVersionf is like allowVersion but also accepts a format string and arguments
+// which are used to report a version error if allowVersion returns false.
+func (check *Checker) allowVersionf(pkg *Package, at poser, major, minor int, format string, args ...interface{}) bool {
+ if !check.allowVersion(pkg, at, major, minor) {
+ check.versionErrorf(at, fmt.Sprintf("go%d.%d", major, minor), format, args...)
+ return false
+ }
+ return true
+}
+
// base finds the underlying PosBase of the source file containing pos,
// skipping over intermediate PosBase layers created by //line directives.
func base(pos syntax.Pos) *syntax.PosBase {
case _Clear:
// clear(m)
- if !check.allowVersion(check.pkg, call.Pos(), 1, 21) {
- check.error(call.Fun, UnsupportedFeature, "clear requires go1.21 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 21, "clear") {
return
}
case _Add:
// unsafe.Add(ptr unsafe.Pointer, len IntegerType) unsafe.Pointer
- if !check.allowVersion(check.pkg, call.Pos(), 1, 17) {
- check.error(call.Fun, UnsupportedFeature, "unsafe.Add requires go1.17 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 17, "unsafe.Add") {
return
}
case _Slice:
// unsafe.Slice(ptr *T, len IntegerType) []T
- if !check.allowVersion(check.pkg, call.Pos(), 1, 17) {
- check.error(call.Fun, UnsupportedFeature, "unsafe.Slice requires go1.17 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 17, "unsafe.Slice") {
return
}
case _SliceData:
// unsafe.SliceData(slice []T) *T
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.error(call.Fun, UnsupportedFeature, "unsafe.SliceData requires go1.20 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.SliceData") {
return
}
case _String:
// unsafe.String(ptr *byte, len IntegerType) string
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.error(call.Fun, UnsupportedFeature, "unsafe.String requires go1.20 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.String") {
return
}
case _StringData:
// unsafe.StringData(str string) *byte
- if !check.allowVersion(check.pkg, call.Pos(), 1, 20) {
- check.error(call.Fun, UnsupportedFeature, "unsafe.StringData requires go1.20 or later")
+ if !check.allowVersionf(check.pkg, call.Fun, 1, 20, "unsafe.StringData") {
return
}
func (check *Checker) funcInst(tsig *Signature, pos token.Pos, x *operand, ix *typeparams.IndexExpr) {
assert(tsig != nil || ix != nil)
- var versionErr bool // set if version error was reported
- var instErrPos positioner // position for instantion error
+ var instErrPos positioner
if ix != nil {
instErrPos = inNode(ix.Orig, ix.Lbrack)
} else {
instErrPos = atPos(pos)
}
- if !check.allowVersion(check.pkg, pos, 1, 18) {
- check.softErrorf(instErrPos, UnsupportedFeature, "function instantiation requires go1.18 or later")
- versionErr = true
- }
+ versionErr := !check.allowVersionf(check.pkg, instErrPos, 1, 18, "function instantiation")
// targs and xlist are the type arguments and corresponding type expressions, or nil.
var targs []Type
// of a synthetic function f where f's parameters are the parameters and results
// of x and where the arguments to the call of f are values of the parameter and
// result types of x.
- if !versionErr && !check.allowVersion(check.pkg, pos, 1, 21) {
+ if !versionErr && !check.allowVersion(check.pkg, instErrPos, 1, 21) {
if ix != nil {
- check.softErrorf(instErrPos, UnsupportedFeature, "partially instantiated function in assignment requires go1.21 or later")
+ check.versionErrorf(instErrPos, "go1.21", "partially instantiated function in assignment")
} else {
- check.softErrorf(instErrPos, UnsupportedFeature, "implicitly instantiated function in assignment requires go1.21 or later")
+ check.versionErrorf(instErrPos, "go1.21", "implicitly instantiated function in assignment")
}
}
n := tsig.params.Len()
// is an error checking its arguments (for example, if an incorrect number
// of arguments is supplied).
if got == want && want > 0 {
- if !check.allowVersion(check.pkg, ix.Pos(), 1, 18) {
- check.softErrorf(inNode(call.Fun, ix.Lbrack), UnsupportedFeature, "function instantiation requires go1.18 or later")
- }
+ check.allowVersionf(check.pkg, atPos(ix.Lbrack), 1, 18, "function instantiation")
sig = check.instantiateSignature(ix.Pos(), sig, targs, xlist)
assert(sig.TypeParams().Len() == 0) // signature is not generic anymore
// collect type parameters of callee
n := sig.TypeParams().Len()
if n > 0 {
- if !check.allowVersion(check.pkg, call.Pos(), 1, 18) {
+ if !check.allowVersion(check.pkg, call, 1, 18) {
switch call.Fun.(type) {
case *ast.IndexExpr, *ast.IndexListExpr:
ix := typeparams.UnpackIndexExpr(call.Fun)
- check.softErrorf(inNode(call.Fun, ix.Lbrack), UnsupportedFeature, "function instantiation requires go1.18 or later")
+ check.versionErrorf(inNode(call.Fun, ix.Lbrack), "go1.18", "function instantiation")
default:
- check.softErrorf(inNode(call, call.Lparen), UnsupportedFeature, "implicit function instantiation requires go1.18 or later")
+ check.versionErrorf(inNode(call, call.Lparen), "go1.18", "implicit function instantiation")
}
}
// rename type parameters to avoid problems with recursive calls
}
}
}
- if len(genericArgs) > 0 && !check.allowVersion(check.pkg, call.Pos(), 1, 21) {
- // at the moment we only support implicit instantiations of argument functions
- check.softErrorf(inNode(call, call.Lparen), UnsupportedFeature, "implicitly instantiated function as argument requires go1.21 or later")
- }
+ // at the moment we only support implicit instantiations of argument functions
+ _ = len(genericArgs) > 0 && check.allowVersionf(check.pkg, args[genericArgs[0]], 1, 21, "implicitly instantiated function as argument")
// tparams holds the type parameters of the callee and generic function arguments, if any:
// the first n type parameters belong to the callee, followed by mi type parameters for each
switch a := Tu.(type) {
case *Array:
if Identical(s.Elem(), a.Elem()) {
- if check == nil || check.allowVersion(check.pkg, x.Pos(), 1, 20) {
+ if check == nil || check.allowVersion(check.pkg, x, 1, 20) {
return true
}
// check != nil
case *Pointer:
if a, _ := under(a.Elem()).(*Array); a != nil {
if Identical(s.Elem(), a.Elem()) {
- if check == nil || check.allowVersion(check.pkg, x.Pos(), 1, 17) {
+ if check == nil || check.allowVersion(check.pkg, x, 1, 17) {
return true
}
// check != nil
check.validType(t)
}
// If typ is local, an error was already reported where typ is specified/defined.
- if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, tdecl.Pos(), 1, 18) {
- check.errorf(tdecl.Type, UnsupportedFeature, "using type constraint %s requires go1.18 or later", rhs)
- }
+ _ = check.isImportedConstraint(rhs) && check.allowVersionf(check.pkg, tdecl.Type, 1, 18, "using type constraint %s", rhs)
}).describef(obj, "validType(%s)", obj.Name())
alias := tdecl.Assign.IsValid()
// alias declaration
if alias {
- if !check.allowVersion(check.pkg, tdecl.Pos(), 1, 9) {
- check.error(atPos(tdecl.Assign), UnsupportedFeature, "type aliases requires go1.9 or later")
- }
-
+ check.allowVersionf(check.pkg, atPos(tdecl.Assign), 1, 9, "type aliases")
check.brokenAlias(obj)
rhs = check.typ(tdecl.Type)
check.validAlias(obj, rhs)
// Check that RHS is otherwise at least of integer type.
switch {
case allInteger(y.typ):
- if !allUnsigned(y.typ) && !check.allowVersion(check.pkg, x.Pos(), 1, 13) {
- check.errorf(y, UnsupportedFeature, invalidOp+"signed shift count %s requires go1.13 or later", y)
+ if !allUnsigned(y.typ) && !check.allowVersionf(check.pkg, y, 1, 13, invalidOp+"signed shift count %s", y) {
x.mode = invalid
return
}
// so that ordinary, non-type parameter interfaces implement comparable.
if constraint && comparable(V, true /* spec comparability */, nil, nil) {
// V is comparable if we are at Go 1.20 or higher.
- if check == nil || check.allowVersion(check.pkg, pos, 1, 20) {
+ if check == nil || check.allowVersion(check.pkg, atPos(pos), 1, 20) { // atPos needed so that go/types generate passes
return true
}
if cause != nil {
check.declarePkgObj(name, obj, di)
}
case typeDecl:
- if d.spec.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, d.spec.Pos(), 1, 18) {
- check.softErrorf(d.spec.TypeParams.List[0], UnsupportedFeature, "type parameter requires go1.18 or later")
- }
+ _ = d.spec.TypeParams.NumFields() != 0 && check.allowVersionf(pkg, d.spec.TypeParams.List[0], 1, 18, "type parameter")
obj := NewTypeName(d.spec.Name.Pos(), pkg, d.spec.Name.Name, nil)
check.declarePkgObj(d.spec.Name, obj, &declInfo{file: fileScope, tdecl: d.spec})
case funcDecl:
}
check.recordDef(d.decl.Name, obj)
}
- if d.decl.Type.TypeParams.NumFields() != 0 && !check.allowVersion(pkg, d.decl.Pos(), 1, 18) && !hasTParamError {
- check.softErrorf(d.decl.Type.TypeParams.List[0], UnsupportedFeature, "type parameter requires go1.18 or later")
- }
+ _ = d.decl.Type.TypeParams.NumFields() != 0 && !hasTParamError && check.allowVersionf(pkg, d.decl.Type.TypeParams.List[0], 1, 18, "type parameter")
info := &declInfo{file: fileScope, fdecl: d.decl}
// Methods are not package-level objects but we still track them in the
// object map so that we can handle them like regular functions (if the
}
// check != nil
check.later(func() {
- if !check.allowVersion(m.pkg, pos, 1, 14) || !Identical(m.typ, other.Type()) {
+ if !check.allowVersion(m.pkg, atPos(pos), 1, 14) || !Identical(m.typ, other.Type()) {
check.errorf(atPos(pos), DuplicateDecl, "duplicate method %s", m.name)
check.errorf(atPos(mpos[other.(*Func)]), DuplicateDecl, "\tother declaration of %s", m.name) // secondary error, \t indented
}
assert(!isTypeParam(typ))
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, pos, 1, 18) {
- check.errorf(atPos(pos), UnsupportedFeature, "embedding constraint interface %s requires go1.18 or later", typ)
+ if check != nil && check.isImportedConstraint(typ) && !check.allowVersionf(check.pkg, atPos(pos), 1, 18, "embedding constraint interface %s", typ) {
continue
}
comparable = tset.comparable
}
terms = tset.terms
case *Union:
- if check != nil && !check.allowVersion(check.pkg, pos, 1, 18) {
- check.errorf(atPos(pos), UnsupportedFeature, "embedding interface element %s requires go1.18 or later", u)
+ if check != nil && !check.allowVersionf(check.pkg, atPos(pos), 1, 18, "embedding interface element %s", u) {
continue
}
tset := computeUnionTypeSet(check, unionSets, pos, u)
if u == Typ[Invalid] {
continue
}
- if check != nil && !check.allowVersion(check.pkg, pos, 1, 18) {
- check.errorf(atPos(pos), UnsupportedFeature, "embedding non-interface type %s requires go1.18 or later", typ)
+ if check != nil && !check.allowVersionf(check.pkg, atPos(pos), 1, 18, "embedding non-interface type %s", typ) {
continue
}
terms = termlist{{false, typ}}
}
return
case universeAny, universeComparable:
- if !check.allowVersion(check.pkg, e.Pos(), 1, 18) {
- check.versionErrorf(e, "go1.18", "predeclared %s", e.Name)
+ if !check.allowVersionf(check.pkg, e, 1, 18, "predeclared %s", e.Name) {
return // avoid follow-on errors
}
}
case *ast.IndexExpr, *ast.IndexListExpr:
ix := typeparams.UnpackIndexExpr(e)
- if !check.allowVersion(check.pkg, e.Pos(), 1, 18) {
- check.softErrorf(inNode(e, ix.Lbrack), UnsupportedFeature, "type instantiation requires go1.18 or later")
- }
+ check.allowVersionf(check.pkg, inNode(e, ix.Lbrack), 1, 18, "type instantiation")
return check.instantiatedType(ix, def)
case *ast.ParenExpr:
import (
"errors"
+ "fmt"
"go/ast"
"go/token"
- . "internal/types/errors"
"strings"
)
// literal is not compatible with the current language version.
func (check *Checker) langCompat(lit *ast.BasicLit) {
s := lit.Value
- if len(s) <= 2 || check.allowVersion(check.pkg, lit.Pos(), 1, 13) {
+ if len(s) <= 2 || check.allowVersion(check.pkg, lit, 1, 13) {
return
}
// len(s) > 2
if strings.Contains(s, "_") {
- check.error(lit, UnsupportedFeature, "underscores in numeric literals requires go1.13 or later")
+ check.versionErrorf(lit, "go1.13", "underscores in numeric literals")
return
}
if s[0] != '0' {
}
radix := s[1]
if radix == 'b' || radix == 'B' {
- check.error(lit, UnsupportedFeature, "binary literals requires go1.13 or later")
+ check.versionErrorf(lit, "go1.13", "binary literals")
return
}
if radix == 'o' || radix == 'O' {
- check.error(lit, UnsupportedFeature, "0o/0O-style octal literals requires go1.13 or later")
+ check.versionErrorf(lit, "go1.13", "0o/0O-style octal literals")
return
}
if lit.Kind != token.INT && (radix == 'x' || radix == 'X') {
- check.error(lit, UnsupportedFeature, "hexadecimal floating-point literals requires go1.13 or later")
+ check.versionErrorf(lit, "go1.13", "hexadecimal floating-point literals")
}
}
// allowVersion reports whether the given package
// is allowed to use version major.minor.
-func (check *Checker) allowVersion(pkg *Package, pos token.Pos, major, minor int) bool {
+func (check *Checker) allowVersion(pkg *Package, at positioner, major, minor int) bool {
// We assume that imported packages have all been checked,
// so we only have to check for the local package.
if pkg != check.pkg {
// If the source file declares its Go version, use that to decide.
if check.posVers != nil {
- if v, ok := check.posVers[check.fset.File(pos)]; ok && v.major >= 1 {
+ if v, ok := check.posVers[check.fset.File(at.Pos())]; ok && v.major >= 1 {
return v.major > major || v.major == major && v.minor >= minor
}
}
return ma == 0 && mi == 0 || ma > major || ma == major && mi >= minor
}
+// allowVersionf is like allowVersion but also accepts a format string and arguments
+// which are used to report a version error if allowVersion returns false.
+func (check *Checker) allowVersionf(pkg *Package, at positioner, major, minor int, format string, args ...interface{}) bool {
+ if !check.allowVersion(pkg, at, major, minor) {
+ check.versionErrorf(at, fmt.Sprintf("go%d.%d", major, minor), format, args...)
+ return false
+ }
+ return true
+}
+
type version struct {
major, minor int
}
func f2(int, func(int)) {}
func _() {
- f1( /* ERROR "implicitly instantiated function as argument requires go1.21 or later" */ g)
- f2( /* ERROR "implicitly instantiated function as argument requires go1.21 or later" */ 0, g)
+ f1(g /* ERROR "implicitly instantiated function as argument requires go1.21 or later" */)
+ f2(0, g /* ERROR "implicitly instantiated function as argument requires go1.21 or later" */)
}