Skip to content

Commit 0b8fa04

Browse files
committed
add some test cases for instance of NLL problem case 3
That includes a filtering lending iterator using GATs from 92985 but it still is not enough to make it practical for real world use due to other GATs limitations.
1 parent 1ee67b5 commit 0b8fa04

File tree

2 files changed

+299
-0
lines changed

2 files changed

+299
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// This test is an example of a filtering lending iterator with GATs from #92985 (that is similar to
2+
// NLL problem case #3) to ensure it "works" with the polonius alpha analysis as with the datalog
3+
// implementation.
4+
//
5+
// The polonius analysis only changes how the `Filter::next` function is borrowcked, not the bounds
6+
// on the predicate from using the GAT. So even if the #92985 limitation is removed, the unrelated
7+
// 'static limitation on the predicate argument is still there, and the pattern is still impractical
8+
// to use in the real world.
9+
10+
//@ edition: 2021
11+
//@ check-pass
12+
//@ ignore-compare-mode-polonius (explicit revisions)
13+
//@ revisions: polonius legacy
14+
//@ [polonius] compile-flags: -Z polonius=next
15+
//@ [legacy] compile-flags: -Z polonius=legacy
16+
17+
trait LendingIterator {
18+
type Item<'a>
19+
where
20+
Self: 'a;
21+
fn next(&mut self) -> Option<Self::Item<'_>>;
22+
23+
fn filter<P>(self, predicate: P) -> Filter<Self, P>
24+
where
25+
Self: Sized,
26+
P: FnMut(&Self::Item<'_>) -> bool,
27+
{
28+
Filter { iter: self, predicate }
29+
}
30+
}
31+
32+
pub struct Filter<I, P> {
33+
iter: I,
34+
predicate: P,
35+
}
36+
impl<I: LendingIterator, P> LendingIterator for Filter<I, P>
37+
where
38+
P: FnMut(&I::Item<'_>) -> bool,
39+
{
40+
type Item<'a>
41+
= I::Item<'a>
42+
where
43+
Self: 'a;
44+
45+
fn next(&mut self) -> Option<I::Item<'_>> {
46+
while let Some(item) = self.iter.next() {
47+
if (self.predicate)(&item) {
48+
return Some(item);
49+
}
50+
}
51+
return None;
52+
}
53+
}
54+
55+
fn main() {}
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
// This is a collection of regression tests related to the NLL problem case 3 that was deferred from
2+
// the implementation of the NLL RFC, and left to be implemented by polonius. Most of them are from
3+
// open issues, e.g. tagged fixed-by-polonius, to ensure that the polonius alpha analysis does
4+
// handle them, as does the datalog implementation.
5+
6+
//@ check-pass
7+
//@ ignore-compare-mode-polonius (explicit revisions)
8+
//@ revisions: polonius legacy
9+
//@ [polonius] compile-flags: -Z polonius=next
10+
//@ [legacy] compile-flags: -Z polonius=legacy
11+
12+
use std::collections::HashMap;
13+
use std::hash::Hash;
14+
15+
fn from_the_rfc<'r, K: Hash + Eq + Copy, V: Default>(
16+
map: &'r mut HashMap<K, V>,
17+
key: K,
18+
) -> &'r mut V {
19+
match map.get_mut(&key) {
20+
Some(value) => value,
21+
None => {
22+
map.insert(key, V::default());
23+
map.get_mut(&key).unwrap()
24+
}
25+
}
26+
}
27+
28+
fn issue_112087<'a>(opt: &'a mut Option<i32>, b: bool) -> Result<&'a mut Option<i32>, &'a mut i32> {
29+
if let Some(v) = opt {
30+
if b {
31+
return Err(v);
32+
}
33+
}
34+
35+
*opt = None;
36+
return Ok(opt);
37+
}
38+
39+
// issue 54663
40+
fn foo(x: &mut u8) -> Option<&u8> {
41+
if let Some(y) = bar(x) {
42+
return Some(y);
43+
}
44+
bar(x)
45+
}
46+
47+
fn bar(x: &mut u8) -> Option<&u8> {
48+
Some(x)
49+
}
50+
51+
// issue 123839
52+
struct Foo {
53+
val: i32,
54+
status: i32,
55+
err_str: String,
56+
}
57+
58+
impl Foo {
59+
fn bar(self: &mut Self) -> Result<(), &str> {
60+
if self.val == 0 {
61+
self.status = -1;
62+
Err("val is zero")
63+
} else if self.val < 0 {
64+
self.status = -2;
65+
self.err_str = format!("unexpected negative val {}", self.val);
66+
Err(&self.err_str)
67+
} else {
68+
Ok(())
69+
}
70+
}
71+
fn foo(self: &mut Self) -> Result<(), &str> {
72+
self.bar()?; // rust reports this line conflicts with the next line
73+
self.status = 1; // and this line is the victim
74+
Ok(())
75+
}
76+
}
77+
78+
// issue 124070
79+
struct S {
80+
field: String,
81+
}
82+
83+
impl S {
84+
fn f(&mut self) -> &str {
85+
let a = &mut self.field;
86+
87+
if false {
88+
return a;
89+
}
90+
91+
return &self.field;
92+
}
93+
}
94+
95+
// issue 124254
96+
fn find_lowest_or_first_empty_pos(list: &mut [Option<u8>]) -> &mut Option<u8> {
97+
let mut low_pos_val: Option<(usize, u8)> = None;
98+
for (idx, i) in list.iter_mut().enumerate() {
99+
let Some(s) = i else {
100+
return i;
101+
};
102+
103+
low_pos_val = match low_pos_val {
104+
Some((_oidx, oval)) if oval > *s => Some((idx, *s)),
105+
Some(old) => Some(old),
106+
None => Some((idx, *s)),
107+
};
108+
}
109+
let Some((lowest_idx, _)) = low_pos_val else {
110+
unreachable!("Can't have zero length list!");
111+
};
112+
&mut list[lowest_idx]
113+
}
114+
115+
fn issue_124254() {
116+
let mut list = [Some(1), Some(2), None, Some(3)];
117+
let v = find_lowest_or_first_empty_pos(&mut list);
118+
assert!(v.is_none());
119+
assert_eq!(v as *mut _ as usize, list.as_ptr().wrapping_add(2) as usize);
120+
121+
let mut list = [Some(1), Some(2), Some(3), Some(0)];
122+
let v = find_lowest_or_first_empty_pos(&mut list);
123+
assert_eq!(v, &mut Some(0));
124+
assert_eq!(v as *mut _ as usize, list.as_ptr().wrapping_add(3) as usize);
125+
126+
println!("pass");
127+
}
128+
129+
// issue 21906
130+
struct A {
131+
a: i32,
132+
}
133+
134+
impl A {
135+
fn one(&mut self) -> &i32 {
136+
self.a = 10;
137+
&self.a
138+
}
139+
fn two(&mut self) -> &i32 {
140+
loop {
141+
let k = self.one();
142+
if *k > 10i32 {
143+
return k;
144+
}
145+
}
146+
}
147+
}
148+
149+
// issue 51545
150+
fn borrow(o: &mut Option<i32>) -> Option<&mut i32> {
151+
match o.as_mut() {
152+
Some(i) => Some(i),
153+
None => o.as_mut(),
154+
}
155+
}
156+
157+
// issue 58787
158+
159+
struct Node {
160+
rest: List,
161+
}
162+
163+
struct List(Option<Box<Node>>);
164+
165+
fn issue_58787(arg: &mut List) {
166+
let mut list = arg;
167+
168+
match list.0 {
169+
Some(ref mut d) => {
170+
if true {
171+
list = &mut d.rest;
172+
}
173+
}
174+
None => (),
175+
}
176+
177+
match list.0 {
178+
Some(ref mut d) => {
179+
list = &mut d.rest;
180+
}
181+
None => (),
182+
}
183+
184+
match list {
185+
List(Some(d)) => {
186+
if true {
187+
list = &mut d.rest;
188+
}
189+
}
190+
List(None) => (),
191+
}
192+
193+
match list {
194+
List(Some(d)) => {
195+
list = &mut d.rest;
196+
}
197+
List(None) => (),
198+
}
199+
200+
match &mut list.0 {
201+
Some(d) => {
202+
if true {
203+
list = &mut d.rest;
204+
}
205+
}
206+
None => (),
207+
}
208+
209+
match &mut list.0 {
210+
Some(d) => {
211+
list = &mut d.rest;
212+
}
213+
None => (),
214+
}
215+
216+
list.0 = None;
217+
}
218+
219+
// issue 68934
220+
enum Either<A,B> {
221+
Left(A),
222+
Right(B)
223+
}
224+
225+
enum Tree<'a, A, B> {
226+
ALeaf(A),
227+
BLeaf(B),
228+
ABranch(&'a mut Tree<'a, A, B>, A),
229+
BBranch(&'a mut Tree<'a, A, B>, B)
230+
}
231+
232+
impl<'a, A: PartialOrd, B> Tree<'a, A ,B> {
233+
fn deep_fetch(&mut self, value: Either<A, B>) -> Result<&mut Self, (&mut Self, Either<A,B>)> {
234+
match (self, value) {
235+
(Tree::ABranch(ref mut a, ref v), Either::Left(vv)) if v > &vv => {
236+
a.deep_fetch(Either::Left(vv))
237+
}
238+
239+
(this, _v) => Err((this, _v))
240+
}
241+
}
242+
}
243+
244+
fn main() {}

0 commit comments

Comments
 (0)