mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.typeparams] cmd/compile: refactor closure construction
typecheck.tcClosure is complicated with many code flows because all of its callers setup the closure funcs in slightly different ways. E.g., it's non-obvious who's responsible for setting the underlying func's Sym or adding it to target.Decls, or how to write new code that constructs a closure without interfering with existing code. This CL refactors everything to use three common functions in package ir: NewClosureFunc (which handle creating the Func, Name, and ClosureExpr and wiring them together), NameClosure (which generates and assigns its unique Sym), and UseClosure (which handles adding the Func to target.Decls). Most IR builders can actually name the closure right away, but the legacy noder+typecheck path may not yet know the name of the enclosing function. In particular, for methods declared with aliased receiver parameters, we need to wait until after typechecking top-level declarations to know the method's true name. So they're left anonymous until typecheck. UseClosure does relatively little work today, but it serves as a useful spot to check that the code setting up closures got it right. It may also eventually serve as an optimization point for early lifting of trivial closures, which may or may not ultimately be beneficial. Change-Id: I7da1e93c70d268f575b12d6aaeb2336eb910a6f1 Reviewed-on: https://go-review.googlesource.com/c/go/+/327051 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
This commit is contained in:
parent
8f00eb0099
commit
0132b91127
10 changed files with 200 additions and 196 deletions
|
|
@ -280,8 +280,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
// }
|
||||
|
||||
// Make a new internal function.
|
||||
fn := ir.NewFunc(pos)
|
||||
fn.SetIsHiddenClosure(true)
|
||||
fn := ir.NewClosureFunc(pos, outer)
|
||||
ir.NameClosure(fn.OClosure, outer)
|
||||
|
||||
// This is the dictionary we want to use.
|
||||
// It may be a constant, or it may be a dictionary acquired from the outer function's dictionary.
|
||||
|
|
@ -346,13 +346,8 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
|
||||
// Build an internal function with the right signature.
|
||||
closureType := types.NewSignature(x.Type().Pkg(), nil, nil, formalParams, formalResults)
|
||||
sym := typecheck.ClosureName(outer)
|
||||
sym.SetFunc(true)
|
||||
fn.Nname = ir.NewNameAt(pos, sym)
|
||||
fn.Nname.Class = ir.PFUNC
|
||||
fn.Nname.Func = fn
|
||||
fn.Nname.Defn = fn
|
||||
typed(closureType, fn.Nname)
|
||||
typed(x.Type(), fn.OClosure)
|
||||
fn.SetTypecheck(1)
|
||||
|
||||
// Build body of closure. This involves just calling the wrapped function directly
|
||||
|
|
@ -401,15 +396,12 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
typecheck.Stmt(innerCall)
|
||||
ir.CurFunc = nil
|
||||
fn.Body = []ir.Node{innerCall}
|
||||
if outer == nil {
|
||||
g.target.Decls = append(g.target.Decls, fn)
|
||||
}
|
||||
|
||||
// We're all done with the captured dictionary (and receiver, for method values).
|
||||
ir.FinishCaptureNames(pos, outer, fn)
|
||||
|
||||
// Make a closure referencing our new internal function.
|
||||
c := ir.NewClosureExpr(pos, fn)
|
||||
c := ir.UseClosure(fn.OClosure, g.target)
|
||||
var init []ir.Node
|
||||
if outer != nil {
|
||||
init = append(init, dictAssign)
|
||||
|
|
@ -417,9 +409,7 @@ func (g *irgen) buildClosure(outer *ir.Func, x ir.Node) ir.Node {
|
|||
if rcvrValue != nil {
|
||||
init = append(init, rcvrAssign)
|
||||
}
|
||||
c.SetInit(init)
|
||||
typed(x.Type(), c)
|
||||
return c
|
||||
return ir.InitExpr(init, c)
|
||||
}
|
||||
|
||||
// instantiateMethods instantiates all the methods of all fully-instantiated
|
||||
|
|
@ -859,24 +849,18 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
}
|
||||
|
||||
case ir.OCLOSURE:
|
||||
// We're going to create a new closure from scratch, so clear m
|
||||
// to avoid using the ir.Copy by accident until we reassign it.
|
||||
m = nil
|
||||
|
||||
x := x.(*ir.ClosureExpr)
|
||||
// Need to duplicate x.Func.Nname, x.Func.Dcl, x.Func.ClosureVars, and
|
||||
// x.Func.Body.
|
||||
oldfn := x.Func
|
||||
newfn := ir.NewFunc(oldfn.Pos())
|
||||
if oldfn.ClosureCalled() {
|
||||
newfn.SetClosureCalled(true)
|
||||
}
|
||||
newfn.SetIsHiddenClosure(true)
|
||||
m.(*ir.ClosureExpr).Func = newfn
|
||||
// Closure name can already have brackets, if it derives
|
||||
// from a generic method
|
||||
newsym := typecheck.MakeInstName(oldfn.Nname.Sym(), subst.ts.Targs, subst.isMethod)
|
||||
newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), newsym)
|
||||
newfn.Nname.Func = newfn
|
||||
newfn.Nname.Defn = newfn
|
||||
ir.MarkFunc(newfn.Nname)
|
||||
newfn.OClosure = m.(*ir.ClosureExpr)
|
||||
newfn := ir.NewClosureFunc(oldfn.Pos(), subst.newf)
|
||||
ir.NameClosure(newfn.OClosure, subst.newf)
|
||||
|
||||
newfn.SetClosureCalled(oldfn.ClosureCalled())
|
||||
|
||||
saveNewf := subst.newf
|
||||
ir.CurFunc = newfn
|
||||
|
|
@ -885,7 +869,7 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
newfn.ClosureVars = subst.namelist(oldfn.ClosureVars)
|
||||
|
||||
typed(subst.ts.Typ(oldfn.Nname.Type()), newfn.Nname)
|
||||
typed(newfn.Nname.Type(), m)
|
||||
typed(newfn.Nname.Type(), newfn.OClosure)
|
||||
newfn.SetTypecheck(1)
|
||||
|
||||
// Make sure type of closure function is set before doing body.
|
||||
|
|
@ -893,7 +877,8 @@ func (subst *subster) node(n ir.Node) ir.Node {
|
|||
subst.newf = saveNewf
|
||||
ir.CurFunc = saveNewf
|
||||
|
||||
subst.g.target.Decls = append(subst.g.target.Decls, newfn)
|
||||
m = ir.UseClosure(newfn.OClosure, subst.g.target)
|
||||
m.(*ir.ClosureExpr).SetInit(subst.list(x.Init()))
|
||||
|
||||
case ir.OCONVIFACE:
|
||||
x := x.(*ir.ConvExpr)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue