changeset 12786:9aae04f4fcf6

revset: disable subset optimization for parents() and children() (issue2437) For the boolean operators, the subset optimization works by calculating the cheaper argument first, and passing the subset to the second argument to restrict the revision domain. This works well for filtering predicates. But parents() don't work like a filter: it may return revisions outside the specified set. So, combining it with boolean operators may easily yield incorrect results. For instance, for the following revision graph: 0 -- 1 the expression '0 and parents(1)' should evaluate as follows: 0 and parents(1) -> 0 and 0 -> 0 But since [0] is passed to parents() as a subset, we get instead: 0 and parents(1 and 0) -> 0 and parents([]) -> 0 and [] -> [] This also affects children(), p1() and p2(), for the same reasons. Predicates that call these (like heads()) are also affected. We work around this issue by ignoring the subset when propagating the call inside those predicates.
author Wagner Bruna <wbruna@yahoo.com>
date Fri, 15 Oct 2010 03:30:38 -0300
parents c7d23b4ca4ba
children e8a8993b625e
files mercurial/revset.py tests/test-revset.t
diffstat 2 files changed, 21 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revset.py	Wed Oct 20 14:57:36 2010 -0500
+++ b/mercurial/revset.py	Fri Oct 15 03:30:38 2010 -0300
@@ -193,21 +193,21 @@
 def p1(repo, subset, x):
     ps = set()
     cl = repo.changelog
-    for r in getset(repo, subset, x):
+    for r in getset(repo, range(len(repo)), x):
         ps.add(cl.parentrevs(r)[0])
     return [r for r in subset if r in ps]
 
 def p2(repo, subset, x):
     ps = set()
     cl = repo.changelog
-    for r in getset(repo, subset, x):
+    for r in getset(repo, range(len(repo)), x):
         ps.add(cl.parentrevs(r)[1])
     return [r for r in subset if r in ps]
 
 def parents(repo, subset, x):
     ps = set()
     cl = repo.changelog
-    for r in getset(repo, subset, x):
+    for r in getset(repo, range(len(repo)), x):
         ps.update(cl.parentrevs(r))
     return [r for r in subset if r in ps]
 
@@ -238,7 +238,7 @@
 def children(repo, subset, x):
     cs = set()
     cl = repo.changelog
-    s = set(getset(repo, subset, x))
+    s = set(getset(repo, range(len(repo)), x))
     for r in xrange(0, len(repo)):
         for p in cl.parentrevs(r):
             if p in s:
--- a/tests/test-revset.t	Wed Oct 20 14:57:36 2010 -0500
+++ b/tests/test-revset.t	Fri Oct 15 03:30:38 2010 -0300
@@ -339,3 +339,20 @@
   0
   $ log '4::8 - 8'
   4
+
+issue2437
+
+  $ log '3 and p1(5)'
+  3
+  $ log '4 and p2(6)'
+  4
+  $ log '1 and parents(:2)'
+  1
+  $ log '2 and children(1:)'
+  2
+  $ log 'roots(all()) or roots(all())'
+  0
+  $ log 'heads(branch(é)) or heads(branch(é))'
+  9
+  $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
+  4