1
0
mirror of https://github.com/golang/go synced 2024-11-26 11:48:03 -07:00

[dev.typeparams] cmd/compile: get rid of concretify use for bounds.

We just need to substitute from the typeparams to the shapes for the dst
type of the bound.

Removed concretify substituter, not used anymore. Also removed
shape2params, not needed anymore.

However, since the dst type is now not concrete, this gives more cases
where the linker can't find a method.

I realized that we need to call MarkUsedIfaceMethod to mark a method as
used on a particular interface, else a type's method can be still
deadcoded even though MarkTypeUsedInInterface has been called on the
concrete type. I added a new version MarkUsedIfaceMethodIndex to fit my
use case.

Change-Id: Id67b72b350889dd3688b42739c337d5d79a0d1a2
Reviewed-on: https://go-review.googlesource.com/c/go/+/337230
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-07-23 17:19:51 -07:00
parent 77e0bf294c
commit 3dc0a0a2c5
2 changed files with 28 additions and 20 deletions

View File

@ -855,13 +855,9 @@ type subster struct {
ts typecheck.Tsubster ts typecheck.Tsubster
info *instInfo // Place to put extra info in the instantiation info *instInfo // Place to put extra info in the instantiation
// Which type parameter the shape type came from.
shape2param map[*types.Type]*types.Type
// unshapeify maps from shape types to the concrete types they represent. // unshapeify maps from shape types to the concrete types they represent.
// TODO: remove when we no longer need it. // TODO: remove when we no longer need it.
unshapify typecheck.Tsubster unshapify typecheck.Tsubster
concretify typecheck.Tsubster
// TODO: some sort of map from <shape type, interface type> to index in the // TODO: some sort of map from <shape type, interface type> to index in the
// dictionary where a *runtime.itab for the corresponding <concrete type, // dictionary where a *runtime.itab for the corresponding <concrete type,
@ -920,23 +916,11 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs
Targs: shapes, Targs: shapes,
Vars: make(map[*ir.Name]*ir.Name), Vars: make(map[*ir.Name]*ir.Name),
}, },
shape2param: map[*types.Type]*types.Type{},
unshapify: typecheck.Tsubster{ unshapify: typecheck.Tsubster{
Tparams: shapes, Tparams: shapes,
Targs: targs, Targs: targs,
Vars: make(map[*ir.Name]*ir.Name), Vars: make(map[*ir.Name]*ir.Name),
}, },
concretify: typecheck.Tsubster{
Tparams: tparams,
Targs: targs,
Vars: make(map[*ir.Name]*ir.Name),
},
}
for i := range shapes {
if !shapes[i].IsShape() {
panic("must be a shape type")
}
subst.shape2param[shapes[i]] = tparams[i]
} }
newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1) newf.Dcl = make([]*ir.Name, 0, len(gf.Dcl)+1)
@ -992,7 +976,6 @@ func (g *irgen) genericSubst(newsym *types.Sym, nameNode *ir.Name, shapes, targs
// g.instTypeList. // g.instTypeList.
g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...) g.instTypeList = append(g.instTypeList, subst.ts.InstTypeList...)
g.instTypeList = append(g.instTypeList, subst.unshapify.InstTypeList...) g.instTypeList = append(g.instTypeList, subst.unshapify.InstTypeList...)
g.instTypeList = append(g.instTypeList, subst.concretify.InstTypeList...)
if doubleCheck { if doubleCheck {
okConvs := map[ir.Node]bool{} okConvs := map[ir.Node]bool{}
@ -1258,7 +1241,10 @@ func (subst *subster) node(n ir.Node) ir.Node {
// 1) convert x to the bound interface // 1) convert x to the bound interface
// 2) call M on that interface // 2) call M on that interface
gsrc := x.(*ir.SelectorExpr).X.Type() gsrc := x.(*ir.SelectorExpr).X.Type()
dst := subst.concretify.Typ(gsrc.Bound()) dst := gsrc.Bound()
if dst.HasTParam() {
dst = subst.ts.Typ(dst)
}
mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, x, dst, gsrc) mse.X = subst.convertUsingDictionary(m.Pos(), mse.X, x, dst, gsrc)
} }
} }
@ -1714,6 +1700,18 @@ func (g *irgen) finalizeSyms() {
se := n.(*ir.SelectorExpr) se := n.(*ir.SelectorExpr)
srctype = subst.Typ(se.X.Type()) srctype = subst.Typ(se.X.Type())
dsttype = subst.Typ(se.X.Type().Bound()) dsttype = subst.Typ(se.X.Type().Bound())
found := false
for i, m := range dsttype.AllMethods().Slice() {
if se.Sel == m.Sym {
// Mark that this method se.Sel is
// used for the dsttype interface, so
// it won't get deadcoded.
reflectdata.MarkUsedIfaceMethodIndex(lsym, dsttype, i)
found = true
break
}
}
assert(found)
} else { } else {
assert(n.Op() == ir.OCONVIFACE) assert(n.Op() == ir.OCONVIFACE)
srctype = subst.Typ(n.(*ir.ConvExpr).X.Type()) srctype = subst.Typ(n.(*ir.ConvExpr).X.Type())

View File

@ -2006,13 +2006,23 @@ func MarkUsedIfaceMethod(n *ir.CallExpr) {
tsym := TypeLinksym(ityp) tsym := TypeLinksym(ityp)
r := obj.Addrel(ir.CurFunc.LSym) r := obj.Addrel(ir.CurFunc.LSym)
r.Sym = tsym r.Sym = tsym
// dot.Xoffset is the method index * PtrSize (the offset of code pointer // dot.Offset() is the method index * PtrSize (the offset of code pointer
// in itab). // in itab).
midx := dot.Offset() / int64(types.PtrSize) midx := dot.Offset() / int64(types.PtrSize)
r.Add = InterfaceMethodOffset(ityp, midx) r.Add = InterfaceMethodOffset(ityp, midx)
r.Type = objabi.R_USEIFACEMETHOD r.Type = objabi.R_USEIFACEMETHOD
} }
// MarkUsedIfaceMethodIndex marks that that method number ix (in the AllMethods list)
// of interface type ityp is used, and should be attached to lsym.
func MarkUsedIfaceMethodIndex(lsym *obj.LSym, ityp *types.Type, ix int) {
tsym := TypeLinksym(ityp)
r := obj.Addrel(lsym)
r.Sym = tsym
r.Add = InterfaceMethodOffset(ityp, int64(ix))
r.Type = objabi.R_USEIFACEMETHOD
}
// getDictionary returns the dictionary for the given named generic function // getDictionary returns the dictionary for the given named generic function
// or method, with the given type arguments. // or method, with the given type arguments.
func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node { func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {