# #[refine] user stories ## All the things we might want to test Features: - [ ] Impl trait in return position - [ ] Impl trait in argument position - [ ] Where clause refinement - [ ] Lifetime refinement (explicit) - [ ] Lifetime refinement (elided) - [ ] Safe refinement of unsafe method - [ ] Return type bounds - [ ] (Extension) Adding generic arguments Variations: - [ ] Warn-by-default vs allow-by-default vs error-by-default - [ ] Current lifetime behavior (refinement allowed but unusable) - [ ] Refinement allowed and usable without `#[refine]` - [ ] Allow `#[refine]` on individual arguments, return types, or where clauses - [ ] `#[refine('a, ExactSizeIterator)]` - [ ] RPIT captures all lifetimes in scope Scenarios: - [x] Adding impl Trait bounds to a trait method's return type - [ ] Using a concrete type in place of `-> impl Trait` - [x] Making code generic that already depends on `#[refine]` - [ ] Migrating from RPITIT to associated type, or vice versa - [ ] `impl From<&u32>` requires a named lifetime - [ ] Surprising refinement: Carelessly putting a concrete type - [ ] Surprising refinement: Subtle elided lifetime mismatch - [ ] Surprising refinement: Missing where clause ## TODO: scenario of a breaking change involving lifetimes ## Scenario: Refining a return type using `-> impl Trait` Let's say the standard library defines the following `IntoIter` trait. ```rust trait IntoIter { type Item; fn into_iter(self) -> impl Iterator<Item = Self::Item>; } ``` A library maintainer creates a very simple data structure, `MyVec`, that is internally based on the `Vec` type. ```rust pub struct MyVec<T> { inner: Vec<T>, } impl<T> MyVec<T> { pub fn new() -> MyVec<T> { ... } pub fn push(&mut self, elem: T) { ... } pub fn len(&self) -> usize { ... } } ``` The maintainer then implements the `Iterable` trait for `MyVec`. ```rust impl<T> IntoIter for MyVec<T> { type Item = T; fn iter(self) -> impl Iterator<Item = T> { self.inner.into_iter() } } ``` Later, she realizes that she wants to expose the `rev` operation to reverse an iterator. This operation is only available on the `DoubleEndedIterator` trait, which inherits from `Iterator`. ```rust for item in my_vec.into_iter().rev() { // ^^^ // error: the trait bound `impl Iterator<Item = T>: DoubleEndedIterator` // is not satisfied ... } ``` Since the iterator for `Vec` already exposes this functionality, she simply changes the signature on her `IntoIter` implementation to reflect this. This results in a different compiler error. ```rust impl<T> IntoIter for MyVec<T> { type Item = T; fn iter(self) -> impl DoubleEndedIterator<Item = T> { // ^^^^^^^^^^^^^^^^^^^ // error: impl return type does not match the return type in the trait // note: expected `impl Iterator<Item = T>`, saw `impl DoubleEndedIterator<Item = T>` // note: consider changing the signature: // fn iter(self) -> impl Iterator<Item = T> { // ^^^^^^^^ // note: consider adding `#[refine]`: // #[refine] // +++++++++ // fn iter(self) -> impl DoubleEndedIterator<Item = T> { self.inner.into_iter() } } ``` Following the second suggestion, the maintainer adds `#[refine]` to the method signature, and everything compiles. ```rust impl<T> IntoIter for MyVec<T> { type Item = T; #[refine] fn iter(self) -> impl DoubleEndedIterator<Item = T> { self.inner.into_iter() } } ``` ## Scenario: Unexpected Erasure of Refined Information A library maintainer writes a trait and trait implementation like this: ```rust trait IntoErasedIterator { fn into_erased_iter(self) -> impl Iterator; } impl<T> IntoErasedIterator for Vec<T> { #[refine] fn into_erased_iter(self) -> impl ExactSizeIterator { self.into_iter() } } ``` A library user then uses the refined information like this when the receiver type is known: ```rust fn main() { let x = vec![1, 2, 3]; let it = x.into_erased_iter(); println!("{}", it.len()); } ``` However, they then decide to refactor their code and erased the refined information via impl Trait in argument position: ```rust fn main() { let x = vec![1, 2, 3]; extracted(x); } fn extracted(x: impl IntoErasedIterator) { let it = x.into_erased_iter(); println!("{}", it.len()); // error: it does not have method `len` } ``` And now this unexpectedly causes a compiler error.