return n.Canonical().flags&nameByval != 0
}
+// CaptureName returns a Name suitable for referring to n from within function
+// fn or from the package block if fn is nil. If n is a free variable declared
+// within a function that encloses fn, then CaptureName returns a closure
+// variable that refers to n and adds it to fn.ClosureVars. Otherwise, it simply
+// returns n.
+func CaptureName(pos src.XPos, fn *Func, n *Name) *Name {
+ if n.IsClosureVar() {
+ base.FatalfAt(pos, "misuse of CaptureName on closure variable: %v", n)
+ }
+ if n.Op() != ONAME || n.Curfn == nil || n.Curfn == fn {
+ return n // okay to use directly
+ }
+ if fn == nil {
+ base.FatalfAt(pos, "package-block reference to %v, declared in %v", n, n.Curfn)
+ }
+
+ c := n.Innermost
+ if c != nil && c.Curfn == fn {
+ return c
+ }
+
+ // Do not have a closure var for the active closure yet; make one.
+ c = NewNameAt(pos, n.Sym())
+ c.Curfn = fn
+ c.Class = PAUTOHEAP
+ c.SetIsClosureVar(true)
+ c.Defn = n
+
+ // Link into list of active closure variables.
+ // Popped from list in FinishCaptureNames.
+ c.Outer = n.Innermost
+ n.Innermost = c
+ fn.ClosureVars = append(fn.ClosureVars, c)
+
+ return c
+}
+
+// FinishCaptureNames handles any work leftover from calling CaptureName
+// earlier. outerfn should be the function that immediately encloses fn.
+func FinishCaptureNames(pos src.XPos, outerfn, fn *Func) {
+ // closure-specific variables are hanging off the
+ // ordinary ones; see CaptureName above.
+ // unhook them.
+ // make the list of pointers for the closure call.
+ for _, cv := range fn.ClosureVars {
+ // Unlink from n; see comment in syntax.go type Param for these fields.
+ n := cv.Defn.(*Name)
+ n.Innermost = cv.Outer
+
+ // If the closure usage of n is not dense, we need to make it
+ // dense by recapturing n within the enclosing function.
+ //
+ // That is, suppose we just finished parsing the innermost
+ // closure f4 in this code:
+ //
+ // func f() {
+ // n := 1
+ // func() { // f2
+ // use(n)
+ // func() { // f3
+ // func() { // f4
+ // use(n)
+ // }()
+ // }()
+ // }()
+ // }
+ //
+ // At this point cv.Outer is f2's n; there is no n for f3. To
+ // construct the closure f4 from within f3, we need to use f3's
+ // n and in this case we need to create f3's n with CaptureName.
+ //
+ // We'll decide later in walk whether to use v directly or &v.
+ cv.Outer = CaptureName(pos, outerfn, n)
+ }
+}
+
// SameSource reports whether two nodes refer to the same source
// element.
//
p.funcBody(fn, expr.Body)
- // closure-specific variables are hanging off the
- // ordinary ones in the symbol table; see oldname.
- // unhook them.
- // make the list of pointers for the closure call.
- for _, v := range fn.ClosureVars {
- // Unlink from v1; see comment in syntax.go type Param for these fields.
- v1 := v.Defn
- v1.Name().Innermost = v.Outer
-
- // If the closure usage of v is not dense,
- // we need to make it dense; now that we're out
- // of the function in which v appeared,
- // look up v.Sym in the enclosing function
- // and keep it around for use in the compiled code.
- //
- // That is, suppose we just finished parsing the innermost
- // closure f4 in this code:
- //
- // func f() {
- // v := 1
- // func() { // f2
- // use(v)
- // func() { // f3
- // func() { // f4
- // use(v)
- // }()
- // }()
- // }()
- // }
- //
- // At this point v.Outer is f2's v; there is no f3's v.
- // To construct the closure f4 from within f3,
- // we need to use f3's v and in this case we need to create f3's v.
- // We are now in the context of f3, so calling oldname(v.Sym)
- // obtains f3's v, creating it if necessary (as it is in the example).
- //
- // capturevars will decide whether to use v directly or &v.
- v.Outer = oldname(v.Sym()).(*ir.Name)
- }
+ ir.FinishCaptureNames(base.Pos, ir.CurFunc, fn)
return clo
}
return ir.NewIdent(base.Pos, s)
}
- if ir.CurFunc != nil && n.Op() == ir.ONAME && n.Name().Curfn != nil && n.Name().Curfn != ir.CurFunc {
- // Inner func is referring to var in outer func.
- //
+ if n, ok := n.(*ir.Name); ok {
// TODO(rsc): If there is an outer variable x and we
// are parsing x := 5 inside the closure, until we get to
// the := it looks like a reference to the outer x so we'll
// make x a closure variable unnecessarily.
- n := n.(*ir.Name)
- c := n.Innermost
- if c == nil || c.Curfn != ir.CurFunc {
- // Do not have a closure var for the active closure yet; make one.
- c = typecheck.NewName(s)
- c.Class = ir.PAUTOHEAP
- c.SetIsClosureVar(true)
- c.Defn = n
-
- // Link into list of active closure variables.
- // Popped from list in func funcLit.
- c.Outer = n.Innermost
- n.Innermost = c
-
- ir.CurFunc.ClosureVars = append(ir.CurFunc.ClosureVars, c)
- }
-
- // return ref to closure var, not original
- return c
+ return ir.CaptureName(base.Pos, ir.CurFunc, n)
}
return n