Suggests adding named lifetime when the return contains value borrowed from more than one lifetimes of the function's inputs
This commit is contained in:
parent
388538fc96
commit
523fe7a121
8 changed files with 184 additions and 40 deletions
|
@ -303,6 +303,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
|
|||
None,
|
||||
format!("captures `{}`", hidden_region),
|
||||
None,
|
||||
Some(reg_info.def_id),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,13 +8,17 @@ use rustc_data_structures::fx::FxIndexSet;
|
|||
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::intravisit::{walk_ty, Visitor};
|
||||
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
|
||||
use rustc_hir::{
|
||||
self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
|
||||
TyKind,
|
||||
};
|
||||
use rustc_middle::ty::{
|
||||
self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
|
||||
};
|
||||
use rustc_span::symbol::Ident;
|
||||
use rustc_span::Span;
|
||||
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use std::ops::ControlFlow;
|
||||
|
||||
impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||
|
@ -268,6 +272,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
Some(arg),
|
||||
captures,
|
||||
Some((param.param_ty_span, param.param_ty.to_string())),
|
||||
Some(anon_reg_sup.def_id),
|
||||
);
|
||||
|
||||
let reported = err.emit();
|
||||
|
@ -283,6 +288,7 @@ pub fn suggest_new_region_bound(
|
|||
arg: Option<String>,
|
||||
captures: String,
|
||||
param: Option<(Span, String)>,
|
||||
scope_def_id: Option<LocalDefId>,
|
||||
) {
|
||||
debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
|
||||
// FIXME: account for the need of parens in `&(dyn Trait + '_)`
|
||||
|
@ -340,12 +346,69 @@ pub fn suggest_new_region_bound(
|
|||
_ => false,
|
||||
}) {
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
fn_return.span.shrink_to_hi(),
|
||||
&format!("{declare} `{ty}` {captures}, {explicit}",),
|
||||
&plus_lt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
// get a lifetime name of existing named lifetimes if any
|
||||
let existing_lt_name = if let Some(id) = scope_def_id
|
||||
&& let Some(generics) = tcx.hir().get_generics(id)
|
||||
&& let named_lifetimes = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
|
||||
.map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
|
||||
.filter(|n| ! matches!(n, None))
|
||||
.collect::<Vec<_>>()
|
||||
&& named_lifetimes.len() > 0 {
|
||||
named_lifetimes[0].clone()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let name = if let Some(name) = &existing_lt_name {
|
||||
format!("{}", name)
|
||||
} else {
|
||||
format!("'a")
|
||||
};
|
||||
// if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
|
||||
// introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
|
||||
if let Some(id) = scope_def_id
|
||||
&& let Some(generics) = tcx.hir().get_generics(id)
|
||||
&& let mut spans_suggs = generics
|
||||
.params
|
||||
.iter()
|
||||
.filter(|p| p.is_elided_lifetime())
|
||||
.map(|p|
|
||||
if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
|
||||
(p.span.shrink_to_hi(),format!("{name} "))
|
||||
} else { // Underscore (elided with '_)
|
||||
(p.span, format!("{name}"))
|
||||
}
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
&& spans_suggs.len() > 1
|
||||
{
|
||||
let use_lt =
|
||||
if existing_lt_name == None {
|
||||
spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
|
||||
format!("you can introduce a named lifetime parameter `{name}`")
|
||||
} else {
|
||||
// make use the existing named lifetime
|
||||
format!("you can use the named lifetime parameter `{name}`")
|
||||
};
|
||||
spans_suggs
|
||||
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
|
||||
err.multipart_suggestion_verbose(
|
||||
&format!(
|
||||
"{declare} `{ty}` {captures}, {use_lt}",
|
||||
),
|
||||
spans_suggs,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
} else {
|
||||
err.span_suggestion_verbose(
|
||||
fn_return.span.shrink_to_hi(),
|
||||
&format!("{declare} `{ty}` {captures}, {explicit}",),
|
||||
&plus_lt,
|
||||
Applicability::MaybeIncorrect,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
TyKind::TraitObject(_, lt, _) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue