Skip to content

Perform lifetime elision (more) syntactically, before type-checking. #39305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Jan 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
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
63 changes: 63 additions & 0 deletions src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,69 @@ struct ListNode {
This works because `Box` is a pointer, so its size is well-known.
"##,

E0106: r##"
This error indicates that a lifetime is missing from a type. If it is an error
inside a function signature, the problem may be with failing to adhere to the
lifetime elision rules (see below).

Here are some simple examples of where you'll run into this error:

```compile_fail,E0106
struct Foo { x: &bool } // error
struct Foo<'a> { x: &'a bool } // correct

enum Bar { A(u8), B(&bool), } // error
enum Bar<'a> { A(u8), B(&'a bool), } // correct

type MyStr = &str; // error
type MyStr<'a> = &'a str; // correct
```

Lifetime elision is a special, limited kind of inference for lifetimes in
function signatures which allows you to leave out lifetimes in certain cases.
For more background on lifetime elision see [the book][book-le].

The lifetime elision rules require that any function signature with an elided
output lifetime must either have

- exactly one input lifetime
- or, multiple input lifetimes, but the function must also be a method with a
`&self` or `&mut self` receiver

In the first case, the output lifetime is inferred to be the same as the unique
input lifetime. In the second case, the lifetime is instead inferred to be the
same as the lifetime on `&self` or `&mut self`.

Here are some examples of elision errors:

```compile_fail,E0106
// error, no input lifetimes
fn foo() -> &str { }

// error, `x` and `y` have distinct lifetimes inferred
fn bar(x: &str, y: &str) -> &str { }

// error, `y`'s lifetime is inferred to be distinct from `x`'s
fn baz<'a>(x: &'a str, y: &str) -> &str { }
```

Here's an example that is currently an error, but may work in a future version
of Rust:

```compile_fail,E0106
struct Foo<'a>(&'a str);

trait Quux { }
impl Quux for Foo { }
```

Lifetime elision in implementation headers was part of the lifetime elision
RFC. It is, however, [currently unimplemented][iss15872].

[book-le]: https://doc.rust-lang.org/nightly/book/lifetimes.html#lifetime-elision
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,

E0109: r##"
You tried to give a type parameter to a type which doesn't need it. Erroneous
code example:
Expand Down
17 changes: 10 additions & 7 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ pub trait Visitor<'v> : Sized {
fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) {
walk_ty_param_bound(self, bounds)
}
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: &'v TraitBoundModifier) {
fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) {
walk_poly_trait_ref(self, t, m)
}
fn visit_variant_data(&mut self,
Expand Down Expand Up @@ -421,7 +421,7 @@ pub fn walk_lifetime_def<'v, V: Visitor<'v>>(visitor: &mut V, lifetime_def: &'v

pub fn walk_poly_trait_ref<'v, V>(visitor: &mut V,
trait_ref: &'v PolyTraitRef,
_modifier: &'v TraitBoundModifier)
_modifier: TraitBoundModifier)
where V: Visitor<'v>
{
walk_list!(visitor, visit_lifetime_def, &trait_ref.bound_lifetimes);
Expand Down Expand Up @@ -547,8 +547,8 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
TyPtr(ref mutable_type) => {
visitor.visit_ty(&mutable_type.ty)
}
TyRptr(ref opt_lifetime, ref mutable_type) => {
walk_list!(visitor, visit_lifetime, opt_lifetime);
TyRptr(ref lifetime, ref mutable_type) => {
visitor.visit_lifetime(lifetime);
visitor.visit_ty(&mutable_type.ty)
}
TyNever => {},
Expand All @@ -566,8 +566,11 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) {
visitor.visit_ty(ty);
visitor.visit_nested_body(length)
}
TyTraitObject(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
TyTraitObject(ref bounds, ref lifetime) => {
for bound in bounds {
visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None);
}
visitor.visit_lifetime(lifetime);
}
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
Expand Down Expand Up @@ -695,7 +698,7 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v

pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) {
match *bound {
TraitTyParamBound(ref typ, ref modifier) => {
TraitTyParamBound(ref typ, modifier) => {
visitor.visit_poly_trait_ref(typ, modifier);
}
RegionTyParamBound(ref lifetime) => {
Expand Down
Loading