]> Cypherpunks.ru repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: add debugging support for delayed actions
authorRobert Griesemer <gri@golang.org>
Thu, 14 Oct 2021 01:50:06 +0000 (18:50 -0700)
committerRobert Griesemer <gri@golang.org>
Fri, 15 Oct 2021 17:05:16 +0000 (17:05 +0000)
Add a simple mechanism to provide formatted descriptions for
delayed actions. The comment strings are printed when tracing
is enabled and the delayed action is executed. This results
in more easily decipherable tracing output.

Requires debug mode in order to minimize the overhead during normal
execution. Use the mechanism in a few places to show typical use.

Also cleaned up a few unrelated comments.

Change-Id: Ic273c380c3963341500396ec62b694d143c25de2
Reviewed-on: https://go-review.googlesource.com/c/go/+/355871
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/check.go
src/cmd/compile/internal/types2/decl.go
src/cmd/compile/internal/types2/instantiate.go
src/cmd/compile/internal/types2/interface.go
src/cmd/compile/internal/types2/struct.go
src/cmd/compile/internal/types2/typexpr.go

index d89ec3d29f24463628e307ce10855dd2e09be919..470376f8e8c7c76dfb313af327164a1e144e9e17 100644 (file)
@@ -74,6 +74,28 @@ type dotImportKey struct {
        name  string
 }
 
+// An action describes a (delayed) action.
+type action struct {
+       f    func()      // action to be executed
+       desc *actionDesc // action description; may be nil, requires debug to be set
+}
+
+// If debug is set, describef sets a printf-formatted description for action a.
+// Otherwise, it is a no-op.
+func (a *action) describef(pos poser, format string, args ...interface{}) {
+       if debug {
+               a.desc = &actionDesc{pos, format, args}
+       }
+}
+
+// An actionDesc provides information on an action.
+// For debugging only.
+type actionDesc struct {
+       pos    poser
+       format string
+       args   []interface{}
+}
+
 // A Checker maintains the state of the type checker.
 // It must be created with NewChecker.
 type Checker struct {
@@ -108,7 +130,7 @@ type Checker struct {
        firstErr error                    // first error encountered
        methods  map[*TypeName][]*Func    // maps package scope type names to associated non-blank (non-interface) methods
        untyped  map[syntax.Expr]exprInfo // map of expressions without final type
-       delayed  []func()                 // stack of delayed action segments; segments are processed in FIFO order
+       delayed  []action                 // stack of delayed action segments; segments are processed in FIFO order
        objPath  []Object                 // path of object dependencies during type inference (for cycle reporting)
 
        // context within which the current object is type-checked
@@ -144,8 +166,12 @@ func (check *Checker) rememberUntyped(e syntax.Expr, lhs bool, mode operandMode,
 // either at the end of the current statement, or in case of a local constant
 // or variable declaration, before the constant or variable is in scope
 // (so that f still sees the scope before any new declarations).
-func (check *Checker) later(f func()) {
-       check.delayed = append(check.delayed, f)
+// later returns the pushed action so one can provide a description
+// via action.describef for debugging, if desired.
+func (check *Checker) later(f func()) *action {
+       i := len(check.delayed)
+       check.delayed = append(check.delayed, action{f: f})
+       return &check.delayed[i]
 }
 
 // push pushes obj onto the object path and returns its index in the path.
@@ -259,6 +285,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
 
        print := func(msg string) {
                if check.conf.Trace {
+                       fmt.Println()
                        fmt.Println(msg)
                }
        }
@@ -309,7 +336,12 @@ func (check *Checker) processDelayed(top int) {
        // add more actions (such as nested functions), so
        // this is a sufficiently bounded process.
        for i := top; i < len(check.delayed); i++ {
-               check.delayed[i]() // may append to check.delayed
+               a := &check.delayed[i]
+               if check.conf.Trace && a.desc != nil {
+                       fmt.Println()
+                       check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...)
+               }
+               a.f() // may append to check.delayed
        }
        assert(top <= len(check.delayed)) // stack must not have shrunk
        check.delayed = check.delayed[:top]
index 9fd60d6aa2bdf9d4d839758241f809648645d989..a605057579816cfc43853a0c0173c185c51cfcfa 100644 (file)
@@ -557,7 +557,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named
                if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
                        check.errorf(tdecl.Type.Pos(), "using type constraint %s requires go1.18 or later", rhs)
                }
-       })
+       }).describef(obj, "validType(%s)", obj.Name())
 
        alias := tdecl.Alias
        if alias && tdecl.TParamList != nil {
index 5da371f201bdbad03ae5fc5b45162ddf4019d9bd..5e45ea33ce6c7e25130e65be3cac520575306ba7 100644 (file)
@@ -63,7 +63,6 @@ func (check *Checker) instantiate(pos syntax.Pos, typ Type, targs []Type, posLis
                        if res != nil {
                                // Calling under() here may lead to endless instantiations.
                                // Test case: type T[P any] T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected.
                                under = safeUnderlying(res)
                        }
                        check.trace(pos, "=> %s (under = %s)", res, under)
@@ -115,7 +114,7 @@ func (check *Checker) instance(pos syntax.Pos, typ Type, targs []Type, ctxt *Con
                        }
                }
                tname := NewTypeName(pos, t.obj.pkg, t.obj.name, nil)
-               named := check.newNamed(tname, t, nil, nil, nil) // methods and tparams are set when named is resolved
+               named := check.newNamed(tname, t, nil, nil, nil) // underlying, tparams, and methods are set when named is resolved
                named.targs = NewTypeList(targs)
                named.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, []*Func) {
                        return expandNamed(ctxt, n, pos)
index 0879d29d3d79df295f858c74902792355b2aa72e..0704628dc69a2987ddede660a337099d3d0ebe59 100644 (file)
@@ -172,7 +172,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *syntax.InterfaceType
        check.later(func() {
                computeInterfaceTypeSet(check, iface.Pos(), ityp)
                ityp.check = nil
-       })
+       }).describef(iface, "compute type set for %s", ityp)
 }
 
 func flattenUnion(list []syntax.Expr, x syntax.Expr) []syntax.Expr {
index f0c27c015043975601acf2c023575e6ac0b76ad9..933d7ef947d2b32025ac53019b7414c40b6bbdf5 100644 (file)
@@ -154,7 +154,7 @@ func (check *Checker) structType(styp *Struct, e *syntax.StructType) {
                                                check.error(embeddedPos, "embedded field type cannot be a pointer to an interface")
                                        }
                                }
-                       })
+                       }).describef(embeddedPos, "check embedded type %s", embeddedTyp)
                }
        }
 
index 746fe78b3802eb46ae0b3591be0872be9d7b3403..646becbdae07b8014b751905555a16228defa9e1 100644 (file)
@@ -214,8 +214,6 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
                        if T != nil {
                                // Calling under() here may lead to endless instantiations.
                                // Test case: type T[P any] *T[P]
-                               // TODO(gri) investigate if that's a bug or to be expected
-                               // (see also analogous comment in Checker.instantiate).
                                under = safeUnderlying(T)
                        }
                        if T == under {