@@ -221,16 +221,17 @@ func (n *Named) setUnderlying(typ Type) {
221
221
222
222
// expandNamed ensures that the underlying type of n is instantiated.
223
223
// The underlying type will be Typ[Invalid] if there was an error.
224
- func expandNamed (env * Environment , n * Named , instPos syntax.Pos ) (* TypeParamList , Type , []* Func ) {
224
+ func expandNamed (env * Environment , n * Named , instPos syntax.Pos ) (tparams * TypeParamList , underlying Type , methods []* Func ) {
225
225
n .orig .resolve (env )
226
226
227
- var u Type
228
- if n .check .validateTArgLen (instPos , n .orig .tparams .Len (), n .targs .Len ()) {
227
+ check := n .check
228
+
229
+ if check .validateTArgLen (instPos , n .orig .tparams .Len (), n .targs .Len ()) {
229
230
// TODO(rfindley): handling an optional Checker and Environment here (and
230
231
// in subst) feels overly complicated. Can we simplify?
231
232
if env == nil {
232
- if n . check != nil {
233
- env = n . check .conf .Environment
233
+ if check != nil {
234
+ env = check .conf .Environment
234
235
} else {
235
236
// If we're instantiating lazily, we might be outside the scope of a
236
237
// type-checking pass. In that case we won't have a pre-existing
@@ -239,16 +240,84 @@ func expandNamed(env *Environment, n *Named, instPos syntax.Pos) (*TypeParamList
239
240
env = NewEnvironment ()
240
241
}
241
242
h := env .TypeHash (n .orig , n .targs .list ())
242
- // add the instance to the environment to avoid infinite recursion.
243
- // addInstance may return a different, existing instance, but we
244
- // shouldn't return that instance from expand.
243
+ // ensure that an instance is recorded for h to avoid infinite recursion.
245
244
env .typeForHash (h , n )
246
245
}
247
- u = n .check .subst (instPos , n .orig .underlying , makeSubstMap (n .orig .tparams .list (), n .targs .list ()), env )
246
+ smap := makeSubstMap (n .orig .tparams .list (), n .targs .list ())
247
+ underlying = n .check .subst (instPos , n .orig .underlying , smap , env )
248
+ for i := 0 ; i < n .orig .NumMethods (); i ++ {
249
+ origm := n .orig .Method (i )
250
+
251
+ // During type checking origm may not have a fully set up type, so defer
252
+ // instantiation of its signature until later.
253
+ m := NewFunc (origm .pos , origm .pkg , origm .name , nil )
254
+ m .hasPtrRecv = ptrRecv (origm )
255
+ // Setting instRecv here allows us to complete later (we need the
256
+ // instRecv to get targs and the original method).
257
+ m .instRecv = n
258
+
259
+ methods = append (methods , m )
260
+ }
261
+ } else {
262
+ underlying = Typ [Invalid ]
263
+ }
264
+
265
+ // Methods should not escape the type checker API without being completed. If
266
+ // we're in the context of a type checking pass, we need to defer this until
267
+ // later (not all methods may have types).
268
+ completeMethods := func () {
269
+ for _ , m := range methods {
270
+ if m .instRecv != nil {
271
+ check .completeMethod (env , m )
272
+ }
273
+ }
274
+ }
275
+ if check != nil {
276
+ check .later (completeMethods )
277
+ } else {
278
+ completeMethods ()
279
+ }
280
+
281
+ return n .orig .tparams , underlying , methods
282
+ }
283
+
284
+ func (check * Checker ) completeMethod (env * Environment , m * Func ) {
285
+ assert (m .instRecv != nil )
286
+ rbase := m .instRecv
287
+ m .instRecv = nil
288
+ m .setColor (black )
289
+
290
+ assert (rbase .TypeArgs ().Len () > 0 )
291
+
292
+ // Look up the original method.
293
+ _ , orig := lookupMethod (rbase .orig .methods , rbase .obj .pkg , m .name )
294
+ assert (orig != nil )
295
+ if check != nil {
296
+ check .objDecl (orig , nil )
297
+ }
298
+ origSig := orig .typ .(* Signature )
299
+ if origSig .RecvTypeParams ().Len () != rbase .targs .Len () {
300
+ m .typ = origSig // or new(Signature), but we can't use Typ[Invalid]: Funcs must have Signature type
301
+ return // error reported elsewhere
302
+ }
303
+
304
+ smap := makeSubstMap (origSig .RecvTypeParams ().list (), rbase .targs .list ())
305
+ sig := check .subst (orig .pos , origSig , smap , env ).(* Signature )
306
+ if sig == origSig {
307
+ // No substitution occurred, but we still need to create a new signature to
308
+ // hold the instantiated receiver.
309
+ copy := * origSig
310
+ sig = & copy
311
+ }
312
+ var rtyp Type
313
+ if ptrRecv (m ) {
314
+ rtyp = NewPointer (rbase )
248
315
} else {
249
- u = Typ [ Invalid ]
316
+ rtyp = rbase
250
317
}
251
- return n .orig .tparams , u , n .orig .methods
318
+ sig .recv = NewParam (origSig .recv .pos , origSig .recv .pkg , origSig .recv .name , rtyp )
319
+
320
+ m .typ = sig
252
321
}
253
322
254
323
// safeUnderlying returns the underlying of typ without expanding instances, to
0 commit comments