Repository: pest-parser/pest (language: rust)

Issue:
Stack overflow achieved with left recursion undetected
**Describe the bug**
Managed to create a stack overflow by avoiding the "anti-left-recursive" check. 

**To Reproduce**
 - Create a left-recursive grammar rule (e.g. `expr = { expr ~ infix ~ expr }`)
 - Add a predicate checking an obviously true (or obviously false) statement (e.g `expr = { !(EOI) ~ expr ~ infix ~ expr }`)
 - `pest_derive` does not trigger left-recursion, and let you construct a left-recursive parser.

**Expected behavior**
`pest-derive` should ignore predicates for checking left-recursion, since those don't consume any character.



Discussion / hints:
@Tartasprint was collecting these edge cases: https://github.com/pest-parser/pest/discussions/851

not sure if this one falls under examples there

I can give a look. Sorry I never finished what I started. To be honest I don't remember much, except I was pretty sure I documented all edge cases at the time. But I'll try again.

Fix patch:
diff --git a/meta/src/validator.rs b/meta/src/validator.rs
index eff89969..26ce300f 100644
--- a/meta/src/validator.rs
+++ b/meta/src/validator.rs
@@ -667,7 +667,13 @@ fn left_recursion<'a, 'i: 'a>(rules: HashMap<String, &'a ParserNode<'i>>) -> Vec
                 None
             }
             ParserExpr::Seq(ref lhs, ref rhs) => {
-                if is_non_failing(&lhs.expr, rules, &mut vec![trace.last().unwrap().clone()]) {
+                if is_non_failing(&lhs.expr, rules, &mut vec![trace.last().unwrap().clone()])
+                    || is_non_progressing(
+                        &lhs.expr,
+                        rules,
+                        &mut vec![trace.last().unwrap().clone()],
+                    )
+                {
                     check_expr(rhs, rules, trace)
                 } else {
                     check_expr(lhs, rules, trace)
@@ -1811,6 +1817,22 @@ mod tests {
     #[test]
     #[should_panic(expected = "grammar error
 
+ --> 1:14
+  |
+1 | a = { !\"a\" ~ a }
+  |              ^
+  |
+  = rule a is left-recursive (a -> a); pest::pratt_parser might be useful in this case")]
+    fn non_progressing_left_recursion() {
+        let input = "a = { !\"a\" ~ a }";
+        unwrap_or_report(consume_rules(
+            PestParser::parse(Rule::grammar_rules, input).unwrap(),
+        ));
+    }
+
+    #[test]
+    #[should_panic(expected = "grammar error
+
  --> 1:7
   |
 1 | a = { \"a\"* | \"a\" | \"b\" }


Test patch: