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::error::ExpectedFound;
|
||||||
use rustc_middle::ty::print::RegionHighlightMode;
|
use rustc_middle::ty::print::RegionHighlightMode;
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
use rustc_middle::ty::{self, TyCtxt, TypeVisitable};
|
||||||
use rustc_span::Span;
|
use rustc_span::{Ident, Span};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::error_reporting::infer::nice_region_error::NiceRegionError;
|
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.
|
// Get the span of all the used type parameters in the method.
|
||||||
let assoc_item = self.tcx().associated_item(trait_item_def_id);
|
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 {
|
match assoc_item.kind {
|
||||||
ty::AssocKind::Fn { .. } => {
|
ty::AssocKind::Fn { .. } => {
|
||||||
if let Some(hir_id) =
|
if let Some(hir_id) =
|
||||||
|
|
@ -122,13 +123,49 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
|
||||||
found,
|
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> {
|
struct TypeParamSpanVisitor<'tcx> {
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
types: Vec<Span>,
|
types: Vec<Span>,
|
||||||
|
elided_lifetime_paths: Vec<ElidedLifetimeInPath>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||||
|
|
@ -138,6 +175,83 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
|
||||||
self.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>) {
|
fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
|
||||||
match arg.kind {
|
match arg.kind {
|
||||||
hir::TyKind::Ref(_, ref mut_ty) => {
|
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