Skip to content

Commit d19507a

Browse files
committed
Make corrections/wording changes to elision documents
* Don't talk about a future feature * Add examples of elision in function pointers/traits * A rule for 'static bounds on trait objects * Static lifetime elision doesn't happen in function pointers/traits
1 parent 21b4b9f commit d19507a

File tree

2 files changed

+51
-64
lines changed

2 files changed

+51
-64
lines changed

Diff for: src/lifetime-elision.md

+51-62
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,18 @@ compiler can infer a sensible default choice.
66
## Lifetime elision in functions
77

88
In order to make common patterns more ergonomic, Rust allows lifetimes to be
9-
*elided* in function signatures.
9+
*elided* in [function item], [function pointer] and [closure trait] signatures.
10+
The following rules are used to infer lifetime parameters for elided lifetimes.
11+
It is an error to elide lifetime parameters that cannot be infered.
1012

11-
A *lifetime position* is anywhere you can write a lifetime in a type:
13+
* Each elided lifetime in the parameters becomes a distinct lifetime parameter.
14+
* If there is exactly one lifetime used in the parameters (elided or not), that
15+
lifetime is assigned to *all* elided output lifetimes.
1216

13-
```rust,ignore
14-
&'a T
15-
&'a mut T
16-
T<'a>
17-
```
18-
19-
Lifetime positions can appear as either "input" or "output":
20-
21-
* For `fn` definitions, input refers to the types of the formal arguments
22-
in the `fn` definition, while output refers to
23-
result types. So `fn foo(s: &str) -> (&str, &str)` has elided one lifetime in
24-
input position and two lifetimes in output position.
25-
Note that the input positions of a `fn` method definition do not
26-
include the lifetimes that occur in the method's `impl` header
27-
(nor lifetimes that occur in the trait header, for a default method).
28-
29-
* In the future, it should be possible to elide `impl` headers in the same manner.
30-
31-
Elision rules are as follows:
32-
33-
* Each elided lifetime in input position becomes a distinct lifetime
34-
parameter.
35-
36-
* If there is exactly one input lifetime position (elided or not), that lifetime
37-
is assigned to *all* elided output lifetimes.
17+
In method signatures there is another rule
3818

39-
* If there are multiple input lifetime positions, but one of them is `&self` or
40-
`&mut self`, the lifetime of `self` is assigned to *all* elided output lifetimes.
41-
42-
* Otherwise, it is an error to elide an output lifetime.
19+
* If the receiver has type `&Self` or `&mut Self`, then the lifetime of that
20+
reference to `Self` is assigned to all elided output lifetime parameters.
4321

4422
Examples:
4523

@@ -60,25 +38,38 @@ fn frob(s: &str, t: &str) -> &str; // ILLEGAL
6038
fn get_mut(&mut self) -> &mut T; // elided
6139
fn get_mut<'a>(&'a mut self) -> &'a mut T; // expanded
6240
63-
fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command // elided
64-
fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command // expanded
41+
fn args<T: ToCStr>(&mut self, args: &[T]) -> &mut Command; // elided
42+
fn args<'a, 'b, T: ToCStr>(&'a mut self, args: &'b [T]) -> &'a mut Command; // expanded
6543
6644
fn new(buf: &mut [u8]) -> BufWriter; // elided
67-
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a> // expanded
45+
fn new<'a>(buf: &'a mut [u8]) -> BufWriter<'a>; // expanded
46+
47+
type FunPtr = fn(&str) -> &str; // elided
48+
type FunPtr = for<'a> fn(&'a str) -> &'a str; // expanded
6849
50+
type FunTrait = Fn(&str) -> &str; // elided
51+
type FunTrait = for<'a> Fn(&'a str) -> &'a str; // expanded
6952
```
7053

7154
## Defaults trait object lifetimes
7255

73-
The assumed lifetime of references held by a trait object is called its
74-
*default object lifetime bound*. These were defined in [RFC 599] and amended in
56+
The assumed lifetime of references held by a [trait object] is called its
57+
_default object lifetime bound_. These were defined in [RFC 599] and amended in
7558
[RFC 1156].
7659

77-
For traits that themselves have no lifetime parameters:
78-
* If there is a unique bound from the containing type then that is the default.
60+
If the trait object is used as for a type argument of a generic type then the
61+
containing type is first used to try to infer a bound.
62+
* If there is a unique bound from the containing type then that is the default
7963
* If there is more than one bound from the containing type then an explicit
80-
bound must be specified.
81-
* Otherwise the default bound is `'static`.
64+
bound must be specified
65+
66+
Then the bounds on the trait are used:
67+
68+
* If the trait is defined with a single lifetime _bound_ then that bound is
69+
used.
70+
* If `'static` is used for any lifetime bound then `'static` is used.
71+
* If the trait has no lifetime bounds, then the lifetime is inferred in
72+
expressions and is `'static` outside of expressions.
8273

8374
```rust,ignore
8475
// For the following trait...
@@ -104,15 +95,10 @@ std::cell::Ref<'a, Foo + 'a>
10495
struct TwoBounds<'a, 'b, T: ?Sized + 'a + 'b>
10596
TwoBounds<'a, 'b, Foo> // Error: the lifetime bound for this object type cannot
10697
// be deduced from context
107-
10898
```
10999

110-
The `+ 'static` and `+ 'a` refer to the default bounds of those kinds of trait
111-
objects, and also to how you can directly override them. Note that the innermost
112-
object sets the bound, so `&'a Box<Foo>` is still `&'a Box<Foo + 'static>`.
113-
114-
For traits that have a single lifetime _bound_ of their own then, instead of
115-
infering 'static as the default bound, the bound on the trait is used instead
100+
Note that the innermost object sets the bound, so `&'a Box<Foo>` is still `&'a
101+
Box<Foo + 'static>`.
116102

117103
```rust,ignore
118104
// For the following trait...
@@ -133,48 +119,51 @@ TwoBounds<'a, 'b, Foo<'c>>
133119

134120
## `'static` lifetime elision
135121

136-
Both constant and static declarations of reference types have *implicit*
122+
Both [constant] and [static] declarations of reference types have *implicit*
137123
`'static` lifetimes unless an explicit lifetime is specified. As such, the
138124
constant declarations involving `'static` above may be written without the
139-
lifetimes. Returning to our previous example:
125+
lifetimes.
140126

141127
```rust
142-
const BIT1: u32 = 1 << 0;
143-
const BIT2: u32 = 1 << 1;
144-
145-
const BITS: [u32; 2] = [BIT1, BIT2];
128+
// STRING: &'static str
146129
const STRING: &str = "bitstring";
147130

148131
struct BitsNStrings<'a> {
149132
mybits: [u32; 2],
150133
mystring: &'a str,
151134
}
152135

136+
// BITS_N_STRINGS: BitsNStrings<'static>
153137
const BITS_N_STRINGS: BitsNStrings = BitsNStrings {
154-
mybits: BITS,
138+
mybits: [1, 2],
155139
mystring: STRING,
156140
};
157141
```
158142

159143
Note that if the `static` or `const` items include function or closure
160144
references, which themselves include references, the compiler will first try
161-
the standard elision rules ([see discussion in the nomicon][elision-nomicon]).
162-
If it is unable to resolve the lifetimes by its usual rules, it will default to
163-
using the `'static` lifetime. By way of example:
145+
the standard elision rules. If it is unable to resolve the lifetimes by its
146+
usual rules, then it will error. By way of example:
164147

165148
```rust,ignore
166149
// Resolved as `fn<'a>(&'a str) -> &'a str`.
167150
const RESOLVED_SINGLE: fn(&str) -> &str = ..
168151
169152
// Resolved as `Fn<'a, 'b, 'c>(&'a Foo, &'b Bar, &'c Baz) -> usize`.
170-
const RESOLVED_MULTIPLE: Fn(&Foo, &Bar, &Baz) -> usize = ..
153+
const RESOLVED_MULTIPLE: &Fn(&Foo, &Bar, &Baz) -> usize = ..
171154
172155
// There is insufficient information to bound the return reference lifetime
173-
// relative to the argument lifetimes, so the signature is resolved as
174-
// `Fn(&'static Foo, &'static Bar) -> &'static Baz`.
175-
const RESOLVED_STATIC: Fn(&Foo, &Bar) -> &Baz = ..
156+
// relative to the argument lifetimes, so this is an error.
157+
const RESOLVED_STATIC: &Fn(&Foo, &Bar) -> &Baz = ..
176158
```
177159

160+
[closure trait]: types.html#closure-types
161+
[constant]: items.html#constant-items
162+
[function item]: types.html#function-item-types
163+
[function pointer]: types.html#function-pointers
164+
[implementation]: items/implementations.html
178165
[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
179166
[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
180-
[elision-nomicon]: ../nomicon/lifetime-elision.html
167+
[static]: items.html#static-items
168+
[trait object]: types.html#trait-objects
169+
[type aliases]: items/type-aliases.html

Diff for: src/types.md

-2
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,6 @@ The notation `&self` is a shorthand for `self: &Self`.
525525
[`Vec<T>`]: ../std/vec/struct.Vec.html
526526
[dynamically sized type]: dynamically-sized-types.html
527527
[dynamically sized types]: dynamically-sized-types.html
528-
[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
529-
[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
530528
[struct expression]: expressions/struct-expr.html
531529
[closure expression]: expressions/closure-expr.html
532530
[auto traits]: special-types-and-traits.html#auto-traits

0 commit comments

Comments
 (0)