1
Fork 0

Use kw::Empty for elided lifetimes in path.

This commit is contained in:
Camille GILLOT 2022-11-06 11:40:31 +00:00
parent 41090346d8
commit 1c737d6997
12 changed files with 281 additions and 83 deletions

View file

@ -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)
}

View file

@ -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)
}),

View file

@ -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
}

View file

@ -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,
];

View file

@ -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>,

View file

@ -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
}
}

View file

@ -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 {

View file

@ -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,
}
}