]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] cmd/compile: fix use of method values with stenciled methods
authorDan Scales <danscales@google.com>
Fri, 7 May 2021 20:20:34 +0000 (13:20 -0700)
committerDan Scales <danscales@google.com>
Wed, 12 May 2021 22:25:00 +0000 (22:25 +0000)
We were handling the case where an OFUNCINST node was used as a function
value, but not the case when an OFUNCINST node was used as a method
value. In the case of a method value, we need to create a new selector
expression that references the newly stenciled method.

To make this work, also needed small fix to noder2 code to properly set the
Sel of a method SelectorExpr (should be just the base method name, not
the full method name including the type string). This has to be correct,
so that the function created by MethodValueWrapper() can be typechecked
successfully.

Fixes #45817

Change-Id: I7343e8a0d35fc46b44dfe4d45b77997ba6c8733e
Reviewed-on: https://go-review.googlesource.com/c/go/+/319589
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/ir/expr.go
src/cmd/compile/internal/noder/expr.go
src/cmd/compile/internal/noder/stencil.go
test/typeparam/issue45817.go [new file with mode: 0644]

index f70645f07913f8c309023d0fc84208d8e09b85b3..9ea8b619653a4907c29f6516c28e26bd8d7bae48 100644 (file)
@@ -494,8 +494,13 @@ func NewNameOffsetExpr(pos src.XPos, name *Name, offset int64, typ *types.Type)
 // A SelectorExpr is a selector expression X.Sel.
 type SelectorExpr struct {
        miniExpr
-       X         Node
-       Sel       *types.Sym
+       X Node
+       // Sel is the name of the field or method being selected, without (in the
+       // case of methods) any preceding type specifier. If the field/method is
+       // exported, than the Sym uses the local package regardless of the package
+       // of the containing type.
+       Sel *types.Sym
+       // The actual selected field - may not be filled in until typechecking.
        Selection *types.Field
        Prealloc  *Name // preallocated storage for OCALLPART, if any
 }
index c7695ed920435291bab7c64a0cbfdfb08b8b8a7e..b7f7a34953a81c707728cc2968fc70abdd90c6ea 100644 (file)
@@ -266,7 +266,7 @@ func (g *irgen) selectorExpr(pos src.XPos, typ types2.Type, expr *syntax.Selecto
                                recvType2 = recvType2Base
                                // method is the generic method associated with the gen type
                                method := g.obj(types2.AsNamed(recvType2).Method(last))
-                               n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, method.Sym())
+                               n = ir.NewSelectorExpr(pos, ir.OCALLPART, x, typecheck.Lookup(expr.Sel.Value))
                                n.(*ir.SelectorExpr).Selection = types.NewField(pos, method.Sym(), method.Type())
                                n.(*ir.SelectorExpr).Selection.Nname = method
                                typed(method.Type(), n)
index 3ebc8dff6d84322d2d5c2379e9497a87ebb1d73b..751a62825665749b0aecd1e8a7563cbb1567908b 100644 (file)
@@ -112,14 +112,30 @@ func (g *irgen) stencil() {
                // EditChildren rather than Visit), where we actually change the
                // OFUNCINST node to an ONAME for the instantiated function.
                // EditChildren is more expensive than Visit, so we only do this
-               // in the infrequent case of an OFUNCINSt without a corresponding
+               // in the infrequent case of an OFUNCINST without a corresponding
                // call.
                if foundFuncInst {
                        var edit func(ir.Node) ir.Node
                        edit = func(x ir.Node) ir.Node {
                                if x.Op() == ir.OFUNCINST {
-                                       st := g.getInstantiationForNode(x.(*ir.InstExpr))
-                                       return st.Nname
+                                       // inst.X is either a function name node
+                                       // or a selector expression for a method.
+                                       inst := x.(*ir.InstExpr)
+                                       st := g.getInstantiationForNode(inst)
+                                       modified = true
+                                       if inst.X.Op() == ir.ONAME {
+                                               return st.Nname
+                                       }
+                                       assert(inst.X.Op() == ir.OCALLPART)
+
+                                       // Return a new selector expression referring
+                                       // to the newly stenciled function.
+                                       oldse := inst.X.(*ir.SelectorExpr)
+                                       newse := ir.NewSelectorExpr(oldse.Pos(), ir.OCALLPART, oldse.X, oldse.Sel)
+                                       newse.Selection = types.NewField(oldse.Pos(), st.Sym(), st.Type())
+                                       newse.Selection.Nname = st
+                                       typed(inst.Type(), newse)
+                                       return newse
                                }
                                ir.EditChildren(x, edit)
                                return x
diff --git a/test/typeparam/issue45817.go b/test/typeparam/issue45817.go
new file mode 100644 (file)
index 0000000..744698f
--- /dev/null
@@ -0,0 +1,25 @@
+// run -gcflags=-G=3
+
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+       "fmt"
+)
+
+type s[T any] struct {
+       a T
+}
+func (x s[T]) f() T {
+       return x.a
+}
+func main() {
+       x := s[int]{a:7}
+       f := x.f
+       if got, want := f(), 7; got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+}