mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal/gc: add tracing support to debug type checking
The compiler must first be built with the constant enableTrace set to true (typecheck.go). After that, the -t flag becomes available which enables tracing output of type-checking functions. With enableTrace == false, the tracing code becomes dead code and won't affect the compiler. Typical output might look like this: path/y.go:4:6: typecheck 0xc00033e180 DCLTYPE <node DCLTYPE> tc=0 path/y.go:4:6: . typecheck1 0xc00033e180 DCLTYPE <node DCLTYPE> tc=2 path/y.go:4:6: . . typecheck 0xc000331a40 TYPE T tc=1 path/y.go:4:6: . . . typecheck1 0xc000331a40 TYPE T tc=2 path/y.go:4:6: . . . . typecheckdef 0xc000331a40 TYPE T tc=2 path/y.go:4:6: . . . . => 0xc000331a40 TYPE T tc=2 type=*T path/y.go:4:6: . . . => 0xc000331a40 TYPE T tc=2 type=*T path/y.go:4:6: . . => 0xc000331a40 TYPE T tc=1 type=*T path/y.go:4:6: . => 0xc00033e180 DCLTYPE <node DCLTYPE> tc=2 type=<T> path/y.go:4:6: => 0xc00033e180 DCLTYPE <node DCLTYPE> tc=1 type=<T> Disabled by default. Change-Id: Ifd8385290d1cf0d3fc5e8468b2f4ab84e8eff338 Reviewed-on: https://go-review.googlesource.com/c/146782 Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
c21ba09bcd
commit
e25823edce
2 changed files with 94 additions and 5 deletions
|
|
@ -229,6 +229,9 @@ func Main(archInit func(*Arch)) {
|
||||||
flag.BoolVar(&flag_race, "race", false, "enable race detector")
|
flag.BoolVar(&flag_race, "race", false, "enable race detector")
|
||||||
}
|
}
|
||||||
objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
|
objabi.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
|
||||||
|
if enableTrace {
|
||||||
|
flag.BoolVar(&trace, "t", false, "trace type-checking")
|
||||||
|
}
|
||||||
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
|
flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
|
||||||
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
|
flag.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
|
||||||
objabi.Flagcount("w", "debug type checking", &Debug['w'])
|
objabi.Flagcount("w", "debug type checking", &Debug['w'])
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,50 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// To enable tracing support (-t flag), set enableTrace to true.
|
||||||
|
const enableTrace = false
|
||||||
|
|
||||||
|
var trace bool
|
||||||
|
var traceIndent []byte
|
||||||
|
|
||||||
|
func tracePrint(title string, n *Node) func(np **Node) {
|
||||||
|
indent := traceIndent
|
||||||
|
|
||||||
|
// guard against nil
|
||||||
|
var pos, op string
|
||||||
|
var tc uint8
|
||||||
|
if n != nil {
|
||||||
|
pos = linestr(n.Pos)
|
||||||
|
op = n.Op.String()
|
||||||
|
tc = n.Typecheck()
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s: %s%s %p %s %v tc=%d\n", pos, indent, title, n, op, n, tc)
|
||||||
|
traceIndent = append(traceIndent, ". "...)
|
||||||
|
|
||||||
|
return func(np **Node) {
|
||||||
|
traceIndent = traceIndent[:len(traceIndent)-2]
|
||||||
|
|
||||||
|
// if we have a result, use that
|
||||||
|
if np != nil {
|
||||||
|
n = *np
|
||||||
|
}
|
||||||
|
|
||||||
|
// guard against nil
|
||||||
|
// use outer pos, op so we don't get empty pos/op if n == nil (nicer output)
|
||||||
|
var tc uint8
|
||||||
|
var typ *types.Type
|
||||||
|
if n != nil {
|
||||||
|
pos = linestr(n.Pos)
|
||||||
|
op = n.Op.String()
|
||||||
|
tc = n.Typecheck()
|
||||||
|
typ = n.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("%s: %s=> %p %s %v tc=%d type=%#L\n", pos, indent, n, op, n, tc, typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Etop = 1 << iota // evaluated at statement level
|
Etop = 1 << iota // evaluated at statement level
|
||||||
Erv // evaluated in value context
|
Erv // evaluated in value context
|
||||||
|
|
@ -31,11 +75,16 @@ const (
|
||||||
var typecheckdefstack []*Node
|
var typecheckdefstack []*Node
|
||||||
|
|
||||||
// resolve ONONAME to definition, if any.
|
// resolve ONONAME to definition, if any.
|
||||||
func resolve(n *Node) *Node {
|
func resolve(n *Node) (res *Node) {
|
||||||
if n == nil || n.Op != ONONAME {
|
if n == nil || n.Op != ONONAME {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only trace if there's work to do
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("resolve", n)(&res)
|
||||||
|
}
|
||||||
|
|
||||||
if n.Sym.Pkg != localpkg {
|
if n.Sym.Pkg != localpkg {
|
||||||
if inimport {
|
if inimport {
|
||||||
Fatalf("recursive inimport")
|
Fatalf("recursive inimport")
|
||||||
|
|
@ -150,7 +199,7 @@ var typecheck_tcstack []*Node
|
||||||
// typecheck type checks node n.
|
// typecheck type checks node n.
|
||||||
// The result of typecheck MUST be assigned back to n, e.g.
|
// The result of typecheck MUST be assigned back to n, e.g.
|
||||||
// n.Left = typecheck(n.Left, top)
|
// n.Left = typecheck(n.Left, top)
|
||||||
func typecheck(n *Node, top int) *Node {
|
func typecheck(n *Node, top int) (res *Node) {
|
||||||
// cannot type check until all the source has been parsed
|
// cannot type check until all the source has been parsed
|
||||||
if !typecheckok {
|
if !typecheckok {
|
||||||
Fatalf("early typecheck")
|
Fatalf("early typecheck")
|
||||||
|
|
@ -160,6 +209,11 @@ func typecheck(n *Node, top int) *Node {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only trace if there's work to do
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheck", n)(&res)
|
||||||
|
}
|
||||||
|
|
||||||
lno := setlineno(n)
|
lno := setlineno(n)
|
||||||
|
|
||||||
// Skip over parens.
|
// Skip over parens.
|
||||||
|
|
@ -294,7 +348,11 @@ func indexlit(n *Node) *Node {
|
||||||
|
|
||||||
// The result of typecheck1 MUST be assigned back to n, e.g.
|
// The result of typecheck1 MUST be assigned back to n, e.g.
|
||||||
// n.Left = typecheck1(n.Left, top)
|
// n.Left = typecheck1(n.Left, top)
|
||||||
func typecheck1(n *Node, top int) *Node {
|
func typecheck1(n *Node, top int) (res *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheck1", n)(&res)
|
||||||
|
}
|
||||||
|
|
||||||
switch n.Op {
|
switch n.Op {
|
||||||
case OLITERAL, ONAME, ONONAME, OTYPE:
|
case OLITERAL, ONAME, ONONAME, OTYPE:
|
||||||
if n.Sym == nil {
|
if n.Sym == nil {
|
||||||
|
|
@ -2381,7 +2439,11 @@ func lookdot1(errnode *Node, s *types.Sym, t *types.Type, fs *types.Fields, dost
|
||||||
|
|
||||||
// typecheckMethodExpr checks selector expressions (ODOT) where the
|
// typecheckMethodExpr checks selector expressions (ODOT) where the
|
||||||
// base expression is a type expression (OTYPE).
|
// base expression is a type expression (OTYPE).
|
||||||
func typecheckMethodExpr(n *Node) *Node {
|
func typecheckMethodExpr(n *Node) (res *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckMethodExpr", n)(&res)
|
||||||
|
}
|
||||||
|
|
||||||
t := n.Left.Type
|
t := n.Left.Type
|
||||||
|
|
||||||
// Compute the method set for t.
|
// Compute the method set for t.
|
||||||
|
|
@ -2924,7 +2986,11 @@ func pushtype(n *Node, t *types.Type) {
|
||||||
|
|
||||||
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
||||||
// n.Left = typecheckcomplit(n.Left)
|
// n.Left = typecheckcomplit(n.Left)
|
||||||
func typecheckcomplit(n *Node) *Node {
|
func typecheckcomplit(n *Node) (res *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckcomplit", n)(&res)
|
||||||
|
}
|
||||||
|
|
||||||
lno := lineno
|
lno := lineno
|
||||||
defer func() {
|
defer func() {
|
||||||
lineno = lno
|
lineno = lno
|
||||||
|
|
@ -3337,6 +3403,10 @@ func samesafeexpr(l *Node, r *Node) bool {
|
||||||
// if this assignment is the definition of a var on the left side,
|
// if this assignment is the definition of a var on the left side,
|
||||||
// fill in the var's type.
|
// fill in the var's type.
|
||||||
func typecheckas(n *Node) {
|
func typecheckas(n *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckas", n)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
// delicate little dance.
|
// delicate little dance.
|
||||||
// the definition of n may refer to this assignment
|
// the definition of n may refer to this assignment
|
||||||
// as its definition, in which case it will call typecheckas.
|
// as its definition, in which case it will call typecheckas.
|
||||||
|
|
@ -3393,6 +3463,10 @@ func checkassignto(src *types.Type, dst *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckas2(n *Node) {
|
func typecheckas2(n *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckas2", n)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
ls := n.List.Slice()
|
ls := n.List.Slice()
|
||||||
for i1, n1 := range ls {
|
for i1, n1 := range ls {
|
||||||
// delicate little dance.
|
// delicate little dance.
|
||||||
|
|
@ -3521,6 +3595,10 @@ out:
|
||||||
|
|
||||||
// type check function definition
|
// type check function definition
|
||||||
func typecheckfunc(n *Node) {
|
func typecheckfunc(n *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckfunc", n)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
for _, ln := range n.Func.Dcl {
|
for _, ln := range n.Func.Dcl {
|
||||||
if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
|
if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
|
||||||
ln.Name.Decldepth = 1
|
ln.Name.Decldepth = 1
|
||||||
|
|
@ -3637,6 +3715,10 @@ func copytype(n *Node, t *types.Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckdeftype(n *Node) {
|
func typecheckdeftype(n *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckdeftype", n)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
n.Type.Sym = n.Sym
|
n.Type.Sym = n.Sym
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
|
n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
|
||||||
|
|
@ -3654,6 +3736,10 @@ func typecheckdeftype(n *Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckdef(n *Node) {
|
func typecheckdef(n *Node) {
|
||||||
|
if enableTrace && trace {
|
||||||
|
defer tracePrint("typecheckdef", n)(nil)
|
||||||
|
}
|
||||||
|
|
||||||
lno := setlineno(n)
|
lno := setlineno(n)
|
||||||
|
|
||||||
if n.Op == ONONAME {
|
if n.Op == ONONAME {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue