package types2
import (
- "bytes"
"cmd/compile/internal/syntax"
"fmt"
"go/constant"
+ . "internal/types/errors"
)
func (err *error_) recordAltDecl(obj Object) {
if obj.Name() != "_" {
if alt := scope.Insert(obj); alt != nil {
var err error_
+ err.code = DuplicateDecl
err.errorf(obj, "%s redeclared in this block", obj.Name())
err.recordAltDecl(alt)
check.report(&err)
// objDecl type-checks the declaration of obj in its respective (file) environment.
// For the meaning of def, see Checker.definedType, in typexpr.go.
-func (check *Checker) objDecl(obj Object, def *Named) {
+func (check *Checker) objDecl(obj Object, def *TypeName) {
if check.conf.Trace && obj.Type() == nil {
if check.indent == 0 {
fmt.Println() // empty line between top-level objects for readability
// the syntactic information. We should consider storing
// this information explicitly in the object.
var alias bool
- if d := check.objMap[obj]; d != nil {
- alias = d.tdecl.Alias // package-level object
+ if check.enableAlias {
+ alias = obj.IsAlias()
} else {
- alias = obj.IsAlias() // function local object
+ if d := check.objMap[obj]; d != nil {
+ alias = d.tdecl.Alias // package-level object
+ } else {
+ alias = obj.IsAlias() // function local object
+ }
}
if !alias {
ndef++
func (check *Checker) cycleError(cycle []Object) {
// name returns the (possibly qualified) object name.
// This is needed because with generic types, cycles
- // may refer to imported types. See issue #50788.
- // TODO(gri) Thus functionality is used elsewhere. Factor it out.
+ // may refer to imported types. See go.dev/issue/50788.
+ // TODO(gri) This functionality is used elsewhere. Factor it out.
name := func(obj Object) string {
- var buf bytes.Buffer
- writePackage(&buf, obj.Pkg(), check.qualifier)
- buf.WriteString(obj.Name())
- return buf.String()
+ return packagePrefix(obj.Pkg(), check.qualifier) + obj.Name()
}
// TODO(gri) Should we start with the last (rather than the first) object in the cycle
// If obj is a type alias, mark it as valid (not broken) in order to avoid follow-on errors.
tname, _ := obj.(*TypeName)
if tname != nil && tname.IsAlias() {
- check.validAlias(tname, Typ[Invalid])
+ // If we use Alias nodes, it is initialized with Typ[Invalid].
+ // TODO(gri) Adjust this code if we initialize with nil.
+ if !check.enableAlias {
+ check.validAlias(tname, Typ[Invalid])
+ }
}
+
+ // report a more concise error for self references
+ if len(cycle) == 1 {
+ if tname != nil {
+ check.errorf(obj, InvalidDeclCycle, "invalid recursive type: %s refers to itself", objName)
+ } else {
+ check.errorf(obj, InvalidDeclCycle, "invalid cycle in declaration: %s refers to itself", objName)
+ }
+ return
+ }
+
var err error_
- if tname != nil && check.conf.CompilerErrorMessages {
+ err.code = InvalidDeclCycle
+ if tname != nil {
err.errorf(obj, "invalid recursive type %s", objName)
} else {
- err.errorf(obj, "illegal cycle in declaration of %s", objName)
+ err.errorf(obj, "invalid cycle in declaration of %s", objName)
}
for range cycle {
err.errorf(obj, "%s refers to", objName)
func firstInSrc(path []Object) int {
fst, pos := 0, path[0].Pos()
for i, t := range path[1:] {
- if t.Pos().Cmp(pos) < 0 {
+ if cmpPos(t.Pos(), pos) < 0 {
fst, pos = i+1, t.Pos()
}
}
t := check.typ(typ)
if !isConstType(t) {
// don't report an error if the type is an invalid C (defined) type
- // (issue #22090)
- if under(t) != Typ[Invalid] {
- check.errorf(typ, _InvalidConstType, "invalid constant type %s", t)
+ // (go.dev/issue/22090)
+ if isValid(under(t)) {
+ check.errorf(typ, InvalidConstType, "invalid constant type %s", t)
}
obj.typ = Typ[Invalid]
return
// expression and not the current constant declaration. Use
// the constant identifier position for any errors during
// init expression evaluation since that is all we have
- // (see issues #42991, #42992).
+ // (see issues go.dev/issue/42991, go.dev/issue/42992).
check.errpos = obj.pos
}
- check.expr(&x, init)
+ check.expr(nil, &x, init)
}
check.initConst(obj, &x)
}
func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
assert(obj.typ == nil)
- // If we have undefined variable types due to errors,
- // mark variables as used to avoid follow-on errors.
- // Matches compiler behavior.
- defer func() {
- if obj.typ == Typ[Invalid] {
- obj.used = true
- }
- for _, lhs := range lhs {
- if lhs.typ == Typ[Invalid] {
- lhs.used = true
- }
- }
- }()
-
// determine type, if any
if typ != nil {
obj.typ = check.varType(typ)
if lhs == nil || len(lhs) == 1 {
assert(lhs == nil || lhs[0] == obj)
var x operand
- check.expr(&x, init)
+ check.expr(obj.typ, &x, init)
check.initVar(obj, &x, "variable declaration")
return
}
// We have multiple variables on the lhs and one init expr.
// Make sure all variables have been given the same type if
// one was specified, otherwise they assume the type of the
- // init expression values (was issue #15755).
+ // init expression values (was go.dev/issue/15755).
if typ != nil {
for _, lhs := range lhs {
lhs.typ = obj.typ
// isImportedConstraint reports whether typ is an imported type constraint.
func (check *Checker) isImportedConstraint(typ Type) bool {
- named, _ := typ.(*Named)
+ named := asNamed(typ)
if named == nil || named.obj.pkg == check.pkg || named.obj.pkg == nil {
return false
}
return u != nil && !u.IsMethodSet()
}
-func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named) {
+func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *TypeName) {
assert(obj.typ == nil)
var rhs Type
check.later(func() {
- if t, _ := obj.typ.(*Named); t != nil { // type may be invalid
+ if t := asNamed(obj.typ); t != nil { // type may be invalid
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, 1, 18) {
- check.versionErrorf(tdecl.Type, "go1.18", "using type constraint %s", rhs)
- }
+ _ = check.isImportedConstraint(rhs) && check.verifyVersionf(tdecl.Type, go1_18, "using type constraint %s", rhs)
}).describef(obj, "validType(%s)", obj.Name())
- alias := tdecl.Alias
- if alias && tdecl.TParamList != nil {
+ aliasDecl := tdecl.Alias
+ if aliasDecl && tdecl.TParamList != nil {
// The parser will ensure this but we may still get an invalid AST.
// Complain and continue as regular type definition.
- check.error(tdecl, _BadDecl, "generic type cannot be alias")
- alias = false
+ check.error(tdecl, BadDecl, "generic type cannot be alias")
+ aliasDecl = false
}
// alias declaration
- if alias {
- if !check.allowVersion(check.pkg, 1, 9) {
- check.versionErrorf(tdecl, "go1.9", "type aliases")
+ if aliasDecl {
+ check.verifyVersionf(tdecl, go1_9, "type aliases")
+ if check.enableAlias {
+ // TODO(gri) Should be able to use nil instead of Typ[Invalid] to mark
+ // the alias as incomplete. Currently this causes problems
+ // with certain cycles. Investigate.
+ alias := check.newAlias(obj, Typ[Invalid])
+ setDefType(def, alias)
+ rhs = check.definedType(tdecl.Type, obj)
+ assert(rhs != nil)
+ alias.fromRHS = rhs
+ Unalias(alias) // resolve alias.actual
+ } else {
+ check.brokenAlias(obj)
+ rhs = check.typ(tdecl.Type)
+ check.validAlias(obj, rhs)
}
-
- check.brokenAlias(obj)
- rhs = check.typ(tdecl.Type)
- check.validAlias(obj, rhs)
return
}
// type definition or generic type declaration
named := check.newNamed(obj, nil, nil)
- def.setUnderlying(named)
+ setDefType(def, named)
if tdecl.TParamList != nil {
check.openScope(tdecl, "type parameters")
}
// determine underlying type of named
- rhs = check.definedType(tdecl.Type, named)
+ rhs = check.definedType(tdecl.Type, obj)
assert(rhs != nil)
named.fromRHS = rhs
named.underlying = Typ[Invalid]
}
- // Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
+ // Disallow a lone type parameter as the RHS of a type declaration (go.dev/issue/45639).
// We don't need this restriction anymore if we make the underlying type of a type
// parameter its constraint interface: if the RHS is a lone type parameter, we will
// use its underlying type (like we do for any RHS in a type declaration), and its
// underlying type is an interface and the type declaration is well defined.
if isTypeParam(rhs) {
- check.error(tdecl.Type, _MisplacedTypeParam, "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]
}
}
}
// Set the type parameters before collecting the type constraints because
- // the parameterized type may be used by the constraints (issue #47887).
+ // the parameterized type may be used by the constraints (go.dev/issue/47887).
// Example: type T[P T[P]] interface{}
*dst = bindTParams(tparams)
// the underlying type and thus type set of a type parameter is.
// But we may need some additional form of cycle detection within
// type parameter lists.
- check.error(f.Type, _MisplacedTypeParam, "cannot use a type parameter as constraint")
+ check.error(f.Type, MisplacedTypeParam, "cannot use a type parameter as constraint")
bound = Typ[Invalid]
}
}
// spec: "If the base type is a struct type, the non-blank method
// and field names must be distinct."
- base, _ := obj.typ.(*Named) // shouldn't fail but be conservative
+ base := asNamed(obj.typ) // shouldn't fail but be conservative
if base != nil {
assert(base.TypeArgs().Len() == 0) // collectMethods should not be called on an instantiated type
- // See issue #52529: we must delay the expansion of underlying here, as
+ // See go.dev/issue/52529: we must delay the expansion of underlying here, as
// base may not be fully set-up.
check.later(func() {
check.checkFieldUniqueness(base)
// to it must be unique."
assert(m.name != "_")
if alt := mset.insert(m); alt != nil {
- var err error_
- err.code = _DuplicateMethod
- if check.conf.CompilerErrorMessages {
- err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
+ if alt.Pos().IsKnown() {
+ check.errorf(m.pos, DuplicateMethod, "method %s.%s already declared at %s", obj.Name(), m.name, alt.Pos())
} else {
- err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
+ check.errorf(m.pos, DuplicateMethod, "method %s.%s already declared", obj.Name(), m.name)
}
- err.recordAltDecl(alt)
- check.report(&err)
continue
}
// For historical consistency, we report the primary error on the
// method, and the alt decl on the field.
var err error_
- err.code = _DuplicateFieldAndMethod
+ err.code = DuplicateFieldAndMethod
err.errorf(alt, "field and method with the same name %s", fld.name)
err.recordAltDecl(fld)
check.report(&err)
obj.color_ = saved
if len(fdecl.TParamList) > 0 && fdecl.Body == nil {
- check.softErrorf(fdecl, _BadDecl, "parameterized function is missing function body")
+ check.softErrorf(fdecl, BadDecl, "generic function is missing function body")
}
// function body must be type-checked after global declarations
// declare all constants
lhs := make([]*Const, len(s.NameList))
- values := unpackExpr(last.Values)
+ values := syntax.UnpackListExpr(last.Values)
for i, name := range s.NameList {
obj := NewConst(name.Pos(), pkg, name.Value, nil, iota)
lhs[i] = obj
}
// initialize all variables
- values := unpackExpr(s.Values)
+ values := syntax.UnpackListExpr(s.Values)
for i, obj := range lhs0 {
var lhs []*Var
var init syntax.Expr
check.pop().setColor(black)
default:
- check.errorf(s, 0, invalidAST+"unknown syntax.Decl node %T", s)
+ check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
}
}
}