]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types: add debugging support for delayed actions
authorRobert Findley <rfindley@google.com>
Wed, 27 Oct 2021 15:23:06 +0000 (11:23 -0400)
committerRobert Findley <rfindley@google.com>
Thu, 28 Oct 2021 15:34:49 +0000 (15:34 +0000)
This is a port of CL 355871 to go/types.

Change-Id: I2dbc3c625c16b545a271a19606ef34ce04a4a6df
Reviewed-on: https://go-review.googlesource.com/c/go/+/359136
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/check.go
src/go/types/decl.go
src/go/types/instantiate.go
src/go/types/interface.go
src/go/types/struct.go
src/go/types/typexpr.go

index 3fc9c03917f466038e2f033b7d38323979f55060..2b8ef9f061321371c1a6f5a712e7a96a67777d31 100644 (file)
@@ -76,6 +76,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 positioner, 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    positioner
+       format string
+       args   []interface{}
+}
+
 // A Checker maintains the state of the type checker.
 // It must be created with NewChecker.
 type Checker struct {
@@ -111,7 +133,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[ast.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)
        defTypes []*Named              // defined types created during type checking, for final validation.
 
@@ -148,8 +170,12 @@ func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, ty
 // 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.
@@ -304,7 +330,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 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 3e97fbbccd251e02e2f66e64e14cb7ea93228def..6982fed0b8e3e8459ce2a1b131c694330b26edff 100644 (file)
@@ -610,7 +610,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *ast.TypeSpec, def *Named) {
                if check.isImportedConstraint(rhs) && !check.allowVersion(check.pkg, 1, 18) {
                        check.errorf(tdecl.Type, _Todo, "using type constraint %s requires go1.18 or later", rhs)
                }
-       })
+       }).describef(obj, "validType(%s)", obj.Name())
 
        alias := tdecl.Assign.IsValid()
        if alias && tdecl.TypeParams.NumFields() != 0 {
index 2bb31b17ee2fabc36e839346d58333d536aa1bdb..3720cb725acb11a073240ca94f87dd98ea9cf664 100644 (file)
@@ -65,7 +65,7 @@ func (check *Checker) instance(pos token.Pos, typ Type, targs []Type, ctxt *Cont
                        }
                }
                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 c170ed4a6062536cfac25f2c108b42953fac8c06..78813e665bf1b605986eb202f8c73f320eaeb75b 100644 (file)
@@ -221,7 +221,7 @@ func (check *Checker) interfaceType(ityp *Interface, iface *ast.InterfaceType, d
        check.later(func() {
                computeInterfaceTypeSet(check, iface.Pos(), ityp)
                ityp.check = nil
-       })
+       }).describef(iface, "compute type set for %s", ityp)
 }
 
 func flattenUnion(list []ast.Expr, x ast.Expr) []ast.Expr {
index 24a2435ff7d3f05ac0a4f27758dde89202cdcfcb..442c7a66e329daa5acd7e9148b815f8764381998 100644 (file)
@@ -155,7 +155,7 @@ func (check *Checker) structType(styp *Struct, e *ast.StructType) {
                                                check.error(embeddedPos, _InvalidPtrEmbed, "embedded field type cannot be a pointer to an interface")
                                        }
                                }
-                       })
+                       }).describef(embeddedPos, "check embedded type %s", embeddedTyp)
                }
        }
 
index e812c3d5d5eb67c1ee10c56edfdfdc1e5a622476..092e355b38794eaf71b87e1a5495a6cae867c55b 100644 (file)
@@ -210,8 +210,6 @@ func (check *Checker) typInternal(e0 ast.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 {