mirror of
https://github.com/golang/go
synced 2024-09-29 22:24:33 -06:00
cmd/compile/internal/types2: add debugging support for delayed actions
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>
This commit is contained in:
parent
a80e53ec43
commit
8c99421f01
@ -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]
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user