From: Dan Scales Date: Sun, 14 Nov 2021 00:17:52 +0000 (-0800) Subject: cmd/compile: fix position info for implicit nodes due to generics X-Git-Tag: go1.18beta1~324 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=1dc9af5cdc6dabe4841afb4edf9dbf5124946ea0;p=gostls13.git cmd/compile: fix position info for implicit nodes due to generics The main fix is that we should call ir.SetPos() at the beginning of (*subster).node.edit function, since that is analogous to the ir.SetPos() at the beginning of typecheck.typecheck(). It ensures that transform functions can use base.Pos() with appropriate results, just like their corresponding tc*() functions do. A small fix is to make sure that the new nodes creates for dictionary references have the correct position based on the location of the function call. Another small fix is to the use of base.Pos when creating a new selector expression (including implicit XDOTs) for a method expression in buildClosure(). Also, I converted the final use of base.Pos in stencil.go to src.NoXPos, since the nodes created by AddImplicitDots will be checked for their type, but won't actually be used. I also needed to add an ir.SetPos() at the beginning of transformCall(), since transformCall() is called in the modify and dict passes, when we base.Pos is not being set for each node. This change fixes all the line numbering problems printed out from Alessandro's program, except for auto-generated functions (which I think are fine). Fixes #49523 Change-Id: I9836a497b7beba25ecafdde653a6c2036a3020d3 Reviewed-on: https://go-review.googlesource.com/c/go/+/363835 Trust: Dan Scales Run-TryBot: Dan Scales TryBot-Result: Go Bot Reviewed-by: Keith Randall --- diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 4f9f8107bc..174006ab5e 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -500,7 +500,7 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // explicitly traverse any embedded fields in the receiver // argument in order to call the method instantiation. arg0 := formalParams[0].Nname.(ir.Node) - arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, arg0, x.(*ir.SelectorExpr).Sel)).X + arg0 = typecheck.AddImplicitDots(ir.NewSelectorExpr(x.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, @@ -616,7 +616,7 @@ func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.N } } if !usingSubdict { - dict = g.getDictionaryValue(nameNode, targs, isMeth) + dict = g.getDictionaryValue(n.Pos(), nameNode, targs, isMeth) } return dict, usingSubdict } @@ -905,6 +905,10 @@ func (subst *subster) node(n ir.Node) ir.Node { // Use closure to capture all state needed by the ir.EditChildren argument. var edit func(ir.Node) ir.Node edit = func(x ir.Node) ir.Node { + // Analogous to ir.SetPos() at beginning of typecheck.typecheck() - + // allows using base.Pos during the transform functions, just like + // the tc*() functions. + ir.SetPos(x) switch x.Op() { case ir.OTYPE: return ir.TypeNode(subst.ts.Typ(x.Type())) @@ -1555,9 +1559,9 @@ func (g *genInst) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool if se.X.Type().IsShape() { // This is a method call enabled by a type bound. - // We need this extra check for type expressions, which - // don't add in the implicit XDOTs. - tmpse := ir.NewSelectorExpr(base.Pos, ir.OXDOT, se.X, se.Sel) + // We need this extra check for method expressions, + // which don't add in the implicit XDOTs. + tmpse := ir.NewSelectorExpr(src.NoXPos, ir.OXDOT, se.X, se.Sel) tmpse = typecheck.AddImplicitDots(tmpse) tparam := tmpse.X.Type() if !tparam.IsShape() { @@ -1725,7 +1729,7 @@ func (g *genInst) finalizeSyms() { g.dictSymsToFinalize = nil } -func (g *genInst) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node { +func (g *genInst) getDictionaryValue(pos src.XPos, gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node { sym := g.getDictionarySym(gf, targs, isMeth) // Make (or reuse) a node referencing the dictionary symbol. @@ -1733,15 +1737,18 @@ func (g *genInst) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bo if sym.Def != nil { n = sym.Def.(*ir.Name) } else { - n = typecheck.NewName(sym) + // We set the position of a static dictionary to be the position of + // one of its uses. + n = ir.NewNameAt(pos, sym) + n.Curfn = ir.CurFunc n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter n.SetTypecheck(1) n.Class = ir.PEXTERN sym.Def = n } - // Return the address of the dictionary. - np := typecheck.NodAddr(n) + // Return the address of the dictionary. Addr node gets position that was passed in. + np := typecheck.NodAddrAt(pos, n) // Note: treat dictionary pointers as uintptrs, so they aren't pointers // with respect to GC. That saves on stack scanning work, write barriers, etc. // We can get away with it because dictionaries are global variables. diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 47e6397206..a673484821 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -133,6 +133,9 @@ func transformConvCall(n *ir.CallExpr) ir.Node { // (non-conversion, non-builtin part) of typecheck.tcCall. This code should work even // in the case of OCALL/OFUNCINST. func transformCall(n *ir.CallExpr) { + // Set base.Pos, since transformArgs below may need it, but transformCall + // is called in some passes that don't set base.Pos. + ir.SetPos(n) // n.Type() can be nil for calls with no return value assert(n.Typecheck() == 1) transformArgs(n)