permit '_
and &T
in impl headers
Deprecated forms of elision are not supported.
This commit is contained in:
parent
df70060bd6
commit
94468dac63
@ -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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
});
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
22
src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Normal file
22
src/test/ui/feature-gate-in_band_lifetimes-impl.rs
Normal 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() {}
|
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal file
15
src/test/ui/feature-gate-in_band_lifetimes-impl.stderr
Normal 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`.
|
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal file
38
src/test/ui/in-band-lifetimes/impl/assoc-type.rs
Normal 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() { }
|
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal file
15
src/test/ui/in-band-lifetimes/impl/assoc-type.stderr
Normal 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`.
|
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal file
45
src/test/ui/in-band-lifetimes/impl/dyn-trait.rs
Normal 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() {
|
||||
}
|
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal file
22
src/test/ui/in-band-lifetimes/impl/dyn-trait.stderr
Normal 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`.
|
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal file
23
src/test/ui/in-band-lifetimes/impl/path-elided.rs
Normal 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() {}
|
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/path-elided.stderr
Normal 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`.
|
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal file
47
src/test/ui/in-band-lifetimes/impl/path-underscore.rs
Normal 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();
|
||||
}
|
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal file
43
src/test/ui/in-band-lifetimes/impl/ref-underscore.rs
Normal 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();
|
||||
}
|
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal file
21
src/test/ui/in-band-lifetimes/impl/trait-elided.rs
Normal 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() {}
|
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal file
9
src/test/ui/in-band-lifetimes/impl/trait-elided.stderr
Normal 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`.
|
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal file
48
src/test/ui/in-band-lifetimes/impl/trait-underscore.rs
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user