diff options
| author | Dan Scales <danscales@google.com> | 2022-01-19 14:46:58 -0800 |
|---|---|---|
| committer | Dan Scales <danscales@google.com> | 2022-01-24 17:07:30 +0000 |
| commit | f88c3b9f4d087895c3eab5ac4dd8459c76d0d0d8 (patch) | |
| tree | fe44d2cca3e0c41d42a58492628382461372b7c2 /src/cmd/compile/internal/noder | |
| parent | f9df4ea0c9426eecb93375d31e36cccf95b46e1f (diff) | |
| download | go-f88c3b9f4d087895c3eab5ac4dd8459c76d0d0d8.tar.xz | |
cmd/compile: distinguish bound calls/field access in getInstInfo
Given we have support for field access to type params with a single
structural type, we need to distinguish between methods calls and field
access when we have an OXDOT node on an expression which is a typeparam
(or correspondingly a shape). We were missing checks in getInstInfo,
which figures out the dictionary format, which then caused problems when
we generate the dictionaries. We don't need/want dictionary entries for
field access, only for bound method calls. Added a new function
isBoundMethod() to distinguish OXDOT nodes which are bound calls vs.
field accesses on a shape.
Removed isShapeDeref() - we can't have field access or method call on a
pointer to variable of type param type.
Fixes #50690
Change-Id: Id692f65e6f427f28cd2cfe474dd30e53c71877a7
Reviewed-on: https://go-review.googlesource.com/c/go/+/379674
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/noder')
| -rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 54 |
1 files changed, 31 insertions, 23 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 66c73a9427..50b6c0efcd 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -1036,13 +1036,13 @@ func (subst *subster) node(n ir.Node) ir.Node { } case ir.OXDOT: - // Finish the transformation of an OXDOT, unless this was a - // bound call (a direct call on a type param). A bound call - // will be transformed during the dictPass. Otherwise, m - // will be transformed to an OMETHVALUE node. It will be - // transformed to an ODOTMETH or ODOTINTER node if we find in - // the OCALL case below that the method value is actually - // called. + // Finish the transformation of an OXDOT, unless this is + // bound call or field access on a type param. A bound call + // or field access on a type param will be transformed during + // the dictPass. Otherwise, m will be transformed to an + // OMETHVALUE node. It will be transformed to an ODOTMETH or + // ODOTINTER node if we find in the OCALL case below that the + // method value is actually called. mse := m.(*ir.SelectorExpr) if src := mse.X.Type(); !src.IsShape() { transformDot(mse, false) @@ -1101,10 +1101,11 @@ func (subst *subster) node(n ir.Node) ir.Node { transformEarlyCall(call) case ir.OXDOT: - // This is the case of a bound call on a typeparam, - // which will be handled in the dictPass. - // As with OFUNCINST, we must transform the arguments of the call now, - // so any needed CONVIFACE nodes are exposed. + // This is the case of a bound call or a field access + // on a typeparam, which will be handled in the + // dictPass. As with OFUNCINST, we must transform the + // arguments of the call now, so any needed CONVIFACE + // nodes are exposed. transformEarlyCall(call) case ir.ODOTTYPE, ir.ODOTTYPE2: @@ -1228,13 +1229,13 @@ func (g *genInst) dictPass(info *instInfo) { // No need for transformDot - buildClosure2 has already // transformed to OCALLINTER/ODOTINTER. } else { - dst := info.dictInfo.shapeToBound[m.(*ir.SelectorExpr).X.Type()] // If we can't find the selected method in the // AllMethods of the bound, then this must be an access // to a field of a structural type. If so, we skip the // dictionary lookups - transformDot() will convert to // the desired direct field access. - if typecheck.Lookdot1(mse, mse.Sel, dst, dst.AllMethods(), 1) != nil { + if isBoundMethod(info.dictInfo, mse) { + dst := info.dictInfo.shapeToBound[mse.X.Type()] // Implement x.M as a conversion-to-bound-interface // 1) convert x to the bound interface // 2) call M on that interface @@ -1873,11 +1874,15 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: ce.X}) } } - if ce.X.Op() == ir.OXDOT && - isShapeDeref(ce.X.(*ir.SelectorExpr).X.Type()) { + // Note: this XDOT code is not actually needed as long as we + // continue to disable type parameters on RHS of type + // declarations (#45639). + if ce.X.Op() == ir.OXDOT { callMap[ce.X] = true - infoPrint(" Optional subdictionary at generic bound call: %v\n", n) - info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil}) + if isBoundMethod(info, ce.X.(*ir.SelectorExpr)) { + infoPrint(" Optional subdictionary at generic bound call: %v\n", n) + info.subDictCalls = append(info.subDictCalls, subDictInfo{callNode: n, savedXNode: nil}) + } } case ir.OCALLMETH: ce := n.(*ir.CallExpr) @@ -1900,7 +1905,8 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI info.itabConvs = append(info.itabConvs, n) } case ir.OXDOT: - if n.(*ir.SelectorExpr).X.Type().IsShape() { + se := n.(*ir.SelectorExpr) + if isBoundMethod(info, se) { infoPrint(" Itab for bound call: %v\n", n) info.itabConvs = append(info.itabConvs, n) } @@ -1956,11 +1962,13 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) } -// isShapeDeref returns true if t is either a shape or a pointer to a shape. (We -// can't just use deref(t).IsShape(), since a shape type is a complex type and may -// have a pointer as part of its shape.) -func isShapeDeref(t *types.Type) bool { - return t.IsShape() || t.IsPtr() && t.Elem().IsShape() +// isBoundMethod returns true if the selection indicated by se is a bound method of +// se.X. se.X must be a shape type (i.e. substituted directly from a type param). If +// isBoundMethod returns false, then the selection must be a field access of a +// structural type. +func isBoundMethod(info *dictInfo, se *ir.SelectorExpr) bool { + bound := info.shapeToBound[se.X.Type()] + return typecheck.Lookdot1(se, se.Sel, bound, bound.AllMethods(), 1) != nil } // addType adds t to info.derivedTypes if it is parameterized type (which is not |
