diff --git a/mercurial/revset.py b/mercurial/revset.py
index a12d13eac5131c9aa33fbb5106daf8049624d261_bWVyY3VyaWFsL3JldnNldC5weQ==..5004ef47f437b3bafdd3800551c638a0bf4bb99b_bWVyY3VyaWFsL3JldnNldC5weQ== 100644
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -2423,6 +2423,9 @@
     elif op == 'list':
         ws, ts = zip(*(_optimize(y, small) for y in x[1:]))
         return sum(ws), (op,) + ts
+    elif op == 'keyvalue':
+        w, t = _optimize(x[2], small)
+        return w, (op, x[1], t)
     elif op == 'func':
         f = getsymbol(x[1])
         wa, ta = _optimize(x[2], small)
diff --git a/tests/test-revset.t b/tests/test-revset.t
index a12d13eac5131c9aa33fbb5106daf8049624d261_dGVzdHMvdGVzdC1yZXZzZXQudA==..5004ef47f437b3bafdd3800551c638a0bf4bb99b_dGVzdHMvdGVzdC1yZXZzZXQudA== 100644
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -470,6 +470,25 @@
   hg: parse error: can't use a key-value pair in this context
   [255]
 
+ right-hand side should be optimized recursively
+
+  $ try --optimize 'foo=(not public())'
+  (keyvalue
+    ('symbol', 'foo')
+    (group
+      (not
+        (func
+          ('symbol', 'public')
+          None))))
+  * optimized:
+  (keyvalue
+    ('symbol', 'foo')
+    (func
+      ('symbol', '_notpublic')
+      None))
+  hg: parse error: can't use a key-value pair in this context
+  [255]
+
 Test that symbols only get parsed as functions if there's an opening
 parenthesis.
 
@@ -1649,6 +1668,11 @@
   hg: parse error: topo.firstbranch can only be used when using the topo sort key
   [255]
 
+topo.firstbranch should accept any kind of expressions:
+
+  $ hg log -r 'sort(0, topo, topo.firstbranch=(book1))'
+  0 b12  m111 u112 111 10800
+
   $ cd ..
   $ cd repo