Rollup merge of #152637 - JohnTitor:issue-65866, r=estebank
Add a note about elided lifetime Fixes rust-lang/rust#65866 r? @estebank
This commit is contained in:
commit
9e38745532
3 changed files with 206 additions and 3 deletions
|
|
@ -11,7 +11,7 @@ use rustc_middle::traits::ObligationCauseCode;
|
|||
use rustc_middle::ty::error::ExpectedFound;
|
||||
use rustc_middle::ty::print::RegionHighlightMode;
|
||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::{Ident, Span};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
|
||||
|
|
@ -99,7 +99,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
|
||||
// Get the span of all the used type parameters in the method.
|
||||
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
||||
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
|
||||
let mut visitor =
|
||||
TypeParamSpanVisitor { tcx: self.tcx(), types: vec![], elided_lifetime_paths: vec![] };
|
||||
match assoc_item.kind {
|
||||
ty::AssocKind::Fn { .. } => {
|
||||
if let Some(hir_id) =
|
||||
|
|
@ -122,13 +123,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
|||
found,
|
||||
};
|
||||
|
||||
self.tcx().dcx().emit_err(diag)
|
||||
let mut diag = self.tcx().dcx().create_err(diag);
|
||||
// A limit not to make diag verbose.
|
||||
const ELIDED_LIFETIME_NOTE_LIMIT: usize = 5;
|
||||
let elided_lifetime_paths = visitor.elided_lifetime_paths;
|
||||
let total_elided_lifetime_paths = elided_lifetime_paths.len();
|
||||
let shown_elided_lifetime_paths = if tcx.sess.opts.verbose {
|
||||
total_elided_lifetime_paths
|
||||
} else {
|
||||
ELIDED_LIFETIME_NOTE_LIMIT
|
||||
};
|
||||
|
||||
for elided in elided_lifetime_paths.into_iter().take(shown_elided_lifetime_paths) {
|
||||
diag.span_note(
|
||||
elided.span,
|
||||
format!("`{}` here is elided as `{}`", elided.ident, elided.shorthand),
|
||||
);
|
||||
}
|
||||
if total_elided_lifetime_paths > shown_elided_lifetime_paths {
|
||||
diag.note(format!(
|
||||
"and {} more elided lifetime{} in type paths",
|
||||
total_elided_lifetime_paths - shown_elided_lifetime_paths,
|
||||
if total_elided_lifetime_paths - shown_elided_lifetime_paths == 1 {
|
||||
""
|
||||
} else {
|
||||
"s"
|
||||
},
|
||||
));
|
||||
}
|
||||
diag.emit()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ElidedLifetimeInPath {
|
||||
span: Span,
|
||||
ident: Ident,
|
||||
shorthand: String,
|
||||
}
|
||||
|
||||
struct TypeParamSpanVisitor<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
types: Vec<Span>,
|
||||
elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||
|
|
@ -138,6 +175,83 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
|||
self.tcx
|
||||
}
|
||||
|
||||
fn visit_qpath(&mut self, qpath: &'tcx hir::QPath<'tcx>, id: hir::HirId, _span: Span) {
|
||||
fn record_elided_lifetimes(
|
||||
tcx: TyCtxt<'_>,
|
||||
elided_lifetime_paths: &mut Vec<ElidedLifetimeInPath>,
|
||||
segment: &hir::PathSegment<'_>,
|
||||
) {
|
||||
let Some(args) = segment.args else { return };
|
||||
if args.parenthesized != hir::GenericArgsParentheses::No {
|
||||
// Our diagnostic rendering below uses `<...>` syntax; skip cases like `Fn(..) -> ..`.
|
||||
return;
|
||||
}
|
||||
let elided_count = args
|
||||
.args
|
||||
.iter()
|
||||
.filter(|arg| {
|
||||
let hir::GenericArg::Lifetime(l) = arg else { return false };
|
||||
l.syntax == hir::LifetimeSyntax::Implicit
|
||||
&& matches!(l.source, hir::LifetimeSource::Path { .. })
|
||||
})
|
||||
.count();
|
||||
if elided_count == 0
|
||||
|| elided_lifetime_paths.iter().any(|p| p.span == segment.ident.span)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let sm = tcx.sess.source_map();
|
||||
let mut parts = args
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| match arg {
|
||||
hir::GenericArg::Lifetime(l) => {
|
||||
if l.syntax == hir::LifetimeSyntax::Implicit
|
||||
&& matches!(l.source, hir::LifetimeSource::Path { .. })
|
||||
{
|
||||
"'_".to_string()
|
||||
} else {
|
||||
sm.span_to_snippet(l.ident.span)
|
||||
.unwrap_or_else(|_| format!("'{}", l.ident.name))
|
||||
}
|
||||
}
|
||||
hir::GenericArg::Type(ty) => {
|
||||
sm.span_to_snippet(ty.span).unwrap_or_else(|_| "..".to_string())
|
||||
}
|
||||
hir::GenericArg::Const(ct) => {
|
||||
sm.span_to_snippet(ct.span).unwrap_or_else(|_| "..".to_string())
|
||||
}
|
||||
hir::GenericArg::Infer(_) => "_".to_string(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
parts.extend(args.constraints.iter().map(|constraint| {
|
||||
sm.span_to_snippet(constraint.span)
|
||||
.unwrap_or_else(|_| format!("{} = ..", constraint.ident))
|
||||
}));
|
||||
let shorthand = format!("{}<{}>", segment.ident, parts.join(", "));
|
||||
|
||||
elided_lifetime_paths.push(ElidedLifetimeInPath {
|
||||
span: segment.ident.span,
|
||||
ident: segment.ident,
|
||||
shorthand,
|
||||
});
|
||||
}
|
||||
|
||||
match qpath {
|
||||
hir::QPath::Resolved(_, path) => {
|
||||
for segment in path.segments {
|
||||
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
|
||||
}
|
||||
}
|
||||
hir::QPath::TypeRelative(_, segment) => {
|
||||
record_elided_lifetimes(self.tcx, &mut self.elided_lifetime_paths, segment);
|
||||
}
|
||||
}
|
||||
|
||||
hir::intravisit::walk_qpath(self, qpath, id);
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||
match arg.kind {
|
||||
hir::TyKind::Ref(_, ref mut_ty) => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue