# #[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.