[PATCH 1 of 1 STABLE] revset: evaluate sub expressions correctly (issue3775)

FUJIWARA Katsunori foozy at lares.dti.ne.jp
Tue Jan 22 09:26:43 CST 2013


# HG changeset patch
# User FUJIWARA Katsunori <foozy at lares.dti.ne.jp>
# Date 1358868263 -32400
# Branch stable
# Node ID 379f6afd30a38198efad09becaf70f395fd5f108
# Parent  8a811fa9a9c0785b843e032ed82ce5316a645631
revset: evaluate sub expressions correctly (issue3775)

Before this patch, sub expression may return unexpected result, if it
is joined with another expression by "or":

  - "^"/parentspec():
    "R or R^1" is not equal to "R^1 or R". the former returns only "R".

  - "~"/ancestorspec():
    "R or R~1" is not equal to "R~1 or R". the former returns only "R".

  - ":"/rangeset():
    "10 or (10 or 15):" is not equal to "(10 or 15): or 10". the
    former returns only 10 and 15 or grater (11 to 14 are not
    included).

In "or"-ed expression "A or B", the "subset" passed to evaluation of
"B" doesn't contain revisions gotten from evaluation of "A", for
efficiency.

In the other hand, "stringset()" fails to look corresponding revision
for specified string/symbol up, if "subset" doesn't contain that
revision.

So, predicates looking revisions up indirectly should evaluate sub
expressions of themselves not with passed "subset" but with "entire
revisions in the repository", to prevent "stringset()" from unexpected
failing to look symbols in them up.

But predicates in above example don't so. For example, in the case of
"R or R^1":

  1. "R^1" is evaluated with "subset" containing revisions other than
     "R", because "R" is already gotten by the former of "or"-ed
     expressions

  2. "parentspec()" evaluates "R" of "R^1" with such "subset"

  3. "stringset()" fails to look "R" up, because "R" is not contained
     in "subset"

  4. so, evaluation of "R^1" returns no revision

This patch evaluates sub expressions for predicates above with "entire
revisions in the repository".

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -223,13 +223,9 @@
     return stringset(repo, subset, x)
 
 def rangeset(repo, subset, x, y):
-    m = getset(repo, subset, x)
-    if not m:
-        m = getset(repo, list(repo), x)
-
-    n = getset(repo, subset, y)
-    if not n:
-        n = getset(repo, list(repo), y)
+    cl = repo.changelog
+    m = getset(repo, cl, x)
+    n = getset(repo, cl, y)
 
     if not m or not n:
         return []
@@ -326,7 +322,7 @@
         raise error.ParseError(_("~ expects a number"))
     ps = set()
     cl = repo.changelog
-    for r in getset(repo, subset, x):
+    for r in getset(repo, cl, x):
         for i in range(n):
             r = cl.parentrevs(r)[0]
         ps.add(r)
@@ -1139,7 +1135,7 @@
         raise error.ParseError(_("^ expects a number 0, 1, or 2"))
     ps = set()
     cl = repo.changelog
-    for r in getset(repo, subset, x):
+    for r in getset(repo, cl, x):
         if n == 0:
             ps.add(r)
         elif n == 1:
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -758,6 +758,31 @@
   $ hg log -r "${ISSUE3669_TIP}^" --template '{rev}\n'
   8
 
+test or-ed indirect predicates (issue3775)
+
+  $ log '6 or 6^1' | sort
+  5
+  6
+  $ log '6^1 or 6' | sort
+  5
+  6
+  $ log '4 or 4~1' | sort
+  2
+  4
+  $ log '4~1 or 4' | sort
+  2
+  4
+  $ log '(6 or 8): or 6' | sort
+  6
+  7
+  8
+  9
+  $ log '6 or (6 or 8):' | sort
+  6
+  7
+  8
+  9
+
 tests for 'remote()' predicate:
 #.  (csets in remote) (id)            (remote)
 1.  less than local   current branch  "default"


More information about the Mercurial-devel mailing list