permit '_ and &T in impl headers

Deprecated forms of elision are not supported.
This commit is contained in:
Niko Matsakis 2018-03-21 17:12:39 -04:00
parent df70060bd6
commit 94468dac63
18 changed files with 617 additions and 51 deletions

View File

@ -420,7 +420,10 @@ pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime
LifetimeName::Name(name) => {
visitor.visit_name(lifetime.span, name);
}
LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {}
LifetimeName::Fresh(_) |
LifetimeName::Static |
LifetimeName::Implicit |
LifetimeName::Underscore => {}
}
}

View File

@ -107,6 +107,12 @@ pub struct LoweringContext<'a> {
is_in_loop_condition: bool,
is_in_trait_impl: bool,
/// What to do when we encounter either an "anonymous lifetime
/// reference". The term "anonymous" is meant to encompass both
/// `'_` lifetimes as well as fully elided cases where nothing is
/// written at all (e.g., `&T` or `std::cell::Ref<T>`).
anonymous_lifetime_mode: AnonymousLifetimeMode,
// This is a list of in-band type definitions being generated by
// Argument-position `impl Trait`.
// When traversing a signature such as `fn foo(x: impl Trait)`,
@ -212,6 +218,7 @@ pub fn lower_crate(
catch_scopes: Vec::new(),
loop_scopes: Vec::new(),
is_in_loop_condition: false,
anonymous_lifetime_mode: AnonymousLifetimeMode::PassThrough,
type_def_lifetime_params: DefIdMap(),
current_hir_id_owner: vec![(CRATE_DEF_INDEX, 0)],
item_local_id_counters: NodeMap(),
@ -244,6 +251,51 @@ enum ParenthesizedGenericArgs {
Err,
}
/// What to do when we encounter an **anonymous** lifetime
/// reference. Anonymous lifetime references come in two flavors. You
/// have implicit, or fully elided, references to lifetimes, like the
/// one in `&T` or `Ref<T>`, and you have `'_` lifetimes, like `&'_ T`
/// or `Ref<'_, T>`. These often behave the same, but not always:
///
/// - certain usages of implicit references are deprecated, like
/// `Ref<T>`, and we sometimes just give hard errors in those cases
/// as well.
/// - for object bounds there is a difference: `Box<dyn Foo>` is not
/// the same as `Box<dyn Foo + '_>`.
///
/// We describe the effects of the various modes in terms of three cases:
///
/// - **Modern** -- includes all uses of `'_`, but also the lifetime arg
/// of a `&` (e.g., the missing lifetime in something like `&T`)
/// - **Dyn Bound** -- if you have something like `Box<dyn Foo>`,
/// there is an elided lifetime bound (`Box<dyn Foo + 'X>`). These
/// elided bounds follow special rules. Note that this only covers
/// cases where *nothing* is written; the `'_` in `Box<dyn Foo +
/// '_>` is a case of "modern" elision.
/// - **Deprecated** -- this coverse cases like `Ref<T>`, where the lifetime
/// parameter to ref is completely elided. `Ref<'_, T>` would be the modern,
/// non-deprecated equivalent.
///
/// Currently, the handling of lifetime elision is somewhat spread out
/// between HIR lowering and -- as described below -- the
/// `resolve_lifetime` module. Often we "fallthrough" to that code by generating
/// an "elided" or "underscore" lifetime name. In the future, we probably want to move
/// everything into HIR lowering.
#[derive(Copy, Clone)]
enum AnonymousLifetimeMode {
/// For **Modern** cases, create a new anonymous region parameter
/// and reference that.
///
/// For **Dyn Bound** cases, pass responsibility to
/// `resolve_lifetime` code.
///
/// For **Deprecated** cases, report an error.
CreateParameter,
/// Pass responsibility to `resolve_lifetime` code for all cases.
PassThrough,
}
impl<'a> LoweringContext<'a> {
fn lower_crate(mut self, c: &Crate) -> hir::Crate {
/// Full-crate AST visitor that inserts into a fresh
@ -546,22 +598,37 @@ impl<'a> LoweringContext<'a> {
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))
}
// Creates a new hir::GenericParam for every new lifetime and type parameter
// encountered while evaluating `f`. Definitions are created with the parent
// provided. If no `parent_id` is provided, no definitions will be returned.
fn collect_in_band_defs<T, F>(&mut self, parent_id: DefId, f: F) -> (Vec<hir::GenericParam>, T)
/// Creates a new hir::GenericParam for every new lifetime and
/// type parameter encountered while evaluating `f`. Definitions
/// are created with the parent provided. If no `parent_id` is
/// provided, no definitions will be returned.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
fn collect_in_band_defs<T, F>(
&mut self,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
f: F,
) -> (Vec<hir::GenericParam>, T)
where
F: FnOnce(&mut LoweringContext) -> T,
{
assert!(!self.is_collecting_in_band_lifetimes);
assert!(self.lifetimes_to_define.is_empty());
let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes;
if self.is_collecting_in_band_lifetimes {
self.anonymous_lifetime_mode = anonymous_lifetime_mode;
}
assert!(self.in_band_ty_params.is_empty());
let res = f(self);
self.is_collecting_in_band_lifetimes = false;
self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
let in_band_ty_params = self.in_band_ty_params.split_off(0);
let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
@ -571,8 +638,12 @@ impl<'a> LoweringContext<'a> {
.map(|(span, hir_name)| {
let def_node_id = self.next_id().node_id;
// Get the name we'll use to make the def-path. Note
// that collisions are ok here and this shouldn't
// really show up for end-user.
let str_name = match hir_name {
hir::LifetimeName::Name(n) => n.as_str(),
hir::LifetimeName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(),
hir::LifetimeName::Implicit
| hir::LifetimeName::Underscore
| hir::LifetimeName::Static => {
@ -636,6 +707,16 @@ impl<'a> LoweringContext<'a> {
self.lifetimes_to_define.push((span, hir_name));
}
/// When we have either an elided or `'_` lifetime in an impl
/// header, we convert it to
fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> hir::LifetimeName {
assert!(self.is_collecting_in_band_lifetimes);
let index = self.lifetimes_to_define.len();
let hir_name = hir::LifetimeName::Fresh(index);
self.lifetimes_to_define.push((span, hir_name));
hir_name
}
// Evaluates `f` with the lifetimes in `lt_defs` in-scope.
// This is used to track which lifetimes have already been defined, and
// which are new in-band lifetimes that need to have a definition created
@ -677,12 +758,17 @@ impl<'a> LoweringContext<'a> {
res
}
// Appends in-band lifetime defs and argument-position `impl Trait` defs
// to the existing set of generics.
/// Appends in-band lifetime defs and argument-position `impl
/// Trait` defs to the existing set of generics.
///
/// Presuming that in-band lifetimes are enabled, then
/// `self.anonymous_lifetime_mode` will be updated to match the
/// argument while `f` is running (and restored afterwards).
fn add_in_band_defs<F, T>(
&mut self,
generics: &Generics,
parent_id: DefId,
anonymous_lifetime_mode: AnonymousLifetimeMode,
f: F,
) -> (hir::Generics, T)
where
@ -694,7 +780,7 @@ impl<'a> LoweringContext<'a> {
_ => None,
}),
|this| {
this.collect_in_band_defs(parent_id, |this| {
this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| {
(this.lower_generics(generics), f(this))
})
},
@ -1213,6 +1299,7 @@ impl<'a> LoweringContext<'a> {
return;
}
}
name @ hir::LifetimeName::Fresh(_) => name,
name @ hir::LifetimeName::Name(_) => name,
hir::LifetimeName::Static => return,
};
@ -1757,19 +1844,35 @@ impl<'a> LoweringContext<'a> {
}
fn lower_lifetime(&mut self, l: &Lifetime) -> hir::Lifetime {
let name = match self.lower_ident(l.ident) {
x if x == "'_" => hir::LifetimeName::Underscore,
x if x == "'static" => hir::LifetimeName::Static,
match self.lower_ident(l.ident) {
x if x == "'static" => self.new_named_lifetime(l.id, l.span, hir::LifetimeName::Static),
x if x == "'_" => match self.anonymous_lifetime_mode {
AnonymousLifetimeMode::CreateParameter => {
let fresh_name = self.collect_fresh_in_band_lifetime(l.span);
self.new_named_lifetime(l.id, l.span, fresh_name)
}
AnonymousLifetimeMode::PassThrough => {
self.new_named_lifetime(l.id, l.span, hir::LifetimeName::Underscore)
}
},
name => {
self.maybe_collect_in_band_lifetime(l.span, name);
hir::LifetimeName::Name(name)
self.new_named_lifetime(l.id, l.span, hir::LifetimeName::Name(name))
}
};
}
}
fn new_named_lifetime(
&mut self,
id: NodeId,
span: Span,
name: hir::LifetimeName,
) -> hir::Lifetime {
hir::Lifetime {
id: self.lower_node_id(l.id).node_id,
name,
span: l.span,
id: self.lower_node_id(id).node_id,
span,
name: name,
}
}
@ -2115,9 +2218,12 @@ impl<'a> LoweringContext<'a> {
let body = this.lower_block(body, false);
this.expr_block(body, ThinVec::new())
});
let (generics, fn_decl) = this.add_in_band_defs(generics, fn_def_id, |this| {
this.lower_fn_decl(decl, Some(fn_def_id), true)
});
let (generics, fn_decl) = this.add_in_band_defs(
generics,
fn_def_id,
AnonymousLifetimeMode::PassThrough,
|this| this.lower_fn_decl(decl, Some(fn_def_id), true),
);
hir::ItemFn(
fn_decl,
@ -2178,8 +2284,11 @@ impl<'a> LoweringContext<'a> {
// method, it will not be considered an in-band
// lifetime to be added, but rather a reference to a
// parent lifetime.
let (generics, (trait_ref, lowered_ty)) =
self.add_in_band_defs(ast_generics, def_id, |this| {
let (generics, (trait_ref, lowered_ty)) = self.add_in_band_defs(
ast_generics,
def_id,
AnonymousLifetimeMode::CreateParameter,
|this| {
let trait_ref = trait_ref.as_ref().map(|trait_ref| {
this.lower_trait_ref(trait_ref, ImplTraitContext::Disallowed)
});
@ -2193,7 +2302,8 @@ impl<'a> LoweringContext<'a> {
let lowered_ty = this.lower_ty(ty, ImplTraitContext::Disallowed);
(trait_ref, lowered_ty)
});
},
);
let new_impl_items = self.with_in_scope_lifetime_defs(
ast_generics.params.iter().filter_map(|p| match p {
@ -2378,12 +2488,17 @@ impl<'a> LoweringContext<'a> {
),
TraitItemKind::Method(ref sig, None) => {
let names = this.lower_fn_args_to_names(&sig.decl);
this.add_in_band_defs(&i.generics, trait_item_def_id, |this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Required(names),
)
})
this.add_in_band_defs(
&i.generics,
trait_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Required(names),
)
},
)
}
TraitItemKind::Method(ref sig, Some(ref body)) => {
let body_id = this.lower_body(Some(&sig.decl), |this| {
@ -2391,12 +2506,17 @@ impl<'a> LoweringContext<'a> {
this.expr_block(body, ThinVec::new())
});
this.add_in_band_defs(&i.generics, trait_item_def_id, |this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Provided(body_id),
)
})
this.add_in_band_defs(
&i.generics,
trait_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::TraitItemKind::Method(
this.lower_method_sig(sig, trait_item_def_id, false),
hir::TraitMethod::Provided(body_id),
)
},
)
}
TraitItemKind::Type(ref bounds, ref default) => (
this.lower_generics(&i.generics),
@ -2470,12 +2590,21 @@ impl<'a> LoweringContext<'a> {
});
let impl_trait_return_allow = !this.is_in_trait_impl;
this.add_in_band_defs(&i.generics, impl_item_def_id, |this| {
hir::ImplItemKind::Method(
this.lower_method_sig(sig, impl_item_def_id, impl_trait_return_allow),
body_id,
)
})
this.add_in_band_defs(
&i.generics,
impl_item_def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
hir::ImplItemKind::Method(
this.lower_method_sig(
sig,
impl_item_def_id,
impl_trait_return_allow,
),
body_id,
)
},
)
}
ImplItemKind::Type(ref ty) => (
this.lower_generics(&i.generics),
@ -2598,14 +2727,18 @@ impl<'a> LoweringContext<'a> {
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
let (generics, (fn_dec, fn_args)) =
this.add_in_band_defs(generics, def_id, |this| {
let (generics, (fn_dec, fn_args)) = this.add_in_band_defs(
generics,
def_id,
AnonymousLifetimeMode::PassThrough,
|this| {
(
// Disallow impl Trait in foreign items
this.lower_fn_decl(fdec, None, false),
this.lower_fn_args_to_names(fdec),
)
});
},
);
hir::ForeignItemFn(fn_dec, fn_args, generics)
}
@ -4017,7 +4150,21 @@ impl<'a> LoweringContext<'a> {
/// Invoked to create the lifetime argument for a type `&T`
/// with no explicit lifetime.
fn elided_ref_lifetime(&mut self, span: Span) -> hir::Lifetime {
self.new_implicit_lifetime(span)
match self.anonymous_lifetime_mode {
// Intercept when we are in an impl header and introduce an in-band lifetime.
// Hence `impl Foo for &u32` becomes `impl<'f> Foo for &'f u32` for some fresh
// `'f`.
AnonymousLifetimeMode::CreateParameter => {
let fresh_name = self.collect_fresh_in_band_lifetime(span);
hir::Lifetime {
id: self.next_id().node_id,
span,
name: fresh_name,
}
}
AnonymousLifetimeMode::PassThrough => self.new_implicit_lifetime(span),
}
}
/// Invoked to create the lifetime argument(s) for a path like
@ -4025,7 +4172,22 @@ impl<'a> LoweringContext<'a> {
/// sorts of cases are deprecated. This may therefore report a warning or an
/// error, depending on the mode.
fn elided_path_lifetimes(&mut self, span: Span, count: usize) -> P<[hir::Lifetime]> {
(0..count).map(|_| self.new_implicit_lifetime(span)).collect()
match self.anonymous_lifetime_mode {
// NB. We intentionally ignore the create-parameter mode here
// and instead "pass through" to resolve-lifetimes, which will then
// report an error. This is because we don't want to support
// impl elision for deprecated forms like
//
// impl Foo for std::cell::Ref<u32> // note lack of '_
AnonymousLifetimeMode::CreateParameter => {}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => {}
}
(0..count)
.map(|_| self.new_implicit_lifetime(span))
.collect()
}
/// Invoked to create the lifetime argument(s) for an elided trait object
@ -4033,6 +4195,26 @@ impl<'a> LoweringContext<'a> {
/// when the bound is written, even if it is written with `'_` like in
/// `Box<dyn Debug + '_>`. In those cases, `lower_lifetime` is invoked.
fn elided_dyn_bound(&mut self, span: Span) -> hir::Lifetime {
match self.anonymous_lifetime_mode {
// NB. We intentionally ignore the create-parameter mode here.
// and instead "pass through" to resolve-lifetimes, which will apply
// the object-lifetime-defaulting rules. Elided object lifetime defaults
// do not act like other elided lifetimes. In other words, given this:
//
// impl Foo for Box<dyn Debug>
//
// we do not introduce a fresh `'_` to serve as the bound, but instead
// ultimately translate to the equivalent of:
//
// impl Foo for Box<dyn Debug + 'static>
//
// `resolve_lifetime` has the code to make that happen.
AnonymousLifetimeMode::CreateParameter => {}
// This is the normal case.
AnonymousLifetimeMode::PassThrough => {}
}
self.new_implicit_lifetime(span)
}

View File

@ -209,6 +209,21 @@ pub enum LifetimeName {
/// User typed `'_`.
Underscore,
/// Synthetic name generated when user elided a lifetime in an impl header,
/// e.g. the lifetimes in cases like these:
///
/// impl Foo for &u32
/// impl Foo<'_> for u32
///
/// in that case, we rewrite to
///
/// impl<'f> Foo for &'f u32
/// impl<'f> Foo<'f> for u32
///
/// where `'f` is something like `Fresh(0)`. The indices are
/// unique per impl, but not necessarily continuous.
Fresh(usize),
/// User wrote `'static`
Static,
@ -221,7 +236,7 @@ impl LifetimeName {
use self::LifetimeName::*;
match *self {
Implicit => keywords::Invalid.name(),
Underscore => keywords::UnderscoreLifetime.name(),
Fresh(_) | Underscore => keywords::UnderscoreLifetime.name(),
Static => keywords::StaticLifetime.name(),
Name(name) => name,
}
@ -242,7 +257,13 @@ impl Lifetime {
use self::LifetimeName::*;
match self.name {
Implicit | Underscore => true,
Static | Name(_) => false,
// It might seem surprising that `Fresh(_)` counts as
// *not* elided -- but this is because, as far as the code
// in the compiler is concerned -- `Fresh(_)` variants act
// equivalently to "some fresh name". They correspond to
// early-bound regions on an impl, in other words.
Fresh(_) | Static | Name(_) => false,
}
}

View File

@ -145,6 +145,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for hir::ImplItemId {
impl_stable_hash_for!(enum hir::LifetimeName {
Implicit,
Underscore,
Fresh(index),
Static,
Name(name)
});

View File

@ -582,7 +582,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
// cc #48468
self.resolve_elided_lifetimes(slice::from_ref(lifetime), false)
}
LifetimeName::Static | LifetimeName::Name(_) => {
LifetimeName::Fresh(_) | LifetimeName::Static | LifetimeName::Name(_) => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(lifetime);
}
@ -2086,7 +2086,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
);
err.emit();
}
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {}
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
hir::LifetimeName::Name(_) => {}
}
}
@ -2138,7 +2139,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
))
.emit();
}
hir::LifetimeName::Implicit | hir::LifetimeName::Name(_) => {
hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit |
hir::LifetimeName::Name(_) => {
self.resolve_lifetime_ref(bound);
}
}

View File

@ -0,0 +1,22 @@
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
#![feature(underscore_lifetimes)]
trait MyTrait<'a> { }
impl<'a> MyTrait<'a> for &u32 { }
//~^ ERROR missing lifetime specifier
impl<'a> MyTrait<'_> for &'a f32 { }
//~^ ERROR missing lifetime specifier
fn main() {}

View File

@ -0,0 +1,15 @@
error[E0106]: missing lifetime specifier
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:16:26
|
LL | impl<'a> MyTrait<'a> for &u32 { }
| ^ expected lifetime parameter
error[E0106]: missing lifetime specifier
--> $DIR/feature-gate-in_band_lifetimes-impl.rs:19:18
|
LL | impl<'a> MyTrait<'_> for &'a f32 { }
| ^^ expected lifetime parameter
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`.

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that we do not yet support elision in associated types, even
// when there is just one name we could take from the impl header.
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait {
type Output;
}
impl MyTrait for &i32 {
type Output = &i32;
//~^ ERROR missing lifetime specifier
}
impl MyTrait for &u32 {
type Output = &'_ i32;
//~^ ERROR missing lifetime specifier
}
// This is what you have to do:
impl MyTrait for &'a f32 {
type Output = &'a f32;
}
fn main() { }

View File

@ -0,0 +1,15 @@
error[E0106]: missing lifetime specifier
--> $DIR/assoc-type.rs:24:19
|
LL | type Output = &i32;
| ^ expected lifetime parameter
error[E0106]: missing lifetime specifier
--> $DIR/assoc-type.rs:29:20
|
LL | type Output = &'_ i32;
| ^^ expected lifetime parameter
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0106`.

View File

@ -0,0 +1,45 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
// 'b> MyTrait<'a> for &'b i32`.
#![allow(warnings)]
#![feature(dyn_trait)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
use std::fmt::Debug;
// Equivalent to `Box<dyn Debug + 'static>`:
trait StaticTrait { }
impl StaticTrait for Box<dyn Debug> { }
// Equivalent to `Box<dyn Debug + 'static>`:
trait NotStaticTrait { }
impl NotStaticTrait for Box<dyn Debug + '_> { }
fn static_val<T: StaticTrait>(_: T) {
}
fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
static_val(x); //~ ERROR cannot infer
}
fn not_static_val<T: NotStaticTrait>(_: T) {
}
fn with_dyn_debug_not_static<'a>(x: Box<dyn Debug + 'a>) {
not_static_val(x); // OK
}
fn main() {
}

View File

@ -0,0 +1,22 @@
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> $DIR/dyn-trait.rs:34:16
|
LL | static_val(x); //~ ERROR cannot infer
| ^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body at 33:1...
--> $DIR/dyn-trait.rs:33:1
|
LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the expression is assignable:
expected std::boxed::Box<std::fmt::Debug>
found std::boxed::Box<std::fmt::Debug + 'a>
= note: but, the lifetime must be valid for the static lifetime...
= note: ...so that the types are compatible:
expected StaticTrait
found StaticTrait
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.

View File

@ -0,0 +1,23 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait { }
struct Foo<'a> { x: &'a u32 }
impl MyTrait for Foo {
//~^ ERROR missing lifetime specifier
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0106]: missing lifetime specifier
--> $DIR/path-elided.rs:19:18
|
LL | impl MyTrait for Foo {
| ^^^ expected lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.

View File

@ -0,0 +1,47 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that `impl MyTrait for Foo<'_>` works.
// run-pass
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait { }
struct Foo<'a> { x: &'a u32 }
impl MyTrait for Foo<'_> {
}
fn impls_my_trait<T: MyTrait>() { }
fn impls_my_trait_val<T: MyTrait>(_: T) {
impls_my_trait::<T>();
}
fn random_where_clause()
where for<'a> Foo<'a>: MyTrait { }
fn main() {
let x = 22;
let f = Foo { x: &x };
// This type is `Foo<'x>` for a local lifetime `'x`; so the impl
// must apply to any lifetime to apply to this.
impls_my_trait_val(f);
impls_my_trait::<Foo<'static>>();
random_where_clause();
}

View File

@ -0,0 +1,43 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that `impl MyTrait for &i32` works and is equivalent to any lifetime.
// run-pass
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait { }
impl MyTrait for &i32 {
}
fn impls_my_trait<T: MyTrait>() { }
fn impls_my_trait_val<T: MyTrait>(_: T) {
impls_my_trait::<T>();
}
fn random_where_clause()
where for<'a> &'a i32: MyTrait { }
fn main() {
let x = 22;
let f = &x;
impls_my_trait_val(f);
impls_my_trait::<&'static i32>();
random_where_clause();
}

View File

@ -0,0 +1,21 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait<'a> { }
impl MyTrait for u32 {
//~^ ERROR missing lifetime specifier
}
fn main() {}

View File

@ -0,0 +1,9 @@
error[E0106]: missing lifetime specifier
--> $DIR/trait-elided.rs:17:6
|
LL | impl MyTrait for u32 {
| ^^^^^^^ expected lifetime parameter
error: aborting due to previous error
For more information about this error, try `rustc --explain E0106`.

View File

@ -0,0 +1,48 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// Test that `impl MyTrait<'_> for &i32` is equivalent to `impl<'a,
// 'b> MyTrait<'a> for &'b i32`.
//
// run-pass
#![allow(warnings)]
#![feature(in_band_lifetimes)]
#![feature(underscore_lifetimes)]
trait MyTrait<'a> { }
// This is equivalent to `MyTrait<'a> for &'b i32`, which is proven by
// the code below.
impl MyTrait<'_> for &i32 {
}
// When called, T will be `&'x i32` for some `'x`, so since we can
// prove that `&'x i32: for<'a> MyTrait<'a>, then we know that the
// lifetime parameter above is disconnected.
fn impls_my_trait<T: for<'a> MyTrait<'a>>() { }
fn impls_my_trait_val<T: for<'a> MyTrait<'a>>(_: T) {
impls_my_trait::<T>();
}
fn random_where_clause()
where for<'a, 'b> &'a i32: MyTrait<'b> { }
fn main() {
let x = 22;
let f = &x;
impls_my_trait_val(f);
impls_my_trait::<&'static i32>();
random_where_clause();
}