typecheckinl(n)
+ // Recursively identify all referenced functions for
+ // reexport. We want to include even non-called functions,
+ // because after inlining they might be callable.
inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
switch n.Op {
case ONAME:
- // Mark any referenced global variables or
- // functions for reexport. Skip methods,
- // because they're reexported alongside their
- // receiver type.
- if n.Class() == PEXTERN || n.Class() == PFUNC && !n.isMethodExpression() {
+ switch n.Class() {
+ case PFUNC:
+ if n.isMethodExpression() {
+ inlFlood(asNode(n.Type.Nname()))
+ } else {
+ inlFlood(n)
+ exportsym(n)
+ }
+ case PEXTERN:
exportsym(n)
}
- case OCALLFUNC, OCALLMETH:
- // Recursively flood any functions called by
- // this one.
- inlFlood(asNode(n.Left.Type.Nname()))
+ case ODOTMETH:
+ fn := asNode(n.Type.Nname())
+ inlFlood(fn)
+
+ case OCALLPART:
+ // Okay, because we don't yet inline indirect
+ // calls to method values.
+ case OCLOSURE:
+ // If the closure is inlinable, we'll need to
+ // flood it too. But today we don't support
+ // inlining functions that contain closures.
+ //
+ // When we do, we'll probably want:
+ // inlFlood(n.Func.Closure.Func.Nname)
+ Fatalf("unexpected closure in inlinable function")
}
return true
})
switch {
case fn.Op == ONAME && fn.Class() == PFUNC:
if fn.isMethodExpression() {
- return asNode(fn.Sym.Def)
+ n := asNode(fn.Type.Nname())
+ // Check that receiver type matches fn.Left.
+ // TODO(mdempsky): Handle implicit dereference
+ // of pointer receiver argument?
+ if n == nil || !types.Identical(n.Type.Recv().Type, fn.Left.Type) {
+ return nil
+ }
+ return n
}
return fn
case fn.Op == OCLOSURE:
func staticValue(n *Node) *Node {
for {
+ if n.Op == OCONVNOP {
+ n = n.Left
+ continue
+ }
+
n1 := staticValue1(n)
if n1 == nil {
return n
}
}
+ nreturns := 0
+ inspectList(asNodes(fn.Func.Inl.Body), func(n *Node) bool {
+ if n != nil && n.Op == ORETURN {
+ nreturns++
+ }
+ return true
+ })
+
+ // We can delay declaring+initializing result parameters if:
+ // (1) there's only one "return" statement in the inlined
+ // function, and (2) the result parameters aren't named.
+ delayretvars := nreturns == 1
+
// temporaries for return values.
var retvars []*Node
for i, t := range fn.Type.Results().Fields().Slice() {
var m *Node
- mpos := t.Pos
if n := asNode(t.Nname); n != nil && !n.isBlank() {
m = inlvar(n)
m = typecheck(m, ctxExpr)
inlvars[n] = m
+ delayretvars = false // found a named result parameter
} else {
// anonymous return values, synthesize names for use in assignment that replaces return
m = retvar(t, i)
// were not part of the original callee.
if !strings.HasPrefix(m.Sym.Name, "~R") {
m.Name.SetInlFormal(true)
- m.Pos = mpos
+ m.Pos = t.Pos
inlfvars = append(inlfvars, m)
}
}
- ninit.Append(nod(ODCL, m, nil))
retvars = append(retvars, m)
}
ninit.Append(vas)
}
- // Zero the return parameters.
- for _, n := range retvars {
- ras := nod(OAS, n, nil)
- ras = typecheck(ras, ctxStmt)
- ninit.Append(ras)
+ if !delayretvars {
+ // Zero the return parameters.
+ for _, n := range retvars {
+ ninit.Append(nod(ODCL, n, nil))
+ ras := nod(OAS, n, nil)
+ ras = typecheck(ras, ctxStmt)
+ ninit.Append(ras)
+ }
}
retlabel := autolabel(".i")
}
subst := inlsubst{
- retlabel: retlabel,
- retvars: retvars,
- inlvars: inlvars,
- bases: make(map[*src.PosBase]*src.PosBase),
- newInlIndex: newIndex,
+ retlabel: retlabel,
+ retvars: retvars,
+ delayretvars: delayretvars,
+ inlvars: inlvars,
+ bases: make(map[*src.PosBase]*src.PosBase),
+ newInlIndex: newIndex,
}
body := subst.list(asNodes(fn.Func.Inl.Body))
// Temporary result variables.
retvars []*Node
+ // Whether result variables should be initialized at the
+ // "return" statement.
+ delayretvars bool
+
inlvars map[*Node]*Node
// bases maps from original PosBase to PosBase with an extra
as.List.Append(n)
}
as.Rlist.Set(subst.list(n.List))
+
+ if subst.delayretvars {
+ for _, n := range as.List.Slice() {
+ as.Ninit.Append(nod(ODCL, n, nil))
+ n.Name.Defn = as
+ }
+ }
+
as = typecheck(as, ctxStmt)
m.Ninit.Append(as)
}