#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
pub struct Lifetime {
pub hir_id: HirId,
- pub span: Span,
/// Either "`'a`", referring to a named lifetime definition,
- /// or "``" (i.e., `kw::Empty`), for elision placeholders.
+ /// `'_` referring to an anonymous lifetime (either explicitly `'_` or `&type`),
+ /// or "``" (i.e., `kw::Empty`) when appearing in path.
///
- /// HIR lowering inserts these placeholders in type paths that
- /// refer to type definitions needing lifetime parameters,
- /// `&T` and `&mut T`, and trait objects without `... + 'a`.
- pub name: LifetimeName,
+ /// See `Lifetime::suggestion_position` for practical use.
+ pub ident: Ident,
+
+ /// Semantics of this lifetime.
+ pub res: LifetimeName,
}
#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
#[derive(HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
- Param(LocalDefId, ParamName),
+ Param(LocalDefId),
/// Implicit lifetime in a context like `dyn Foo`. This is
/// distinguished from implicit lifetimes elsewhere because the
}
impl LifetimeName {
- pub fn ident(&self) -> Ident {
- match *self {
- LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Error => Ident::empty(),
- LifetimeName::Infer => Ident::with_dummy_span(kw::UnderscoreLifetime),
- LifetimeName::Static => Ident::with_dummy_span(kw::StaticLifetime),
- LifetimeName::Param(_, param_name) => param_name.ident(),
- }
- }
-
- pub fn is_anonymous(&self) -> bool {
- match *self {
- LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Infer
- | LifetimeName::Param(_, ParamName::Fresh)
- | LifetimeName::Error => true,
- LifetimeName::Static | LifetimeName::Param(..) => false,
- }
- }
-
pub fn is_elided(&self) -> bool {
match self {
LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
}
}
-
- fn is_static(&self) -> bool {
- self == &LifetimeName::Static
- }
-
- pub fn normalize_to_macros_2_0(&self) -> LifetimeName {
- match *self {
- LifetimeName::Param(def_id, param_name) => {
- LifetimeName::Param(def_id, param_name.normalize_to_macros_2_0())
- }
- lifetime_name => lifetime_name,
- }
- }
}
impl fmt::Display for Lifetime {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.name.ident().fmt(f)
+ if self.ident.name != kw::Empty { self.ident.name.fmt(f) } else { "'_".fmt(f) }
}
}
+pub enum LifetimeSuggestionPosition {
+ /// The user wrote `'a` or `'_`.
+ Normal,
+ /// The user wrote `&type` or `&mut type`.
+ Ampersand,
+ /// The user wrote `Path` and omitted the `<'_>`.
+ ElidedPath,
+ /// The user wrote `Path<T>`, and omitted the `'_,`.
+ ElidedPathArgument,
+ /// The user wrote `dyn Trait` and omitted the `+ '_`.
+ ObjectDefault,
+}
+
impl Lifetime {
pub fn is_elided(&self) -> bool {
- self.name.is_elided()
+ self.res.is_elided()
+ }
+
+ pub fn is_anonymous(&self) -> bool {
+ self.ident.name == kw::Empty || self.ident.name == kw::UnderscoreLifetime
+ }
+
+ pub fn suggestion_position(&self) -> (LifetimeSuggestionPosition, Span) {
+ if self.ident.name == kw::Empty {
+ if self.ident.span.is_empty() {
+ (LifetimeSuggestionPosition::ElidedPathArgument, self.ident.span)
+ } else {
+ (LifetimeSuggestionPosition::ElidedPath, self.ident.span.shrink_to_hi())
+ }
+ } else if self.res == LifetimeName::ImplicitObjectLifetimeDefault {
+ (LifetimeSuggestionPosition::ObjectDefault, self.ident.span)
+ } else if self.ident.span.is_empty() {
+ (LifetimeSuggestionPosition::Ampersand, self.ident.span)
+ } else {
+ (LifetimeSuggestionPosition::Normal, self.ident.span)
+ }
}
pub fn is_static(&self) -> bool {
- self.name.is_static()
+ self.res == LifetimeName::Static
}
}
impl GenericArg<'_> {
pub fn span(&self) -> Span {
match self {
- GenericArg::Lifetime(l) => l.span,
+ GenericArg::Lifetime(l) => l.ident.span,
GenericArg::Type(t) => t.span,
GenericArg::Const(c) => c.span,
GenericArg::Infer(i) => i.span,
}
pub fn is_synthetic(&self) -> bool {
- matches!(self, GenericArg::Lifetime(lifetime) if lifetime.name.ident() == Ident::empty())
+ matches!(self, GenericArg::Lifetime(lifetime) if lifetime.ident == Ident::empty())
}
pub fn descr(&self) -> &'static str {
match self {
GenericBound::Trait(t, ..) => t.span,
GenericBound::LangItemTrait(_, span, ..) => *span,
- GenericBound::Outlives(l) => l.span,
+ GenericBound::Outlives(l) => l.ident.span,
}
}
}
}
}
+ /// If there are generic parameters, return where to introduce a new one.
+ pub fn span_for_lifetime_suggestion(&self) -> Option<Span> {
+ if let Some(first) = self.params.first()
+ && self.span.contains(first.span)
+ {
+ // `fn foo<A>(t: impl Trait)`
+ // ^ suggest `'a, ` here
+ Some(first.span.shrink_to_lo())
+ } else {
+ None
+ }
+ }
+
/// If there are generic parameters, return where to introduce a new one.
pub fn span_for_param_suggestion(&self) -> Option<Span> {
if self.params.iter().any(|p| self.span.contains(p.span)) {
impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
pub fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
- match self.lifetime.name {
- LifetimeName::Param(id, _) => id == param_def_id,
- _ => false,
- }
+ self.lifetime.res == LifetimeName::Param(param_def_id)
}
}
pub c_variadic: bool,
/// Does the function have an implicit self?
pub implicit_self: ImplicitSelfKind,
+ /// Is lifetime elision allowed.
+ pub lifetime_elision_allowed: bool,
}
/// Represents what type of implicit self a function has, if any.
| Node::Variant(Variant { ident, .. })
| Node::Item(Item { ident, .. })
| Node::PathSegment(PathSegment { ident, .. }) => Some(*ident),
- Node::Lifetime(lt) => Some(lt.name.ident()),
+ Node::Lifetime(lt) => Some(lt.ident),
Node::GenericParam(p) => Some(p.name.ident()),
Node::TypeBinding(b) => Some(b.ident),
Node::Param(..)