From f4b87f314dd7a890e9d3b42d7d6427cc7f51f9a2 Mon Sep 17 00:00:00 2001 From: Mark Freeman Date: Fri, 3 Apr 2026 11:52:55 -0400 Subject: cmd/compile/internal/noder: recognize generic method instantiation This change slightly extends expression traversal to recognize explicit instantiation of generic methods. The relevant MethodVal and MethodExpr snippets are extracted into helper functions, since they are needed in two places. Change-Id: I85d49d89f2422fa4c2d09de28fb6552f171a2a1f Reviewed-on: https://go-review.googlesource.com/c/go/+/762560 LUCI-TryBot-Result: Go LUCI Reviewed-by: Robert Griesemer --- src/cmd/compile/internal/noder/writer.go | 91 +++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 31 deletions(-) (limited to 'src/cmd/compile/internal/noder') diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index c4c7458a27..f01d26122e 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -1959,41 +1959,30 @@ func (w *writer) expr(expr syntax.Expr) { w.selector(sel.Obj()) case types2.MethodVal: - w.Code(exprMethodVal) - typ := w.recvExpr(expr, sel) - w.pos(expr) - w.methodExpr(expr, typ, sel) + w.methVal(expr, sel) case types2.MethodExpr: - w.Code(exprMethodExpr) - - tv := w.p.typeAndValue(expr.X) - assert(tv.IsType()) - - index := sel.Index() - implicits := index[:len(index)-1] - - typ := tv.Type - w.typ(typ) - - w.Len(len(implicits)) - for _, ix := range implicits { - w.Len(ix) - typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() - } - - recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() - if w.Bool(isPtrTo(typ, recv)) { // need deref - typ = recv - } else if w.Bool(isPtrTo(recv, typ)) { // need addr - typ = recv - } - - w.pos(expr) - w.methodExpr(expr, typ, sel) + w.methExpr(expr, sel) } case *syntax.IndexExpr: + // might be explicit instantiation of a generic method + if selector, ok := expr.X.(*syntax.SelectorExpr); ok { + if sel, ok := w.p.info.Selections[selector]; ok { + switch sel.Kind() { + default: + w.p.fatalf(selector, "unexpected selection kind: %v", sel.Kind()) + case types2.FieldVal: + // not a method + case types2.MethodVal: + w.methVal(selector, sel) + return + case types2.MethodExpr: + w.methExpr(selector, sel) + return + } + } + } _ = w.p.typeOf(expr.Index) // ensure this is an index expression, not an instantiation xtyp := w.p.typeOf(expr.X) @@ -2165,7 +2154,11 @@ func (w *writer) expr(expr syntax.Expr) { writeFunExpr := func() { fun := syntax.Unparen(expr.Fun) - if selector, ok := fun.(*syntax.SelectorExpr); ok { + expr := fun + if idx, ok := expr.(*syntax.IndexExpr); ok { + expr = idx.X + } + if selector, ok := expr.(*syntax.SelectorExpr); ok { if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal { w.Bool(true) // method call typ := w.recvExpr(selector, sel) @@ -2219,6 +2212,42 @@ func (w *writer) optExpr(expr syntax.Expr) { } } +func (w *writer) methVal(expr *syntax.SelectorExpr, sel *types2.Selection) { + w.Code(exprMethodVal) + typ := w.recvExpr(expr, sel) + w.pos(expr) + w.methodExpr(expr, typ, sel) +} + +func (w *writer) methExpr(expr *syntax.SelectorExpr, sel *types2.Selection) { + w.Code(exprMethodExpr) + + tv := w.p.typeAndValue(expr.X) + assert(tv.IsType()) + + index := sel.Index() + implicits := index[:len(index)-1] + + typ := tv.Type + w.typ(typ) + + w.Len(len(implicits)) + for _, ix := range implicits { + w.Len(ix) + typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() + } + + recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() + if w.Bool(isPtrTo(typ, recv)) { // need deref + typ = recv + } else if w.Bool(isPtrTo(recv, typ)) { // need addr + typ = recv + } + + w.pos(expr) + w.methodExpr(expr, typ, sel) +} + // recvExpr writes out expr.X, but handles any implicit addressing, // dereferencing, and field selections appropriate for the method // selection. -- cgit v1.3-5-g9baa