Skip to content

Commit b0f8f6f

Browse files
authored
Merge pull request #613 from witheve/fix-not-without-dependencies
Fix not without dependencies
2 parents 3e5c0fa + 9fa3a19 commit b0f8f6f

File tree

2 files changed

+46
-4
lines changed

2 files changed

+46
-4
lines changed

src/runtime/join.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export interface ProposalProvider {
7171
// Check if a prefix of solved variables is a valid potential solution
7272
// for this provider. SolvingFor is used to ignore accept calls that
7373
// aren't related to variables the provider is solving for.
74-
accept(index: MultiIndex, prefix: any[], solvingFor: Variable, force?: boolean): boolean
74+
accept(index: MultiIndex, prefix: any[], solvingFor: Variable, force?: boolean, prejoin?: boolean): boolean
7575
}
7676

7777
//---------------------------------------------------------------------
@@ -497,8 +497,18 @@ export class NotScan {
497497
propose() { return; }
498498
resolveProposal() { throw new Error("Resolving a not proposal"); }
499499

500-
accept(multiIndex: MultiIndex, prefix, solvingFor, force?) {
501-
if(!force && !this.internalVars[solvingFor.id] && this.internalVars.length || !fullyResolved(this.args, prefix)) return true;
500+
accept(multiIndex: MultiIndex, prefix, solvingFor, force?, prejoin?) {
501+
// if we're in the prejoin phase and this not has no args, then we need
502+
// to evaluate the not to see if we should run. If we didn't do this, arg-less
503+
// nots won't get evaluated during Generic Join since we're never solving for a
504+
// variable that this scan cares about.
505+
if((!prejoin || this.args.length)
506+
// if we aren't forcing and not solving for the current variable, then we just accept
507+
// as it is
508+
&& (!force && !this.internalVars[solvingFor.id] && this.internalVars.length)
509+
// we also blind accept if we have args that haven't been filled in yet, as we don't
510+
// have the dependencies necessary to make a decision
511+
|| !fullyResolved(this.args, prefix)) return true;
502512
let resolved = this.resolve(prefix);
503513
let notPrefix = [];
504514
let ix = 0;
@@ -825,13 +835,22 @@ function preJoinAccept(multiIndex: MultiIndex, providers : ProposalProvider[], v
825835
if(value !== undefined && vars[ix] !== undefined) {
826836
presolved++;
827837
for(let provider of providers) {
828-
if(!provider.accept(multiIndex, prefix, solvingFor)) {
838+
if(!provider.accept(multiIndex, prefix, solvingFor, false, true)) {
829839
return {accepted: false, presolved};
830840
}
831841
}
832842
}
833843
ix++;
834844
}
845+
// we still need to do a single prejoin pass to make sure that any nots
846+
// that may have no external dependencies are given a chance to end this
847+
// evaluation
848+
let fakeVar = new Variable(0);
849+
for(let provider of providers) {
850+
if(provider instanceof NotScan && !provider.accept(multiIndex, prefix, fakeVar, false, true)) {
851+
return {accepted: false, presolved};
852+
}
853+
}
835854
return {accepted: true, presolved};
836855
}
837856

test/join.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2647,6 +2647,29 @@ test("not can't provide a variable for an attribute access", (assert) => {
26472647
assert.end();
26482648
})
26492649

2650+
test("not without dependencies filters correctly", (assert) => {
2651+
let expected = {
2652+
insert: [[1, "tag", "foo"]],
2653+
remove: [],
2654+
};
2655+
evaluate(assert, expected, `
2656+
add some stuff
2657+
~~~
2658+
commit
2659+
[#foo]
2660+
~~~
2661+
2662+
foo bar
2663+
~~~
2664+
search
2665+
not([#foo])
2666+
bind
2667+
[#bar]
2668+
~~~
2669+
`);
2670+
assert.end();
2671+
})
2672+
26502673

26512674
test("indirect constant equality in if", (assert) => {
26522675
let expected = {

0 commit comments

Comments
 (0)