]> Cypherpunks.ru repositories - gostls13.git/blob - src/go/types/interface.go
[dev.typeparams] go/types: rename newTypeSet -> computeTypeSet
[gostls13.git] / src / go / types / interface.go
1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package types
6
7 import (
8         "go/ast"
9         "go/internal/typeparams"
10         "go/token"
11 )
12
13 func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, def *Named) {
14         var tlist []ast.Expr
15         var tname *ast.Ident // "type" name of first entry in a type list declaration
16
17         addEmbedded := func(pos token.Pos, typ Type) {
18                 ityp.embeddeds = append(ityp.embeddeds, typ)
19                 if ityp.embedPos == nil {
20                         ityp.embedPos = new([]token.Pos)
21                 }
22                 *ityp.embedPos = append(*ityp.embedPos, pos)
23         }
24
25         for _, f := range iface.Methods.List {
26                 if len(f.Names) == 0 {
27                         // We have an embedded type; possibly a union of types.
28                         addEmbedded(f.Type.Pos(), parseUnion(check, flattenUnion(nil, f.Type)))
29                         continue
30                 }
31
32                 // We have a method with name f.Names[0], or a type
33                 // of a type list (name.Name == "type").
34                 // (The parser ensures that there's only one method
35                 // and we don't care if a constructed AST has more.)
36                 name := f.Names[0]
37                 if name.Name == "_" {
38                         check.errorf(name, _BlankIfaceMethod, "invalid method name _")
39                         continue // ignore
40                 }
41
42                 // TODO(rfindley) Remove type list handling once the parser doesn't accept type lists anymore.
43                 if name.Name == "type" {
44                         // Report an error for the first type list per interface
45                         // if we don't allow type lists, but continue.
46                         if !allowTypeLists && tlist == nil {
47                                 check.softErrorf(name, _Todo, "use generalized embedding syntax instead of a type list")
48                         }
49                         // For now, collect all type list entries as if it
50                         // were a single union, where each union element is
51                         // of the form ~T.
52                         // TODO(rfindley) remove once we disallow type lists
53                         op := new(ast.UnaryExpr)
54                         op.Op = token.TILDE
55                         op.X = f.Type
56                         tlist = append(tlist, op)
57                         // Report an error if we have multiple type lists in an
58                         // interface, but only if they are permitted in the first place.
59                         if allowTypeLists && tname != nil && tname != name {
60                                 check.errorf(name, _Todo, "cannot have multiple type lists in an interface")
61                         }
62                         tname = name
63                         continue
64                 }
65
66                 typ := check.typ(f.Type)
67                 sig, _ := typ.(*Signature)
68                 if sig == nil {
69                         if typ != Typ[Invalid] {
70                                 check.invalidAST(f.Type, "%s is not a method signature", typ)
71                         }
72                         continue // ignore
73                 }
74
75                 // Always type-check method type parameters but complain if they are not enabled.
76                 // (This extra check is needed here because interface method signatures don't have
77                 // a receiver specification.)
78                 if sig.tparams != nil {
79                         var at positioner = f.Type
80                         if tparams := typeparams.Get(f.Type); tparams != nil {
81                                 at = tparams
82                         }
83                         check.errorf(at, _Todo, "methods cannot have type parameters")
84                 }
85
86                 // use named receiver type if available (for better error messages)
87                 var recvTyp Type = ityp
88                 if def != nil {
89                         recvTyp = def
90                 }
91                 sig.recv = NewVar(name.Pos(), check.pkg, "", recvTyp)
92
93                 m := NewFunc(name.Pos(), check.pkg, name.Name, sig)
94                 check.recordDef(name, m)
95                 ityp.methods = append(ityp.methods, m)
96         }
97
98         // type constraints
99         if tlist != nil {
100                 // TODO(rfindley): this differs from types2 due to the use of Pos() below,
101                 // which should actually be on the ~. Confirm that this position is correct.
102                 addEmbedded(tlist[0].Pos(), parseUnion(check, tlist))
103         }
104
105         // All methods and embedded elements for this interface are collected;
106         // i.e., this interface is may be used in a type set computation.
107         ityp.complete = true
108
109         if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
110                 // empty interface
111                 ityp.tset = &topTypeSet
112                 return
113         }
114
115         // sort for API stability
116         sortMethods(ityp.methods)
117         // (don't sort embeddeds: they must correspond to *embedPos entries)
118
119         // Compute type set with a non-nil *Checker as soon as possible
120         // to report any errors. Subsequent uses of type sets should be
121         // using this computed type set and won't need to pass in a *Checker.
122         check.later(func() { computeTypeSet(check, iface.Pos(), ityp) })
123 }
124
125 func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr {
126         if o, _ := x.(*ast.BinaryExpr); o != nil && o.Op == token.OR {
127                 list = flattenUnion(list, o.X)
128                 x = o.Y
129         }
130         return append(list, x)
131 }