1
0
mirror of https://github.com/golang/go synced 2024-11-11 19:01:37 -07:00

[dev.regabi] cmd/compile: stop mangling SelectorExpr.Sel for ODOTMETH

ODOTMETH is unique among SelectorExpr expressions, in that Sel gets
mangled so that it no longer has the original identifier that was
selected (e.g., just "Foo"), but instead the qualified symbol name for
the selected method (e.g., "pkg.Type.Foo"). This is rarely useful, and
instead results in a lot of compiler code needing to worry about
undoing this change.

This CL changes ODOTMETH to leave the original symbol in place. The
handful of code locations where the mangled symbol name is actually
wanted are updated to use ir.MethodExprName(n).Sym() or (equivalently)
ir.MethodExprName(n).Func.Sym() instead.

Historically, the compiler backend has mistakenly used types.Syms
where it should have used ir.Name/ir.Funcs. And this change in
particular may risk breaking something, as the SelectorExpr.Sel will
no longer point at a symbol that uniquely identifies the called
method. However, I expect CL 280294 (desugar OCALLMETH into OCALLFUNC)
to have substantially reduced this risk, as ODOTMETH expressions are
now replaced entirely earlier in the compiler.

Passes toolstash -cmp.

Change-Id: If3c9c3b7df78ea969f135840574cf89e1d263876
Reviewed-on: https://go-review.googlesource.com/c/go/+/280436
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
Matthew Dempsky 2020-12-26 18:56:36 -08:00
parent 135ce1c485
commit e6c973198d
8 changed files with 38 additions and 70 deletions

View File

@ -324,19 +324,17 @@ func (v *hairyVisitor) doNode(n ir.Node) error {
if t == nil {
base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
}
if types.IsRuntimePkg(n.X.Sym().Pkg) {
fn := n.X.Sym().Name
if fn == "heapBits.nextArena" {
// Special case: explicitly allow
// mid-stack inlining of
// runtime.heapBits.next even though
// it calls slow-path
// runtime.heapBits.nextArena.
break
}
fn := ir.MethodExprName(n.X).Func
if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
// Special case: explicitly allow
// mid-stack inlining of
// runtime.heapBits.next even though
// it calls slow-path
// runtime.heapBits.nextArena.
break
}
if inlfn := ir.MethodExprName(n.X).Func; inlfn.Inl != nil {
v.budget -= inlfn.Inl.Cost
if fn.Inl != nil {
v.budget -= fn.Inl.Cost
break
}
// Call cost for non-leaf inlining.
@ -531,7 +529,7 @@ func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.No
// Prevent inlining some reflect.Value methods when using checkptr,
// even when package reflect was compiled without it (#35073).
n := n.(*ir.CallExpr)
if s := n.X.Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
return n
}
}

View File

@ -756,7 +756,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, ".<nil>")
return
}
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Method.Sym))
fmt.Fprintf(s, ".%s", n.Method.Sym.Name)
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
n := n.(*SelectorExpr)
@ -765,7 +765,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, ".<nil>")
return
}
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sel))
fmt.Fprintf(s, ".%s", n.Sel.Name)
case ODOTTYPE, ODOTTYPE2:
n := n.(*TypeAssertExpr)

View File

@ -571,7 +571,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
}
n.X = typecheck(n.X, ctxExpr|ctxType)
n.X = DefaultLit(n.X, nil)
t := n.X.Type()
@ -581,8 +580,6 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
return n
}
s := n.Sel
if n.X.Op() == ir.OTYPE {
return typecheckMethodExpr(n)
}
@ -629,7 +626,10 @@ func tcDot(n *ir.SelectorExpr, top int) ir.Node {
}
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
return tcCallPart(n, s)
// Create top-level function.
fn := makepartialcall(n)
return ir.NewCallPartExpr(n.Pos(), n.X, n.Selection, fn)
}
return n
}

View File

@ -249,7 +249,9 @@ var globClosgen int32
// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
// for partial calls.
func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
func makepartialcall(dot *ir.SelectorExpr) *ir.Func {
t0 := dot.Type()
meth := dot.Sel
rcvrtype := dot.X.Type()
sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
@ -263,11 +265,10 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
ir.CurFunc = nil
// Set line number equal to the line number where the method is declared.
var m *types.Field
if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
base.Pos = m.Pos
if pos := dot.Selection.Pos; pos.IsKnown() {
base.Pos = pos
}
// Note: !m.Pos.IsKnown() happens for method expressions where
// Note: !dot.Selection.Pos.IsKnown() happens for method expressions where
// the method is implicitly declared. The Error method of the
// built-in error type is one such method. We leave the line
// number at the use of the method expression in this
@ -280,6 +281,7 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
fn := DeclFunc(sym, tfn)
fn.SetDupok(true)
fn.SetNeedctxt(true)
fn.SetWrapper(true)
// Declare and initialize variable holding receiver.
cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
@ -382,23 +384,6 @@ func tcClosure(clo *ir.ClosureExpr, top int) {
Target.Decls = append(Target.Decls, fn)
}
func tcCallPart(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
switch n.Op() {
case ir.ODOTINTER, ir.ODOTMETH:
break
default:
base.Fatalf("invalid typecheckpartialcall")
}
dot := n.(*ir.SelectorExpr)
// Create top-level function.
fn := makepartialcall(dot, dot.Type(), sym)
fn.SetWrapper(true)
return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
}
// type check function definition
// To be called by typecheck, not directly.
// (Call typecheckFunc instead.)

View File

@ -594,23 +594,15 @@ func (w *exportWriter) selector(s *types.Sym) {
base.Fatalf("missing currPkg")
}
// Method selectors are rewritten into method symbols (of the
// form T.M) during typechecking, but we want to write out
// just the bare method name.
name := s.Name
if i := strings.LastIndex(name, "."); i >= 0 {
name = name[i+1:]
} else {
pkg := w.currPkg
if types.IsExported(name) {
pkg = types.LocalPkg
}
if s.Pkg != pkg {
base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
}
pkg := w.currPkg
if types.IsExported(s.Name) {
pkg = types.LocalPkg
}
if s.Pkg != pkg {
base.Fatalf("package mismatch in selector: %v in package %q, but want %q", s, s.Pkg.Path, pkg.Path)
}
w.string(name)
w.string(s.Name)
}
func (w *exportWriter) typ(t *types.Type) {

View File

@ -1297,7 +1297,6 @@ func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
return nil
}
n.Sel = ir.MethodSym(n.X.Type(), f2.Sym)
n.Selection = f2
n.SetType(f2.Type)
n.SetOp(ir.ODOTMETH)

View File

@ -180,15 +180,6 @@ func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
b.WriteString(s.Name)
}
func SymMethodName(s *Sym) string {
// Skip leading "type." in method name
name := s.Name
if i := strings.LastIndex(name, "."); i >= 0 {
name = name[i+1:]
}
return name
}
// Type
var BasicTypeNames = []string{
@ -595,7 +586,10 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
if funarg != FunargNone {
name = fmt.Sprint(f.Nname)
} else if verb == 'L' {
name = SymMethodName(s)
name = s.Name
if name == ".F" {
name = "F" // Hack for toolstash -cmp.
}
if !IsExported(name) && mode != fmtTypeIDName {
name = sconv(s, 0, mode) // qualify non-exported names (used on structs, not on funarg)
}

View File

@ -35,8 +35,8 @@ func main() {
_ = f.Exported
_ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported."
_ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported."
_ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
_ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method unexported."
_ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook."
}