]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/gc: add tracing support to debug type checking
authorRobert Griesemer <gri@golang.org>
Thu, 1 Nov 2018 20:46:50 +0000 (13:46 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 2 Nov 2018 22:17:47 +0000 (22:17 +0000)
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>
src/cmd/compile/internal/gc/main.go
src/cmd/compile/internal/gc/typecheck.go

index 059bf5d1fceecc99fba2e07ba76039a7082717aa..49a4e05d99efe2922959dd4de8412837f61247d0 100644 (file)
@@ -229,6 +229,9 @@ func Main(archInit func(*Arch)) {
                flag.BoolVar(&flag_race, "race", false, "enable race detector")
        }
        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.BoolVar(&Debug_vlog, "v", false, "increase debug verbosity")
        objabi.Flagcount("w", "debug type checking", &Debug['w'])
index 6ee52eae843c89339ecee7eb2c62344d3727ed6b..be11a9841f0bf6cb753f7c7234dafa6f2eb98b97 100644 (file)
@@ -12,6 +12,50 @@ import (
        "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 (
        Etop      = 1 << iota // evaluated at statement level
        Erv                   // evaluated in value context
@@ -31,11 +75,16 @@ const (
 var typecheckdefstack []*Node
 
 // resolve ONONAME to definition, if any.
-func resolve(n *Node) *Node {
+func resolve(n *Node) (res *Node) {
        if n == nil || n.Op != ONONAME {
                return n
        }
 
+       // only trace if there's work to do
+       if enableTrace && trace {
+               defer tracePrint("resolve", n)(&res)
+       }
+
        if n.Sym.Pkg != localpkg {
                if inimport {
                        Fatalf("recursive inimport")
@@ -150,7 +199,7 @@ var typecheck_tcstack []*Node
 // typecheck type checks node n.
 // The result of typecheck MUST be assigned back to n, e.g.
 //     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
        if !typecheckok {
                Fatalf("early typecheck")
@@ -160,6 +209,11 @@ func typecheck(n *Node, top int) *Node {
                return nil
        }
 
+       // only trace if there's work to do
+       if enableTrace && trace {
+               defer tracePrint("typecheck", n)(&res)
+       }
+
        lno := setlineno(n)
 
        // Skip over parens.
@@ -294,7 +348,11 @@ func indexlit(n *Node) *Node {
 
 // The result of typecheck1 MUST be assigned back to n, e.g.
 //     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 {
        case OLITERAL, ONAME, ONONAME, OTYPE:
                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
 // 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
 
        // 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.
 //     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
        defer func() {
                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,
 // fill in the var's type.
 func typecheckas(n *Node) {
+       if enableTrace && trace {
+               defer tracePrint("typecheckas", n)(nil)
+       }
+
        // delicate little dance.
        // the definition of n may refer to this assignment
        // 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) {
+       if enableTrace && trace {
+               defer tracePrint("typecheckas2", n)(nil)
+       }
+
        ls := n.List.Slice()
        for i1, n1 := range ls {
                // delicate little dance.
@@ -3521,6 +3595,10 @@ out:
 
 // type check function definition
 func typecheckfunc(n *Node) {
+       if enableTrace && trace {
+               defer tracePrint("typecheckfunc", n)(nil)
+       }
+
        for _, ln := range n.Func.Dcl {
                if ln.Op == ONAME && (ln.Class() == PPARAM || ln.Class() == PPARAMOUT) {
                        ln.Name.Decldepth = 1
@@ -3637,6 +3715,10 @@ func copytype(n *Node, t *types.Type) {
 }
 
 func typecheckdeftype(n *Node) {
+       if enableTrace && trace {
+               defer tracePrint("typecheckdeftype", n)(nil)
+       }
+
        n.Type.Sym = n.Sym
        n.SetTypecheck(1)
        n.Name.Param.Ntype = typecheck(n.Name.Param.Ntype, Etype)
@@ -3654,6 +3736,10 @@ func typecheckdeftype(n *Node) {
 }
 
 func typecheckdef(n *Node) {
+       if enableTrace && trace {
+               defer tracePrint("typecheckdef", n)(nil)
+       }
+
        lno := setlineno(n)
 
        if n.Op == ONONAME {