// Copyright 2013 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. // This file implements type-checking of identifiers and type expressions. package types import ( "fmt" "go/ast" "go/constant" "go/internal/typeparams" "go/token" "sort" "strconv" "strings" ) // ident type-checks identifier e and initializes x with the value or type of e. // If an error occurred, x.mode is set to invalid. // For the meaning of def, see Checker.definedType, below. // If wantType is set, the identifier e is expected to denote a type. // func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) { x.mode = invalid x.expr = e // Note that we cannot use check.lookup here because the returned scope // may be different from obj.Parent(). See also Scope.LookupParent doc. scope, obj := check.scope.LookupParent(e.Name, check.pos) if obj == nil { if e.Name == "_" { check.errorf(e, _InvalidBlank, "cannot use _ as value or type") } else { check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name) } return } check.recordUse(e, obj) // Type-check the object. // Only call Checker.objDecl if the object doesn't have a type yet // (in which case we must actually determine it) or the object is a // TypeName and we also want a type (in which case we might detect // a cycle which needs to be reported). Otherwise we can skip the // call and avoid a possible cycle error in favor of the more // informative "not a type/value" error that this function's caller // will issue (see issue #25790). typ := obj.Type() if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType { check.objDecl(obj, def) typ = obj.Type() // type must have been assigned by Checker.objDecl } assert(typ != nil) // The object may have been dot-imported. // If so, mark the respective package as used. // (This code is only needed for dot-imports. Without them, // we only have to mark variables, see *Var case below). if pkgName := check.dotImportMap[dotImportKey{scope, obj}]; pkgName != nil { pkgName.used = true } switch obj := obj.(type) { case *PkgName: check.errorf(e, _InvalidPkgUse, "use of package %s not in selector", obj.name) return case *Const: check.addDeclDep(obj) if typ == Typ[Invalid] { return } if obj == universeIota { if check.iota == nil { check.errorf(e, _InvalidIota, "cannot use iota outside constant declaration") return } x.val = check.iota } else { x.val = obj.val } assert(x.val != nil) x.mode = constant_ case *TypeName: x.mode = typexpr case *Var: // It's ok to mark non-local variables, but ignore variables // from other packages to avoid potential race conditions with // dot-imported variables. if obj.pkg == check.pkg { obj.used = true } check.addDeclDep(obj) if typ == Typ[Invalid] { return } x.mode = variable case *Func: check.addDeclDep(obj) x.mode = value case *Builtin: x.id = obj.id x.mode = builtin case *Nil: x.mode = value default: unreachable() } x.typ = typ } // typ type-checks the type expression e and returns its type, or Typ[Invalid]. // The type must not be an (uninstantiated) generic type. func (check *Checker) typ(e ast.Expr) Type { return check.definedType(e, nil) } // varType type-checks the type expression e and returns its type, or Typ[Invalid]. // The type must not be an (uninstantiated) generic type and it must be ordinary // (see ordinaryType). func (check *Checker) varType(e ast.Expr) Type { typ := check.definedType(e, nil) check.ordinaryType(e, typ) return typ } // ordinaryType reports an error if typ is an interface type containing // type lists or is (or embeds) the predeclared type comparable. func (check *Checker) ordinaryType(pos positioner, typ Type) { // We don't want to call under() (via asInterface) or complete interfaces // while we are in the middle of type-checking parameter declarations that // might belong to interface methods. Delay this check to the end of // type-checking. check.later(func() { if t := asInterface(typ); t != nil { check.completeInterface(pos.Pos(), t) // TODO(gri) is this the correct position? if t.allTypes != nil { check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", t.allTypes) return } if t._IsComparable() { check.softErrorf(pos, _Todo, "interface is (or embeds) comparable") } } }) } // anyType type-checks the type expression e and returns its type, or Typ[Invalid]. // The type may be generic or instantiated. func (check *Checker) anyType(e ast.Expr) Type { typ := check.typInternal(e, nil) assert(isTyped(typ)) check.recordTypeAndValue(e, typexpr, typ, nil) return typ } // definedType is like typ but also accepts a type name def. // If def != nil, e is the type specification for the defined type def, declared // in a type declaration, and def.underlying will be set to the type of e before // any components of e are type-checked. // func (check *Checker) definedType(e ast.Expr, def *Named) Type { typ := check.typInternal(e, def) assert(isTyped(typ)) if isGeneric(typ) { check.errorf(e, _Todo, "cannot use generic type %s without instantiation", typ) typ = Typ[Invalid] } check.recordTypeAndValue(e, typexpr, typ, nil) return typ } // genericType is like typ but the type must be an (uninstantiated) generic type. func (check *Checker) genericType(e ast.Expr, reportErr bool) Type { typ := check.typInternal(e, nil) assert(isTyped(typ)) if typ != Typ[Invalid] && !isGeneric(typ) { if reportErr { check.errorf(e, _Todo, "%s is not a generic type", typ) } typ = Typ[Invalid] } // TODO(gri) what is the correct call below? check.recordTypeAndValue(e, typexpr, typ, nil) return typ } // isubst returns an x with identifiers substituted per the substitution map smap. // isubst only handles the case of (valid) method receiver type expressions correctly. func isubst(x ast.Expr, smap map[*ast.Ident]*ast.Ident) ast.Expr { switch n := x.(type) { case *ast.Ident: if alt := smap[n]; alt != nil { return alt } case *ast.StarExpr: X := isubst(n.X, smap) if X != n.X { new := *n new.X = X return &new } case *ast.IndexExpr: elems := typeparams.UnpackExpr(n.Index) var newElems []ast.Expr for i, elem := range elems { new := isubst(elem, smap) if new != elem { if newElems == nil { newElems = make([]ast.Expr, len(elems)) copy(newElems, elems) } newElems[i] = new } } if newElems != nil { index := typeparams.PackExpr(newElems) new := *n new.Index = index return &new } case *ast.ParenExpr: return isubst(n.X, smap) // no need to keep parentheses default: // Other receiver type expressions are invalid. // It's fine to ignore those here as they will // be checked elsewhere. } return x } // funcType type-checks a function or method type. func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { check.openScope(ftyp, "function") check.scope.isFunc = true check.recordScope(ftyp, check.scope) sig.scope = check.scope defer check.closeScope() var recvTyp ast.Expr // rewritten receiver type; valid if != nil if recvPar != nil && len(recvPar.List) > 0 { // collect generic receiver type parameters, if any // - a receiver type parameter is like any other type parameter, except that it is declared implicitly // - the receiver specification acts as local declaration for its type parameters, which may be blank _, rname, rparams := check.unpackRecv(recvPar.List[0].Type, true) if len(rparams) > 0 { // Blank identifiers don't get declared and regular type-checking of the instantiated // parameterized receiver type expression fails in Checker.collectParams of receiver. // Identify blank type parameters and substitute each with a unique new identifier named // "n_" (where n is the parameter index) and which cannot conflict with any user-defined // name. var smap map[*ast.Ident]*ast.Ident // substitution map from "_" to "n_" identifiers for i, p := range rparams { if p.Name == "_" { new := *p new.Name = fmt.Sprintf("%d_", i) rparams[i] = &new // use n_ identifier instead of _ so it can be looked up if smap == nil { smap = make(map[*ast.Ident]*ast.Ident) } smap[p] = &new } } if smap != nil { // blank identifiers were found => use rewritten receiver type recvTyp = isubst(recvPar.List[0].Type, smap) } sig.rparams = check.declareTypeParams(nil, rparams) // determine receiver type to get its type parameters // and the respective type parameter bounds var recvTParams []*TypeName if rname != nil { // recv should be a Named type (otherwise an error is reported elsewhere) // Also: Don't report an error via genericType since it will be reported // again when we type-check the signature. // TODO(gri) maybe the receiver should be marked as invalid instead? if recv := asNamed(check.genericType(rname, false)); recv != nil { recvTParams = recv.tparams } } // provide type parameter bounds // - only do this if we have the right number (otherwise an error is reported elsewhere) if len(sig.rparams) == len(recvTParams) { // We have a list of *TypeNames but we need a list of Types. list := make([]Type, len(sig.rparams)) for i, t := range sig.rparams { list[i] = t.typ } smap := makeSubstMap(recvTParams, list) for i, tname := range sig.rparams { bound := recvTParams[i].typ.(*_TypeParam).bound // bound is (possibly) parameterized in the context of the // receiver type declaration. Substitute parameters for the // current context. // TODO(gri) should we assume now that bounds always exist? // (no bound == empty interface) if bound != nil { bound = check.subst(tname.pos, bound, smap) tname.typ.(*_TypeParam).bound = bound } } } } } if tparams := typeparams.Get(ftyp); tparams != nil { sig.tparams = check.collectTypeParams(tparams) // Always type-check method type parameters but complain that they are not allowed. // (A separate check is needed when type-checking interface method signatures because // they don't have a receiver specification.) if recvPar != nil { check.errorf(tparams, _Todo, "methods cannot have type parameters") } } // Value (non-type) parameters' scope starts in the function body. Use a temporary scope for their // declarations and then squash that scope into the parent scope (and report any redeclarations at // that time). scope := NewScope(check.scope, token.NoPos, token.NoPos, "function body (temp. scope)") recvList, _ := check.collectParams(scope, recvPar, recvTyp, false) // use rewritten receiver type, if any params, variadic := check.collectParams(scope, ftyp.Params, nil, true) results, _ := check.collectParams(scope, ftyp.Results, nil, false) scope.squash(func(obj, alt Object) { check.errorf(obj, _DuplicateDecl, "%s redeclared in this block", obj.Name()) check.reportAltDecl(alt) }) if recvPar != nil { // recv parameter list present (may be empty) // spec: "The receiver is specified via an extra parameter section preceding the // method name. That parameter section must declare a single parameter, the receiver." var recv *Var switch len(recvList) { case 0: // error reported by resolver recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below default: // more than one receiver check.error(recvList[len(recvList)-1], _BadRecv, "method must have exactly one receiver") fallthrough // continue with first receiver case 1: recv = recvList[0] } // TODO(gri) We should delay rtyp expansion to when we actually need the // receiver; thus all checks here should be delayed to later. rtyp, _ := deref(recv.typ) rtyp = expand(rtyp) // spec: "The receiver type must be of the form T or *T where T is a type name." // (ignore invalid types - error was reported before) if t := rtyp; t != Typ[Invalid] { var err string if T := asNamed(t); T != nil { // spec: "The type denoted by T is called the receiver base type; it must not // be a pointer or interface type and it must be declared in the same package // as the method." if T.obj.pkg != check.pkg { err = "type not defined in this package" } else { switch u := optype(T).(type) { case *Basic: // unsafe.Pointer is treated like a regular pointer if u.kind == UnsafePointer { err = "unsafe.Pointer" } case *Pointer, *Interface: err = "pointer or interface type" } } } else { err = "basic or unnamed type" } if err != "" { check.errorf(recv, _InvalidRecv, "invalid receiver %s (%s)", recv.typ, err) // ok to continue } } sig.recv = recv } sig.params = NewTuple(params...) sig.results = NewTuple(results...) sig.variadic = variadic } // goTypeName returns the Go type name for typ and // removes any occurrences of "types." from that name. func goTypeName(typ Type) string { return strings.ReplaceAll(fmt.Sprintf("%T", typ), "types.", "") } // typInternal drives type checking of types. // Must only be called by definedType or genericType. // func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { if trace { check.trace(e0.Pos(), "type %s", e0) check.indent++ defer func() { check.indent-- var under Type if T != nil { // Calling under() here may lead to endless instantiations. // Test case: type T[P any] *T[P] // TODO(gri) investigate if that's a bug or to be expected // (see also analogous comment in Checker.instantiate). under = T.Underlying() } if T == under { check.trace(e0.Pos(), "=> %s // %s", T, goTypeName(T)) } else { check.trace(e0.Pos(), "=> %s (under = %s) // %s", T, under, goTypeName(T)) } }() } switch e := e0.(type) { case *ast.BadExpr: // ignore - error reported before case *ast.Ident: var x operand check.ident(&x, e, def, true) switch x.mode { case typexpr: typ := x.typ def.setUnderlying(typ) return typ case invalid: // ignore - error reported before case novalue: check.errorf(&x, _NotAType, "%s used as type", &x) default: check.errorf(&x, _NotAType, "%s is not a type", &x) } case *ast.SelectorExpr: var x operand check.selector(&x, e) switch x.mode { case typexpr: typ := x.typ def.setUnderlying(typ) return typ case invalid: // ignore - error reported before case novalue: check.errorf(&x, _NotAType, "%s used as type", &x) default: check.errorf(&x, _NotAType, "%s is not a type", &x) } case *ast.IndexExpr: if typeparams.Enabled { exprs := typeparams.UnpackExpr(e.Index) return check.instantiatedType(e.X, exprs, def) } check.errorf(e0, _NotAType, "%s is not a type", e0) check.use(e.X) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. // Consequently, generic types cannot be parenthesized. return check.definedType(e.X, def) case *ast.ArrayType: if e.Len != nil { typ := new(Array) def.setUnderlying(typ) typ.len = check.arrayLength(e.Len) typ.elem = check.varType(e.Elt) return typ } typ := new(Slice) def.setUnderlying(typ) typ.elem = check.varType(e.Elt) return typ case *ast.Ellipsis: // dots are handled explicitly where they are legal // (array composite literals and parameter lists) check.error(e, _InvalidDotDotDot, "invalid use of '...'") check.use(e.Elt) case *ast.StructType: typ := new(Struct) def.setUnderlying(typ) check.structType(typ, e) return typ case *ast.StarExpr: typ := new(Pointer) def.setUnderlying(typ) typ.base = check.varType(e.X) return typ case *ast.FuncType: typ := new(Signature) def.setUnderlying(typ) check.funcType(typ, nil, e) return typ case *ast.InterfaceType: typ := new(Interface) def.setUnderlying(typ) if def != nil { typ.obj = def.obj } check.interfaceType(typ, e, def) return typ case *ast.MapType: typ := new(Map) def.setUnderlying(typ) typ.key = check.varType(e.Key) typ.elem = check.varType(e.Value) // 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." // // Delay this check because it requires fully setup types; // it is safe to continue in any case (was issue 6667). check.later(func() { if !Comparable(typ.key) { var why string if asTypeParam(typ.key) != nil { why = " (missing comparable constraint)" } check.errorf(e.Key, _IncomparableMapKey, "incomparable map key type %s%s", typ.key, why) } }) return typ case *ast.ChanType: typ := new(Chan) def.setUnderlying(typ) dir := SendRecv switch e.Dir { case ast.SEND | ast.RECV: // nothing to do case ast.SEND: dir = SendOnly case ast.RECV: dir = RecvOnly default: check.invalidAST(e, "unknown channel direction %d", e.Dir) // ok to continue } typ.dir = dir typ.elem = check.varType(e.Value) return typ default: check.errorf(e0, _NotAType, "%s is not a type", e0) } typ := Typ[Invalid] def.setUnderlying(typ) return typ } // typeOrNil type-checks the type expression (or nil value) e // and returns the type of e, or nil. If e is a type, it must // not be an (uninstantiated) generic type. // If e is neither a type nor nil, typeOrNil returns Typ[Invalid]. // TODO(gri) should we also disallow non-var types? func (check *Checker) typeOrNil(e ast.Expr) Type { var x operand check.rawExpr(&x, e, nil) switch x.mode { case invalid: // ignore - error reported before case novalue: check.errorf(&x, _NotAType, "%s used as type", &x) case typexpr: check.instantiatedOperand(&x) return x.typ case value: if x.isNil() { return nil } fallthrough default: check.errorf(&x, _NotAType, "%s is not a type", &x) } return Typ[Invalid] } func (check *Checker) instantiatedType(x ast.Expr, targs []ast.Expr, def *Named) Type { b := check.genericType(x, true) // TODO(gri) what about cycles? if b == Typ[Invalid] { return b // error already reported } base := asNamed(b) if base == nil { unreachable() // should have been caught by genericType } // create a new type instance rather than instantiate the type // TODO(gri) should do argument number check here rather than // when instantiating the type? typ := new(instance) def.setUnderlying(typ) typ.check = check typ.pos = x.Pos() typ.base = base // evaluate arguments (always) typ.targs = check.typeList(targs) if typ.targs == nil { def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation return Typ[Invalid] } // determine argument positions (for error reporting) typ.poslist = make([]token.Pos, len(targs)) for i, arg := range targs { typ.poslist[i] = arg.Pos() } // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { t := typ.expand() check.validType(t, nil) }) return typ } // arrayLength type-checks the array length expression e // and returns the constant length >= 0, or a value < 0 // to indicate an error (and thus an unknown length). func (check *Checker) arrayLength(e ast.Expr) int64 { var x operand check.expr(&x, e) if x.mode != constant_ { if x.mode != invalid { check.errorf(&x, _InvalidArrayLen, "array length %s must be constant", &x) } return -1 } if isUntyped(x.typ) || isInteger(x.typ) { if val := constant.ToInt(x.val); val.Kind() == constant.Int { if representableConst(val, check, Typ[Int], nil) { if n, ok := constant.Int64Val(val); ok && n >= 0 { return n } check.errorf(&x, _InvalidArrayLen, "invalid array length %s", &x) return -1 } } } check.errorf(&x, _InvalidArrayLen, "array length %s must be integer", &x) return -1 } // typeList provides the list of types corresponding to the incoming expression list. // If an error occurred, the result is nil, but all list elements were type-checked. func (check *Checker) typeList(list []ast.Expr) []Type { res := make([]Type, len(list)) // res != nil even if len(list) == 0 for i, x := range list { t := check.varType(x) if t == Typ[Invalid] { res = nil } if res != nil { res[i] = t } } return res } // collectParams declares the parameters of list in scope and returns the corresponding // variable list. If type0 != nil, it is used instead of the first type in list. func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, type0 ast.Expr, variadicOk bool) (params []*Var, variadic bool) { if list == nil { return } var named, anonymous bool for i, field := range list.List { ftype := field.Type if i == 0 && type0 != nil { ftype = type0 } if t, _ := ftype.(*ast.Ellipsis); t != nil { ftype = t.Elt if variadicOk && i == len(list.List)-1 && len(field.Names) <= 1 { variadic = true } else { check.softErrorf(t, _MisplacedDotDotDot, "can only use ... with final parameter in list") // ignore ... and continue } } typ := check.varType(ftype) // The parser ensures that f.Tag is nil and we don't // care if a constructed AST contains a non-nil tag. if len(field.Names) > 0 { // named parameter for _, name := range field.Names { if name.Name == "" { check.invalidAST(name, "anonymous parameter") // ok to continue } par := NewParam(name.Pos(), check.pkg, name.Name, typ) check.declare(scope, name, par, scope.pos) params = append(params, par) } named = true } else { // anonymous parameter par := NewParam(ftype.Pos(), check.pkg, "", typ) check.recordImplicit(field, par) params = append(params, par) anonymous = true } } if named && anonymous { check.invalidAST(list, "list contains both named and anonymous parameters") // ok to continue } // For a variadic function, change the last parameter's type from T to []T. // Since we type-checked T rather than ...T, we also need to retro-actively // record the type for ...T. if variadic { last := params[len(params)-1] last.typ = &Slice{elem: last.typ} check.recordTypeAndValue(list.List[len(list.List)-1].Type, typexpr, last.typ, nil) } return } func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { if alt := oset.insert(obj); alt != nil { check.errorf(atPos(pos), _DuplicateDecl, "%s redeclared", obj.Name()) check.reportAltDecl(alt) return false } return true } func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) { var tlist *ast.Ident // "type" name of first entry in a type list declaration var types []ast.Expr for _, f := range iface.Methods.List { if len(f.Names) > 0 { // We have a method with name f.Names[0], or a type // of a type list (name.Name == "type"). // (The parser ensures that there's only one method // and we don't care if a constructed AST has more.) name := f.Names[0] if name.Name == "_" { check.errorf(name, _BlankIfaceMethod, "invalid method name _") continue // ignore } if name.Name == "type" { // Always collect all type list entries, even from // different type lists, under the assumption that // the author intended to include all types. types = append(types, f.Type) if tlist != nil && tlist != name { check.errorf(name, _Todo, "cannot have multiple type lists in an interface") } tlist = name continue } typ := check.typ(f.Type) sig, _ := typ.(*Signature) if sig == nil { if typ != Typ[Invalid] { check.invalidAST(f.Type, "%s is not a method signature", typ) } continue // ignore } // Always type-check method type parameters but complain if they are not enabled. // (This extra check is needed here because interface method signatures don't have // a receiver specification.) if sig.tparams != nil { var at positioner = f.Type if tparams := typeparams.Get(f.Type); tparams != nil { at = tparams } check.errorf(at, _Todo, "methods cannot have type parameters") } // use named receiver type if available (for better error messages) var recvTyp Type = ityp if def != nil { recvTyp = def } sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp) m := NewFunc(name.Pos(), check.pkg, name.Name, sig) check.recordDef(name, m) ityp.methods = append(ityp.methods, m) } else { // We have an embedded type. completeInterface will // eventually verify that we have an interface. ityp.embeddeds = append(ityp.embeddeds, check.typ(f.Type)) check.posMap[ityp] = append(check.posMap[ityp], f.Type.Pos()) } } // type constraints ityp.types = _NewSum(check.collectTypeConstraints(iface.Pos(), types)) if len(ityp.methods) == 0 && ityp.types == nil && len(ityp.embeddeds) == 0 { // empty interface ityp.allMethods = markComplete return } // sort for API stability sortMethods(ityp.methods) sortTypes(ityp.embeddeds) check.later(func() { check.completeInterface(iface.Pos(), ityp) }) } func (check *Checker) completeInterface(pos token.Pos, ityp *Interface) { if ityp.allMethods != nil { return } // completeInterface may be called via the LookupFieldOrMethod, // MissingMethod, Identical, or IdenticalIgnoreTags external API // in which case check will be nil. In this case, type-checking // must be finished and all interfaces should have been completed. if check == nil { panic("internal error: incomplete interface") } if trace { // Types don't generally have position information. // If we don't have a valid pos provided, try to use // one close enough. if !pos.IsValid() && len(ityp.methods) > 0 { pos = ityp.methods[0].pos } check.trace(pos, "complete %s", ityp) check.indent++ defer func() { check.indent-- check.trace(pos, "=> %s (methods = %v, types = %v)", ityp, ityp.allMethods, ityp.allTypes) }() } // An infinitely expanding interface (due to a cycle) is detected // elsewhere (Checker.validType), so here we simply assume we only // have valid interfaces. Mark the interface as complete to avoid // infinite recursion if the validType check occurs later for some // reason. ityp.allMethods = markComplete // Methods of embedded interfaces are collected unchanged; i.e., the identity // of a method I.m's Func Object of an interface I is the same as that of // the method m in an interface that embeds interface I. On the other hand, // if a method is embedded via multiple overlapping embedded interfaces, we // don't provide a guarantee which "original m" got chosen for the embedding // interface. See also issue #34421. // // If we don't care to provide this identity guarantee anymore, instead of // reusing the original method in embeddings, we can clone the method's Func // Object and give it the position of a corresponding embedded interface. Then // we can get rid of the mpos map below and simply use the cloned method's // position. var seen objset var methods []*Func mpos := make(map[*Func]token.Pos) // method specification or method embedding position, for good error messages addMethod := func(pos token.Pos, m *Func, explicit bool) { switch other := seen.insert(m); { case other == nil: methods = append(methods, m) mpos[m] = pos case explicit: 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 default: // We have a duplicate method name in an embedded (not explicitly declared) method. // Check method signatures after all types are computed (issue #33656). // If we're pre-go1.14 (overlapping embeddings are not permitted), report that // error here as well (even though we could do it eagerly) because it's the same // error message. check.later(func() { if !check.allowVersion(m.pkg, 1, 14) || !check.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 } }) } } for _, m := range ityp.methods { addMethod(m.pos, m, true) } // collect types allTypes := ityp.types posList := check.posMap[ityp] for i, typ := range ityp.embeddeds { pos := posList[i] // embedding position utyp := under(typ) etyp := asInterface(utyp) if etyp == nil { if utyp != Typ[Invalid] { var format string if _, ok := utyp.(*_TypeParam); ok { format = "%s is a type parameter, not an interface" } else { format = "%s is not an interface" } // TODO: correct error code. check.errorf(atPos(pos), _InvalidIfaceEmbed, format, typ) } continue } check.completeInterface(pos, etyp) for _, m := range etyp.allMethods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } allTypes = intersect(allTypes, etyp.allTypes) } if methods != nil { sort.Sort(byUniqueMethodName(methods)) ityp.allMethods = methods } ityp.allTypes = allTypes } // intersect computes the intersection of the types x and y. // Note: A incomming nil type stands for the top type. A top // type result is returned as nil. func intersect(x, y Type) (r Type) { defer func() { if r == theTop { r = nil } }() switch { case x == theBottom || y == theBottom: return theBottom case x == nil || x == theTop: return y case y == nil || x == theTop: return x } xtypes := unpackType(x) ytypes := unpackType(y) // Compute the list rtypes which includes only // types that are in both xtypes and ytypes. // Quadratic algorithm, but good enough for now. // TODO(gri) fix this var rtypes []Type for _, x := range xtypes { if includes(ytypes, x) { rtypes = append(rtypes, x) } } if rtypes == nil { return theBottom } return _NewSum(rtypes) } func sortTypes(list []Type) { sort.Stable(byUniqueTypeName(list)) } // byUniqueTypeName named type lists can be sorted by their unique type names. type byUniqueTypeName []Type func (a byUniqueTypeName) Len() int { return len(a) } func (a byUniqueTypeName) Less(i, j int) bool { return sortName(a[i]) < sortName(a[j]) } func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func sortName(t Type) string { if named := asNamed(t); named != nil { return named.obj.Id() } return "" } func sortMethods(list []*Func) { sort.Sort(byUniqueMethodName(list)) } func assertSortedMethods(list []*Func) { if !debug { panic("internal error: assertSortedMethods called outside debug mode") } if !sort.IsSorted(byUniqueMethodName(list)) { panic("internal error: methods not sorted") } } // byUniqueMethodName method lists can be sorted by their unique method names. type byUniqueMethodName []*Func func (a byUniqueMethodName) Len() int { return len(a) } func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (check *Checker) tag(t *ast.BasicLit) string { if t != nil { if t.Kind == token.STRING { if val, err := strconv.Unquote(t.Value); err == nil { return val } } check.invalidAST(t, "incorrect tag syntax: %q", t.Value) } return "" } func (check *Checker) structType(styp *Struct, e *ast.StructType) { list := e.Fields if list == nil { return } // struct fields and tags var fields []*Var var tags []string // for double-declaration checks var fset objset // current field typ and tag var typ Type var tag string add := func(ident *ast.Ident, embedded bool, pos token.Pos) { if tag != "" && tags == nil { tags = make([]string, len(fields)) } if tags != nil { tags = append(tags, tag) } name := ident.Name fld := NewField(pos, check.pkg, name, typ, embedded) // spec: "Within a struct, non-blank field names must be unique." if name == "_" || check.declareInSet(&fset, pos, fld) { fields = append(fields, fld) check.recordDef(ident, fld) } } // addInvalid adds an embedded field of invalid type to the struct for // fields with errors; this keeps the number of struct fields in sync // with the source as long as the fields are _ or have different names // (issue #25627). addInvalid := func(ident *ast.Ident, pos token.Pos) { typ = Typ[Invalid] tag = "" add(ident, true, pos) } for _, f := range list.List { typ = check.varType(f.Type) tag = check.tag(f.Tag) if len(f.Names) > 0 { // named fields for _, name := range f.Names { add(name, false, name.Pos()) } } else { // embedded field // spec: "An embedded type 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." 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) name = ast.NewIdent("_") name.NamePos = pos addInvalid(name, pos) continue } add(name, true, pos) // Because we have a name, typ must be of the form T or *T, where T is the name // of a (named or alias) type, and t (= deref(typ)) must be the type of T. // We must delay this check to the end because we don't want to instantiate // (via under(t)) a possibly incomplete type. // for use in the closure below embeddedTyp := typ embeddedPos := f.Type check.later(func() { t, isPtr := deref(embeddedTyp) switch t := optype(t).(type) { case *Basic: if t == Typ[Invalid] { // error was reported before return } // unsafe.Pointer is treated like a regular pointer if t.kind == UnsafePointer { check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be unsafe.Pointer") } case *Pointer: check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer") case *Interface: if isPtr { check.errorf(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface") } } }) } } styp.fields = fields styp.tags = tags } func embeddedFieldIdent(e ast.Expr) *ast.Ident { switch e := e.(type) { case *ast.Ident: return e case *ast.StarExpr: // *T is valid, but **T is not if _, ok := e.X.(*ast.StarExpr); !ok { return embeddedFieldIdent(e.X) } case *ast.SelectorExpr: return e.Sel case *ast.IndexExpr: return embeddedFieldIdent(e.X) } return nil // invalid embedded field } func (check *Checker) collectTypeConstraints(pos token.Pos, types []ast.Expr) []Type { list := make([]Type, 0, len(types)) // assume all types are correct for _, texpr := range types { if texpr == nil { check.invalidAST(atPos(pos), "missing type constraint") continue } list = append(list, check.varType(texpr)) } // Ensure that each type is only present once in the type list. Types may be // interfaces, which may not be complete yet. It's ok to do this check at the // end because it's not a requirement for correctness of the code. // Note: This is a quadratic algorithm, but type lists tend to be short. check.later(func() { for i, t := range list { if t := asInterface(t); t != nil { check.completeInterface(types[i].Pos(), t) } if includes(list[:i], t) { check.softErrorf(types[i], _Todo, "duplicate type %s in type list", t) } } }) return list } // includes reports whether typ is in list. func includes(list []Type, typ Type) bool { for _, e := range list { if Identical(typ, e) { return true } } return false }