Rollup merge of #96409 - marmeladema:fix-nll-introduce-named-lifetime-suggestion, r=jackh726
Recover suggestions to introduce named lifetime under NLL Fixes #96157 r? ```@jackh726``` Built on top of #96385 so only the second commit is relevant
This commit is contained in:
commit
cbfbc3be7d
20 changed files with 333 additions and 78 deletions
|
@ -6,6 +6,7 @@ use crate::infer::error_reporting::nice_region_error::util::AnonymousParamInfo;
|
|||
use crate::infer::error_reporting::nice_region_error::NiceRegionError;
|
||||
use crate::infer::lexical_region_resolve::RegionResolutionError;
|
||||
use crate::infer::SubregionOrigin;
|
||||
use crate::infer::TyCtxt;
|
||||
|
||||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed};
|
||||
use rustc_hir as hir;
|
||||
|
@ -145,84 +146,83 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
self.suggest_adding_lifetime_params(sub, ty_sup, ty_sub, &mut err);
|
||||
if suggest_adding_lifetime_params(self.tcx(), sub, ty_sup, ty_sub, &mut err) {
|
||||
err.note("each elided lifetime in input position becomes a distinct lifetime");
|
||||
}
|
||||
|
||||
let reported = err.emit();
|
||||
Some(reported)
|
||||
}
|
||||
|
||||
fn suggest_adding_lifetime_params(
|
||||
&self,
|
||||
sub: Region<'tcx>,
|
||||
ty_sup: &Ty<'_>,
|
||||
ty_sub: &Ty<'_>,
|
||||
err: &mut Diagnostic,
|
||||
) {
|
||||
if let (
|
||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
|
||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
|
||||
) = (ty_sub, ty_sup)
|
||||
{
|
||||
if lifetime_sub.name.is_elided() && lifetime_sup.name.is_elided() {
|
||||
if let Some(anon_reg) = self.tcx().is_suitable_region(sub) {
|
||||
let hir_id = self.tcx().hir().local_def_id_to_hir_id(anon_reg.def_id);
|
||||
|
||||
let node = self.tcx().hir().get(hir_id);
|
||||
let is_impl = matches!(&node, hir::Node::ImplItem(_));
|
||||
let generics = match node {
|
||||
hir::Node::Item(&hir::Item {
|
||||
kind: hir::ItemKind::Fn(_, ref generics, ..),
|
||||
..
|
||||
})
|
||||
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
|
||||
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
let (suggestion_param_name, introduce_new) = generics
|
||||
.params
|
||||
.iter()
|
||||
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
|
||||
.and_then(|p| self.tcx().sess.source_map().span_to_snippet(p.span).ok())
|
||||
.map(|name| (name, false))
|
||||
.unwrap_or_else(|| ("'a".to_string(), true));
|
||||
|
||||
let mut suggestions = vec![
|
||||
if let hir::LifetimeName::Underscore = lifetime_sub.name {
|
||||
(lifetime_sub.span, suggestion_param_name.clone())
|
||||
} else {
|
||||
(lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
|
||||
},
|
||||
if let hir::LifetimeName::Underscore = lifetime_sup.name {
|
||||
(lifetime_sup.span, suggestion_param_name.clone())
|
||||
} else {
|
||||
(lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
|
||||
},
|
||||
];
|
||||
|
||||
if introduce_new {
|
||||
let new_param_suggestion = match &generics.params {
|
||||
[] => (generics.span, format!("<{}>", suggestion_param_name)),
|
||||
[first, ..] => {
|
||||
(first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name))
|
||||
}
|
||||
};
|
||||
|
||||
suggestions.push(new_param_suggestion);
|
||||
}
|
||||
|
||||
let mut sugg = String::from("consider introducing a named lifetime parameter");
|
||||
if is_impl {
|
||||
sugg.push_str(" and update trait if needed");
|
||||
}
|
||||
err.multipart_suggestion(
|
||||
sugg.as_str(),
|
||||
suggestions,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
err.note("each elided lifetime in input position becomes a distinct lifetime");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn suggest_adding_lifetime_params<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
sub: Region<'tcx>,
|
||||
ty_sup: &Ty<'_>,
|
||||
ty_sub: &Ty<'_>,
|
||||
err: &mut Diagnostic,
|
||||
) -> bool {
|
||||
let (
|
||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
|
||||
hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
|
||||
) = (ty_sub, ty_sup) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if !lifetime_sub.name.is_elided() || !lifetime_sup.name.is_elided() {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(anon_reg) = tcx.is_suitable_region(sub) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id);
|
||||
|
||||
let node = tcx.hir().get(hir_id);
|
||||
let is_impl = matches!(&node, hir::Node::ImplItem(_));
|
||||
let generics = match node {
|
||||
hir::Node::Item(&hir::Item { kind: hir::ItemKind::Fn(_, ref generics, ..), .. })
|
||||
| hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
|
||||
| hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
let (suggestion_param_name, introduce_new) = generics
|
||||
.params
|
||||
.iter()
|
||||
.find(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
|
||||
.and_then(|p| tcx.sess.source_map().span_to_snippet(p.span).ok())
|
||||
.map(|name| (name, false))
|
||||
.unwrap_or_else(|| ("'a".to_string(), true));
|
||||
|
||||
let mut suggestions = vec![
|
||||
if let hir::LifetimeName::Underscore = lifetime_sub.name {
|
||||
(lifetime_sub.span, suggestion_param_name.clone())
|
||||
} else {
|
||||
(lifetime_sub.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
|
||||
},
|
||||
if let hir::LifetimeName::Underscore = lifetime_sup.name {
|
||||
(lifetime_sup.span, suggestion_param_name.clone())
|
||||
} else {
|
||||
(lifetime_sup.span.shrink_to_hi(), suggestion_param_name.clone() + " ")
|
||||
},
|
||||
];
|
||||
|
||||
if introduce_new {
|
||||
let new_param_suggestion = match &generics.params {
|
||||
[] => (generics.span, format!("<{}>", suggestion_param_name)),
|
||||
[first, ..] => (first.span.shrink_to_lo(), format!("{}, ", suggestion_param_name)),
|
||||
};
|
||||
|
||||
suggestions.push(new_param_suggestion);
|
||||
}
|
||||
|
||||
let mut sugg = String::from("consider introducing a named lifetime parameter");
|
||||
if is_impl {
|
||||
sugg.push_str(" and update trait if needed");
|
||||
}
|
||||
err.multipart_suggestion(sugg.as_str(), suggestions, Applicability::MaybeIncorrect);
|
||||
|
||||
true
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ use rustc_middle::ty::{self, Region, TyCtxt};
|
|||
/// ```
|
||||
/// The function returns the nested type corresponding to the anonymous region
|
||||
/// for e.g., `&u8` and `Vec<&u8>`.
|
||||
pub(crate) fn find_anon_type<'tcx>(
|
||||
pub fn find_anon_type<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
region: Region<'tcx>,
|
||||
br: &ty::BoundRegionKind,
|
||||
|
|
|
@ -14,6 +14,8 @@ mod static_impl_trait;
|
|||
mod trait_impl_difference;
|
||||
mod util;
|
||||
|
||||
pub use different_lifetimes::suggest_adding_lifetime_params;
|
||||
pub use find_anon_type::find_anon_type;
|
||||
pub use static_impl_trait::suggest_new_region_bound;
|
||||
pub use util::find_param_with_region;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue