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) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
// Regression test for https://github.com/rust-lang/rust/issues/65866.
|
||||
|
||||
mod plain {
|
||||
struct Foo;
|
||||
|
||||
struct Re<'a> {
|
||||
_data: &'a u16,
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn bar(&self, r: &mut Re);
|
||||
//~^ NOTE expected
|
||||
//~| NOTE `Re` here is elided as `Re<'_>`
|
||||
}
|
||||
|
||||
impl Bar for Foo {
|
||||
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
//~| NOTE expected signature
|
||||
//~| NOTE found
|
||||
//~| HELP the lifetime requirements
|
||||
//~| HELP verify the lifetime relationships
|
||||
}
|
||||
}
|
||||
|
||||
mod with_type_args {
|
||||
struct Foo;
|
||||
|
||||
struct Re<'a, T> {
|
||||
_data: (&'a u16, T),
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn bar(&self, r: &mut Re<u8>);
|
||||
//~^ NOTE expected
|
||||
//~| NOTE `Re` here is elided as `Re<'_, u8>`
|
||||
}
|
||||
|
||||
impl Bar for Foo {
|
||||
fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
|
||||
//~^ ERROR `impl` item signature doesn't match `trait` item signature
|
||||
//~| NOTE expected signature
|
||||
//~| NOTE found
|
||||
//~| HELP the lifetime requirements
|
||||
//~| HELP verify the lifetime relationships
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:17:9
|
||||
|
|
||||
LL | fn bar(&self, r: &mut Re);
|
||||
| -------------------------- expected `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
|
||||
...
|
||||
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
|
||||
|
|
||||
= note: expected signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'3>)`
|
||||
found signature `fn(&'1 plain::Foo, &'2 mut plain::Re<'1>)`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
note: `Re` here is elided as `Re<'_>`
|
||||
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:11:31
|
||||
|
|
||||
LL | fn bar(&self, r: &mut Re);
|
||||
| ^^
|
||||
|
||||
error: `impl` item signature doesn't match `trait` item signature
|
||||
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:40:9
|
||||
|
|
||||
LL | fn bar(&self, r: &mut Re<u8>);
|
||||
| ------------------------------ expected `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
|
||||
...
|
||||
LL | fn bar<'a, 'b>(&'a self, _r: &'b mut Re<'a, u8>) {}
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
|
||||
|
|
||||
= note: expected signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'3, u8>)`
|
||||
found signature `fn(&'1 with_type_args::Foo, &'2 mut with_type_args::Re<'1, u8>)`
|
||||
= help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
|
||||
= help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
|
||||
note: `Re` here is elided as `Re<'_, u8>`
|
||||
--> $DIR/trait-impl-mismatch-elided-lifetime-issue-65866.rs:34:31
|
||||
|
|
||||
LL | fn bar(&self, r: &mut Re<u8>);
|
||||
| ^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue