mirror of
https://github.com/golang/go
synced 2024-10-04 15:09:59 +00:00
go/types: don't set a Config.Context if none is provided
Users can re-use a type checking context by passing it via types.Config. There is no need for us to expose the internal type checking context when the config context is unset, and in fact doing so could lead to a memory leak for users that re-use types.Config, expecting it to be small and immutable. Keep track of the Context on Checker instead, and zero it out at the end of type checking. Change-Id: Iff5b328a09cd0af76fcd4869f5f15352131b5986 Reviewed-on: https://go-review.googlesource.com/c/go/+/363175 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>
This commit is contained in:
parent
958f405371
commit
530e320b2a
|
@ -81,7 +81,7 @@ func (check *Checker) instantiateSignature(pos token.Pos, typ *Signature, targs
|
|||
}()
|
||||
}
|
||||
|
||||
inst := check.instance(pos, typ, targs, check.conf.Context).(*Signature)
|
||||
inst := check.instance(pos, typ, targs, check.bestContext(nil)).(*Signature)
|
||||
assert(len(posList) <= len(targs))
|
||||
tparams := typ.TypeParams().list()
|
||||
if i, err := check.verify(pos, tparams, targs); err != nil {
|
||||
|
|
|
@ -105,6 +105,7 @@ type Checker struct {
|
|||
// package information
|
||||
// (initialized by NewChecker, valid for the life-time of checker)
|
||||
conf *Config
|
||||
ctxt *Context // context for de-duplicating instances
|
||||
fset *token.FileSet
|
||||
pkg *Package
|
||||
*Info
|
||||
|
@ -203,11 +204,6 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
|||
conf = new(Config)
|
||||
}
|
||||
|
||||
// make sure we have a context
|
||||
if conf.Context == nil {
|
||||
conf.Context = NewContext()
|
||||
}
|
||||
|
||||
// make sure we have an info struct
|
||||
if info == nil {
|
||||
info = new(Info)
|
||||
|
@ -220,6 +216,7 @@ func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Ch
|
|||
|
||||
return &Checker{
|
||||
conf: conf,
|
||||
ctxt: conf.Context,
|
||||
fset: fset,
|
||||
pkg: pkg,
|
||||
Info: info,
|
||||
|
@ -322,6 +319,7 @@ func (check *Checker) checkFiles(files []*ast.File) (err error) {
|
|||
check.seenPkgMap = nil
|
||||
check.recvTParamMap = nil
|
||||
check.defTypes = nil
|
||||
check.ctxt = nil
|
||||
|
||||
// TODO(rFindley) There's more memory we should release at this point.
|
||||
|
||||
|
|
|
@ -68,7 +68,7 @@ func (check *Checker) objDecl(obj Object, def *Named) {
|
|||
// Funcs with m.instRecv set have not yet be completed. Complete them now
|
||||
// so that they have a type when objDecl exits.
|
||||
if m, _ := obj.(*Func); m != nil && m.instRecv != nil {
|
||||
check.completeMethod(check.conf.Context, m)
|
||||
check.completeMethod(nil, m)
|
||||
}
|
||||
|
||||
// Checking the declaration of obj means inferring its type
|
||||
|
|
|
@ -222,15 +222,17 @@ func (n *Named) setUnderlying(typ Type) {
|
|||
|
||||
// bestContext returns the best available context. In order of preference:
|
||||
// - the given ctxt, if non-nil
|
||||
// - check.Config.Context, if check is non-nil
|
||||
// - check.ctxt, if check is non-nil
|
||||
// - a new Context
|
||||
func (check *Checker) bestContext(ctxt *Context) *Context {
|
||||
if ctxt != nil {
|
||||
return ctxt
|
||||
}
|
||||
if check != nil {
|
||||
assert(check.conf.Context != nil)
|
||||
return check.conf.Context
|
||||
if check.ctxt == nil {
|
||||
check.ctxt = NewContext()
|
||||
}
|
||||
return check.ctxt
|
||||
}
|
||||
return NewContext()
|
||||
}
|
||||
|
|
|
@ -211,7 +211,7 @@ func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast
|
|||
var err string
|
||||
switch T := rtyp.(type) {
|
||||
case *Named:
|
||||
T.resolve(check.conf.Context)
|
||||
T.resolve(check.bestContext(nil))
|
||||
// The receiver type may be an instantiated type referred to
|
||||
// by an alias (which cannot have receiver parameters for now).
|
||||
if T.TypeArgs() != nil && sig.RecvTypeParams() == nil {
|
||||
|
|
|
@ -409,9 +409,10 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
|
|||
}
|
||||
|
||||
// create the instance
|
||||
h := check.conf.Context.instanceHash(orig, targs)
|
||||
ctxt := check.bestContext(nil)
|
||||
h := ctxt.instanceHash(orig, targs)
|
||||
// targs may be incomplete, and require inference. In any case we should de-duplicate.
|
||||
inst, _ := check.conf.Context.lookup(h, orig, targs).(*Named)
|
||||
inst, _ := ctxt.lookup(h, orig, targs).(*Named)
|
||||
// If inst is non-nil, we can't just return here. Inst may have been
|
||||
// constructed via recursive substitution, in which case we wouldn't do the
|
||||
// validation below. Ensure that the validation (and resulting errors) runs
|
||||
|
@ -420,7 +421,7 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
|
|||
tname := NewTypeName(x.Pos(), orig.obj.pkg, orig.obj.name, nil)
|
||||
inst = check.newNamed(tname, orig, nil, nil, nil) // underlying, methods and tparams are set when named is resolved
|
||||
inst.targs = NewTypeList(targs)
|
||||
inst = check.conf.Context.update(h, orig, targs, inst).(*Named)
|
||||
inst = ctxt.update(h, orig, targs, inst).(*Named)
|
||||
}
|
||||
def.setUnderlying(inst)
|
||||
|
||||
|
@ -446,7 +447,7 @@ func (check *Checker) instantiatedType(x ast.Expr, targsx []ast.Expr, def *Named
|
|||
// This is an instance from the source, not from recursive substitution,
|
||||
// and so it must be resolved during type-checking so that we can report
|
||||
// errors.
|
||||
inst.resolve(check.conf.Context)
|
||||
inst.resolve(ctxt)
|
||||
// Since check is non-nil, we can still mutate inst. Unpinning the resolver
|
||||
// frees some memory.
|
||||
inst.resolver = nil
|
||||
|
|
Loading…
Reference in a new issue