]>
Commit | Line | Data |
---|---|---|
416331ca XL |
1 | // rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T` |
2 | // should act as assertion that item does not borrow from its stream; | |
3 | // but an earlier buggy rustc allowed `.map(|x: &_| x)` which does | |
4 | // have such an item. | |
5 | // | |
6 | // This tests double-checks that we do not allow such behavior to leak | |
7 | // through again. | |
8 | ||
9 | // revisions: migrate nll | |
10 | ||
11 | // Since we are testing nll (and migration) explicitly as a separate | |
12 | // revisions, don't worry about the --compare-mode=nll on this test. | |
13 | ||
14 | // ignore-compare-mode-nll | |
15 | // ignore-compare-mode-polonius | |
16 | ||
17 | //[nll]compile-flags: -Z borrowck=mir | |
18 | ||
f035d41b | 19 | pub trait Stream { |
416331ca XL |
20 | type Item; |
21 | fn next(self) -> Option<Self::Item>; | |
22 | } | |
23 | ||
24 | // Example stream | |
25 | pub struct Repeat(u64); | |
26 | ||
27 | impl<'a> Stream for &'a mut Repeat { | |
28 | type Item = &'a u64; | |
29 | fn next(self) -> Option<Self::Item> { | |
30 | Some(&self.0) | |
31 | } | |
32 | } | |
33 | ||
34 | pub struct Map<S, F> { | |
35 | stream: S, | |
36 | func: F, | |
37 | } | |
38 | ||
39 | impl<'a, A, F, T> Stream for &'a mut Map<A, F> | |
f035d41b XL |
40 | where |
41 | &'a mut A: Stream, | |
42 | F: FnMut(<&'a mut A as Stream>::Item) -> T, | |
416331ca XL |
43 | { |
44 | type Item = T; | |
45 | fn next(self) -> Option<T> { | |
46 | match self.stream.next() { | |
47 | Some(item) => Some((self.func)(item)), | |
48 | None => None, | |
49 | } | |
50 | } | |
51 | } | |
52 | ||
53 | pub struct Filter<S, F> { | |
54 | stream: S, | |
55 | func: F, | |
56 | } | |
57 | ||
58 | impl<'a, A, F, T> Stream for &'a mut Filter<A, F> | |
f035d41b XL |
59 | where |
60 | for<'b> &'b mut A: Stream<Item = T>, // <---- BAD | |
61 | F: FnMut(&T) -> bool, | |
416331ca XL |
62 | { |
63 | type Item = <&'a mut A as Stream>::Item; | |
64 | fn next(self) -> Option<Self::Item> { | |
65 | while let Some(item) = self.stream.next() { | |
66 | if (self.func)(&item) { | |
67 | return Some(item); | |
68 | } | |
69 | } | |
70 | None | |
71 | } | |
72 | } | |
73 | ||
f035d41b XL |
74 | pub trait StreamExt |
75 | where | |
76 | for<'b> &'b mut Self: Stream, | |
77 | { | |
78 | fn mapx<F>(self, func: F) -> Map<Self, F> | |
79 | where | |
80 | Self: Sized, | |
81 | for<'a> &'a mut Map<Self, F>: Stream, | |
416331ca | 82 | { |
f035d41b | 83 | Map { func: func, stream: self } |
416331ca XL |
84 | } |
85 | ||
f035d41b XL |
86 | fn filterx<F>(self, func: F) -> Filter<Self, F> |
87 | where | |
88 | Self: Sized, | |
89 | for<'a> &'a mut Filter<Self, F>: Stream, | |
416331ca | 90 | { |
f035d41b | 91 | Filter { func: func, stream: self } |
416331ca XL |
92 | } |
93 | ||
f035d41b XL |
94 | fn countx(mut self) -> usize |
95 | where | |
96 | Self: Sized, | |
416331ca XL |
97 | { |
98 | let mut count = 0; | |
99 | while let Some(_) = self.next() { | |
100 | count += 1; | |
101 | } | |
102 | count | |
103 | } | |
104 | } | |
105 | ||
f035d41b | 106 | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {} |
416331ca | 107 | |
f035d41b XL |
108 | fn identity<T>(x: &T) -> &T { |
109 | x | |
110 | } | |
111 | ||
112 | fn variant1() { | |
416331ca | 113 | let source = Repeat(10); |
f035d41b XL |
114 | |
115 | // Here, the call to `mapx` returns a type `T` to which `StreamExt` | |
116 | // is not applicable, because `for<'b> &'b mut T: Stream`) doesn't hold. | |
117 | // | |
118 | // More concretely, the type `T` is `Map<Repeat, Closure>`, and | |
119 | // the where clause doesn't hold because the signature of the | |
120 | // closure gets inferred to a signature like `|&'_ Stream| -> &'_` | |
121 | // for some specific `'_`, rather than a more generic | |
122 | // signature. | |
123 | // | |
124 | // Why *exactly* we opt for this signature is a bit unclear to me, | |
125 | // we deduce it somehow from a reuqirement that `Map: Stream` I | |
126 | // guess. | |
127 | let map = source.mapx(|x: &_| x); | |
128 | let filter = map.filterx(|x: &_| true); | |
129 | //[migrate]~^ ERROR no method named `filterx` | |
130 | //[nll]~^^ ERROR no method named `filterx` | |
416331ca | 131 | } |
f035d41b XL |
132 | |
133 | fn variant2() { | |
134 | let source = Repeat(10); | |
135 | ||
136 | // Here, we use a function, which is not subject to the vagaries | |
137 | // of closure signature inference. In this case, we get the error | |
138 | // on `countx` as, I think, the test originally expected. | |
139 | let map = source.mapx(identity); | |
140 | let filter = map.filterx(|x: &_| true); | |
141 | let count = filter.countx(); | |
142 | //[migrate]~^ ERROR no method named `countx` | |
143 | //[nll]~^^ ERROR no method named `countx` | |
144 | } | |
145 | ||
146 | fn main() {} |