Use kw::Empty for elided lifetimes in path.
This commit is contained in:
parent
41090346d8
commit
1c737d6997
12 changed files with 281 additions and 83 deletions
|
@ -2101,7 +2101,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
LifetimeRes::Fresh { param, .. } => {
|
||||
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
|
||||
let param = self.local_def_id(param);
|
||||
hir::LifetimeName::Param(param)
|
||||
}
|
||||
|
|
|
@ -309,7 +309,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
|||
let id = NodeId::from_u32(i);
|
||||
let l = self.lower_lifetime(&Lifetime {
|
||||
id,
|
||||
ident: Ident::new(kw::UnderscoreLifetime, elided_lifetime_span),
|
||||
ident: Ident::new(kw::Empty, elided_lifetime_span),
|
||||
});
|
||||
GenericArg::Lifetime(l)
|
||||
}),
|
||||
|
|
|
@ -29,14 +29,15 @@ use std::fmt;
|
|||
#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
|
||||
pub struct Lifetime {
|
||||
pub hir_id: HirId,
|
||||
pub ident: Ident,
|
||||
|
||||
/// 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`.
|
||||
/// See `Lifetime::suggestion_position` for practical use.
|
||||
pub ident: Ident,
|
||||
|
||||
/// Semantics of this lifetime.
|
||||
pub res: LifetimeName,
|
||||
}
|
||||
|
||||
|
@ -135,6 +136,19 @@ impl fmt::Display for Lifetime {
|
|||
}
|
||||
}
|
||||
|
||||
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.res.is_elided()
|
||||
|
@ -144,6 +158,22 @@ impl Lifetime {
|
|||
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.res == LifetimeName::Static
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use rustc_middle::hir::nested_filter;
|
|||
use rustc_middle::middle::resolve_lifetime::*;
|
||||
use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
|
||||
use rustc_span::def_id::DefId;
|
||||
use rustc_span::symbol::{kw, sym, Ident};
|
||||
use rustc_span::symbol::{sym, Ident};
|
||||
use rustc_span::Span;
|
||||
use std::fmt;
|
||||
|
||||
|
@ -1218,13 +1218,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
|
|||
(generics.span, "<'a>".to_owned())
|
||||
};
|
||||
|
||||
let lifetime_sugg = match lifetime_ref.ident.name {
|
||||
kw::Empty => "'a, ".to_owned(),
|
||||
kw::UnderscoreLifetime => "'a ".to_owned(),
|
||||
_ => "'a ".to_owned(),
|
||||
let lifetime_sugg = match lifetime_ref.suggestion_position() {
|
||||
(hir::LifetimeSuggestionPosition::Normal, span) => (span, "'a".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::Ampersand, span) => (span, "'a ".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ElidedPath, span) => (span, "<'a>".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ElidedPathArgument, span) => (span, "'a, ".to_owned()),
|
||||
(hir::LifetimeSuggestionPosition::ObjectDefault, span) => (span, "+ 'a".to_owned()),
|
||||
};
|
||||
let suggestions = vec![
|
||||
(lifetime_ref.ident.span.shrink_to_hi(), lifetime_sugg),
|
||||
lifetime_sugg,
|
||||
new_param_sugg,
|
||||
];
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ use crate::ty::{EarlyBinder, SubstsRef};
|
|||
use rustc_ast as ast;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{kw, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use super::{EarlyBoundRegion, InstantiatedPredicates, ParamConst, ParamTy, Predicate, TyCtxt};
|
||||
|
@ -78,6 +78,15 @@ impl GenericParamDef {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_anonymous_lifetime(&self) -> bool {
|
||||
match self.kind {
|
||||
GenericParamDefKind::Lifetime => {
|
||||
self.name == kw::UnderscoreLifetime || self.name == kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_value<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
@ -530,7 +530,7 @@ impl ty::EarlyBoundRegion {
|
|||
/// Does this early bound region have a name? Early bound regions normally
|
||||
/// always have names except when using anonymous lifetimes (`'_`).
|
||||
pub fn has_name(&self) -> bool {
|
||||
self.name != kw::UnderscoreLifetime
|
||||
self.name != kw::UnderscoreLifetime && self.name != kw::Empty
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1963,17 +1963,13 @@ impl<'tcx> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx> {
|
|||
let identify_regions = self.tcx.sess.opts.unstable_opts.identify_regions;
|
||||
|
||||
match *region {
|
||||
ty::ReEarlyBound(ref data) => {
|
||||
data.name != kw::Empty && data.name != kw::UnderscoreLifetime
|
||||
}
|
||||
ty::ReEarlyBound(ref data) => data.has_name(),
|
||||
|
||||
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
|
||||
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
|
||||
if let ty::BrNamed(_, name) = br {
|
||||
if name != kw::Empty && name != kw::UnderscoreLifetime {
|
||||
return true;
|
||||
}
|
||||
if br.is_named() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if let Some((region, _)) = highlight.highlight_bound_region {
|
||||
|
@ -2049,11 +2045,9 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
ty::ReLateBound(_, ty::BoundRegion { kind: br, .. })
|
||||
| ty::ReFree(ty::FreeRegion { bound_region: br, .. })
|
||||
| ty::RePlaceholder(ty::Placeholder { name: br, .. }) => {
|
||||
if let ty::BrNamed(_, name) = br {
|
||||
if name != kw::Empty && name != kw::UnderscoreLifetime {
|
||||
p!(write("{}", name));
|
||||
return Ok(self);
|
||||
}
|
||||
if let ty::BrNamed(_, name) = br && br.is_named() {
|
||||
p!(write("{}", name));
|
||||
return Ok(self);
|
||||
}
|
||||
|
||||
if let Some((region, counter)) = highlight.highlight_bound_region {
|
||||
|
@ -2266,7 +2260,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
|
|||
|
||||
(name, ty::BrNamed(CRATE_DEF_ID.to_def_id(), name))
|
||||
}
|
||||
ty::BrNamed(def_id, kw::UnderscoreLifetime) => {
|
||||
ty::BrNamed(def_id, kw::UnderscoreLifetime | kw::Empty) => {
|
||||
let name = next_name(&self);
|
||||
|
||||
if let Some(lt_idx) = lifetime_idx {
|
||||
|
|
|
@ -83,7 +83,9 @@ pub struct BoundRegion {
|
|||
impl BoundRegionKind {
|
||||
pub fn is_named(&self) -> bool {
|
||||
match *self {
|
||||
BoundRegionKind::BrNamed(_, name) => name != kw::UnderscoreLifetime,
|
||||
BoundRegionKind::BrNamed(_, name) => {
|
||||
name != kw::UnderscoreLifetime && name != kw::Empty
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue