Skip to content
Merged
Changes from 1 commit
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
39 changes: 36 additions & 3 deletions active/0039-lifetime-elision.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,14 +94,21 @@ elided a single lifetime.

Lifetime positions can appear as either "input" or "output":

* For `fn` definitions, input refers to argument types while output refers to
* For `fn` definitions, input refers to the types of the formal arguments
in the `fn` definition, while output refers to
result types. So `fn foo(s: &str) -> (&str, &str)` has elided one lifetime in
input position and two lifetimes in output position.
Note that the input positions of a `fn` method definition do not
include the lifetimes that occur in the method's `impl` header
`impl` (nor lifetimes that occur in the trait header, for a default
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

arg, typo here, "impl header impl" probably should be just "impl header". (I was originally going to spell out which components of the impl header I am referring to here, but then decided mid-stream not to bother.)

method).


* For `impl` headers, input refers to the lifetimes appears in the type
receiving the `impl`, while output refers to the trait, if any. So `impl<'a>
Foo<'a>` has `'a` in input position, while `impl<'a> SomeTrait<'a> Foo<'a>`
has `'a` in both input and output positions.
Foo<'a>` has `'a` in input position, while `impl<'a, 'b, 'c>
SomeTrait<'b, 'c> for Foo<'a, 'c>` has `'a` in input position, `'b`
in output position, and `'c` in both input and output positions.

### The rules

Expand Down Expand Up @@ -152,6 +159,32 @@ impl<'a, 'b> Reader for (&'a str, &'b str) { ... } // expanded

impl StrSlice for &str { ... } // elided
impl<'a> StrSlice<'a> for &'a str { ... } // expanded

trait Bar<'a> { fn bound(&'a self) -> &int { ... } fn fresh(&self) -> &int { ... } } // elided
trait Bar<'a> { fn bound(&'a self) -> &'a int { ... } fn fresh<'b>(&'b self) -> &'b int { ... } } // expanded

impl Bar for &str { fn bound(&self) -> &int { ... } } // elided
impl<'a> Bar<'a> for &'a str { fn bound<'b>(&'b self) -> &'b int { ... } } // expanded

// Note that the preceding example's expanded methods do not match the
// signatures from the above trait definition for `Bar`, and in the
// general case the expanded `impl` may not be compatible with the given
// `trait` (and thus would not compile).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The more important point, to me, is that if you use exactly the same signature (with the same elisions) from the trait definition in the impl the expanded forms will match.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I'll try to point that out too.


impl Bar for &str { fn fresh(&self) -> &int { ... } } // elided
impl<'a> Bar<'a> for &'a str { fn fresh<'b>(&'b self) -> &'b int { ... } } // expanded

impl Bar for &str {
fn bound(&'a self) -> &'a int { ... } fn fresh(&self) -> &int { ... } // ILLEGAL: unbound 'a
}

impl<'a> Bar<'a> for &'a str {
fn bound(&'a self) -> &'a int { ... } fn fresh(&self) -> &int { ... } // elided
}
impl<'a> Bar<'a> for &'a str {
fn bound(&'a self) -> &'a int { ... } fn fresh<'b>(&'b self) -> &'b int { ... } // expanded
}

```

## Error messages
Expand Down