mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] Add optional sub-dict entry for typeparam bound calls
In the case that a generic function/method f does a method call on a type param allowed by its bound, an instantiation of f may do a direct method call of a concrete type or a method call defined on a generic type, depending on whether the passed type in a concrete type or an instantiated type with the appropriate method defined. See the test case boundmethod.go added to this change. In order to keep the dictionary format the same for all instantiations of a generic function/method, I decided to have an optional sub-dictionary entry for "bounds" calls. At the point that we are creating the actual dictionary, we can then fill in the needed sub-dictionary, if the type arg is an instantiated type, or a zeroed dictionary entry, if type arg is not instantiated and the method will be on a concrete type. In order to implement this, I now fill in n.Selection for "bounds" method calls in generic functions as well. Also, I need to calculate n.Selection correctly during import for the case where it is now set - method calls on generic types, and bounds calls on typeparams. With this change, the dictionaries/sub-dictionaries are correct for absdiff.go. The new test boundmethod.go illustrates the case where the bound sub-dict entry is not used for a dictionary for stringify[myint], but is used for a dictionary for stringify[StringInt[myint]]. Change-Id: Ie2bcb971b7019a9f1da68c97eb03da2333327457 Reviewed-on: https://go-review.googlesource.com/c/go/+/333456 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org> Trust: Dan Scales <danscales@google.com>
This commit is contained in:
parent
0dcab98fd8
commit
1c783dc148
5 changed files with 172 additions and 27 deletions
|
|
@ -207,29 +207,43 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
|
|||
n := ir.NewSelectorExpr(pos, ir.OXDOT, x, typecheck.Lookup(expr.Sel.Value))
|
||||
typed(g.typ(typ), n)
|
||||
|
||||
// Fill in n.Selection for a generic method reference, even though we
|
||||
// won't use it directly, since it is useful for analysis.
|
||||
// Specifically do not fill in for fields or interfaces methods, so
|
||||
// n.Selection being non-nil means a method reference, rather than an
|
||||
// interface reference or reference to a field with a function value.
|
||||
// Fill in n.Selection for a generic method reference or a bound
|
||||
// interface method, even though we won't use it directly, since it
|
||||
// is useful for analysis. Specifically do not fill in for fields or
|
||||
// other interfaces methods (method call on an interface value), so
|
||||
// n.Selection being non-nil means a method reference for a generic
|
||||
// type or a method reference due to a bound.
|
||||
obj2 := g.info.Selections[expr].Obj()
|
||||
sig := types2.AsSignature(obj2.Type())
|
||||
if sig == nil || sig.Recv() == nil {
|
||||
return n
|
||||
}
|
||||
// recvType is the type of the last embedded field. Because of the
|
||||
index := g.info.Selections[expr].Index()
|
||||
last := index[len(index)-1]
|
||||
// recvType is the receiver of the method being called. Because of the
|
||||
// way methods are imported, g.obj(obj2) doesn't work across
|
||||
// packages, so we have to lookup the method via the receiver type.
|
||||
recvType := deref2(sig.Recv().Type())
|
||||
if types2.AsInterface(recvType.Underlying()) != nil {
|
||||
fieldType := n.X.Type()
|
||||
for _, ix := range index[:len(index)-1] {
|
||||
fieldType = fieldType.Field(ix).Type
|
||||
}
|
||||
if fieldType.Kind() == types.TTYPEPARAM {
|
||||
n.Selection = fieldType.Bound().AllMethods().Index(last)
|
||||
//fmt.Printf(">>>>> %v: Bound call %v\n", base.FmtPos(pos), n.Sel)
|
||||
} else {
|
||||
assert(fieldType.Kind() == types.TINTER)
|
||||
//fmt.Printf(">>>>> %v: Interface call %v\n", base.FmtPos(pos), n.Sel)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
index := g.info.Selections[expr].Index()
|
||||
last := index[len(index)-1]
|
||||
recvObj := types2.AsNamed(recvType).Obj()
|
||||
recv := g.pkg(recvObj.Pkg()).Lookup(recvObj.Name()).Def
|
||||
n.Selection = recv.Type().Methods().Index(last)
|
||||
//fmt.Printf(">>>>> %v: Method call %v\n", base.FmtPos(pos), n.Sel)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue