]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/cmd/compile/internal/types2/decl.go
go/types, types2: introduce _Alias type node
[gostls13.git] / src / cmd / compile / internal / types2 / decl.go
index 94cbdd2b90090ff6f91b6a9eb435c4312ef0ddce..6fd2c2cad8f112e1bd1fed4ed4b31520c33805cd 100644 (file)
@@ -8,6 +8,7 @@ import (
        "cmd/compile/internal/syntax"
        "fmt"
        "go/constant"
+       . "internal/types/errors"
 )
 
 func (err *error_) recordAltDecl(obj Object) {
@@ -27,6 +28,7 @@ func (check *Checker) declare(scope *Scope, id *syntax.Name, obj Object, pos syn
        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)
@@ -51,9 +53,9 @@ func pathString(path []Object) string {
        return s
 }
 
-// objDecl type-checks the declaration of obj in its respective (file) context.
+// 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
@@ -66,12 +68,6 @@ func (check *Checker) objDecl(obj Object, def *Named) {
                }()
        }
 
-       // Funcs with m.instRecv set have not yet be completed. Complete them now
-       // so that they have a type when objDecl exits.
-       if m, _ := obj.(*Func); m != nil && m.instRecv != nil {
-               check.completeMethod(check.conf.Context, m)
-       }
-
        // Checking the declaration of obj means inferring its type
        // (and possibly its value, for constants).
        // An object's type (and thus the object) may be in one of
@@ -178,11 +174,11 @@ func (check *Checker) objDecl(obj Object, def *Named) {
                unreachable()
        }
 
-       // save/restore current context and setup object context
-       defer func(ctxt context) {
-               check.context = ctxt
-       }(check.context)
-       check.context = context{
+       // save/restore current environment and set up object environment
+       defer func(env environment) {
+               check.environment = env
+       }(check.environment)
+       check.environment = environment{
                scope: d.file,
        }
 
@@ -228,13 +224,23 @@ func (check *Checker) validCycle(obj Object) (valid bool) {
        assert(obj.color() >= grey)
        start := obj.color() - grey // index of obj in objPath
        cycle := check.objPath[start:]
-       nval := 0 // number of (constant or variable) values in the cycle
-       ndef := 0 // number of type definitions in the cycle
+       tparCycle := false // if set, the cycle is through a type parameter list
+       nval := 0          // number of (constant or variable) values in the cycle; valid if !generic
+       ndef := 0          // number of type definitions in the cycle; valid if !generic
+loop:
        for _, obj := range cycle {
                switch obj := obj.(type) {
                case *Const, *Var:
                        nval++
                case *TypeName:
+                       // If we reach a generic type that is part of a cycle
+                       // and we are in a type parameter list, we have a cycle
+                       // through a type parameter list, which is invalid.
+                       if check.inTParamList && isGeneric(obj.typ) {
+                               tparCycle = true
+                               break loop
+                       }
+
                        // Determine if the type name is an alias or not. For
                        // package-level objects, use the object map which
                        // provides syntactic information (which doesn't rely
@@ -245,10 +251,14 @@ func (check *Checker) validCycle(obj Object) (valid bool) {
                        // 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.conf._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++
@@ -262,145 +272,94 @@ func (check *Checker) validCycle(obj Object) (valid bool) {
 
        if check.conf.Trace {
                check.trace(obj.Pos(), "## cycle detected: objPath = %s->%s (len = %d)", pathString(cycle), obj.Name(), len(cycle))
-               check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
+               if tparCycle {
+                       check.trace(obj.Pos(), "## cycle contains: generic type in a type parameter list")
+               } else {
+                       check.trace(obj.Pos(), "## cycle contains: %d values, %d type definitions", nval, ndef)
+               }
                defer func() {
-                       if !valid {
+                       if valid {
+                               check.trace(obj.Pos(), "=> cycle is valid")
+                       } else {
                                check.trace(obj.Pos(), "=> error: cycle is invalid")
                        }
                }()
        }
 
-       // A cycle involving only constants and variables is invalid but we
-       // ignore them here because they are reported via the initialization
-       // cycle check.
-       if nval == len(cycle) {
-               return true
-       }
-
-       // A cycle involving only types (and possibly functions) must have at least
-       // one type definition to be permitted: If there is no type definition, we
-       // have a sequence of alias type names which will expand ad infinitum.
-       if nval == 0 && ndef > 0 {
-               return true
-       }
-
-       check.cycleError(cycle)
-       return false
-}
-
-type typeInfo uint
-
-// validType verifies that the given type does not "expand" infinitely
-// producing a cycle in the type graph. Cycles are detected by marking
-// defined types.
-// (Cycles involving alias types, as in "type A = [10]A" are detected
-// earlier, via the objDecl cycle detection mechanism.)
-func (check *Checker) validType(typ Type, path []Object) typeInfo {
-       const (
-               unknown typeInfo = iota
-               marked
-               valid
-               invalid
-       )
-
-       switch t := typ.(type) {
-       case *Array:
-               return check.validType(t.elem, path)
-
-       case *Struct:
-               for _, f := range t.fields {
-                       if check.validType(f.typ, path) == invalid {
-                               return invalid
-                       }
+       if !tparCycle {
+               // A cycle involving only constants and variables is invalid but we
+               // ignore them here because they are reported via the initialization
+               // cycle check.
+               if nval == len(cycle) {
+                       return true
                }
 
-       case *Union:
-               for _, t := range t.terms {
-                       if check.validType(t.typ, path) == invalid {
-                               return invalid
-                       }
-               }
-
-       case *Interface:
-               for _, etyp := range t.embeddeds {
-                       if check.validType(etyp, path) == invalid {
-                               return invalid
-                       }
+               // A cycle involving only types (and possibly functions) must have at least
+               // one type definition to be permitted: If there is no type definition, we
+               // have a sequence of alias type names which will expand ad infinitum.
+               if nval == 0 && ndef > 0 {
+                       return true
                }
-
-       case *Named:
-               // If t is parameterized, we should be considering the instantiated (expanded)
-               // form of t, but in general we can't with this algorithm: if t is an invalid
-               // type it may be so because it infinitely expands through a type parameter.
-               // Instantiating such a type would lead to an infinite sequence of instantiations.
-               // In general, we need "type flow analysis" to recognize those cases.
-               // Example: type A[T any] struct{ x A[*T] } (issue #48951)
-               // In this algorithm we always only consider the orginal, uninstantiated type.
-               // This won't recognize some invalid cases with parameterized types, but it
-               // will terminate.
-               t = t.orig
-
-               // don't touch the type if it is from a different package or the Universe scope
-               // (doing so would lead to a race condition - was issue #35049)
-               if t.obj.pkg != check.pkg {
-                       return valid
-               }
-
-               // don't report a 2nd error if we already know the type is invalid
-               // (e.g., if a cycle was detected earlier, via under).
-               if t.underlying == Typ[Invalid] {
-                       t.info = invalid
-                       return invalid
-               }
-
-               switch t.info {
-               case unknown:
-                       t.info = marked
-                       t.info = check.validType(t.fromRHS, append(path, t.obj)) // only types of current package added to path
-               case marked:
-                       // cycle detected
-                       for i, tn := range path {
-                               if t.obj.pkg != check.pkg {
-                                       panic("type cycle via package-external type")
-                               }
-                               if tn == t.obj {
-                                       check.cycleError(path[i:])
-                                       t.info = invalid
-                                       t.underlying = Typ[Invalid]
-                                       return invalid
-                               }
-                       }
-                       panic("cycle start not found")
-               }
-               return t.info
        }
 
-       return valid
+       check.cycleError(cycle)
+       return false
 }
 
 // cycleError reports a declaration cycle starting with
 // the object in cycle that is "first" in the source.
 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 go.dev/issue/50788.
+       // TODO(gri) This functionality is used elsewhere. Factor it out.
+       name := func(obj Object) 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
        //           since that is the earliest point in the source where we start seeing the
        //           cycle? That would be more consistent with other error messages.
        i := firstInSrc(cycle)
        obj := cycle[i]
+       objName := name(obj)
+       // 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() {
+               // If we use Alias nodes, it is initialized with Typ[Invalid].
+               // TODO(gri) Adjust this code if we initialize with nil.
+               if !check.conf._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 check.conf.CompilerErrorMessages {
-               err.errorf(obj, "invalid recursive type %s", obj.Name())
+       err.code = InvalidDeclCycle
+       if tname != nil {
+               err.errorf(obj, "invalid recursive type %s", objName)
        } else {
-               err.errorf(obj, "illegal cycle in declaration of %s", obj.Name())
+               err.errorf(obj, "invalid cycle in declaration of %s", objName)
        }
        for range cycle {
-               err.errorf(obj, "%s refers to", obj.Name())
+               err.errorf(obj, "%s refers to", objName)
                i++
                if i >= len(cycle) {
                        i = 0
                }
                obj = cycle[i]
+               objName = name(obj)
        }
-       err.errorf(obj, "%s", obj.Name())
+       err.errorf(obj, "%s", objName)
        check.report(&err)
 }
 
@@ -409,7 +368,7 @@ func (check *Checker) cycleError(cycle []Object) {
 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()
                }
        }
@@ -435,9 +394,9 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
                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, "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
@@ -454,10 +413,10 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
                        // 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)
 }
@@ -465,20 +424,6 @@ func (check *Checker) constDecl(obj *Const, typ, init syntax.Expr, inherited boo
 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)
@@ -504,7 +449,7 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
        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
        }
@@ -526,19 +471,19 @@ func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init syntax.Expr) {
        // 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
                }
        }
 
-       check.initVars(lhs, []syntax.Expr{init}, nopos)
+       check.initVars(lhs, []syntax.Expr{init}, nil)
 }
 
 // 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
        }
@@ -546,41 +491,50 @@ func (check *Checker) isImportedConstraint(typ Type) bool {
        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() {
-               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.versionErrorf(tdecl.Type.Pos(), "go1.18", "using type constraint %s", rhs)
+               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.
+               _ = 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, "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.conf._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)
                }
-
-               obj.typ = Typ[Invalid]
-               rhs = check.varType(tdecl.Type)
-               obj.typ = rhs
                return
        }
 
        // type definition or generic type declaration
-       named := check.newNamed(obj, nil, nil, nil, nil)
-       def.setUnderlying(named)
+       named := check.newNamed(obj, nil, nil)
+       setDefType(def, named)
 
        if tdecl.TParamList != nil {
                check.openScope(tdecl, "type parameters")
@@ -589,22 +543,23 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
        }
 
        // determine underlying type of named
-       rhs = check.definedType(tdecl.Type, named)
+       rhs = check.definedType(tdecl.Type, obj)
        assert(rhs != nil)
        named.fromRHS = rhs
 
-       // If the underlying was not set while type-checking the right-hand side, it
-       // is invalid and an error should have been reported elsewhere.
+       // If the underlying type was not set while type-checking the right-hand
+       // side, it is invalid and an error should have been reported elsewhere.
        if named.underlying == nil {
                named.underlying = Typ[Invalid]
        }
 
-       // Disallow a lone type parameter as the RHS of a type declaration (issue #45639).
-       // We can look directly at named.underlying because even if it is still a *Named
-       // 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, "cannot use a type parameter as RHS in type declaration")
+       // 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")
                named.underlying = Typ[Invalid]
        }
 }
@@ -620,36 +575,42 @@ func (check *Checker) collectTypeParams(dst **TypeParamList, list []*syntax.Fiel
        }
 
        // 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)
 
+       // Signal to cycle detection that we are in a type parameter list.
+       // We can only be inside one type parameter list at any given time:
+       // function closures may appear inside a type parameter list but they
+       // cannot be generic, and their bodies are processed in delayed and
+       // sequential fashion. Note that with each new declaration, we save
+       // the existing environment and restore it when done; thus inTParamList
+       // is true exactly only when we are in a specific type parameter list.
+       assert(!check.inTParamList)
+       check.inTParamList = true
+       defer func() {
+               check.inTParamList = false
+       }()
+
        // Keep track of bounds for later validation.
        var bound Type
-       var bounds []Type
-       var posers []poser
        for i, f := range list {
                // Optimization: Re-use the previous type bound if it hasn't changed.
                // This also preserves the grouped output of type parameter lists
                // when printing type strings.
                if i == 0 || f.Type != list[i-1].Type {
                        bound = check.bound(f.Type)
-                       bounds = append(bounds, bound)
-                       posers = append(posers, f.Type)
+                       if isTypeParam(bound) {
+                               // We may be able to allow this since it is now well-defined what
+                               // 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")
+                               bound = Typ[Invalid]
+                       }
                }
                tparams[i].bound = bound
        }
-
-       check.later(func() {
-               for i, bound := range bounds {
-                       if _, ok := under(bound).(*TypeParam); ok {
-                               check.error(posers[i], "cannot use a type parameter as constraint")
-                       }
-               }
-               for _, tpar := range tparams {
-                       tpar.iface() // compute type set
-               }
-       })
 }
 
 func (check *Checker) bound(x syntax.Expr) Type {
@@ -699,19 +660,19 @@ func (check *Checker) collectMethods(obj *TypeName) {
        // and field names must be distinct."
        base := asNamed(obj.typ) // shouldn't fail but be conservative
        if base != nil {
-               u := base.under()
-               if t, _ := u.(*Struct); t != nil {
-                       for _, fld := range t.fields {
-                               if fld.name != "_" {
-                                       assert(mset.insert(fld) == nil)
-                               }
-                       }
-               }
+               assert(base.TypeArgs().Len() == 0) // collectMethods should not be called on an instantiated type
+
+               // 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)
+               }).describef(obj, "verifying field uniqueness for %v", base)
 
                // Checker.Files may be called multiple times; additional package files
                // may add methods to already type-checked types. Add pre-existing methods
                // so that we can detect redeclarations.
-               for _, m := range base.methods {
+               for i := 0; i < base.NumMethods(); i++ {
+                       m := base.Method(i)
                        assert(m.name != "_")
                        assert(mset.insert(m) == nil)
                }
@@ -723,27 +684,47 @@ func (check *Checker) collectMethods(obj *TypeName) {
                // to it must be unique."
                assert(m.name != "_")
                if alt := mset.insert(m); alt != nil {
-                       var err error_
-                       switch alt.(type) {
-                       case *Var:
-                               err.errorf(m.pos, "field and method with the same name %s", m.name)
-                       case *Func:
-                               if check.conf.CompilerErrorMessages {
-                                       err.errorf(m.pos, "%s.%s redeclared in this block", obj.Name(), m.name)
-                               } else {
-                                       err.errorf(m.pos, "method %s already declared for %s", m.name, obj)
-                               }
-                       default:
-                               unreachable()
+                       if alt.Pos().IsKnown() {
+                               check.errorf(m.pos, DuplicateMethod, "method %s.%s already declared at %s", obj.Name(), m.name, alt.Pos())
+                       } else {
+                               check.errorf(m.pos, DuplicateMethod, "method %s.%s already declared", obj.Name(), m.name)
                        }
-                       err.recordAltDecl(alt)
-                       check.report(&err)
                        continue
                }
 
                if base != nil {
-                       base.resolve(nil) // TODO(mdempsky): Probably unnecessary.
-                       base.methods = append(base.methods, m)
+                       base.AddMethod(m)
+               }
+       }
+}
+
+func (check *Checker) checkFieldUniqueness(base *Named) {
+       if t, _ := base.under().(*Struct); t != nil {
+               var mset objset
+               for i := 0; i < base.NumMethods(); i++ {
+                       m := base.Method(i)
+                       assert(m.name != "_")
+                       assert(mset.insert(m) == nil)
+               }
+
+               // Check that any non-blank field names of base are distinct from its
+               // method names.
+               for _, fld := range t.fields {
+                       if fld.name != "_" {
+                               if alt := mset.insert(fld); alt != nil {
+                                       // Struct fields should already be unique, so we should only
+                                       // encounter an alternate via collision with a method name.
+                                       _ = alt.(*Func)
+
+                                       // 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.errorf(alt, "field and method with the same name %s", fld.name)
+                                       err.recordAltDecl(fld)
+                                       check.report(&err)
+                               }
+                       }
                }
        }
 }
@@ -770,7 +751,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
        obj.color_ = saved
 
        if len(fdecl.TParamList) > 0 && fdecl.Body == nil {
-               check.softErrorf(fdecl, "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
@@ -778,7 +759,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
        if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
                check.later(func() {
                        check.funcBody(decl, obj.name, sig, fdecl.Body, nil)
-               })
+               }).describef(obj, "func %s", obj.name)
        }
 }
 
@@ -797,7 +778,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
                        top := len(check.delayed)
 
                        // iota is the index of the current constDecl within the group
-                       if first < 0 || list[index-1].(*syntax.ConstDecl).Group != s.Group {
+                       if first < 0 || s.Group == nil || list[index-1].(*syntax.ConstDecl).Group != s.Group {
                                first = index
                                last = nil
                        }
@@ -816,7 +797,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
 
                        // 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
@@ -853,7 +834,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
                        }
 
                        // initialize all variables
-                       values := unpackExpr(s.Values)
+                       values := syntax.UnpackListExpr(s.Values)
                        for i, obj := range lhs0 {
                                var lhs []*Var
                                var init syntax.Expr
@@ -915,7 +896,7 @@ func (check *Checker) declStmt(list []syntax.Decl) {
                        check.pop().setColor(black)
 
                default:
-                       check.errorf(s, invalidAST+"unknown syntax.Decl node %T", s)
+                       check.errorf(s, InvalidSyntaxTree, "unknown syntax.Decl node %T", s)
                }
        }
 }