1
0
mirror of https://github.com/golang/go synced 2024-11-22 20:40:03 -07:00

cmd/compile: delay fillinMethods to deal with mutually-recursive types

We need to delay fillinMethods until we get to a top-level type, so we
know all the TFORW types have been filled in, and we can do the
substitutions required by fillinMethods.

Fixes #47710

Change-Id: I298de7e7753ed31a2c2b1ff04f35177a8afc7a66
Reviewed-on: https://go-review.googlesource.com/c/go/+/345149
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-08-18 06:28:40 -07:00
parent c927599783
commit d7e2e2ec2b
4 changed files with 112 additions and 67 deletions

View File

@ -149,6 +149,9 @@ type irgen struct {
// statements yet.
exprStmtOK bool
// types which we need to finish, by doing g.fillinMethods.
typesToFinalize []*typeDelayInfo
// Fully-instantiated generic types whose methods should be instantiated
instTypeList []*types.Type
@ -184,6 +187,11 @@ type delayInfo struct {
off int
}
type typeDelayInfo struct {
typ *types2.Named
ntyp *types.Type
}
func (g *irgen) generate(noders []*noder) {
types.LocalPkg.Name = g.self.Name()
types.LocalPkg.Height = g.self.Height()

View File

@ -35,6 +35,16 @@ func (g *irgen) typ(typ types2.Type) *types.Type {
types.DeferCheckSize()
res := g.typ1(typ)
types.ResumeCheckSize()
// Finish up any types on typesToFinalize, now that we are at the top of a
// fully-defined (possibly recursive) type. fillinMethods could create more
// types to finalize.
for len(g.typesToFinalize) > 0 {
l := len(g.typesToFinalize)
info := g.typesToFinalize[l-1]
g.typesToFinalize = g.typesToFinalize[:l-1]
g.fillinMethods(info.typ, info.ntyp)
}
return res
}
@ -151,10 +161,19 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
ntyp.SetRParams(rparams)
//fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam())
ntyp.SetUnderlying(g.typ1(typ.Underlying()))
g.fillinMethods(typ, ntyp)
// Save the symbol for the base generic type.
ntyp.OrigSym = g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())
ntyp.SetUnderlying(g.typ1(typ.Underlying()))
if typ.NumMethods() != 0 {
// Save a delayed call to g.fillinMethods() (once
// potentially recursive types have been fully
// resolved).
g.typesToFinalize = append(g.typesToFinalize,
&typeDelayInfo{
typ: typ,
ntyp: ntyp,
})
}
return ntyp
}
obj := g.obj(typ.Obj())
@ -266,11 +285,11 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
}
}
// fillinMethods fills in the method name nodes and types for a defined type. This
// is needed for later typechecking when looking up methods of instantiated types,
// and for actually generating the methods for instantiated types.
// fillinMethods fills in the method name nodes and types for a defined type with at
// least one method. This is needed for later typechecking when looking up methods of
// instantiated types, and for actually generating the methods for instantiated
// types.
func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
if typ.NumMethods() != 0 {
targs2 := typ.TArgs()
targs := make([]*types.Type, targs2.Len())
for i := range targs {
@ -336,7 +355,6 @@ func (g *irgen) fillinMethods(typ *types2.Named, ntyp *types.Type) {
// Generate all the methods for a new fully-instantiated type.
g.instTypeList = append(g.instTypeList, ntyp)
}
}
}
func (g *irgen) signature(recv *types.Field, sig *types2.Signature) *types.Type {

View File

@ -927,7 +927,7 @@ func formalType(t *types.Type) *types.Type {
func writeType(t *types.Type) *obj.LSym {
t = formalType(t)
if t.IsUntyped() {
if t.IsUntyped() || t.HasTParam() {
base.Fatalf("writeType %v", t)
}

View File

@ -0,0 +1,19 @@
// compile -G=3
// 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 p
type FooType[t any] interface {
Foo(BarType[t])
}
type BarType[t any] interface {
Int(IntType[t]) FooType[int]
}
type IntType[t any] int
func (n IntType[t]) Foo(BarType[t]) {}
func (n IntType[_]) String() {}