[Solved] Can not return ref to temporary

#1
  1. This code compiles:
use combine_language::LanguageEnv;
use combine::stream::easy;
use combine::choice;
use combine::parser::Parser;
use crate::parser::MyParser;
use combine::parser::combinator::no_partial;



pub struct FooParser<'a> {
    env: LanguageEnv<'a, easy::Stream<&'a str>>, //  = unimplemented!();
}

/*
impl <'a> FooParser<'a> {
    pub fn bad(&'a self) -> impl Parser<Input=easy::Stream<&'a str>, Output=String, PartialState=()> {
        let mut rops = "1 2 3 4 5 6 7 8"
            .split_whitespace()
            .map(|s: &str| self.env.reserved_op(s))
            .collect::<Vec<_>>();

        let t = choice(rops.as_mut_slice())
            .map(|s: &str| s.to_string()) ;

        return no_partial(t);
    }
}
*/

pub fn good<'a>() -> impl Parser<Input=easy::Stream<&'a str>, Output=String, PartialState=()> {
    let env: LanguageEnv<'a, easy::Stream<&'a str>> = unimplemented!();
    let mut rops = "1 2 3 4 5 6 7 8"
        .split_whitespace()
        .map(|s: &str| env.reserved_op(s))
        .collect::<Vec<_>>();

    let t = choice(rops.as_mut_slice())
        .map(|s: &str| s.to_string()) ;

    return no_partial(t);
}
  1. If we uncomment the impl FooParser part, it fails to compile Complaining:
   |
21 |         let t = choice(rops.as_mut_slice())
   |                        ---- `rops` is borrowed here
...
24 |         return no_partial(t);
   |                ^^^^^^^^^^^^^ returns a value referencing data owned by the current function
  1. Here is what is confusing me: 1. the choice function does NOT want to take Vec as an argument. It actually wants a mut slice. 2. The “good” function is identical to be bad function, except that it is not part of a struct FooParser.

  2. What is going on?

0 Likes

#2

The “good” function won’t compile either if you change the unimplemented! into something that actually returns. It’s only compiling now because the compiler sees that it always panics, so the problematic parts of the function are unreachable.

Perhaps the combine crate could be extended in a future version to allow choice to take an owned Vec. Until then, you could use an array instead, though it’s not quite as convenient to initialize:

    pub fn f(&'a self) -> impl Parser<Input=easy::Stream<&'a str>, Output=String, PartialState=()> {
        let rops = [
            self.env.reserved_op("1"),
            self.env.reserved_op("2"),
            self.env.reserved_op("3"),
            self.env.reserved_op("4"),
            self.env.reserved_op("5"),
            self.env.reserved_op("6"),
            self.env.reserved_op("7"),
            self.env.reserved_op("8"),
        ];

        let t = choice(rops).map(|s: &str| s.to_string()) ;

        no_partial(t)
    }
1 Like

#3

Wow, I did not expect rustc to be this clever. Thanks for explaining.

0 Likes