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 <danscales@google.com>
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
Dan Scales 2021-11-13 16:17:52 -08:00
parent f986191325
commit 1dc9af5cdc
2 changed files with 19 additions and 9 deletions

View File

@ -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.

View File

@ -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)