about summary refs log tree commit diff
path: root/compiler/rustc_error_codes/src/error_codes/E0626.md
blob: 71c1f811aa7742ad67cdba2e64aa4dbbf224a016 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
This error occurs because a borrow in a movable coroutine persists across a
yield point.

Erroneous code example:

```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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`:

```
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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:

```
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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:

```compile_fail,E0626
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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:

```
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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:

```
# #![feature(coroutines, coroutine_trait, stmt_expr_attributes)]
# use std::ops::Coroutine;
# use std::pin::Pin;
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>.
```