Repository: Geal/nom
Pull request #502 (2017-05-03 18:51:17)

Make `named_args!` input slice lifetime hopefully different from provided lifetime
At current, `named_args!(foo<'a>(thing: &mut 'a Whatever)<Something>, ...);` generates code which looks something like:

```rust
fn foo<'a>(input: &'a [u8], thing: &mut 'a Whatever) -> IResult<&'a [u8], Something> {...}
```

But when used with `manyn!` or `fold_manyn!`, we end up with an error:

```rust
named_args!(atom<'a>(tomb: &'a mut ())<String>,
            map!(map_res!(is_not_s!(" \t\r\n()"), str::from_utf8), ToString::to_string));


named_args!(list<'a>(tomb: &'a mut ())<String>,
            delimited!(char!('('), fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()), char!(')')));
```

The above code complains that `tomb` is being reborrowed. This is because as far as Rust knows, the mutable borrow on `'a` extends past the use of the mutable reference (because the `input` slice lives on with the same lifetime as the mutable reference which is no longer in use.) This PR changes `named_args!` such that it generates code like this instead:

```rust
fn foo<'this_is_probably_unique_i_hope_please, 'a>(input: &'this_is_probably_unique_i_hope_please [u8], thing: &mut 'a Whatever) -> IResult<&'this_is_probably_unique_i_hope_please [u8], Something> {...}
```

I have to admit this is a total hack, but it works and I don't have a better solution. A test is included with this PR which compiles with the change.


Patch:
diff --git a/src/macros.rs b/src/macros.rs
index 5b35645..0cf92c2 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -168,7 +168,7 @@ macro_rules! named_args {
         }
     };
     (pub $func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
-        pub fn $func_name<'a>(input: &'a [u8], $( $arg : $typ ),*) -> $crate::IResult<&'a [u8], $return_type> {
+        pub fn $func_name<'this_is_probably_unique_i_hope_please, 'a>(input: &'this_is_probably_unique_i_hope_please [u8], $( $arg : $typ ),*) -> $crate::IResult<&'this_is_probably_unique_i_hope_please [u8], $return_type> {
             $submac!(input, $($args)*)
         }
     };
@@ -178,7 +178,7 @@ macro_rules! named_args {
         }
     };
     ($func_name:ident < 'a > ( $( $arg:ident : $typ:ty ),* ) < $return_type:ty > , $submac:ident!( $($args:tt)* ) ) => {
-        fn $func_name<'a>(input: &'a [u8], $( $arg : $typ ),*) -> $crate::IResult<&'a [u8], $return_type> {
+        fn $func_name<'this_is_probably_unique_i_hope_please, 'a>(input: &'this_is_probably_unique_i_hope_please [u8], $( $arg : $typ ),*) -> $crate::IResult<&'this_is_probably_unique_i_hope_please [u8], $return_type> {
             $submac!(input, $($args)*)
         }
     };


Test patch:
diff --git a/tests/reborrow_fold.rs b/tests/reborrow_fold.rs
new file mode 100644
index 0000000..0527cb2
--- /dev/null
+++ b/tests/reborrow_fold.rs
@@ -0,0 +1,16 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+
+#[macro_use]
+extern crate nom;
+
+use std::str;
+
+
+named_args!(atom<'a>(tomb: &'a mut ())<String>,
+            map!(map_res!(is_not_s!(" \t\r\n()"), str::from_utf8), ToString::to_string));
+
+
+named_args!(list<'a>(tomb: &'a mut ())<String>,
+            delimited!(char!('('), fold_many0!(call!(atom, tomb), "".to_string(), |acc: String, next: String| acc + next.as_str()), char!(')')));