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