@@ -98,17 +98,24 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
98
98
check .posMap [ityp ] = append (check .posMap [ityp ], tlist [0 ].(* ast.UnaryExpr ).X .Pos ())
99
99
}
100
100
101
+ // All methods and embedded elements for this interface are collected;
102
+ // i.e., this interface is may be used in a type set computation.
103
+ ityp .complete = true
104
+
101
105
if len (ityp .methods ) == 0 && len (ityp .embeddeds ) == 0 {
102
106
// empty interface
103
- ityp .allMethods = markComplete
107
+ ityp .tset = & topTypeSet
104
108
return
105
109
}
106
110
107
111
// sort for API stability
108
112
sortMethods (ityp .methods )
109
113
sortTypes (ityp .embeddeds )
110
114
111
- check .later (func () { check .completeInterface (iface .Pos (), ityp ) })
115
+ // Compute type set with a non-nil *Checker as soon as possible
116
+ // to report any errors. Subsequent uses of type sets should be
117
+ // using this computed type set and won't need to pass in a *Checker.
118
+ check .later (func () { newTypeSet (check , iface .Pos (), ityp ) })
112
119
}
113
120
114
121
func flattenUnion (list []ast.Expr , x ast.Expr ) []ast.Expr {
@@ -119,24 +126,26 @@ func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr {
119
126
return append (list , x )
120
127
}
121
128
122
- func (check * Checker ) completeInterface (pos token.Pos , ityp * Interface ) {
123
- if ityp .allMethods != nil {
124
- return
129
+ // newTypeSet may be called with check == nil.
130
+ // TODO(gri) move this function into typeset.go eventually
131
+ func newTypeSet (check * Checker , pos token.Pos , ityp * Interface ) * TypeSet {
132
+ if ityp .tset != nil {
133
+ return ityp .tset
125
134
}
126
135
127
- // completeInterface may be called via the LookupFieldOrMethod,
128
- // MissingMethod, Identical, or IdenticalIgnoreTags external API
129
- // in which case check will be nil. In this case, type-checking
130
- // must be finished and all interfaces should have been completed.
131
- if check == nil {
132
- panic ("internal error: incomplete interface" )
136
+ // If the interface is not fully set up yet, the type set will
137
+ // not be complete, which may lead to errors when using the the
138
+ // type set (e.g. missing method). Don't compute a partial type
139
+ // set (and don't store it!), so that we still compute the full
140
+ // type set eventually. Instead, return the top type set and
141
+ // let any follow-on errors play out.
142
+ //
143
+ // TODO(gri) Consider recording when this happens and reporting
144
+ // it as an error (but only if there were no other errors so to
145
+ // to not have unnecessary follow-on errors).
146
+ if ! ityp .complete {
147
+ return & topTypeSet
133
148
}
134
- completeInterface (check , pos , ityp )
135
- }
136
-
137
- // completeInterface may be called with check == nil.
138
- func completeInterface (check * Checker , pos token.Pos , ityp * Interface ) {
139
- assert (ityp .allMethods == nil )
140
149
141
150
if check != nil && trace {
142
151
// Types don't generally have position information.
@@ -146,11 +155,11 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) {
146
155
pos = ityp .methods [0 ].pos
147
156
}
148
157
149
- check .trace (pos , "complete %s" , ityp )
158
+ check .trace (pos , "type set for %s" , ityp )
150
159
check .indent ++
151
160
defer func () {
152
161
check .indent --
153
- check .trace (pos , "=> %s (methods = %v, types = %v) " , ityp , ityp . allMethods , ityp . allTypes )
162
+ check .trace (pos , "=> %s " , ityp . typeSet () )
154
163
}()
155
164
}
156
165
@@ -159,7 +168,7 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) {
159
168
// have valid interfaces. Mark the interface as complete to avoid
160
169
// infinite recursion if the validType check occurs later for some
161
170
// reason.
162
- ityp .allMethods = markComplete
171
+ ityp .tset = new ( TypeSet ) // TODO(gri) is this sufficient?
163
172
164
173
// Methods of embedded interfaces are collected unchanged; i.e., the identity
165
174
// of a method I.m's Func Object of an interface I is the same as that of
@@ -229,14 +238,12 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) {
229
238
var types Type
230
239
switch t := under (typ ).(type ) {
231
240
case * Interface :
232
- if t .allMethods == nil {
233
- completeInterface (check , pos , t )
234
- }
235
- for _ , m := range t .allMethods {
241
+ tset := newTypeSet (check , pos , t )
242
+ for _ , m := range tset .methods {
236
243
addMethod (pos , m , false ) // use embedding position pos rather than m.pos
237
244
238
245
}
239
- types = t . allTypes
246
+ types = tset . types
240
247
case * Union :
241
248
// TODO(gri) combine with default case once we have
242
249
// converted all tests to new notation and we
@@ -273,9 +280,11 @@ func completeInterface(check *Checker, pos token.Pos, ityp *Interface) {
273
280
274
281
if methods != nil {
275
282
sort .Sort (byUniqueMethodName (methods ))
276
- ityp .allMethods = methods
283
+ ityp .tset . methods = methods
277
284
}
278
- ityp .allTypes = allTypes
285
+ ityp .tset .types = allTypes
286
+
287
+ return ityp .tset
279
288
}
280
289
281
290
func sortTypes (list []Type ) {
0 commit comments