aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2016-05-23 17:43:09 -0700
committerRobert Griesemer <gri@golang.org>2016-05-27 23:39:38 +0000
commit795809b5c7d7e281e392399b9a366cbe92aa9e98 (patch)
tree21fe7fee6efc763e010eeaa742719aae78dd9d15
parent429bbf331247ef598802a94a23670bfe1cf61d6f (diff)
downloadgo-795809b5c7d7e281e392399b9a366cbe92aa9e98.tar.gz
go-795809b5c7d7e281e392399b9a366cbe92aa9e98.zip
go/types: better debugging output for init order computation
Also: Added some test cases for issue #10709. No impact when debugging output is disabled (default). For #10709. Change-Id: I0751befb222c86d46225377a674f6bad2990349e Reviewed-on: https://go-review.googlesource.com/23442 Reviewed-by: Alan Donovan <adonovan@google.com>
-rw-r--r--src/go/types/api_test.go41
-rw-r--r--src/go/types/initorder.go45
-rw-r--r--src/go/types/resolver.go2
3 files changed, 75 insertions, 13 deletions
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
index 8b8ae1bb5d..035ffd6f39 100644
--- a/src/go/types/api_test.go
+++ b/src/go/types/api_test.go
@@ -572,6 +572,47 @@ func TestInitOrderInfo(t *testing.T) {
`, []string{
"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
}},
+ // test case for issue 10709
+ // TODO(gri) enable once the issue is fixed
+ // {`package p13
+
+ // var (
+ // v = t.m()
+ // t = makeT(0)
+ // )
+
+ // type T struct{}
+
+ // func (T) m() int { return 0 }
+
+ // func makeT(n int) T {
+ // if n > 0 {
+ // return makeT(n-1)
+ // }
+ // return T{}
+ // }`, []string{
+ // "t = makeT(0)", "v = t.m()",
+ // }},
+ // test case for issue 10709: same as test before, but variable decls swapped
+ {`package p14
+
+ var (
+ t = makeT(0)
+ v = t.m()
+ )
+
+ type T struct{}
+
+ func (T) m() int { return 0 }
+
+ func makeT(n int) T {
+ if n > 0 {
+ return makeT(n-1)
+ }
+ return T{}
+ }`, []string{
+ "t = makeT(0)", "v = t.m()",
+ }},
}
for _, test := range tests {
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
index ac9016b46e..cf9b8709d8 100644
--- a/src/go/types/initorder.go
+++ b/src/go/types/initorder.go
@@ -15,25 +15,40 @@ func (check *Checker) initOrder() {
// built from several calls to (*Checker).Files. Clear it.
check.Info.InitOrder = check.Info.InitOrder[:0]
- // compute the object dependency graph and
- // initialize a priority queue with the list
- // of graph nodes
+ // Compute the transposed object dependency graph and initialize
+ // a priority queue with the list of graph nodes.
pq := nodeQueue(dependencyGraph(check.objMap))
heap.Init(&pq)
const debug = false
if debug {
- fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+ fmt.Printf("Computing initialization order for %s\n\n", check.pkg)
+ fmt.Println("Object dependency graph:")
+ for obj, d := range check.objMap {
+ if len(d.deps) > 0 {
+ fmt.Printf("\t%s depends on\n", obj.Name())
+ for dep := range d.deps {
+ fmt.Printf("\t\t%s\n", dep.Name())
+ }
+ } else {
+ fmt.Printf("\t%s has no dependencies\n", obj.Name())
+ }
+ }
+ fmt.Println()
+
+ fmt.Println("Transposed object dependency graph:")
for _, n := range pq {
- for _, o := range n.out {
- fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+ fmt.Printf("\t%s depends on %d nodes\n", n.obj.Name(), n.in)
+ for _, out := range n.out {
+ fmt.Printf("\t\t%s is dependent\n", out.obj.Name())
}
}
fmt.Println()
- fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+
+ fmt.Println("Processing nodes:")
}
- // determine initialization order by removing the highest priority node
+ // Determine initialization order by removing the highest priority node
// (the one with the fewest dependencies) and its edges from the graph,
// repeatedly, until there are no nodes left.
// In a valid Go program, those nodes always have zero dependencies (after
@@ -45,6 +60,11 @@ func (check *Checker) initOrder() {
// get the next node
n := heap.Pop(&pq).(*objNode)
+ if debug {
+ fmt.Printf("\t%s (src pos %d) depends on %d nodes now\n",
+ n.obj.Name(), n.obj.order(), n.in)
+ }
+
// if n still depends on other nodes, we have a cycle
if n.in > 0 {
mark++ // mark nodes using a different value each time
@@ -86,14 +106,15 @@ func (check *Checker) initOrder() {
}
init := &Initializer{infoLhs, info.init}
check.Info.InitOrder = append(check.Info.InitOrder, init)
-
- if debug {
- fmt.Printf("\t%s\n", init)
- }
}
if debug {
fmt.Println()
+ fmt.Println("Initialization order:")
+ for _, init := range check.Info.InitOrder {
+ fmt.Printf("\t%s\n", init)
+ }
+ fmt.Println()
}
}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index 992188f0ff..cb8e72e4a6 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -32,7 +32,7 @@ func (d *declInfo) hasInitializer() bool {
return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
}
-// addDep adds obj as a dependency to d.
+// addDep adds obj to the set of objects d's init expression depends on.
func (d *declInfo) addDep(obj Object) {
m := d.deps
if m == nil {