0

I am trying to make my own programming language in rust, and most features are done, so I thought I could add to the UnknownIdentifier error the ability to find the closest match to whatever the user wanted

However before I even got to finding the closest match I found out that cloning HashMap<String, Object> moves it into the closure

ErrorGenerator::error function:

#[allow(non_snake_case)]
mod ErrorGenerator {
    pub fn error(name: &str, explanation: &str, line: usize, col: usize, file: String, after_f: Box<dyn Fn() -> ()>) -> ! {
        eprintln!("\n[ERROR] {}, Line {:?}, Column {:?}", file, line, col);
        eprintln!("    {}: {}", name, explanation);
        after_f();
        exit(1);
    }
}
ErrorGenerator::error(
    "UnknownIdentifier",
    &format!("unknown identifier: `{}`, this identifier could not be found", tokenc.repr()),
    tokenc.line,
    tokenc.col,
    tokenc.file,
    Box::new(||{
        let mut hashc: Vec<String> = hashs.clone().into_keys().collect();
        hashc.sort();
    }),
);

This is the error it gives:

error[E0597]: `hashs` does not live long enough
    --> src/runtime/runtime.rs:960:70
     |
959  |                                       Box::new(||{
     |                                       -        -- value captured here
     |  _____________________________________|
     | |
960  | |                                         let mut hashc: Vec<String> = hashs.clone().into_keys().collect();
     | |                                                                      ^^^^^ borrowed value does not live long enough
961  | |                                         hashc.sort();
962  | |                                     }),
     | |______________________________________- cast requires that `hashs` is borrowed for `'static`
...
1203 |       }
     |       - `hashs` dropped here while still borrowed

The problem's solution is probably either:

  • A way to borrow in 'static lifetime a mutable variable created in a method into a closure or
  • A way to clone HashMap<String, Object> without moving it into the closure

You can find the full code in https://github.com/kaiserthe13th/tr-lang/tree/unknown-id-err-impl

1 Answer 1

3

What happens is that the compiler doesn't clone hashs then passes the clone to your callback; instead, it passes a reference to hashs to your callback and clones it inside the callback.

However, the callback is required to be 'static, and if it holds a reference to the containing function it is not! So the compiler is complaining.

What you want is to clone the hashmap before, then pass the clone to the callback. Like:

ErrorGenerator::error(
    "UnknownIdentifier",
    &format!("unknown identifier: `{}`, this identifier could not be found", tokenc.repr()),
    tokenc.line,
    tokenc.col,
    tokenc.file,
    {
        let hashc = hashs.clone();
        Box::new(|| {
            let mut hashc: Vec<String> = hashc.into_keys().collect();
            hashc.sort();
        })
    },
);

If you'll do that, you'll also recognize that the closure needs to be FnOnce() since you're moving out of hashc (.into_keys()). So after_f: Box<dyn FnOnce()>.

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot, I tried the same but without FnOnce, because I am not familiar enough with closures I guess
I'll put you in the thanks section of the project
This answer looks good. A nitty thing is cloning HashMap will clone its keys, values and hasher. That might not be efficient if what you need is the clone of the keys. I think you can clone the keys directly, instead of the hashmap, and move the cloned keys to the closure. With that, FnOnce will not be required.
@Joe_Jingyu Yes, you're right, but I perhaps the OP needs to perform more work with the hashmap so I just answered the question. If not, a better usage will be to do outside the closure let hashc: Vec<String> = hashs.keys().cloned().collect();.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.