@@ -35,6 +35,16 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
35
35
types .DeferCheckSize ()
36
36
res := g .typ1 (typ )
37
37
types .ResumeCheckSize ()
38
+
39
+ // Finish up any types on typesToFinalize, now that we are at the top of a
40
+ // fully-defined (possibly recursive) type. fillinMethods could create more
41
+ // types to finalize.
42
+ for len (g .typesToFinalize ) > 0 {
43
+ l := len (g .typesToFinalize )
44
+ info := g .typesToFinalize [l - 1 ]
45
+ g .typesToFinalize = g .typesToFinalize [:l - 1 ]
46
+ g .fillinMethods (info .typ , info .ntyp )
47
+ }
38
48
return res
39
49
}
40
50
@@ -151,10 +161,19 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
151
161
ntyp .SetRParams (rparams )
152
162
//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
153
163
154
- ntyp .SetUnderlying (g .typ1 (typ .Underlying ()))
155
- g .fillinMethods (typ , ntyp )
156
164
// Save the symbol for the base generic type.
157
165
ntyp .OrigSym = g .pkg (typ .Obj ().Pkg ()).Lookup (typ .Obj ().Name ())
166
+ ntyp .SetUnderlying (g .typ1 (typ .Underlying ()))
167
+ if typ .NumMethods () != 0 {
168
+ // Save a delayed call to g.fillinMethods() (once
169
+ // potentially recursive types have been fully
170
+ // resolved).
171
+ g .typesToFinalize = append (g .typesToFinalize ,
172
+ & typeDelayInfo {
173
+ typ : typ ,
174
+ ntyp : ntyp ,
175
+ })
176
+ }
158
177
return ntyp
159
178
}
160
179
obj := g .obj (typ .Obj ())
@@ -266,76 +285,75 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
266
285
}
267
286
}
268
287
269
- // fillinMethods fills in the method name nodes and types for a defined type. This
270
- // is needed for later typechecking when looking up methods of instantiated types,
271
- // and for actually generating the methods for instantiated types.
288
+ // fillinMethods fills in the method name nodes and types for a defined type with at
289
+ // least one method. This is needed for later typechecking when looking up methods of
290
+ // instantiated types, and for actually generating the methods for instantiated
291
+ // types.
272
292
func (g * irgen ) fillinMethods (typ * types2.Named , ntyp * types.Type ) {
273
- if typ .NumMethods () != 0 {
274
- targs2 := typ .TArgs ()
275
- targs := make ([]* types.Type , targs2 .Len ())
276
- for i := range targs {
277
- targs [i ] = g .typ1 (targs2 .At (i ))
278
- }
293
+ targs2 := typ .TArgs ()
294
+ targs := make ([]* types.Type , targs2 .Len ())
295
+ for i := range targs {
296
+ targs [i ] = g .typ1 (targs2 .At (i ))
297
+ }
279
298
280
- methods := make ([]* types.Field , typ .NumMethods ())
281
- for i := range methods {
282
- m := typ .Method (i )
283
- recvType := deref2 (types2 .AsSignature (m .Type ()).Recv ().Type ())
284
- var meth * ir.Name
285
- if m .Pkg () != g .self {
286
- // Imported methods cannot be loaded by name (what
287
- // g.obj() does) - they must be loaded via their
288
- // type.
289
- meth = g .obj (recvType .(* types2.Named ).Obj ()).Type ().Methods ().Index (i ).Nname .(* ir.Name )
299
+ methods := make ([]* types.Field , typ .NumMethods ())
300
+ for i := range methods {
301
+ m := typ .Method (i )
302
+ recvType := deref2 (types2 .AsSignature (m .Type ()).Recv ().Type ())
303
+ var meth * ir.Name
304
+ if m .Pkg () != g .self {
305
+ // Imported methods cannot be loaded by name (what
306
+ // g.obj() does) - they must be loaded via their
307
+ // type.
308
+ meth = g .obj (recvType .(* types2.Named ).Obj ()).Type ().Methods ().Index (i ).Nname .(* ir.Name )
309
+ } else {
310
+ meth = g .obj (m )
311
+ }
312
+ if recvType != types2 .Type (typ ) {
313
+ // Unfortunately, meth is the type of the method of the
314
+ // generic type, so we have to do a substitution to get
315
+ // the name/type of the method of the instantiated type,
316
+ // using m.Type().RParams() and typ.TArgs()
317
+ inst2 := instTypeName2 ("" , typ .TArgs ())
318
+ name := meth .Sym ().Name
319
+ i1 := strings .Index (name , "[" )
320
+ i2 := strings .Index (name [i1 :], "]" )
321
+ assert (i1 >= 0 && i2 >= 0 )
322
+ // Generate the name of the instantiated method.
323
+ name = name [0 :i1 ] + inst2 + name [i1 + i2 + 1 :]
324
+ newsym := meth .Sym ().Pkg .Lookup (name )
325
+ var meth2 * ir.Name
326
+ if newsym .Def != nil {
327
+ meth2 = newsym .Def .(* ir.Name )
290
328
} else {
291
- meth = g .obj (m )
292
- }
293
- if recvType != types2 .Type (typ ) {
294
- // Unfortunately, meth is the type of the method of the
295
- // generic type, so we have to do a substitution to get
296
- // the name/type of the method of the instantiated type,
297
- // using m.Type().RParams() and typ.TArgs()
298
- inst2 := instTypeName2 ("" , typ .TArgs ())
299
- name := meth .Sym ().Name
300
- i1 := strings .Index (name , "[" )
301
- i2 := strings .Index (name [i1 :], "]" )
302
- assert (i1 >= 0 && i2 >= 0 )
303
- // Generate the name of the instantiated method.
304
- name = name [0 :i1 ] + inst2 + name [i1 + i2 + 1 :]
305
- newsym := meth .Sym ().Pkg .Lookup (name )
306
- var meth2 * ir.Name
307
- if newsym .Def != nil {
308
- meth2 = newsym .Def .(* ir.Name )
309
- } else {
310
- meth2 = ir .NewNameAt (meth .Pos (), newsym )
311
- rparams := types2 .AsSignature (m .Type ()).RParams ()
312
- tparams := make ([]* types.Type , rparams .Len ())
313
- for i := range tparams {
314
- tparams [i ] = g .typ1 (rparams .At (i ))
315
- }
316
- assert (len (tparams ) == len (targs ))
317
- ts := typecheck.Tsubster {
318
- Tparams : tparams ,
319
- Targs : targs ,
320
- }
321
- // Do the substitution of the type
322
- meth2 .SetType (ts .Typ (meth .Type ()))
323
- // Add any new fully instantiated types
324
- // seen during the substitution to
325
- // g.instTypeList.
326
- g .instTypeList = append (g .instTypeList , ts .InstTypeList ... )
327
- newsym .Def = meth2
329
+ meth2 = ir .NewNameAt (meth .Pos (), newsym )
330
+ rparams := types2 .AsSignature (m .Type ()).RParams ()
331
+ tparams := make ([]* types.Type , rparams .Len ())
332
+ for i := range tparams {
333
+ tparams [i ] = g .typ1 (rparams .At (i ))
328
334
}
329
- meth = meth2
335
+ assert (len (tparams ) == len (targs ))
336
+ ts := typecheck.Tsubster {
337
+ Tparams : tparams ,
338
+ Targs : targs ,
339
+ }
340
+ // Do the substitution of the type
341
+ meth2 .SetType (ts .Typ (meth .Type ()))
342
+ // Add any new fully instantiated types
343
+ // seen during the substitution to
344
+ // g.instTypeList.
345
+ g .instTypeList = append (g .instTypeList , ts .InstTypeList ... )
346
+ newsym .Def = meth2
330
347
}
331
- methods [i ] = types .NewField (meth .Pos (), g .selector (m ), meth .Type ())
332
- methods [i ].Nname = meth
333
- }
334
- ntyp .Methods ().Set (methods )
335
- if ! ntyp .HasTParam () && ! ntyp .HasShape () {
336
- // Generate all the methods for a new fully-instantiated type.
337
- g .instTypeList = append (g .instTypeList , ntyp )
348
+ meth = meth2
338
349
}
350
+ methods [i ] = types .NewField (meth .Pos (), g .selector (m ), meth .Type ())
351
+ methods [i ].Nname = meth
352
+ }
353
+ ntyp .Methods ().Set (methods )
354
+ if ! ntyp .HasTParam () && ! ntyp .HasShape () {
355
+ // Generate all the methods for a new fully-instantiated type.
356
+ g .instTypeList = append (g .instTypeList , ntyp )
339
357
}
340
358
}
341
359
0 commit comments