Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

free after value resolution #335

Merged
merged 2 commits into from Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/module.js
Expand Up @@ -56,10 +56,15 @@ async function module_value(name) {
var v = this._scope.get(name);
if (!v) throw new RuntimeError(name + " is not defined");
if (v._observer === no_observer) {
v._observer = true;
this._runtime._dirty.add(v);
v = this.variable(true).define([name], identity);
try {
return await module_revalue(this._runtime, v);
} finally {
v.delete();
}
} else {
return module_revalue(this._runtime, v);
}
return module_revalue(this._runtime, v);
}

// If the variable is redefined before its value resolves, try again.
Expand Down
33 changes: 33 additions & 0 deletions test/module/value-test.js
Expand Up @@ -115,3 +115,36 @@ tape("module.value(name) does not force recomputation", async test => {
test.deepEqual(await module.value("foo"), 1);
test.deepEqual(await module.value("foo"), 1);
});

tape("module.value(name) does not expose stale values", async test => {
const runtime = new Runtime();
const module = runtime.module();
let resolve;
const variable = module.define("foo", [], new Promise((y) => (resolve = y)));
const value = module.value("foo");
await new Promise((resolve) => setTimeout(resolve, 100));
variable.define("foo", [], () => "fresh");
resolve("stale");
test.strictEqual(await value, "fresh");
});

tape("module.value(name) does not continue observing", async test => {
const foos = [];
const runtime = new Runtime();
const module = runtime.module();
module.define("foo", [], async function*() {
try {
foos.push(1), yield 1;
foos.push(2), yield 2;
foos.push(3), yield 3;
} finally {
foos.push(-1);
}
});
test.strictEqual(await module.value("foo"), 1);
test.deepEqual(foos, [1]);
await runtime._compute();
test.deepEqual(foos, [1, 2, -1]); // 2 computed prior to being unobserved
await runtime._compute();
test.deepEqual(foos, [1, 2, -1]); // any change would represent a leak
});