aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2024-02-28 15:01:25 -0800
committerGopher Robot <gobot@golang.org>2024-02-29 17:35:02 +0000
commita66a3bf494f652bc4fb209d861cbdba1dea71303 (patch)
tree95c39453ce957de5318dc3f579d5f4956c55bf25 /src
parent613344ffddc9b44912557c7ea3b9bc244251e90e (diff)
downloadgo-a66a3bf494f652bc4fb209d861cbdba1dea71303.tar.xz
go/types, types2: add tracing to Checker.validType
Debugging support. For #65711. Change-Id: I2b8b03d2c6e02d32a4f9272313e852f17da35b3e Reviewed-on: https://go-review.googlesource.com/c/go/+/567975 Reviewed-by: Robert Findley <rfindley@google.com> Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src')
-rw-r--r--src/cmd/compile/internal/types2/validtype.go33
-rw-r--r--src/go/types/generate_test.go2
-rw-r--r--src/go/types/validtype.go33
3 files changed, 49 insertions, 19 deletions
diff --git a/src/cmd/compile/internal/types2/validtype.go b/src/cmd/compile/internal/types2/validtype.go
index a880a3d933..c5668096a5 100644
--- a/src/cmd/compile/internal/types2/validtype.go
+++ b/src/cmd/compile/internal/types2/validtype.go
@@ -4,12 +4,14 @@
package types2
+import "cmd/compile/internal/syntax"
+
// validType verifies that the given type does not "expand" indefinitely
// producing a cycle in the type graph.
// (Cycles involving alias types, as in "type A = [10]A" are detected
// earlier, via the objDecl cycle detection mechanism.)
func (check *Checker) validType(typ *Named) {
- check.validType0(typ, nil, nil)
+ check.validType0(nopos, typ, nil, nil)
}
// validType0 checks if the given type is valid. If typ is a type parameter
@@ -22,8 +24,21 @@ func (check *Checker) validType(typ *Named) {
// of) F in S, leading to the nest S->F. If a type appears in its own nest
// (say S->F->S) we have an invalid recursive type. The path list is the full
// path of named types in a cycle, it is only needed for error reporting.
-func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
- switch t := Unalias(typ).(type) {
+func (check *Checker) validType0(pos syntax.Pos, typ Type, nest, path []*Named) bool {
+ typ = Unalias(typ)
+
+ if check.conf.Trace {
+ if t, _ := typ.(*Named); t != nil && t.obj != nil /* obj should always exist but be conservative */ {
+ pos = t.obj.pos
+ }
+ check.indent++
+ check.trace(pos, "validType(%s) nest %v, path %v", typ, pathString(makeObjList(nest)), pathString(makeObjList(path)))
+ defer func() {
+ check.indent--
+ }()
+ }
+
+ switch t := typ.(type) {
case nil:
// We should never see a nil type but be conservative and panic
// only in debug mode.
@@ -32,25 +47,25 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
}
case *Array:
- return check.validType0(t.elem, nest, path)
+ return check.validType0(pos, t.elem, nest, path)
case *Struct:
for _, f := range t.fields {
- if !check.validType0(f.typ, nest, path) {
+ if !check.validType0(pos, f.typ, nest, path) {
return false
}
}
case *Union:
for _, t := range t.terms {
- if !check.validType0(t.typ, nest, path) {
+ if !check.validType0(pos, t.typ, nest, path) {
return false
}
}
case *Interface:
for _, etyp := range t.embeddeds {
- if !check.validType0(etyp, nest, path) {
+ if !check.validType0(pos, etyp, nest, path) {
return false
}
}
@@ -121,7 +136,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// Every type added to nest is also added to path; thus every type that is in nest
// must also be in path (invariant). But not every type in path is in nest, since
// nest may be pruned (see below, *TypeParam case).
- if !check.validType0(t.Origin().fromRHS, append(nest, t), append(path, t)) {
+ if !check.validType0(pos, t.Origin().fromRHS, append(nest, t), append(path, t)) {
return false
}
@@ -146,7 +161,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// the current (instantiated) type (see the example
// at the end of this file).
// For error reporting we keep the full path.
- return check.validType0(targ, nest[:len(nest)-1], path)
+ return check.validType0(pos, targ, nest[:len(nest)-1], path)
}
}
}
diff --git a/src/go/types/generate_test.go b/src/go/types/generate_test.go
index 893280f39e..a85dfc9b42 100644
--- a/src/go/types/generate_test.go
+++ b/src/go/types/generate_test.go
@@ -173,7 +173,7 @@ var filemap = map[string]action{
"unify.go": fixSprintf,
"universe.go": fixGlobalTypVarDecl,
"util_test.go": fixTokenPos,
- "validtype.go": nil,
+ "validtype.go": func(f *ast.File) { fixTokenPos(f); renameSelectors(f, "Trace->_Trace") },
}
// TODO(gri) We should be able to make these rewriters more configurable/composable.
diff --git a/src/go/types/validtype.go b/src/go/types/validtype.go
index 0638714857..66dba2ea4c 100644
--- a/src/go/types/validtype.go
+++ b/src/go/types/validtype.go
@@ -6,12 +6,14 @@
package types
+import "go/token"
+
// validType verifies that the given type does not "expand" indefinitely
// producing a cycle in the type graph.
// (Cycles involving alias types, as in "type A = [10]A" are detected
// earlier, via the objDecl cycle detection mechanism.)
func (check *Checker) validType(typ *Named) {
- check.validType0(typ, nil, nil)
+ check.validType0(nopos, typ, nil, nil)
}
// validType0 checks if the given type is valid. If typ is a type parameter
@@ -24,8 +26,21 @@ func (check *Checker) validType(typ *Named) {
// of) F in S, leading to the nest S->F. If a type appears in its own nest
// (say S->F->S) we have an invalid recursive type. The path list is the full
// path of named types in a cycle, it is only needed for error reporting.
-func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
- switch t := Unalias(typ).(type) {
+func (check *Checker) validType0(pos token.Pos, typ Type, nest, path []*Named) bool {
+ typ = Unalias(typ)
+
+ if check.conf._Trace {
+ if t, _ := typ.(*Named); t != nil && t.obj != nil /* obj should always exist but be conservative */ {
+ pos = t.obj.pos
+ }
+ check.indent++
+ check.trace(pos, "validType(%s) nest %v, path %v", typ, pathString(makeObjList(nest)), pathString(makeObjList(path)))
+ defer func() {
+ check.indent--
+ }()
+ }
+
+ switch t := typ.(type) {
case nil:
// We should never see a nil type but be conservative and panic
// only in debug mode.
@@ -34,25 +49,25 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
}
case *Array:
- return check.validType0(t.elem, nest, path)
+ return check.validType0(pos, t.elem, nest, path)
case *Struct:
for _, f := range t.fields {
- if !check.validType0(f.typ, nest, path) {
+ if !check.validType0(pos, f.typ, nest, path) {
return false
}
}
case *Union:
for _, t := range t.terms {
- if !check.validType0(t.typ, nest, path) {
+ if !check.validType0(pos, t.typ, nest, path) {
return false
}
}
case *Interface:
for _, etyp := range t.embeddeds {
- if !check.validType0(etyp, nest, path) {
+ if !check.validType0(pos, etyp, nest, path) {
return false
}
}
@@ -123,7 +138,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// Every type added to nest is also added to path; thus every type that is in nest
// must also be in path (invariant). But not every type in path is in nest, since
// nest may be pruned (see below, *TypeParam case).
- if !check.validType0(t.Origin().fromRHS, append(nest, t), append(path, t)) {
+ if !check.validType0(pos, t.Origin().fromRHS, append(nest, t), append(path, t)) {
return false
}
@@ -148,7 +163,7 @@ func (check *Checker) validType0(typ Type, nest, path []*Named) bool {
// the current (instantiated) type (see the example
// at the end of this file).
// For error reporting we keep the full path.
- return check.validType0(targ, nest[:len(nest)-1], path)
+ return check.validType0(pos, targ, nest[:len(nest)-1], path)
}
}
}