[dev.typeparams] cmd/compile: use types2.Constraint() rather than types2.Bound()

types2.Constraint() returns the top-level constraint type, including any
unions or other interface elements. Because of that, we needed to
add/fix some code in the type substituter and generic type instantiater
in the importer to deal with unions and non-method members of an
interface. Also, NewUnion was not correctly setting the HasTParam flag.

I also added a better error message when a symbol is not found in
(*deadcodePass).decodeIfaceMethod().

Change-Id: Id3668dc596dce63690fa05a9e5e42295b5e2bbb5
Reviewed-on: https://go-review.googlesource.com/c/go/+/340670
Trust: Dan Scales <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-08-07 22:26:46 -07:00
parent 9f4d6a8359
commit f5f79c47f9
5 changed files with 42 additions and 4 deletions

View file

@ -227,7 +227,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
// Set g.typs[typ] in case the bound methods reference typ.
g.typs[typ] = tp
bound := g.typ1(typ.Bound())
bound := g.typ1(typ.Constraint())
tp.SetBound(bound)
return tp

View file

@ -1858,18 +1858,26 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
newfields := make([]*types.Field, baseType.Methods().Len())
for i, f := range baseType.Methods().Slice() {
if !f.IsMethod() || types.IsInterfaceMethod(f.Type) {
// Do a normal substitution if this is a non-method (which
// means this must be an interface used as a constraint) or
// an interface method.
t2 := subst.Typ(f.Type)
newfields[i] = types.NewField(f.Pos, f.Sym, t2)
continue
}
recvType := f.Type.Recv().Type
if recvType.IsPtr() {
recvType = recvType.Elem()
}
// Substitute in the method using the type params used in the
// method (not the type params in the definition of the generic type).
subst := Tsubster{
msubst := Tsubster{
Tparams: recvType.RParams(),
Targs: targs,
SubstForwFunc: doInst,
}
t2 := subst.Typ(f.Type)
t2 := msubst.Typ(f.Type)
oldsym := f.Nname.Sym()
newsym := MakeInstName(oldsym, targs, true)
var nname *ir.Name

View file

@ -1165,7 +1165,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
case types.TINTER:
newt = ts.tinter(t)
if newt == t {
if newt == t && !targsChanged {
newt = nil
}
@ -1197,6 +1197,24 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64,
types.TUINTPTR, types.TBOOL, types.TSTRING, types.TFLOAT32, types.TFLOAT64, types.TCOMPLEX64, types.TCOMPLEX128:
newt = t.Underlying()
case types.TUNION:
nt := t.NumTerms()
newterms := make([]*types.Type, nt)
tildes := make([]bool, nt)
changed := false
for i := 0; i < nt; i++ {
term, tilde := t.Term(i)
tildes[i] = tilde
newterms[i] = ts.Typ(term)
if newterms[i] != term {
changed = true
}
}
if changed {
newt = types.NewUnion(newterms, tildes)
}
default:
panic(fmt.Sprintf("Bad type in (*TSubster).Typ: %v", t.Kind()))
}
if newt == nil {
// Even though there were typeparams in the type, there may be no

View file

@ -1912,6 +1912,15 @@ func NewUnion(terms []*Type, tildes []bool) *Type {
}
t.Extra.(*Union).terms = terms
t.Extra.(*Union).tildes = tildes
nt := len(terms)
for i := 0; i < nt; i++ {
if terms[i].HasTParam() {
t.SetHasTParam(true)
}
if terms[i].HasShape() {
t.SetHasShape(true)
}
}
return t
}

View file

@ -408,6 +408,9 @@ func (d *deadcodePass) decodeMethodSig(ldr *loader.Loader, arch *sys.Arch, symId
// Decode the method of interface type symbol symIdx at offset off.
func (d *deadcodePass) decodeIfaceMethod(ldr *loader.Loader, arch *sys.Arch, symIdx loader.Sym, off int64) methodsig {
p := ldr.Data(symIdx)
if p == nil {
panic(fmt.Sprintf("missing symbol %q", ldr.SymName(symIdx)))
}
if decodetypeKind(arch, p)&kindMask != kindInterface {
panic(fmt.Sprintf("symbol %q is not an interface", ldr.SymName(symIdx)))
}