Open
Description
Turns out that stacked borrows and self-referential generators don't go well together. This code fails in Miri:
#![feature(generators, generator_trait)]
use std::{
ops::{Generator, GeneratorState},
pin::Pin,
};
fn firstn() -> impl Generator<Yield = u64, Return = ()> {
static move || {
let mut num = 0;
let num = &mut num;
yield *num;
*num += 1; //~ ERROR: borrow stack
yield *num;
*num += 1;
yield *num;
*num += 1;
}
}
fn main() {
let mut generator_iterator = firstn();
let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) };
let mut sum = 0;
while let GeneratorState::Yielded(x) = pin.as_mut().resume() {
sum += x;
}
println!("{}", sum);
}
The reason it fails is that each time through the loop, we call Pin::as_mut
, which creates a fresh mutable reference to the generator. Since mutable references are unique, that invalidates the pointer that points from one field of the generator to another.
This is basically a particularly bad instance of #133.