Skip to content

Commit a08a5cc

Browse files
committed
Regression test for issue 30786.
1 parent 909f5a0 commit a08a5cc

File tree

2 files changed

+116
-0
lines changed

2 files changed

+116
-0
lines changed

src/test/ui/hrtb/issue-30786.rs

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
pub trait Stream {
10+
type Item;
11+
fn next(self) -> Option<Self::Item>;
12+
}
13+
14+
// Example stream
15+
pub struct Repeat(u64);
16+
17+
impl<'a> Stream for &'a mut Repeat {
18+
type Item = &'a u64;
19+
fn next(self) -> Option<Self::Item> {
20+
Some(&self.0)
21+
}
22+
}
23+
24+
pub struct Map<S, F> {
25+
stream: S,
26+
func: F,
27+
}
28+
29+
impl<'a, A, F, T> Stream for &'a mut Map<A, F>
30+
where &'a mut A: Stream,
31+
F: FnMut(<&'a mut A as Stream>::Item) -> T,
32+
{
33+
type Item = T;
34+
fn next(self) -> Option<T> {
35+
match self.stream.next() {
36+
Some(item) => Some((self.func)(item)),
37+
None => None,
38+
}
39+
}
40+
}
41+
42+
pub struct Filter<S, F> {
43+
stream: S,
44+
func: F,
45+
}
46+
47+
impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
48+
where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
49+
F: FnMut(&T) -> bool,
50+
{
51+
type Item = <&'a mut A as Stream>::Item;
52+
fn next(self) -> Option<Self::Item> {
53+
while let Some(item) = self.stream.next() {
54+
if (self.func)(&item) {
55+
return Some(item);
56+
}
57+
}
58+
None
59+
}
60+
}
61+
62+
pub trait StreamExt where for<'b> &'b mut Self: Stream {
63+
fn map<F>(self, func: F) -> Map<Self, F>
64+
where Self: Sized,
65+
for<'a> &'a mut Map<Self, F>: Stream,
66+
{
67+
Map {
68+
func: func,
69+
stream: self,
70+
}
71+
}
72+
73+
fn filter<F>(self, func: F) -> Filter<Self, F>
74+
where Self: Sized,
75+
for<'a> &'a mut Filter<Self, F>: Stream,
76+
{
77+
Filter {
78+
func: func,
79+
stream: self,
80+
}
81+
}
82+
83+
fn count(mut self) -> usize
84+
where Self: Sized,
85+
{
86+
let mut count = 0;
87+
while let Some(_) = self.next() {
88+
count += 1;
89+
}
90+
count
91+
}
92+
}
93+
94+
impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }
95+
96+
fn main() {
97+
let source = Repeat(10);
98+
let map = source.map(|x: &_| x);
99+
//~^ ERROR implementation of `Stream` is not general enough
100+
//~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map
101+
//~| NOTE but `Stream` is actually implemented for the type `&'1
102+
103+
let filter = map.filter(|x: &_| true);
104+
let count = filter.count(); // Assert that we still have a valid stream.
105+
}

src/test/ui/hrtb/issue-30786.stderr

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
error: implementation of `Stream` is not general enough
2+
--> $DIR/issue-30786.rs:98:22
3+
|
4+
LL | let map = source.map(|x: &_| x);
5+
| ^^^
6+
|
7+
= note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:98:26: 98:35]>`, for any lifetime `'0`
8+
= note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:98:26: 98:35]>`, for some specific lifetime `'1`
9+
10+
error: aborting due to previous error
11+

0 commit comments

Comments
 (0)