]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: add tracing to Checker.validType
authorRobert Griesemer <gri@golang.org>
Wed, 28 Feb 2024 23:01:25 +0000 (15:01 -0800)
committerGopher Robot <gobot@golang.org>
Thu, 29 Feb 2024 17:35:02 +0000 (17:35 +0000)
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>

src/cmd/compile/internal/types2/validtype.go
src/go/types/generate_test.go
src/go/types/validtype.go

index a880a3d93320123f3e62b9569c57990dad80f022..c5668096a54e88101d95f91ac05a118c62d2ef3f 100644 (file)
@@ -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)
                                }
                        }
                }
index 893280f39e5de9e5033f8ade2fd81250783a6527..a85dfc9b421c5cd243b2acea515046e0ec80a902 100644 (file)
@@ -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.
index 063871485732eb1ba67e0f22b8dacfc24e612e39..66dba2ea4c9295352764457d49fb00d9b5b5fa80 100644 (file)
@@ -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)
                                }
                        }
                }