}
// Create a new no-argument function that we'll hand off to defer.
- fn := ir.NewClosureFunc(n.Pos(), true)
+ fn := ir.NewClosureFunc(n.Pos(), n.Pos(), types.NewSignature(nil, nil, nil), e.curfn, typecheck.Target)
fn.SetWrapper(true)
- fn.Nname.SetType(types.NewSignature(nil, nil, nil))
fn.SetEsc(escFuncTagged) // no params; effectively tagged already
fn.Body = []ir.Node{call}
if call, ok := call.(*ir.CallExpr); ok && call.Op() == ir.OCALLFUNC {
}
clo := fn.OClosure
+
if n.Op() == ir.OGO {
clo.IsGoWrap = true
}
return pkg.Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
}
-// NewClosureFunc creates a new Func to represent a function literal.
-// If hidden is true, then the closure is marked hidden (i.e., as a
-// function literal contained within another function, rather than a
-// package-scope variable initialization expression).
-func NewClosureFunc(pos src.XPos, hidden bool) *Func {
- fn := NewFunc(pos)
- fn.SetIsHiddenClosure(hidden)
-
- fn.Nname = NewNameAt(pos, BlankNode.Sym(), nil)
- fn.Nname.Func = fn
- fn.Nname.Defn = fn
-
- fn.OClosure = &ClosureExpr{Func: fn}
- fn.OClosure.op = OCLOSURE
- fn.OClosure.pos = pos
-
- return fn
-}
-
-// NameClosure generates a unique for the given function literal,
-// which must have appeared within outerfn.
-func NameClosure(clo *ClosureExpr, outerfn *Func) {
- fn := clo.Func
- if fn.IsHiddenClosure() != (outerfn != nil) {
- base.FatalfAt(clo.Pos(), "closure naming inconsistency: hidden %v, but outer %v", fn.IsHiddenClosure(), outerfn)
- }
-
- name := fn.Nname
- if !IsBlank(name) {
- base.FatalfAt(clo.Pos(), "closure already named: %v", name)
- }
+// NewClosureFunc creates a new Func to represent a function literal
+// with the given type.
+//
+// fpos the position used for the underlying ODCLFUNC and ONAME,
+// whereas cpos is the position used for the OCLOSURE. They're
+// separate because in the presence of inlining, the OCLOSURE node
+// should have an inline-adjusted position, whereas the ODCLFUNC and
+// ONAME must not.
+//
+// outerfn is the enclosing function, if any. The returned function is
+// appending to pkg.Funcs.
+func NewClosureFunc(fpos, cpos src.XPos, typ *types.Type, outerfn *Func, pkg *Package) *Func {
+ fn := NewFunc(fpos)
+ fn.SetIsHiddenClosure(outerfn != nil)
- name.SetSym(closureName(outerfn, clo.Pos()))
+ name := NewNameAt(fpos, closureName(outerfn, cpos), typ)
MarkFunc(name)
-}
+ name.Func = fn
+ name.Defn = fn
+ fn.Nname = name
-// UseClosure checks that the given function literal has been setup
-// correctly, and then returns it as an expression.
-// It must be called after clo.Func.ClosureVars has been set.
-func UseClosure(clo *ClosureExpr, pkg *Package) Node {
- fn := clo.Func
- name := fn.Nname
+ clo := &ClosureExpr{Func: fn}
+ clo.op = OCLOSURE
+ clo.pos = cpos
+ fn.OClosure = clo
- if IsBlank(name) {
- base.FatalfAt(fn.Pos(), "unnamed closure func: %v", fn)
- }
- // Caution: clo.Typecheck() is still 0 when UseClosure is called by
- // tcClosure.
- if fn.Typecheck() != 1 || name.Typecheck() != 1 {
- base.FatalfAt(fn.Pos(), "missed typecheck: %v", fn)
- }
- if clo.Type() == nil || name.Type() == nil {
- base.FatalfAt(fn.Pos(), "missing types: %v", fn)
- }
- if !types.Identical(clo.Type(), name.Type()) {
- base.FatalfAt(fn.Pos(), "mismatched types: %v", fn)
- }
-
- if base.Flag.W > 1 {
- s := fmt.Sprintf("new closure func: %v", fn)
- Dump(s, fn)
- }
+ fn.SetTypecheck(1)
+ clo.SetType(typ)
+ clo.SetTypecheck(1)
- if pkg != nil {
- pkg.Funcs = append(pkg.Funcs, fn)
- }
+ pkg.Funcs = append(pkg.Funcs, fn)
- if false && IsTrivialClosure(clo) {
- // TODO(mdempsky): Investigate if we can/should optimize this
- // case. walkClosure already handles it later, but it could be
- // useful to recognize earlier (e.g., it might allow multiple
- // inlined calls to a function to share a common trivial closure
- // func, rather than cloning it for each inlined call).
- }
-
- return clo
+ return fn
}
name.Func = ir.NewFunc(r.pos())
name.Func.Nname = name
+ name.Func.SetTypecheck(1)
if r.hasTypeParams() {
name.Func.SetDupok(true)
name.Func = ir.NewFunc(r.pos())
name.Func.Nname = name
+ name.Func.SetTypecheck(1)
if r.hasTypeParams() {
name.Func.SetDupok(true)
}
}
- typecheck.Func(fn)
-
if r.Bool() {
assert(name.Defn == nil)
// position instead. See also the explanation in reader.funcLit.
inlPos := r.inlPos(origPos)
- fn := ir.NewClosureFunc(origPos, r.curfn != nil)
+ // TODO(mdempsky): Remove hard-coding of typecheck.Target.
+ fn := ir.NewClosureFunc(origPos, inlPos, typ, r.curfn, typecheck.Target)
fn.SetWrapper(true)
- clo := fn.OClosure
- clo.SetPos(inlPos)
- ir.NameClosure(clo, r.curfn)
-
- setType(fn.Nname, typ)
- typecheck.Func(fn)
- setType(clo, fn.Type())
var init ir.Nodes
for i, n := range captures {
bodyReader[fn] = pri
pri.funcBody(fn)
- // TODO(mdempsky): Remove hard-coding of typecheck.Target.
- return ir.InitExpr(init, ir.UseClosure(clo, typecheck.Target))
+ return ir.InitExpr(init, fn.OClosure)
}
// syntheticSig duplicates and returns the params and results lists
xtype2 := r.signature(nil)
r.suppressInlPos--
- fn := ir.NewClosureFunc(pos, r.curfn != nil)
- clo := fn.OClosure
- clo.SetPos(r.inlPos(pos)) // see comment above
- ir.NameClosure(clo, r.curfn)
-
- setType(fn.Nname, xtype2)
- typecheck.Func(fn)
- setType(clo, fn.Type())
+ // TODO(mdempsky): Remove hard-coding of typecheck.Target.
+ fn := ir.NewClosureFunc(pos, r.inlPos(pos), xtype2, r.curfn, typecheck.Target)
fn.ClosureVars = make([]*ir.Name, 0, r.Len())
for len(fn.ClosureVars) < cap(fn.ClosureVars) {
r.addBody(fn, nil)
- // TODO(mdempsky): Remove hard-coding of typecheck.Target.
- return ir.UseClosure(clo, typecheck.Target)
+ return fn.OClosure
}
func (r *reader) exprList() []ir.Node {
// TODO(mdempsky): This still feels clumsy. Can we do better?
tmpfn := ir.NewFunc(fn.Pos())
tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), callerfn.Sym(), fn.Type())
+ tmpfn.SetTypecheck(1)
tmpfn.Closgen = callerfn.Closgen
defer func() { callerfn.Closgen = tmpfn.Closgen }()
tmpfn := ir.NewFunc(fn.Pos())
tmpfn.Nname = ir.NewNameAt(fn.Nname.Pos(), fn.Sym(), fn.Type())
+ tmpfn.SetTypecheck(1)
tmpfn.ClosureVars = fn.ClosureVars
{
recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType)
if !needed {
- typecheck.Func(fn)
return
}
fn.Nname = name
setType(name, sig)
+ fn.SetTypecheck(1)
// TODO(mdempsky): De-duplicate with similar logic in funcargs.
defParams := func(class ir.Class, params *types.Type) {
}
func finishWrapperFunc(fn *ir.Func, target *ir.Package) {
- typecheck.Func(fn)
-
ir.WithFunc(fn, func() {
typecheck.Stmts(fn.Body)
})
target := typecheck.Target
- typecheck.TypecheckAllowed = true
-
localPkgReader = newPkgReader(pkgbits.NewPkgDecoder(types.LocalPkg.Path, data))
readPackage(localPkgReader, types.LocalPkg, true)
fn.Body = nf
typecheck.FinishFuncBody()
- typecheck.Func(fn)
ir.WithFunc(fn, func() {
typecheck.Stmts(nf)
})
fnInit.Body.Append(asancall)
typecheck.FinishFuncBody()
- typecheck.Func(fnInit)
ir.CurFunc = fnInit
typecheck.Stmts(fnInit.Body)
ir.CurFunc = nil
typecheck.FinishFuncBody()
fn.SetDupok(true)
- typecheck.Func(fn)
ir.WithFunc(fn, func() {
typecheck.Stmts(fn.Body)
typecheck.FinishFuncBody()
fn.SetDupok(true)
- typecheck.Func(fn)
ir.WithFunc(fn, func() {
typecheck.Stmts(fn.Body)
typecheck.FinishFuncBody()
- typecheck.Func(fn)
ir.CurFunc = fn
typecheck.Stmts(fn.Body)
newfn.Body = append(newfn.Body, as)
typecheck.FinishFuncBody()
- typecheck.Func(newfn)
-
const no = `
// Register new function with decls.
typecheck.Target.Decls = append(typecheck.Target.Decls, newfn)
checkdupfields("argument", typ.Recvs().FieldSlice(), typ.Params().FieldSlice(), typ.Results().FieldSlice())
fn.Nname.SetType(typ)
fn.Nname.SetTypecheck(1)
+ fn.SetTypecheck(1)
return fn
}
return t
}
-// tcClosure typechecks an OCLOSURE node. It also creates the named
-// function associated with the closure.
-// TODO: This creation of the named function should probably really be done in a
-// separate pass from type-checking.
-func tcClosure(clo *ir.ClosureExpr, top int) ir.Node {
- fn := clo.Func
-
- // We used to allow IR builders to typecheck the underlying Func
- // themselves, but that led to too much variety and inconsistency
- // around who's responsible for naming the function, typechecking
- // it, or adding it to Target.Decls.
- //
- // It's now all or nothing. Callers are still allowed to do these
- // themselves, but then they assume responsibility for all of them.
- if fn.Typecheck() == 1 {
- base.FatalfAt(fn.Pos(), "underlying closure func already typechecked: %v", fn)
- }
-
- ir.NameClosure(clo, ir.CurFunc)
- Func(fn)
-
- // Type check the body now, but only if we're inside a function.
- // At top level (in a variable initialization: curfn==nil) we're not
- // ready to type check code yet; we'll check it later, because the
- // underlying closure function we create is added to Target.Decls.
- if ir.CurFunc != nil {
- oldfn := ir.CurFunc
- ir.CurFunc = fn
- Stmts(fn.Body)
- ir.CurFunc = oldfn
- }
-
- out := 0
- for _, v := range fn.ClosureVars {
- if v.Type() == nil {
- // If v.Type is nil, it means v looked like it was going to be
- // used in the closure, but isn't. This happens in struct
- // literals like s{f: x} where we can't distinguish whether f is
- // a field identifier or expression until resolving s.
- continue
- }
-
- // type check closed variables outside the closure, so that the
- // outer frame also captures them.
- Expr(v.Outer)
-
- fn.ClosureVars[out] = v
- out++
- }
- fn.ClosureVars = fn.ClosureVars[:out]
-
- clo.SetType(fn.Type())
-
- return ir.UseClosure(clo, Target)
-}
-
// type check function definition
// To be called by typecheck, not directly.
// (Call typecheck.Func instead.)
// so that the conversion below happens).
checkLHS := func(i int, typ *types.Type) {
- lhs[i] = Resolve(lhs[i])
if n := lhs[i]; typ != nil && ir.DeclaredBy(n, stmt) && n.Type() == nil {
base.Assertf(typ.Kind() == types.TNIL, "unexpected untyped nil")
n.SetType(defaultType(typ))
// to be included in the package-level init function.
var InitTodoFunc = ir.NewFunc(base.Pos)
-var inimport bool // set during import
-
-var TypecheckAllowed bool
-
var (
NeedRuntimeType = func(*types.Type) {}
)
// marks variables that escape the local frame.
// rewrites n.Op to be more specific in some cases.
-// Resolve resolves an ONONAME node to a definition, if any. If n is not an ONONAME node,
-// Resolve returns n unchanged. If n is an ONONAME node and not in the same package,
-// then n.Sym() is resolved using import data. Otherwise, Resolve returns
-// n.Sym().Def. An ONONAME node can be created using ir.NewIdent(), so an imported
-// symbol can be resolved via Resolve(ir.NewIdent(src.NoXPos, sym)).
-func Resolve(n ir.Node) (res ir.Node) {
- if n == nil || n.Op() != ir.ONONAME {
- return n
- }
-
- base.Fatalf("unexpected NONAME node: %+v", n)
- panic("unreachable")
-}
-
func typecheckslice(l []ir.Node, top int) {
for i := range l {
l[i] = typecheck(l[i], top)
var typecheck_tcstack []ir.Node
-func Func(fn *ir.Func) {
- new := Stmt(fn)
- if new != fn {
- base.Fatalf("typecheck changed func")
- }
-}
-
// typecheck type checks node n.
// The result of typecheck MUST be assigned back to n, e.g.
//
// n.Left = typecheck(n.Left, top)
func typecheck(n ir.Node, top int) (res ir.Node) {
- // cannot type check until all the source has been parsed
- if !TypecheckAllowed {
- base.Fatalf("early typecheck")
- }
-
if n == nil {
return nil
}
n = n.(*ir.ParenExpr).X
}
- // Resolve definition of name and value of iota lazily.
- n = Resolve(n)
-
// Skip typecheck if already done.
// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
if n.Typecheck() == 1 || n.Typecheck() == 3 {
n := n.(*ir.UnaryExpr)
return tcUnsafeData(n)
- case ir.OCLOSURE:
- n := n.(*ir.ClosureExpr)
- return tcClosure(n, top)
-
case ir.OITAB:
n := n.(*ir.UnaryExpr)
return tcITab(n)