aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/noder/stencil.go30
-rw-r--r--src/cmd/compile/internal/typecheck/iexport.go4
-rw-r--r--src/cmd/compile/internal/typecheck/iimport.go4
-rw-r--r--test/run.go1
-rw-r--r--test/typeparam/dictionaryCapture.go12
5 files changed, 34 insertions, 17 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())
diff --git a/test/run.go b/test/run.go
index df3befbf21..7afad0ec09 100644
--- a/test/run.go
+++ b/test/run.go
@@ -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(
diff --git a/test/typeparam/dictionaryCapture.go b/test/typeparam/dictionaryCapture.go
index af508859e1..26af7a09b0 100644
--- a/test/typeparam/dictionaryCapture.go
+++ b/test/typeparam/dictionaryCapture.go
@@ -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))