]> Cypherpunks.ru repositories - gostls13.git/blobdiff - src/go/types/interface.go
go/types, types2: introduce _Alias type node
[gostls13.git] / src / go / types / interface.go
index 2211e37c5981771a5adfdd7e10279003ab105962..01bbb08e0efe5573f205756b2c1d450913b4d066 100644 (file)
@@ -7,6 +7,7 @@ package types
 import (
        "go/ast"
        "go/token"
+       . "internal/types/errors"
 )
 
 // ----------------------------------------------------------------------------
@@ -14,17 +15,18 @@ import (
 
 // An Interface represents an interface type.
 type Interface struct {
-       obj       *TypeName    // type name object defining this interface; or nil (for better error messages)
+       check     *Checker     // for error reporting; nil once type set is computed
        methods   []*Func      // ordered list of explicitly declared methods
        embeddeds []Type       // ordered list of explicitly embedded elements
        embedPos  *[]token.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space
+       implicit  bool         // interface is wrapper for type set literal (non-interface T, ~T, or A|B)
        complete  bool         // indicates that obj, methods, and embeddeds are set and type set can be computed
 
        tset *_TypeSet // type set described by this interface, computed lazily
 }
 
 // typeSet returns the type set for interface t.
-func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(nil, token.NoPos, t) }
+func (t *Interface) typeSet() *_TypeSet { return computeInterfaceTypeSet(t.check, nopos, t) }
 
 // emptyInterface represents the empty (completed) interface
 var emptyInterface = Interface{complete: true, tset: &topTypeSet}
@@ -54,7 +56,7 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        }
 
        // set method receivers if necessary
-       typ := new(Interface)
+       typ := (*Checker)(nil).newInterface()
        for _, m := range methods {
                if sig := m.typ.(*Signature); sig.recv == nil {
                        sig.recv = NewVar(m.pos, m.pkg, "", typ)
@@ -71,21 +73,38 @@ func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
        return typ
 }
 
+// check may be nil
+func (check *Checker) newInterface() *Interface {
+       typ := &Interface{check: check}
+       if check != nil {
+               check.needsCleanup(typ)
+       }
+       return typ
+}
+
+// MarkImplicit marks the interface t as implicit, meaning this interface
+// corresponds to a constraint literal such as ~T or A|B without explicit
+// interface embedding. MarkImplicit should be called before any concurrent use
+// of implicit interfaces.
+func (t *Interface) MarkImplicit() {
+       t.implicit = true
+}
+
 // NumExplicitMethods returns the number of explicitly declared methods of interface t.
 func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
 
 // ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
-// The methods are ordered by their unique Id.
+// The methods are ordered by their unique [Id].
 func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
 
 // NumEmbeddeds returns the number of embedded types in interface t.
 func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
 
-// Embedded returns the i'th embedded defined (*Named) type of interface t for 0 <= i < t.NumEmbeddeds().
+// Embedded returns the i'th embedded defined (*[Named]) type of interface t for 0 <= i < t.NumEmbeddeds().
 // The result is nil if the i'th embedded type is not a defined type.
 //
-// Deprecated: Use EmbeddedType which is not restricted to defined (*Named) types.
-func (t *Interface) Embedded(i int) *Named { tname, _ := t.embeddeds[i].(*Named); return tname }
+// Deprecated: Use [Interface.EmbeddedType] which is not restricted to defined (*[Named]) types.
+func (t *Interface) Embedded(i int) *Named { return asNamed(t.embeddeds[i]) }
 
 // EmbeddedType returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
 func (t *Interface) EmbeddedType(i int) Type { return t.embeddeds[i] }
@@ -101,13 +120,17 @@ func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) }
 func (t *Interface) Empty() bool { return t.typeSet().IsAll() }
 
 // IsComparable reports whether each type in interface t's type set is comparable.
-func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable() }
+func (t *Interface) IsComparable() bool { return t.typeSet().IsComparable(nil) }
+
+// IsMethodSet reports whether the interface t is fully described by its method
+// set.
+func (t *Interface) IsMethodSet() bool { return t.typeSet().IsMethodSet() }
 
-// IsConstraint reports whether interface t is not just a method set.
-func (t *Interface) IsConstraint() bool { return t.typeSet().IsConstraint() }
+// IsImplicit reports whether the interface t is a wrapper for a type set literal.
+func (t *Interface) IsImplicit() bool { return t.implicit }
 
 // Complete computes the interface's type set. It must be called by users of
-// NewInterfaceType and NewInterface after the interface's embedded types are
+// [NewInterfaceType] and [NewInterface] after the interface's embedded types are
 // fully defined and before using the interface type in any way other than to
 // form other types. The interface must not contain duplicate methods or a
 // panic occurs. Complete returns the receiver.
@@ -127,10 +150,13 @@ func (t *Interface) String() string   { return TypeString(t, nil) }
 // ----------------------------------------------------------------------------
 // Implementation
 
-func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
-       var tlist []ast.Expr
-       var tname *ast.Ident // "type" name of first entry in a type list declaration
+func (t *Interface) cleanup() {
+       t.typeSet() // any interface that escapes type checking must be safe for concurrent use
+       t.check = nil
+       t.embedPos = nil
+}
 
+func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *TypeName) {
        addEmbedded := func(pos token.Pos, typ Type) {
                ityp.embeddeds = append(ityp.embeddeds, typ)
                if ityp.embedPos == nil {
@@ -141,69 +167,42 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
 
        for _, f := range iface.Methods.List {
                if len(f.Names) == 0 {
-                       // We have an embedded type; possibly a union of types.
-                       addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type)))
+                       addEmbedded(f.Type.Pos(), parseUnion(check, f.Type))
                        continue
                }
+               // f.Name != nil
 
-               // 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.)
+               // We have a method with name f.Names[0].
                name := f.Names[0]
                if name.Name == "_" {
-                       check.errorf(name, _BlankIfaceMethod, "invalid method name _")
+                       check.error(name, BlankIfaceMethod, "methods must have a unique non-blank name")
                        continue // ignore
                }
 
-               // TODO(rfindley) Remove type list handling once the parser doesn't accept type lists anymore.
-               if name.Name == "type" {
-                       // Report an error for the first type list per interface
-                       // if we don't allow type lists, but continue.
-                       if !allowTypeLists && tlist == nil {
-                               check.softErrorf(name, _Todo, "use generalized embedding syntax instead of a type list")
-                       }
-                       // For now, collect all type list entries as if it
-                       // were a single union, where each union element is
-                       // of the form ~T.
-                       // TODO(rfindley) remove once we disallow type lists
-                       op := new(ast.UnaryExpr)
-                       op.Op = token.TILDE
-                       op.X = f.Type
-                       tlist = append(tlist, op)
-                       // Report an error if we have multiple type lists in an
-                       // interface, but only if they are permitted in the first place.
-                       if allowTypeLists && tname != nil && tname != name {
-                               check.errorf(name, _Todo, "cannot have multiple type lists in an interface")
-                       }
-                       tname = 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)
+                       if isValid(typ) {
+                               check.errorf(f.Type, InvalidSyntaxTree, "%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.)
+               // The go/parser doesn't accept method type parameters but an ast.FuncType may have them.
                if sig.tparams != nil {
                        var at positioner = f.Type
                        if ftyp, _ := f.Type.(*ast.FuncType); ftyp != nil && ftyp.TypeParams != nil {
                                at = ftyp.TypeParams
                        }
-                       check.errorf(at, _Todo, "methods cannot have type parameters")
+                       check.error(at, InvalidSyntaxTree, "methods cannot have type parameters")
                }
 
                // use named receiver type if available (for better error messages)
                var recvTyp Type = ityp
                if def != nil {
-                       recvTyp = def
+                       if named := asNamed(def.typ); named != nil {
+                               recvTyp = named
+                       }
                }
                sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp)
 
@@ -212,15 +211,8 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
                ityp.methods = append(ityp.methods, m)
        }
 
-       // type constraints
-       if tlist != nil {
-               // TODO(rfindley): this differs from types2 due to the use of Pos() below,
-               // which should actually be on the ~. Confirm that this position is correct.
-               addEmbedded(tlist[0].Pos(), parseUnion(check, tlist))
-       }
-
        // All methods and embedded elements for this interface are collected;
-       // i.e., this interface is may be used in a type set computation.
+       // i.e., this interface may be used in a type set computation.
        ityp.complete = true
 
        if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
@@ -233,16 +225,10 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
        sortMethods(ityp.methods)
        // (don't sort embeddeds: they must correspond to *embedPos entries)
 
-       // Compute type set with a non-nil *Checker as soon as possible
-       // to report any errors. Subsequent uses of type sets will use
-       // this computed type set and won't need to pass in a *Checker.
-       check.later(func() { computeInterfaceTypeSet(check, iface.Pos(), ityp) })
-}
-
-func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr {
-       if o, _ := x.(*ast.BinaryExpr); o != nil && o.Op == token.OR {
-               list = flattenUnion(list, o.X)
-               x = o.Y
-       }
-       return append(list, x)
+       // Compute type set as soon as possible to report any errors.
+       // Subsequent uses of type sets will use this computed type
+       // set and won't need to pass in a *Checker.
+       check.later(func() {
+               computeInterfaceTypeSet(check, iface.Pos(), ityp)
+       }).describef(iface, "compute type set for %s", ityp)
 }