Auto merge of #104048 - cjgillot:split-lifetime, r=compiler-errors
Separate lifetime ident from lifetime resolution in HIR Drive-by: change how suggested generic args are computed. Fixes https://github.com/rust-lang/rust/issues/103815 I recommend reviewing commit-by-commit.
This commit is contained in:
commit
454784afba
49 changed files with 581 additions and 435 deletions
|
@ -29,15 +29,16 @@ use std::fmt;
|
|||
#[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)]
|
||||
|
@ -88,7 +89,7 @@ impl ParamName {
|
|||
#[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
|
||||
|
@ -116,25 +117,6 @@ pub enum LifetimeName {
|
|||
}
|
||||
|
||||
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,
|
||||
|
@ -146,34 +128,54 @@ impl LifetimeName {
|
|||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +269,7 @@ pub enum GenericArg<'hir> {
|
|||
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,
|
||||
|
@ -284,7 +286,7 @@ impl GenericArg<'_> {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -446,7 +448,7 @@ impl GenericBound<'_> {
|
|||
match self {
|
||||
GenericBound::Trait(t, ..) => t.span,
|
||||
GenericBound::LangItemTrait(_, span, ..) => *span,
|
||||
GenericBound::Outlives(l) => l.span,
|
||||
GenericBound::Outlives(l) => l.ident.span,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -559,6 +561,19 @@ impl<'hir> Generics<'hir> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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)) {
|
||||
|
@ -765,10 +780,7 @@ pub struct WhereRegionPredicate<'hir> {
|
|||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2688,6 +2700,8 @@ pub struct FnDecl<'hir> {
|
|||
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.
|
||||
|
@ -3453,7 +3467,7 @@ impl<'hir> Node<'hir> {
|
|||
| 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(..)
|
||||
|
|
|
@ -1109,17 +1109,7 @@ pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v Ge
|
|||
|
||||
pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
|
||||
visitor.visit_id(lifetime.hir_id);
|
||||
match lifetime.name {
|
||||
LifetimeName::Param(_, ParamName::Plain(ident)) => {
|
||||
visitor.visit_ident(ident);
|
||||
}
|
||||
LifetimeName::Param(_, ParamName::Fresh)
|
||||
| LifetimeName::Param(_, ParamName::Error)
|
||||
| LifetimeName::Static
|
||||
| LifetimeName::Error
|
||||
| LifetimeName::ImplicitObjectLifetimeDefault
|
||||
| LifetimeName::Infer => {}
|
||||
}
|
||||
visitor.visit_ident(lifetime.ident);
|
||||
}
|
||||
|
||||
pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#![feature(associated_type_defaults)]
|
||||
#![feature(closure_track_caller)]
|
||||
#![feature(const_btree_len)]
|
||||
#![feature(let_chains)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(never_type)]
|
||||
#![feature(rustc_attrs)]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue