-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinterface.go
188 lines (151 loc) · 6.45 KB
/
interface.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
// Copyright 2021 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.
package types2
import (
"cmd/compile/internal/syntax"
. "internal/types/errors"
)
// ----------------------------------------------------------------------------
// API
// An Interface represents an interface type.
type Interface struct {
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 *[]syntax.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 all fields (except for tset) are set up
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(t.check, nopos, t) }
// emptyInterface represents the empty interface
var emptyInterface = Interface{complete: true, tset: &topTypeSet}
// NewInterfaceType returns a new interface for the given methods and embedded types.
// NewInterfaceType takes ownership of the provided methods and may modify their types
// by setting missing receivers.
func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
if len(methods) == 0 && len(embeddeds) == 0 {
return &emptyInterface
}
// set method receivers if necessary
typ := (*Checker)(nil).newInterface()
for _, m := range methods {
if sig := m.typ.(*Signature); sig.recv == nil {
sig.recv = newVar(RecvVar, m.pos, m.pkg, "", typ)
}
}
// sort for API stability
sortMethods(methods)
typ.methods = methods
typ.embeddeds = embeddeds
typ.complete = true
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.
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) }
// 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] }
// NumMethods returns the total number of methods of interface t.
func (t *Interface) NumMethods() int { return t.typeSet().NumMethods() }
// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
// The methods are ordered by their unique Id.
func (t *Interface) Method(i int) *Func { return t.typeSet().Method(i) }
// Empty reports whether t is the empty interface.
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(nil) }
// IsMethodSet reports whether the interface t is fully described by its method set.
func (t *Interface) IsMethodSet() bool { return t.typeSet().IsMethodSet() }
// IsImplicit reports whether the interface t is a wrapper for a type set literal.
func (t *Interface) IsImplicit() bool { return t.implicit }
func (t *Interface) Underlying() Type { return t }
func (t *Interface) String() string { return TypeString(t, nil) }
// ----------------------------------------------------------------------------
// Implementation
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 *syntax.InterfaceType, def *TypeName) {
addEmbedded := func(pos syntax.Pos, typ Type) {
ityp.embeddeds = append(ityp.embeddeds, typ)
if ityp.embedPos == nil {
ityp.embedPos = new([]syntax.Pos)
}
*ityp.embedPos = append(*ityp.embedPos, pos)
}
for _, f := range iface.MethodList {
if f.Name == nil {
addEmbedded(atPos(f.Type), parseUnion(check, f.Type))
continue
}
// f.Name != nil
// We have a method with name f.Name.
name := f.Name.Value
if name == "_" {
check.error(f.Name, BlankIfaceMethod, "methods must have a unique non-blank name")
continue // ignore method
}
// Type-check method declaration.
// Note: Don't call check.typ(f.Type) as that would record
// the method incorrectly as a type expression in Info.Types.
ftyp, _ := f.Type.(*syntax.FuncType)
if ftyp == nil {
check.errorf(f.Type, InvalidSyntaxTree, "%s is not a method signature", f.Type)
continue // ignore method
}
sig := new(Signature)
check.funcType(sig, nil, nil, ftyp)
// use named receiver type if available (for better error messages)
var recvTyp Type = ityp
if def != nil {
if named := asNamed(def.typ); named != nil {
recvTyp = named
}
}
sig.recv = newVar(RecvVar, f.Name.Pos(), check.pkg, "", recvTyp)
m := NewFunc(f.Name.Pos(), check.pkg, name, sig)
check.recordDef(f.Name, m)
ityp.methods = append(ityp.methods, m)
}
// All methods and embedded elements for this interface are collected;
// i.e., this interface may be used in a type set computation.
ityp.complete = true
if len(ityp.methods) == 0 && len(ityp.embeddeds) == 0 {
// empty interface
ityp.tset = &topTypeSet
return
}
// sort for API stability
// (don't sort embeddeds: they must correspond to *embedPos entries)
sortMethods(ityp.methods)
// 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)
}