diff options
Diffstat (limited to 'src/go/types/typexpr.go')
-rw-r--r-- | src/go/types/typexpr.go | 793 |
1 files changed, 37 insertions, 756 deletions
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go index 1738d864a6..a812ba6519 100644 --- a/src/go/types/typexpr.go +++ b/src/go/types/typexpr.go @@ -12,8 +12,6 @@ import ( "go/constant" "go/internal/typeparams" "go/token" - "sort" - "strconv" "strings" ) @@ -29,13 +27,24 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) // 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 { + switch obj { + case nil: if e.Name == "_" { - check.errorf(e, _InvalidBlank, "cannot use _ as value or type") + check.error(e, _InvalidBlank, "cannot use _ as value or type") } else { check.errorf(e, _UndeclaredName, "undeclared name: %s", e.Name) } return + case universeAny, universeComparable: + if !check.allowVersion(check.pkg, 1, 18) { + check.errorf(e, _UndeclaredName, "undeclared name: %s (requires version go1.18 or later)", e.Name) + return + } + // If we allow "any" for general use, this if-statement can be removed (issue #33232). + if obj == universeAny { + check.error(e, _Todo, "cannot use any outside constraint position") + return + } } check.recordUse(e, obj) @@ -58,7 +67,7 @@ func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, wantType bool) // 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 { + if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil { pkgName.used = true } @@ -142,12 +151,12 @@ func (check *Checker) ordinaryType(pos positioner, typ Type) { // 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) + tset := computeTypeSet(check, pos.Pos(), t) // TODO(gri) is this the correct position? + if tset.types != nil { + check.softErrorf(pos, _Todo, "interface contains type constraints (%s)", tset.types) return } - if t._IsComparable() { + if tset.IsComparable() { check.softErrorf(pos, _Todo, "interface is (or embeds) comparable") } } @@ -194,205 +203,6 @@ func (check *Checker) genericType(e ast.Expr, reportErr bool) Type { 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 { @@ -462,13 +272,10 @@ func (check *Checker) typInternal(e0 ast.Expr, def *Named) (T Type) { 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.IndexExpr, *ast.MultiIndexExpr: + ix := typeparams.UnpackIndexExpr(e) + // TODO(rfindley): type instantiation should require go1.18 + return check.instantiatedType(ix.X, ix.Indices, def) case *ast.ParenExpr: // Generic types must be instantiated before they can be used in any form. @@ -604,43 +411,32 @@ func (check *Checker) typeOrNil(e ast.Expr) Type { 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 +func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named) Type { + base := check.genericType(x, true) + if base == Typ[Invalid] { + return base // error already reported } - // 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 { + // evaluate arguments + targs := check.typeList(targsx) + if 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() + // determine argument positions + posList := make([]token.Pos, len(targs)) + for i, arg := range targsx { + posList[i] = arg.Pos() } + typ := check.InstantiateLazy(x.Pos(), base, targs, posList, true) + def.setUnderlying(typ) + // make sure we check instantiation works at least once // and that the resulting type is valid check.later(func() { - t := typ.expand() + t := expand(typ) check.validType(t, nil) }) @@ -689,518 +485,3 @@ func (check *Checker) typeList(list []ast.Expr) []Type { } 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 -} |