|
| 1 | +// These are some examples of iterating through and updating a mutable ref, similar in spirit to the |
| 2 | +// linked-list-like pattern of #46859/#48001 where the polonius alpha analysis shows imprecision, |
| 3 | +// unlike the datalog implementation. |
| 4 | +// |
| 5 | +// They differ in that after the loans prior to the loop are either not live after the loop, or with |
| 6 | +// control flow and outlives relationships that are simple enough for the reachability |
| 7 | +// approximation. They're thus accepted by the alpha analysis, like NLLs did for the simplest cases |
| 8 | +// of flow-sensitivity. |
| 9 | + |
| 10 | +//@ ignore-compare-mode-polonius (explicit revisions) |
| 11 | +//@ revisions: nll polonius legacy |
| 12 | +//@ [polonius] check-pass |
| 13 | +//@ [polonius] compile-flags: -Z polonius=next |
| 14 | +//@ [legacy] check-pass |
| 15 | +//@ [legacy] compile-flags: -Z polonius=legacy |
| 16 | + |
| 17 | +// The #46859 OP |
| 18 | +struct List<T> { |
| 19 | + value: T, |
| 20 | + next: Option<Box<List<T>>>, |
| 21 | +} |
| 22 | + |
| 23 | +fn to_refs<T>(mut list: &mut List<T>) -> Vec<&mut T> { |
| 24 | + let mut result = vec![]; |
| 25 | + loop { |
| 26 | + result.push(&mut list.value); |
| 27 | + if let Some(n) = list.next.as_mut() { |
| 28 | + list = n; |
| 29 | + } else { |
| 30 | + return result; |
| 31 | + } |
| 32 | + } |
| 33 | +} |
| 34 | + |
| 35 | +// A similar construction, where paths in the constraint graph are also clearly terminating, so it's |
| 36 | +// fine even for NLLs. |
| 37 | +fn to_refs2<T>(mut list: &mut List<T>) -> Vec<&mut T> { |
| 38 | + let mut result = vec![]; |
| 39 | + loop { |
| 40 | + result.push(&mut list.value); |
| 41 | + if let Some(n) = list.next.as_mut() { |
| 42 | + list = n; |
| 43 | + } else { |
| 44 | + break; |
| 45 | + } |
| 46 | + } |
| 47 | + |
| 48 | + result |
| 49 | +} |
| 50 | + |
| 51 | +// Another MCVE from the same issue, but was rejected by NLLs. |
| 52 | +pub struct Decoder { |
| 53 | + buf_read: BufRead, |
| 54 | +} |
| 55 | + |
| 56 | +impl Decoder { |
| 57 | + pub fn next<'a>(&'a mut self) -> &'a str { |
| 58 | + loop { |
| 59 | + let buf = self.buf_read.fill_buf(); |
| 60 | + //[nll]~^ ERROR cannot borrow `self.buf_read` as mutable more than once at a time |
| 61 | + if let Some(s) = decode(buf) { |
| 62 | + return s; |
| 63 | + } |
| 64 | + // loop to get more input data |
| 65 | + |
| 66 | + // At this point `buf` is not used anymore. |
| 67 | + // With NLL I would expect the borrow to end here, |
| 68 | + // such that `self.buf_read` is not borrowed anymore |
| 69 | + // by the time we start the next loop iteration. |
| 70 | + } |
| 71 | + } |
| 72 | +} |
| 73 | + |
| 74 | +struct BufRead; |
| 75 | + |
| 76 | +impl BufRead { |
| 77 | + fn fill_buf(&mut self) -> &[u8] { |
| 78 | + unimplemented!() |
| 79 | + } |
| 80 | +} |
| 81 | + |
| 82 | +fn decode(_: &[u8]) -> Option<&str> { |
| 83 | + unimplemented!() |
| 84 | +} |
| 85 | + |
| 86 | +fn main() {} |
0 commit comments