From f766d187308e7a5d457e1d5570afe136a8078d0e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 15 Jul 2014 18:03:16 +0200 Subject: [PATCH 1/3] Clarify definition of "input positions" in lifetime elision RFC. Explicitly note that lifetimes from the `impl` (and `trait`/`struct`) are not considered "input positions" for the purposes of expanded `fn` definitions. Added a collection of examples illustrating this. Drive-by: Addressed a review comment from @chris-morgan [here](https://github.com/rust-lang/rfcs/pull/141#discussion_r14227369). --- active/0039-lifetime-elision.md | 39 ++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/active/0039-lifetime-elision.md b/active/0039-lifetime-elision.md index 213c4d40478..b07b0c6d351 100644 --- a/active/0039-lifetime-elision.md +++ b/active/0039-lifetime-elision.md @@ -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 + 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 @@ -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). + +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 From 6c11e049c36e5472ccc099e57cee36dd7a46d315 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 15 Jul 2014 19:15:24 +0200 Subject: [PATCH 2/3] Incorporated aturon's review feedback. --- active/0039-lifetime-elision.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/active/0039-lifetime-elision.md b/active/0039-lifetime-elision.md index b07b0c6d351..5894e0e0dc1 100644 --- a/active/0039-lifetime-elision.md +++ b/active/0039-lifetime-elision.md @@ -163,12 +163,24 @@ 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<'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 +} + +// Note that when the impl reuses the same signature (with the same elisions) +// from the trait definition, the expanded forms will also match, and thus +// the `impl` will be compatible with the `trait`. + 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 +// signatures from the above trait definition for `Bar`; in the general +// case, if the elided signatures between the `impl` and the `trait` do +// not match, an expanded `impl` may not be compatible with the given // `trait` (and thus would not compile). impl Bar for &str { fn fresh(&self) -> &int { ... } } // elided From b02141be1f4c83d4ff7cbcfec5df5a747e27670e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 15 Jul 2014 19:18:03 +0200 Subject: [PATCH 3/3] Fixed typo from my original draft. Also fixed mistake from previous commit (I moved an example up a few lines but forgot to delete the original). --- active/0039-lifetime-elision.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/active/0039-lifetime-elision.md b/active/0039-lifetime-elision.md index 5894e0e0dc1..f9aeb80eebb 100644 --- a/active/0039-lifetime-elision.md +++ b/active/0039-lifetime-elision.md @@ -100,8 +100,7 @@ Lifetime positions can appear as either "input" or "output": 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 - method). + (nor lifetimes that occur in the trait header, for a default method). * For `impl` headers, input refers to the lifetimes appears in the type @@ -190,13 +189,6 @@ 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