Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

p_closurecap.gno

2.24 Kb · 60 lines
 1// Package p_closurecap exercises the "var stopped bool in
 2// memberStorage.IterateByOffset" pattern from boards2/commondao:
 3// a method declares a local var that an inline closure captures and
 4// writes to. Without the unreal-HIV exception in the readonly check,
 5// this failed across borrow-realm transitions because the HIV's PkgID
 6// stamp records the alloc-site realm, but the closure body may run
 7// under a different borrowed realm — the check would fire on a write
 8// the closure itself made to its own captured slot.
 9package p_closurecap
10
11// Inner is the receiver of loop(). When Inner lives in a different
12// realm than the Outer-method's caller realm, PushFrameCall's borrow
13// rule 2 shifts m.Realm to Inner's realm for the entire body of loop()
14// (and the synchronously-invoked closure). That shift is what makes
15// HIV.PkgID (stamped at var stopped's alloc) differ from m.Realm at
16// the closure's write site.
17type Inner struct {
18	N int
19}
20
21// Outer is the var-stopped pattern. The inline closure captures
22// `stopped` and writes to it. Returns true if `fn` ever returned true.
23//
24// The key shape: Outer is a top-level /p/ func (no receiver, so no
25// borrow on entry — HIV stamps with caller's realm), but it delegates
26// to `inn.loop(...)`, where `inn` is supplied by the caller and may
27// live in a different realm. inn.loop's borrow flips m.Realm to inn's
28// realm; the inline closure then writes to `stopped` under that
29// borrowed realm.
30func Outer(inn *Inner, count int, fn func(i int) bool) bool {
31	var stopped bool
32	inn.loop(count, func(i int) bool {
33		stopped = fn(i)
34		return stopped
35	})
36	return stopped
37}
38
39// loop is a /p/ method on *Inner. As a receiver-method on a /p/ type,
40// PushFrameCall's borrow rule 2 fires here: m.Realm becomes
41// Inner.PkgID's realm for the duration of loop().
42func (in *Inner) loop(count int, cb func(i int) bool) {
43	for i := 0; i < count; i++ {
44		if cb(i) {
45			return
46		}
47	}
48}
49
50// MakeCounter returns a closure that captures a local int. The
51// returned closure can be stored in /r/ state — verifying that a
52// persisted closure-capture HIV (whose FuncLit lives in /p/) is still
53// writable when invoked from a foreign realm context.
54func MakeCounter(start int) func() int {
55	c := start
56	return func() int {
57		c++
58		return c
59	}
60}