diff options
author | Dan Scales <danscales@google.com> | 2021-07-06 10:53:00 -0700 |
---|---|---|
committer | Dan Scales <danscales@google.com> | 2021-07-07 17:31:57 +0000 |
commit | b4844c9f54eb6a559d8dc9333cf5b1e66dab8167 (patch) | |
tree | c14c3561c5ccc3542d9b53b3761229b271aa887b /src/cmd/compile/internal | |
parent | 4676c3675e85a8a82a1513ef1f5e38aebc80ddc8 (diff) | |
download | go-b4844c9f54eb6a559d8dc9333cf5b1e66dab8167.tar.gz go-b4844c9f54eb6a559d8dc9333cf5b1e66dab8167.zip |
[dev.typeparams] cmd/compile: handle the (*T).M method expression with dictionaries
The (*T).M method expression is where M is a value method, but the type
(*T) is a pointer to the main type. In this case, after following any
embedded fields, we need to add an extra star operator when using the
receiver arg in the closure call.
Thanks to Cuong for finding/pointing out an example for this case
(typeparam/mdempsky/14.go) This example also shows that we now need the
ability to export/import OEFACE and OIDATA, which I added.
Change-Id: Ida0f81ce757fff78fec6276c60052ed71d207454
Reviewed-on: https://go-review.googlesource.com/c/go/+/333014
Run-TryBot: Dan Scales <danscales@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Diffstat (limited to 'src/cmd/compile/internal')
-rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 30 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/iexport.go | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/typecheck/iimport.go | 4 |
3 files changed, 22 insertions, 16 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index dbaebf7623..656cab84d1 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -94,7 +94,7 @@ func (g *irgen) stencil() { // generic F, not immediately called closureRequired = true } - if n.Op() == ir.OMETHEXPR && len(n.(*ir.SelectorExpr).X.Type().RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { + if n.Op() == ir.OMETHEXPR && len(deref(n.(*ir.SelectorExpr).X.Type()).RParams()) > 0 && !types.IsInterfaceMethod(n.(*ir.SelectorExpr).Selection.Type) { // T.M, T a type which is generic, not immediately // called. Not necessary if the method selected is // actually for an embedded interface field. @@ -229,6 +229,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { outerInfo = g.instInfoMap[outer.Sym()] } usingSubdict := false + valueMethod := false if x.Op() == ir.OFUNCINST { inst := x.(*ir.InstExpr) @@ -269,16 +270,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { } } else { // ir.OMETHEXPR // Method expression T.M where T is a generic type. - // TODO: Is (*T).M right? se := x.(*ir.SelectorExpr) - targs := se.X.Type().RParams() + targs := deref(se.X.Type()).RParams() if len(targs) == 0 { - if se.X.Type().IsPtr() { - targs = se.X.Type().Elem().RParams() - if len(targs) == 0 { - panic("bad") - } - } + panic("bad") } // se.X.Type() is the top-level type of the method expression. To @@ -295,6 +290,10 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { break } } + if !gf.Type().Recv().Type.IsPtr() { + // Remember if value method, so we can detect (*T).M case. + valueMethod = true + } target = g.getInstantiation(gf, targs, true) dictValue, usingSubdict = g.getDictOrSubdict(outerInfo, x, gf, targs, true) if infoPrintMode { @@ -446,8 +445,15 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // If we are doing a method expression, we need to // explicitly traverse any embedded fields in the receiver // argument in order to call the method instantiation. - dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, formalParams[0].Nname.(*ir.Name), x.(*ir.SelectorExpr).Sel)) - args = append(args, dot.X) + arg0 := formalParams[0].Nname.(ir.Node) + arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, arg0, x.(*ir.SelectorExpr).Sel)).X + if valueMethod && arg0.Type().IsPtr() { + // For handling the (*T).M case: if we have a pointer + // receiver after following all the embedded fields, + // but it's a value method, add a star operator. + arg0 = ir.NewStarExpr(arg0.Pos(), arg0) + } + args = append(args, arg0) } else { args = append(args, formalParams[i].Nname.(*ir.Name)) } @@ -1342,7 +1348,7 @@ func (subst *subster) fields(class ir.Class, oldfields []*types.Field, dcl []*ir return newfields } -// defer does a single defer of type t, if it is a pointer type. +// deref does a single deref of type t, if it is a pointer type. func deref(t *types.Type) *types.Type { if t.IsPtr() { return t.Elem() diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index 82bbda5228..b717c373f5 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -1957,7 +1957,7 @@ func (w *exportWriter) expr(n ir.Node) { w.typ(n.Type()) // unary expressions - case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA: n := n.(*ir.UnaryExpr) w.op(n.Op()) w.pos(n.Pos()) @@ -1993,7 +1993,7 @@ func (w *exportWriter) expr(n ir.Node) { // binary expressions case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, - ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE: n := n.(*ir.BinaryExpr) w.op(n.Op()) w.pos(n.Pos()) diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index 17e60effd6..f178869e28 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -1497,7 +1497,7 @@ func (r *importReader) node() ir.Node { return ir.NewLinksymOffsetExpr(pos, Lookup(name).Linksym(), int64(off), typ) // unary expressions - case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV: + case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.ORECV, ir.OIDATA: n := ir.NewUnaryExpr(r.pos(), op, r.expr()) if go117ExportTypes { n.SetType(r.typ()) @@ -1521,7 +1521,7 @@ func (r *importReader) node() ir.Node { // binary expressions case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, - ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR: + ir.OLSH, ir.OMOD, ir.OMUL, ir.ONE, ir.OOR, ir.ORSH, ir.OSUB, ir.OXOR, ir.OEFACE: n := ir.NewBinaryExpr(r.pos(), op, r.expr(), r.expr()) if go117ExportTypes { n.SetType(r.typ()) |