]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: handle the (*T).M method expression with dictionaries
authorDan Scales <danscales@google.com>
Tue, 6 Jul 2021 17:53:00 +0000 (10:53 -0700)
committerDan Scales <danscales@google.com>
Wed, 7 Jul 2021 17:31:57 +0000 (17:31 +0000)
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>

src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/typecheck/iexport.go
src/cmd/compile/internal/typecheck/iimport.go
test/run.go
test/typeparam/dictionaryCapture.go

index dbaebf7623879219780496afba3ed6192cccf827..656cab84d17430f715b302c2494f37766db0df7c 100644 (file)
@@ -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()
index 82bbda5228f544d7f39a5ea7a85356aaad15f329..b717c373f5fb030babf1fccda87e047056b17591 100644 (file)
@@ -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())
index 17e60effd6870bbc48600879bfb9da72e1b5d93c..f178869e285a0f19d226d86ed774404d542e83ef 100644 (file)
@@ -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())
index df3befbf21d3735396b4e636df55ac3a6ebedfb6..7afad0ec09c7f3ad4d8faffaa509695336f79caf 100644 (file)
@@ -2215,7 +2215,6 @@ var g3Failures = setOf(
        "typeparam/mdempsky/11.go",
        "typeparam/mdempsky/12.go",
        "typeparam/mdempsky/13.go",
-       "typeparam/mdempsky/14.go",
 )
 
 var unifiedFailures = setOf(
index af508859e1c3af345e4dae7a522f50969668e32d..26af7a09b0bc68660504d4d5938dc3d2a0cff530 100644 (file)
@@ -73,20 +73,32 @@ func methodExpressions() {
        x := s[int]{a:7}
        f0 := s[int].g0
        f0(x)
+       f0p := (*s[int]).g0
+       f0p(&x)
        f1 := s[int].g1
        is7(f1(x))
+       f1p := (*s[int]).g1
+       is7(f1p(&x))
        f2 := s[int].g2
        is77(f2(x))
+       f2p := (*s[int]).g2
+       is77(f2p(&x))
 }
 
 func genMethodExpressions[T comparable](want T) {
        x := s[T]{a: want}
        f0 := s[T].g0
        f0(x)
+       f0p := (*s[T]).g0
+       f0p(&x)
        f1 := s[T].g1
        if got := f1(x); got != want {
                panic(fmt.Sprintf("f1(x) == %d, want %d", got, want))
        }
+       f1p := (*s[T]).g1
+       if got := f1p(&x); got != want {
+               panic(fmt.Sprintf("f1p(&x) == %d, want %d", got, want))
+       }
        f2 := s[T].g2
        if got1, got2 := f2(x); got1 != want || got2 != want {
                panic(fmt.Sprintf("f2(x) == %d, %d, want %d, %d", got1, got2, want, want))