[dev.regabi] cmd/compile: update ir/fmt for concrete types

An automated rewrite will add concrete type assertions after
a test of n.Op(), when n can be safely type-asserted
(meaning, n is not reassigned a different type, n is not reassigned
and then used outside the scope of the type assertion,
and so on).

This sequence of CLs handles the code that the automated
rewrite does not: adding specific types to function arguments,
adjusting code not to call n.Left() etc when n may have multiple
representations, and so on.

This CL handles package fmt. There are various type assertions
but also some rewriting to lean more heavily on reflection.

Passes buildall w/ toolstash -cmp.

Change-Id: I503467468b42ace11bff2ba014b03cfa345e6d03
Reviewed-on: https://go-review.googlesource.com/c/go/+/277915
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-10 20:55:10 -05:00
parent a997543292
commit 4dfc7333f4
3 changed files with 208 additions and 103 deletions

View file

@ -9,6 +9,7 @@ import (
"fmt" "fmt"
"go/constant" "go/constant"
"io" "io"
"math"
"os" "os"
"path/filepath" "path/filepath"
"reflect" "reflect"
@ -141,7 +142,7 @@ func FmtNode(n Node, s fmt.State, verb rune) {
} }
if n == nil { if n == nil {
fmt.Fprint(s, "<N>") fmt.Fprint(s, "<nil>")
return return
} }
@ -330,12 +331,14 @@ func stmtFmt(n Node, s fmt.State) {
switch n.Op() { switch n.Op() {
case ODCL: case ODCL:
n := n.(*Decl)
fmt.Fprintf(s, "var %v %v", n.Left().Sym(), n.Left().Type()) fmt.Fprintf(s, "var %v %v", n.Left().Sym(), n.Left().Type())
// Don't export "v = <N>" initializing statements, hope they're always // Don't export "v = <N>" initializing statements, hope they're always
// preceded by the DCL which will be re-parsed and typechecked to reproduce // preceded by the DCL which will be re-parsed and typechecked to reproduce
// the "v = <N>" again. // the "v = <N>" again.
case OAS: case OAS:
n := n.(*AssignStmt)
if n.Colas() && !complexinit { if n.Colas() && !complexinit {
fmt.Fprintf(s, "%v := %v", n.Left(), n.Right()) fmt.Fprintf(s, "%v := %v", n.Left(), n.Right())
} else { } else {
@ -343,6 +346,7 @@ func stmtFmt(n Node, s fmt.State) {
} }
case OASOP: case OASOP:
n := n.(*AssignOpStmt)
if n.Implicit() { if n.Implicit() {
if n.SubOp() == OADD { if n.SubOp() == OADD {
fmt.Fprintf(s, "%v++", n.Left()) fmt.Fprintf(s, "%v++", n.Left())
@ -355,6 +359,7 @@ func stmtFmt(n Node, s fmt.State) {
fmt.Fprintf(s, "%v %v= %v", n.Left(), n.SubOp(), n.Right()) fmt.Fprintf(s, "%v %v= %v", n.Left(), n.SubOp(), n.Right())
case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV: case OAS2, OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
n := n.(*AssignListStmt)
if n.Colas() && !complexinit { if n.Colas() && !complexinit {
fmt.Fprintf(s, "%.v := %.v", n.List(), n.Rlist()) fmt.Fprintf(s, "%.v := %.v", n.List(), n.Rlist())
} else { } else {
@ -362,26 +367,33 @@ func stmtFmt(n Node, s fmt.State) {
} }
case OBLOCK: case OBLOCK:
n := n.(*BlockStmt)
if n.List().Len() != 0 { if n.List().Len() != 0 {
fmt.Fprintf(s, "%v", n.List()) fmt.Fprintf(s, "%v", n.List())
} }
case ORETURN: case ORETURN:
n := n.(*ReturnStmt)
fmt.Fprintf(s, "return %.v", n.List()) fmt.Fprintf(s, "return %.v", n.List())
case ORETJMP: case ORETJMP:
n := n.(*BranchStmt)
fmt.Fprintf(s, "retjmp %v", n.Sym()) fmt.Fprintf(s, "retjmp %v", n.Sym())
case OINLMARK: case OINLMARK:
n := n.(*InlineMarkStmt)
fmt.Fprintf(s, "inlmark %d", n.Offset()) fmt.Fprintf(s, "inlmark %d", n.Offset())
case OGO: case OGO:
n := n.(*GoDeferStmt)
fmt.Fprintf(s, "go %v", n.Left()) fmt.Fprintf(s, "go %v", n.Left())
case ODEFER: case ODEFER:
n := n.(*GoDeferStmt)
fmt.Fprintf(s, "defer %v", n.Left()) fmt.Fprintf(s, "defer %v", n.Left())
case OIF: case OIF:
n := n.(*IfStmt)
if simpleinit { if simpleinit {
fmt.Fprintf(s, "if %v; %v { %v }", n.Init().First(), n.Left(), n.Body()) fmt.Fprintf(s, "if %v; %v { %v }", n.Init().First(), n.Left(), n.Body())
} else { } else {
@ -392,6 +404,7 @@ func stmtFmt(n Node, s fmt.State) {
} }
case OFOR, OFORUNTIL: case OFOR, OFORUNTIL:
n := n.(*ForStmt)
opname := "for" opname := "for"
if n.Op() == OFORUNTIL { if n.Op() == OFORUNTIL {
opname = "foruntil" opname = "foruntil"
@ -425,6 +438,7 @@ func stmtFmt(n Node, s fmt.State) {
fmt.Fprintf(s, " { %v }", n.Body()) fmt.Fprintf(s, " { %v }", n.Body())
case ORANGE: case ORANGE:
n := n.(*RangeStmt)
if !exportFormat { if !exportFormat {
fmt.Fprint(s, "for loop") fmt.Fprint(s, "for loop")
break break
@ -437,23 +451,31 @@ func stmtFmt(n Node, s fmt.State) {
fmt.Fprintf(s, "for %.v = range %v { %v }", n.List(), n.Right(), n.Body()) fmt.Fprintf(s, "for %.v = range %v { %v }", n.List(), n.Right(), n.Body())
case OSELECT, OSWITCH: case OSELECT:
n := n.(*SelectStmt)
if !exportFormat { if !exportFormat {
fmt.Fprintf(s, "%v statement", n.Op()) fmt.Fprintf(s, "%v statement", n.Op())
break break
} }
fmt.Fprintf(s, "select { %v }", n.List())
fmt.Fprintf(s, "%v", n.Op()) case OSWITCH:
n := n.(*SwitchStmt)
if !exportFormat {
fmt.Fprintf(s, "%v statement", n.Op())
break
}
fmt.Fprintf(s, "switch")
if simpleinit { if simpleinit {
fmt.Fprintf(s, " %v;", n.Init().First()) fmt.Fprintf(s, " %v;", n.Init().First())
} }
if n.Left() != nil { if n.Left() != nil {
fmt.Fprintf(s, " %v ", n.Left()) fmt.Fprintf(s, " %v ", n.Left())
} }
fmt.Fprintf(s, " { %v }", n.List()) fmt.Fprintf(s, " { %v }", n.List())
case OCASE: case OCASE:
n := n.(*CaseStmt)
if n.List().Len() != 0 { if n.List().Len() != 0 {
fmt.Fprintf(s, "case %.v", n.List()) fmt.Fprintf(s, "case %.v", n.List())
} else { } else {
@ -462,6 +484,7 @@ func stmtFmt(n Node, s fmt.State) {
fmt.Fprintf(s, ": %v", n.Body()) fmt.Fprintf(s, ": %v", n.Body())
case OBREAK, OCONTINUE, OGOTO, OFALL: case OBREAK, OCONTINUE, OGOTO, OFALL:
n := n.(*BranchStmt)
if n.Sym() != nil { if n.Sym() != nil {
fmt.Fprintf(s, "%v %v", n.Op(), n.Sym()) fmt.Fprintf(s, "%v %v", n.Op(), n.Sym())
} else { } else {
@ -469,6 +492,7 @@ func stmtFmt(n Node, s fmt.State) {
} }
case OLABEL: case OLABEL:
n := n.(*LabelStmt)
fmt.Fprintf(s, "%v: ", n.Sym()) fmt.Fprintf(s, "%v: ", n.Sym())
} }
@ -488,7 +512,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
for { for {
if n == nil { if n == nil {
fmt.Fprint(s, "<N>") fmt.Fprint(s, "<nil>")
return return
} }
@ -499,10 +523,23 @@ func exprFmt(n Node, s fmt.State, prec int) {
} }
// Skip implicit operations introduced during typechecking. // Skip implicit operations introduced during typechecking.
switch n.Op() { switch nn := n; nn.Op() {
case OADDR, ODEREF, OCONV, OCONVNOP, OCONVIFACE: case OADDR:
if n.Implicit() { nn := nn.(*AddrExpr)
n = n.Left() if nn.Implicit() {
n = nn.Left()
continue
}
case ODEREF:
nn := nn.(*StarExpr)
if nn.Implicit() {
n = nn.Left()
continue
}
case OCONV, OCONVNOP, OCONVIFACE:
nn := nn.(*ConvExpr)
if nn.Implicit() {
n = nn.Left()
continue continue
} }
} }
@ -522,6 +559,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
switch n.Op() { switch n.Op() {
case OPAREN: case OPAREN:
n := n.(*ParenExpr)
fmt.Fprintf(s, "(%v)", n.Left()) fmt.Fprintf(s, "(%v)", n.Left())
case ONIL: case ONIL:
@ -570,6 +608,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
} }
case ODCLFUNC: case ODCLFUNC:
n := n.(*Func)
if sym := n.Sym(); sym != nil { if sym := n.Sym(); sym != nil {
fmt.Fprint(s, sym) fmt.Fprint(s, sym)
return return
@ -577,6 +616,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "<unnamed Func>") fmt.Fprintf(s, "<unnamed Func>")
case ONAME: case ONAME:
n := n.(*Name)
// Special case: name used as local variable in export. // Special case: name used as local variable in export.
// _ becomes ~b%d internally; print as _ for export // _ becomes ~b%d internally; print as _ for export
if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' { if !exportFormat && n.Sym() != nil && n.Sym().Name[0] == '~' && n.Sym().Name[1] == 'b' {
@ -641,17 +681,15 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, "<func>") fmt.Fprint(s, "<func>")
case OCLOSURE: case OCLOSURE:
n := n.(*ClosureExpr)
if !exportFormat { if !exportFormat {
fmt.Fprint(s, "func literal") fmt.Fprint(s, "func literal")
return return
} }
if n.Body().Len() != 0 {
fmt.Fprintf(s, "%v { %v }", n.Type(), n.Body())
return
}
fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func().Body()) fmt.Fprintf(s, "%v { %v }", n.Type(), n.Func().Body())
case OCOMPLIT: case OCOMPLIT:
n := n.(*CompLitExpr)
if !exportFormat { if !exportFormat {
if n.Implicit() { if n.Implicit() {
fmt.Fprintf(s, "... argument") fmt.Fprintf(s, "... argument")
@ -668,9 +706,11 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "(%v{ %.v })", n.Right(), n.List()) fmt.Fprintf(s, "(%v{ %.v })", n.Right(), n.List())
case OPTRLIT: case OPTRLIT:
n := n.(*AddrExpr)
fmt.Fprintf(s, "&%v", n.Left()) fmt.Fprintf(s, "&%v", n.Left())
case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT: case OSTRUCTLIT, OARRAYLIT, OSLICELIT, OMAPLIT:
n := n.(*CompLitExpr)
if !exportFormat { if !exportFormat {
fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(n.List().Len() != 0)) fmt.Fprintf(s, "%v{%s}", n.Type(), ellipsisIf(n.List().Len() != 0))
return return
@ -678,6 +718,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List()) fmt.Fprintf(s, "(%v{ %.v })", n.Type(), n.List())
case OKEY: case OKEY:
n := n.(*KeyExpr)
if n.Left() != nil && n.Right() != nil { if n.Left() != nil && n.Right() != nil {
fmt.Fprintf(s, "%v:%v", n.Left(), n.Right()) fmt.Fprintf(s, "%v:%v", n.Left(), n.Right())
return return
@ -694,9 +735,11 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, ":") fmt.Fprint(s, ":")
case OSTRUCTKEY: case OSTRUCTKEY:
n := n.(*StructKeyExpr)
fmt.Fprintf(s, "%v:%v", n.Sym(), n.Left()) fmt.Fprintf(s, "%v:%v", n.Sym(), n.Left())
case OCALLPART: case OCALLPART:
n := n.(*CallPartExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
if n.Sym() == nil { if n.Sym() == nil {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
@ -705,6 +748,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym())) fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym()))
case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH: case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
n := n.(*SelectorExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
if n.Sym() == nil { if n.Sym() == nil {
fmt.Fprint(s, ".<nil>") fmt.Fprint(s, ".<nil>")
@ -713,6 +757,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym())) fmt.Fprintf(s, ".%s", types.SymMethodName(n.Sym()))
case ODOTTYPE, ODOTTYPE2: case ODOTTYPE, ODOTTYPE2:
n := n.(*TypeAssertExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
if n.Right() != nil { if n.Right() != nil {
fmt.Fprintf(s, ".(%v)", n.Right()) fmt.Fprintf(s, ".(%v)", n.Right())
@ -721,10 +766,12 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, ".(%v)", n.Type()) fmt.Fprintf(s, ".(%v)", n.Type())
case OINDEX, OINDEXMAP: case OINDEX, OINDEXMAP:
n := n.(*IndexExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
fmt.Fprintf(s, "[%v]", n.Right()) fmt.Fprintf(s, "[%v]", n.Right())
case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR: case OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
n := n.(*SliceExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
fmt.Fprint(s, "[") fmt.Fprint(s, "[")
low, high, max := n.SliceBounds() low, high, max := n.SliceBounds()
@ -744,17 +791,15 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprint(s, "]") fmt.Fprint(s, "]")
case OSLICEHEADER: case OSLICEHEADER:
n := n.(*SliceHeaderExpr)
if n.List().Len() != 2 { if n.List().Len() != 2 {
base.Fatalf("bad OSLICEHEADER list length %d", n.List().Len()) base.Fatalf("bad OSLICEHEADER list length %d", n.List().Len())
} }
fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left(), n.List().First(), n.List().Second()) fmt.Fprintf(s, "sliceheader{%v,%v,%v}", n.Left(), n.List().First(), n.List().Second())
case OCOMPLEX, OCOPY: case OCOMPLEX, OCOPY:
if n.Left() != nil { n := n.(*BinaryExpr)
fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.Left(), n.Right()) fmt.Fprintf(s, "%v(%v, %v)", n.Op(), n.Left(), n.Right())
} else {
fmt.Fprintf(s, "%v(%.v)", n.Op(), n.List())
}
case OCONV, case OCONV,
OCONVIFACE, OCONVIFACE,
@ -764,37 +809,34 @@ func exprFmt(n Node, s fmt.State, prec int) {
OSTR2BYTES, OSTR2BYTES,
OSTR2RUNES, OSTR2RUNES,
ORUNESTR: ORUNESTR:
n := n.(*ConvExpr)
if n.Type() == nil || n.Type().Sym() == nil { if n.Type() == nil || n.Type().Sym() == nil {
fmt.Fprintf(s, "(%v)", n.Type()) fmt.Fprintf(s, "(%v)", n.Type())
} else { } else {
fmt.Fprintf(s, "%v", n.Type()) fmt.Fprintf(s, "%v", n.Type())
} }
if n.Left() != nil { fmt.Fprintf(s, "(%v)", n.Left())
fmt.Fprintf(s, "(%v)", n.Left())
} else {
fmt.Fprintf(s, "(%.v)", n.List())
}
case OREAL, case OREAL,
OIMAG, OIMAG,
OAPPEND,
OCAP, OCAP,
OCLOSE, OCLOSE,
ODELETE,
OLEN, OLEN,
OMAKE,
ONEW, ONEW,
OPANIC, OPANIC,
ORECOVER,
OALIGNOF, OALIGNOF,
OOFFSETOF, OOFFSETOF,
OSIZEOF, OSIZEOF:
n := n.(*UnaryExpr)
fmt.Fprintf(s, "%v(%v)", n.Op(), n.Left())
case OAPPEND,
ODELETE,
OMAKE,
ORECOVER,
OPRINT, OPRINT,
OPRINTN: OPRINTN:
if n.Left() != nil { n := n.(*CallExpr)
fmt.Fprintf(s, "%v(%v)", n.Op(), n.Left())
return
}
if n.IsDDD() { if n.IsDDD() {
fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.List()) fmt.Fprintf(s, "%v(%.v...)", n.Op(), n.List())
return return
@ -802,6 +844,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "%v(%.v)", n.Op(), n.List()) fmt.Fprintf(s, "%v(%.v)", n.Op(), n.List())
case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG: case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
n := n.(*CallExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
if n.IsDDD() { if n.IsDDD() {
fmt.Fprintf(s, "(%.v...)", n.List()) fmt.Fprintf(s, "(%.v...)", n.List())
@ -810,10 +853,7 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "(%.v)", n.List()) fmt.Fprintf(s, "(%.v)", n.List())
case OMAKEMAP, OMAKECHAN, OMAKESLICE: case OMAKEMAP, OMAKECHAN, OMAKESLICE:
if n.List().Len() != 0 { // pre-typecheck n := n.(*MakeExpr)
fmt.Fprintf(s, "make(%v, %.v)", n.Type(), n.List())
return
}
if n.Right() != nil { if n.Right() != nil {
fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Left(), n.Right()) fmt.Fprintf(s, "make(%v, %v, %v)", n.Type(), n.Left(), n.Right())
return return
@ -825,20 +865,34 @@ func exprFmt(n Node, s fmt.State, prec int) {
fmt.Fprintf(s, "make(%v)", n.Type()) fmt.Fprintf(s, "make(%v)", n.Type())
case OMAKESLICECOPY: case OMAKESLICECOPY:
n := n.(*MakeExpr)
fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Left(), n.Right()) fmt.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type(), n.Left(), n.Right())
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV: case OPLUS, ONEG, OBITNOT, ONOT, ORECV:
// Unary // Unary
n := n.(*UnaryExpr)
fmt.Fprintf(s, "%v", n.Op()) fmt.Fprintf(s, "%v", n.Op())
if n.Left() != nil && n.Left().Op() == n.Op() { if n.Left() != nil && n.Left().Op() == n.Op() {
fmt.Fprint(s, " ") fmt.Fprint(s, " ")
} }
exprFmt(n.Left(), s, nprec+1) exprFmt(n.Left(), s, nprec+1)
case OADDR:
n := n.(*AddrExpr)
fmt.Fprintf(s, "%v", n.Op())
if n.Left() != nil && n.Left().Op() == n.Op() {
fmt.Fprint(s, " ")
}
exprFmt(n.Left(), s, nprec+1)
case ODEREF:
n := n.(*StarExpr)
fmt.Fprintf(s, "%v", n.Op())
exprFmt(n.Left(), s, nprec+1)
// Binary // Binary
case OADD, case OADD,
OAND, OAND,
OANDAND,
OANDNOT, OANDNOT,
ODIV, ODIV,
OEQ, OEQ,
@ -851,16 +905,29 @@ func exprFmt(n Node, s fmt.State, prec int) {
OMUL, OMUL,
ONE, ONE,
OOR, OOR,
OOROR,
ORSH, ORSH,
OSEND,
OSUB, OSUB,
OXOR: OXOR:
n := n.(*BinaryExpr)
exprFmt(n.Left(), s, nprec) exprFmt(n.Left(), s, nprec)
fmt.Fprintf(s, " %v ", n.Op()) fmt.Fprintf(s, " %v ", n.Op())
exprFmt(n.Right(), s, nprec+1) exprFmt(n.Right(), s, nprec+1)
case OANDAND,
OOROR:
n := n.(*LogicalExpr)
exprFmt(n.Left(), s, nprec)
fmt.Fprintf(s, " %v ", n.Op())
exprFmt(n.Right(), s, nprec+1)
case OSEND:
n := n.(*SendStmt)
exprFmt(n.Left(), s, nprec)
fmt.Fprintf(s, " <- ")
exprFmt(n.Right(), s, nprec+1)
case OADDSTR: case OADDSTR:
n := n.(*AddStringExpr)
for i, n1 := range n.List().Slice() { for i, n1 := range n.List().Slice() {
if i != 0 { if i != 0 {
fmt.Fprint(s, " + ") fmt.Fprint(s, " + ")
@ -951,27 +1018,12 @@ func dumpNodeHeader(w io.Writer, n Node) {
if base.Debug.DumpPtrs != 0 { if base.Debug.DumpPtrs != 0 {
fmt.Fprintf(w, " p(%p)", n) fmt.Fprintf(w, " p(%p)", n)
} }
if n.Name() != nil && n.Name().Vargen != 0 {
fmt.Fprintf(w, " g(%d)", n.Name().Vargen)
}
if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil { if base.Debug.DumpPtrs != 0 && n.Name() != nil && n.Name().Defn != nil {
// Useful to see where Defn is set and what node it points to // Useful to see where Defn is set and what node it points to
fmt.Fprintf(w, " defn(%p)", n.Name().Defn) fmt.Fprintf(w, " defn(%p)", n.Name().Defn)
} }
if n.Offset() != types.BADWIDTH {
fmt.Fprintf(w, " x(%d)", n.Offset())
}
if n.Class() != 0 {
fmt.Fprintf(w, " class(%v)", n.Class())
}
if n.Colas() {
fmt.Fprintf(w, " colas(%v)", n.Colas())
}
if EscFmt != nil { if EscFmt != nil {
if esc := EscFmt(n); esc != "" { if esc := EscFmt(n); esc != "" {
fmt.Fprintf(w, " %s", esc) fmt.Fprintf(w, " %s", esc)
@ -982,47 +1034,62 @@ func dumpNodeHeader(w io.Writer, n Node) {
fmt.Fprintf(w, " tc(%d)", n.Typecheck()) fmt.Fprintf(w, " tc(%d)", n.Typecheck())
} }
if n.IsDDD() { // Print Node-specific fields of basic type in header line.
fmt.Fprintf(w, " isddd(%v)", n.IsDDD()) v := reflect.ValueOf(n).Elem()
t := v.Type()
nf := t.NumField()
for i := 0; i < nf; i++ {
tf := t.Field(i)
if tf.PkgPath != "" {
// skip unexported field - Interface will fail
continue
}
k := tf.Type.Kind()
if reflect.Bool <= k && k <= reflect.Complex128 {
name := strings.TrimSuffix(tf.Name, "_")
vf := v.Field(i)
vfi := vf.Interface()
if name == "Offset" && vfi == types.BADWIDTH || name != "Offset" && isZero(vf) {
continue
}
if vfi == true {
fmt.Fprintf(w, " %s", name)
} else {
fmt.Fprintf(w, " %s:%+v", name, vf.Interface())
}
}
} }
if n.Implicit() { // Print Node-specific booleans by looking for methods.
fmt.Fprintf(w, " implicit(%v)", n.Implicit()) // Different v, t from above - want *Struct not Struct, for methods.
} v = reflect.ValueOf(n)
t = v.Type()
if n.Op() == ONAME { nm := t.NumMethod()
if n.Name().Addrtaken() { for i := 0; i < nm; i++ {
fmt.Fprint(w, " addrtaken") tm := t.Method(i)
if tm.PkgPath != "" {
// skip unexported method - call will fail
continue
} }
if n.Name().Assigned() { m := v.Method(i)
fmt.Fprint(w, " assigned") mt := m.Type()
if mt.NumIn() == 0 && mt.NumOut() == 1 && mt.Out(0).Kind() == reflect.Bool {
// TODO(rsc): Remove the func/defer/recover wrapping,
// which is guarding against panics in miniExpr,
// once we get down to the simpler state in which
// nodes have no getter methods that aren't allowed to be called.
func() {
defer func() { recover() }()
if m.Call(nil)[0].Bool() {
name := strings.TrimSuffix(tm.Name, "_")
fmt.Fprintf(w, " %s", name)
}
}()
} }
if n.Name().IsClosureVar() {
fmt.Fprint(w, " closurevar")
}
if n.Name().Captured() {
fmt.Fprint(w, " captured")
}
if n.Name().IsOutputParamHeapAddr() {
fmt.Fprint(w, " outputparamheapaddr")
}
}
if n.Bounded() {
fmt.Fprint(w, " bounded")
}
if n.NonNil() {
fmt.Fprint(w, " nonnil")
}
if n.HasCall() {
fmt.Fprint(w, " hascall")
}
if n.Name() != nil && n.Name().Used() {
fmt.Fprint(w, " used")
} }
if n.Op() == OCLOSURE { if n.Op() == OCLOSURE {
n := n.(*ClosureExpr)
if fn := n.Func(); fn != nil && fn.Nname.Sym() != nil { if fn := n.Func(); fn != nil && fn.Nname.Sym() != nil {
fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym()) fmt.Fprintf(w, " fnName(%+v)", fn.Nname.Sym())
} }
@ -1087,6 +1154,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
return return
case OASOP: case OASOP:
n := n.(*AssignOpStmt)
fmt.Fprintf(w, "%+v-%+v", n.Op(), n.SubOp()) fmt.Fprintf(w, "%+v-%+v", n.Op(), n.SubOp())
dumpNodeHeader(w, n) dumpNodeHeader(w, n)
@ -1120,7 +1188,7 @@ func dumpNode(w io.Writer, n Node, depth int) {
if fn.Body().Len() > 0 { if fn.Body().Len() > 0 {
indent(w, depth) indent(w, depth)
fmt.Fprintf(w, "%+v-body", n.Op()) fmt.Fprintf(w, "%+v-body", n.Op())
dumpNodes(w, n.Body(), depth+1) dumpNodes(w, fn.Body(), depth+1)
} }
return return
} }
@ -1186,3 +1254,40 @@ func dumpNodes(w io.Writer, list Nodes, depth int) {
dumpNode(w, n, depth) dumpNode(w, n, depth)
} }
} }
// reflect.IsZero is not available in Go 1.4 (added in Go 1.13), so we use this copy instead.
func isZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.Bool:
return !v.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return v.Int() == 0
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return v.Uint() == 0
case reflect.Float32, reflect.Float64:
return math.Float64bits(v.Float()) == 0
case reflect.Complex64, reflect.Complex128:
c := v.Complex()
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
case reflect.Array:
for i := 0; i < v.Len(); i++ {
if !isZero(v.Index(i)) {
return false
}
}
return true
case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
return v.IsNil()
case reflect.String:
return v.Len() == 0
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if !isZero(v.Field(i)) {
return false
}
}
return true
default:
return false
}
}

View file

@ -34,13 +34,13 @@ func (*Ident) CanBeNtype() {}
// Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL). // Name holds Node fields used only by named nodes (ONAME, OTYPE, some OLITERAL).
type Name struct { type Name struct {
miniExpr miniExpr
subOp Op // uint8 BuiltinOp Op // uint8
class Class // uint8 Class_ Class // uint8
flags bitset16 flags bitset16
pragma PragmaFlag // int16 pragma PragmaFlag // int16
sym *types.Sym sym *types.Sym
fn *Func fn *Func
offset int64 Offset_ int64
val constant.Value val constant.Value
orig Node orig Node
embedFiles *[]string // list of embedded files, for ONAME var embedFiles *[]string // list of embedded files, for ONAME var
@ -180,16 +180,16 @@ func newNameAt(pos src.XPos, op Op, sym *types.Sym) *Name {
func (n *Name) Name() *Name { return n } func (n *Name) Name() *Name { return n }
func (n *Name) Sym() *types.Sym { return n.sym } func (n *Name) Sym() *types.Sym { return n.sym }
func (n *Name) SetSym(x *types.Sym) { n.sym = x } func (n *Name) SetSym(x *types.Sym) { n.sym = x }
func (n *Name) SubOp() Op { return n.subOp } func (n *Name) SubOp() Op { return n.BuiltinOp }
func (n *Name) SetSubOp(x Op) { n.subOp = x } func (n *Name) SetSubOp(x Op) { n.BuiltinOp = x }
func (n *Name) Class() Class { return n.class } func (n *Name) Class() Class { return n.Class_ }
func (n *Name) SetClass(x Class) { n.class = x } func (n *Name) SetClass(x Class) { n.Class_ = x }
func (n *Name) Func() *Func { return n.fn } func (n *Name) Func() *Func { return n.fn }
func (n *Name) SetFunc(x *Func) { n.fn = x } func (n *Name) SetFunc(x *Func) { n.fn = x }
func (n *Name) Offset() int64 { return n.offset } func (n *Name) Offset() int64 { return n.Offset_ }
func (n *Name) SetOffset(x int64) { n.offset = x } func (n *Name) SetOffset(x int64) { n.Offset_ = x }
func (n *Name) Iota() int64 { return n.offset } func (n *Name) Iota() int64 { return n.Offset_ }
func (n *Name) SetIota(x int64) { n.offset = x } func (n *Name) SetIota(x int64) { n.Offset_ = x }
func (*Name) CanBeNtype() {} func (*Name) CanBeNtype() {}
func (*Name) CanBeAnSSASym() {} func (*Name) CanBeAnSSASym() {}

View file

@ -212,7 +212,7 @@ func caller7() {
// **in -> heap // **in -> heap
func param8(i **int) { // ERROR "i does not escape$" func param8(i **int) { // ERROR "i does not escape$"
sink = **i // ERROR "\* \(\*i\) escapes to heap" sink = **i // ERROR "\*\(\*i\) escapes to heap"
} }
func caller8() { func caller8() {
@ -402,7 +402,7 @@ func caller13h() {
var p *int var p *int
v := &Val{&p} // ERROR "&Val{...} does not escape$" v := &Val{&p} // ERROR "&Val{...} does not escape$"
v.param13(&i) v.param13(&i)
sink = **v.p // ERROR "\* \(\*v\.p\) escapes to heap" sink = **v.p // ERROR "\*\(\*v\.p\) escapes to heap"
} }
type Node struct { type Node struct {