Email me

Rust errors / Ownership and borrowing

Rust compiler error · checked with rustc 1.99.0

Rust error E0626: this error occurs because a borrow in a movable coroutine persists across a yield point

What it meansThis error occurs because a borrow in a movable coroutine persists across a yield point.

E0626Ownership and borrowing
Activein rustc 1.99.0
8related errors linked below

The compiler team's explanation

This error occurs because a borrow in a movable coroutine persists across a yield point.

Erroneous code example:

let mut b = #[coroutine] || {
    let a = &String::new(); // <-- This borrow...
    yield (); // ...is still in scope here, when the yield occurs.
    println!("{}", a);
};
Pin::new(&mut b).resume(());

Coroutines may be either unmarked, or marked with static. If it is unmarked, then the coroutine is considered "movable". At present, it is not permitted to have a yield in a movable coroutine that occurs while a borrow is still in scope. To resolve this error, the coroutine may be marked static:

let mut b = #[coroutine] static || { // <-- note the static keyword
    let a = &String::from("hello, world");
    yield ();
    println!("{}", a);
};
let mut b = std::pin::pin!(b);
b.as_mut().resume(());

If the coroutine must remain movable, for example to be used as Unpin without pinning it on the stack or in an allocation, we can alternatively resolve the previous example by removing the borrow and just storing the type by value:

let mut b = #[coroutine] || {
    let a = String::from("hello, world");
    yield ();
    println!("{}", a);
};
Pin::new(&mut b).resume(());

This is a very simple case, of course. In more complex cases, we may wish to have more than one reference to the value that was borrowed -- in those cases, something like the Rc or Arc types may be useful.

This error also frequently arises with iteration:

let mut b = #[coroutine] || {
  let v = vec![1,2,3];
  for &x in &v { // <-- borrow of `v` is still in scope...
    yield x; // ...when this yield occurs.
  }
};
Pin::new(&mut b).resume(());

Such cases can sometimes be resolved by iterating "by value" (or using into_iter()) to avoid borrowing:

let mut b = #[coroutine] || {
  let v = vec![1,2,3];
  for x in v { // <-- Take ownership of the values instead!
    yield x; // <-- Now yield is OK.
  }
};
Pin::new(&mut b).resume(());

If taking ownership is not an option, using indices can work too:

let mut b = #[coroutine] || {
  let v = vec![1,2,3];
  let len = v.len(); // (*)
  for i in 0..len {
    let x = v[i]; // (*)
    yield x; // <-- Now yield is OK.
  }
};
Pin::new(&mut b).resume(());

// (*) -- Unfortunately, these temporaries are currently required.
// See <https://github.com/rust-lang/rust/issues/43122>.

From rustc --explain E0626 (1.99.0), part of the Rust project, MIT or Apache-2.0. Official page.

Related errors

All 518 Rust error codes · Rust crate data · Glossary

Up next

Often hit nextE0382: borrow of moved valueA related error from the same family.Read it next →

Did this answer your question?

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ