polonius_the_crab

Macro polonius_break_dependent

Source
macro_rules! polonius_break_dependent {
    ( $e:expr $(,)? ) => { ... };
}
Expand description

break a dependent value out of a polonius_loop!.

To be used in conjunction with a polonius_loop!(|var| -> …, break: … { invocation.

  • If the , break: … type annotation is forgotten, then invocations to polonius_break_dependent! will fail with an error message complaining about cannot_use__polonius_break_dependentǃ__without_a_break_type_annotation_on__polonius_loopǃ

§Example

  • use {
        ::std::{
            collections::HashMap,
        },
        ::polonius_the_crab::{
            *,
        },
    };
    
    fn example (mut map: &'_ mut HashMap<u8, i32>)
    {
        let mut i = 0;
        //                              needed for `polonius_break_dependent!` to work.
        //                                   vvvvvvvvvvvvvvvvvvvvvvvvvvv
        let entry = polonius_loop!(|map| -> _, break: &'polonius mut i32 {
        //                                             ^^^^^^^^^
        //                                          don't forget the special annotation PoloniusResult.
            if let Some(entry) = map.get_mut(&i) {
                polonius_break_dependent!(entry);
            }
            i += 1;
        });
        // `map` was consumed by the loop, and is thus unusable.
        // But the `break_dependent!`-yielded items is allowed to still be
        // borrowing it.
        *entry = 0;
    }

Now let’s compare it to what happens when polonius_break! is (incorrectly) used in its stead:

§Incorrect usage

The following fails to compile:

  • use {
        ::std::{
            collections::HashMap,
        },
        ::polonius_the_crab::{
            *,
        },
    };
    
    fn example (mut map: &'_ mut HashMap<u8, i32>)
    {
        let mut i = 0;
        let entry = polonius_loop!(|map| -> _ {
            if let Some(entry) = map.get_mut(&i) {
                polonius_break!(entry);
            }
            i += 1;
        });
        *entry = 0;
    }

    with the following error message:

    error: lifetime may not live long enough
      --> src/lib.rs:467:13
       |
    16 |       let entry = polonius_loop!(|map| -> _ {
       |  _________________-
    17 | |         if let Some(entry) = map.get_mut(&i) {
    18 | |             polonius_break!(entry);
       | |             ^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
    19 | |         }
    20 | |         i += 1;
    21 | |     });
       | |      -
       | |      |
       | |______let's call the lifetime of this reference `'1`
       |        return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>

    Using RUSTC_BOOTSTRAP=1 cargo rustc --profile-check -- -Zmacro-backtrace to “improve” the error message, we can get:

    error: lifetime may not live long enough
       --> polonius-the-crab/src/lib.rs:442:12
        |
    351 |                    |mut $var: &mut _| {
        |                               -     - return type of closure is Result<Dependent<()>, ControlFlow<&'2 mut i32>>
        |                               |
        |                               let's call the lifetime of this reference `'1`
    ...
    441 |  / macro_rules! polonius_break {( $($e:expr $(,)?)? ) => (
    442 |  |     return $crate::ඞ::core::result::Result::Err(
        |  |____________^
    443 | ||         $crate::ඞ::core::ops::ControlFlow::Break(
    444 | ||             ($($e ,)? () ,).0
    445 | ||         )
    446 | ||     )
        | ||_____^ returning this value requires that `'1` must outlive `'2`
    447 |  | )}
        |  |__- in this expansion of `polonius_break!`
        |
       ::: src/lib.rs:552:13
        |
    18  |                polonius_break!(entry);
        |                ----------------------- in this macro invocation

Which may be a bit better at hinting that we have a borrowing problem with polonius_break!, whereby the returned value cannot reach some borrowing / lifetime requirements (those stemming from an actually-dependent break value).