Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression test for HRTB bug (issue 30786). #62519

Merged
merged 1 commit into from
Jul 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/test/ui/hrtb/issue-30786.migrate.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
error: implementation of `Stream` is not general enough
--> $DIR/issue-30786.rs:107:22
|
LL | let map = source.map(|x: &_| x);
| ^^^
|
= note: `Stream` would have to be implemented for the type `&'0 mut Map<Repeat, [closure@$DIR/issue-30786.rs:107:26: 107:35]>`, for any lifetime `'0`
= note: but `Stream` is actually implemented for the type `&'1 mut Map<Repeat, [closure@$DIR/issue-30786.rs:107:26: 107:35]>`, for some specific lifetime `'1`

error: aborting due to previous error

14 changes: 14 additions & 0 deletions src/test/ui/hrtb/issue-30786.nll.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
error: higher-ranked subtype error
--> $DIR/issue-30786.rs:111:18
|
LL | let filter = map.filter(|x: &_| true);
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: higher-ranked subtype error
--> $DIR/issue-30786.rs:113:17
|
LL | let count = filter.count(); // Assert that we still have a valid stream.
| ^^^^^^^^^^^^^^

error: aborting due to 2 previous errors

115 changes: 115 additions & 0 deletions src/test/ui/hrtb/issue-30786.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream<Item=T`
// should act as assertion that item does not borrow from its stream;
// but an earlier buggy rustc allowed `.map(|x: &_| x)` which does
// have such an item.
//
// This tests double-checks that we do not allow such behavior to leak
// through again.

// revisions: migrate nll

// Since we are testing nll (and migration) explicitly as a separate
// revisions, don't worry about the --compare-mode=nll on this test.

// ignore-compare-mode-nll

//[nll]compile-flags: -Z borrowck=mir

pub trait Stream {
type Item;
fn next(self) -> Option<Self::Item>;
}

// Example stream
pub struct Repeat(u64);

impl<'a> Stream for &'a mut Repeat {
type Item = &'a u64;
fn next(self) -> Option<Self::Item> {
Some(&self.0)
}
}

pub struct Map<S, F> {
stream: S,
func: F,
}

impl<'a, A, F, T> Stream for &'a mut Map<A, F>
where &'a mut A: Stream,
F: FnMut(<&'a mut A as Stream>::Item) -> T,
{
type Item = T;
fn next(self) -> Option<T> {
match self.stream.next() {
Some(item) => Some((self.func)(item)),
None => None,
}
}
}

pub struct Filter<S, F> {
stream: S,
func: F,
}

impl<'a, A, F, T> Stream for &'a mut Filter<A, F>
where for<'b> &'b mut A: Stream<Item=T>, // <---- BAD
F: FnMut(&T) -> bool,
{
type Item = <&'a mut A as Stream>::Item;
fn next(self) -> Option<Self::Item> {
while let Some(item) = self.stream.next() {
if (self.func)(&item) {
return Some(item);
}
}
None
}
}

pub trait StreamExt where for<'b> &'b mut Self: Stream {
fn map<F>(self, func: F) -> Map<Self, F>
where Self: Sized,
for<'a> &'a mut Map<Self, F>: Stream,
{
Map {
func: func,
stream: self,
}
}

fn filter<F>(self, func: F) -> Filter<Self, F>
where Self: Sized,
for<'a> &'a mut Filter<Self, F>: Stream,
{
Filter {
func: func,
stream: self,
}
}

fn count(mut self) -> usize
where Self: Sized,
{
let mut count = 0;
while let Some(_) = self.next() {
count += 1;
}
count
}
}

impl<T> StreamExt for T where for<'a> &'a mut T: Stream { }

fn main() {
let source = Repeat(10);
let map = source.map(|x: &_| x);
//[migrate]~^ ERROR implementation of `Stream` is not general enough
//[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map
//[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1
let filter = map.filter(|x: &_| true);
//[nll]~^ ERROR higher-ranked subtype error
let count = filter.count(); // Assert that we still have a valid stream.
//[nll]~^ ERROR higher-ranked subtype error
}