about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorFelix S. Klock II <pnkfelix@pnkfx.org>2019-07-09 11:15:05 +0200
committerFelix S. Klock II <pnkfelix@pnkfx.org>2019-07-10 16:43:19 +0200
commitfa0809d3cdacae8638fd7beea2e85310902e21d3 (patch)
tree5abaa18c7522f61c3004773c9a3ac3c22cc7a307 /src
parent0324a2b309cd66cb7bd4a156bd0b84cb136e254f (diff)
downloadrust-fa0809d3cdacae8638fd7beea2e85310902e21d3.tar.gz
rust-fa0809d3cdacae8638fd7beea2e85310902e21d3.zip
Regression test for issue 30786.
Diffstat (limited to 'src')
-rw-r--r--src/test/ui/hrtb/issue-30786.migrate.stderr11
-rw-r--r--src/test/ui/hrtb/issue-30786.nll.stderr14
-rw-r--r--src/test/ui/hrtb/issue-30786.rs115
3 files changed, 140 insertions, 0 deletions
diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr
new file mode 100644
index 00000000000..9a4f8772822
--- /dev/null
+++ b/src/test/ui/hrtb/issue-30786.migrate.stderr
@@ -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
+
diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr
new file mode 100644
index 00000000000..5c865d76851
--- /dev/null
+++ b/src/test/ui/hrtb/issue-30786.nll.stderr
@@ -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
+
diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs
new file mode 100644
index 00000000000..321b83c3459
--- /dev/null
+++ b/src/test/ui/hrtb/issue-30786.rs
@@ -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
+}