Rollup merge of #148405 - Kivooeo:static-span, r=JonathanBrouwer

Fix suggestion when there were a colon already in generics

Finally found time to fix https://github.com/rust-lang/rust/issues/144215

I don't feel like this `colon_flag` is perfect solution and that it can be refactored, but I'd say that this is pretty good as it, I was tried to refactor this a little, but the thing is the scope where `param.colon_span` lives is very limited, so there is not much time to check was there colon or not, I tried to rewrite this into more functional style to address this, but it becomes way more unreadable than this one or even less performant, maybe some comments could push readability of this fix further, maybe a comment for enum or `colon_flag`?
This commit is contained in:
Matthias Krüger 2025-11-02 20:21:04 +01:00 committed by GitHub
commit 285cb31aa1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 59 additions and 12 deletions

View file

@ -774,20 +774,31 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// instead we suggest `T: 'a + 'b` in that case.
let hir_generics = self.tcx.hir_get_generics(scope).unwrap();
let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
Some((span, open_paren_sp)) => {
Some((span, LifetimeSuggestion::NeedsPlus(open_paren_sp)))
}
// If `param` corresponds to `Self`, no usable suggestion span.
None if generics.has_self && param.index == 0 => None,
None => {
let mut colon_flag = false;
let span = if let Some(param) =
hir_generics.params.iter().find(|param| param.def_id == def_id)
&& let ParamName::Plain(ident) = param.name
{
ident.span.shrink_to_hi()
if let Some(sp) = param.colon_span {
colon_flag = true;
sp.shrink_to_hi()
} else {
ident.span.shrink_to_hi()
}
} else {
let span = self.tcx.def_span(def_id);
span.shrink_to_hi()
};
Some((span, false, None))
match colon_flag {
true => Some((span, LifetimeSuggestion::HasColon)),
false => Some((span, LifetimeSuggestion::NeedsColon)),
}
}
};
(scope, sugg_span)
@ -811,17 +822,21 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let mut suggs = vec![];
let lt_name = self.suggest_name_region(generic_param_scope, sub, &mut suggs);
if let Some((sp, has_lifetimes, open_paren_sp)) = type_param_sugg_span
if let Some((sp, suggestion_type)) = type_param_sugg_span
&& suggestion_scope == type_scope
{
let suggestion =
if has_lifetimes { format!(" + {lt_name}") } else { format!(": {lt_name}") };
if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((sp, format!("){suggestion}")));
} else {
suggs.push((sp, suggestion))
match suggestion_type {
LifetimeSuggestion::NeedsPlus(open_paren_sp) => {
let suggestion = format!(" + {lt_name}");
if let Some(open_paren_sp) = open_paren_sp {
suggs.push((open_paren_sp, "(".to_string()));
suggs.push((sp, format!("){suggestion}")));
} else {
suggs.push((sp, suggestion));
}
}
LifetimeSuggestion::NeedsColon => suggs.push((sp, format!(": {lt_name}"))),
LifetimeSuggestion::HasColon => suggs.push((sp, format!(" {lt_name}"))),
}
} else if let GenericKind::Alias(ref p) = bound_kind
&& let ty::Projection = p.kind(self.tcx)
@ -1056,6 +1071,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
}
}
enum LifetimeSuggestion {
NeedsPlus(Option<Span>),
NeedsColon,
HasColon,
}
pub(super) fn note_and_explain_region<'tcx>(
tcx: TyCtxt<'tcx>,
err: &mut Diag<'_>,

View file

@ -0,0 +1,9 @@
//! Regression test for <https://github.com/rust-lang/rust/issues/144215>
#[rustfmt::skip]
struct S<T:>(&'static T);
//~^ ERROR the parameter type `T` may not live long enough
//~| HELP consider adding an explicit lifetime bound
//~| SUGGESTION 'static
fn main() {}

View file

@ -0,0 +1,17 @@
error[E0310]: the parameter type `T` may not live long enough
--> $DIR/missing-param-but-has-colon-144215.rs:4:14
|
LL | struct S<T:>(&'static T);
| ^^^^^^^^^^
| |
| the parameter type `T` must be valid for the static lifetime...
| ...so that the reference type `&'static T` does not outlive the data it points at
|
help: consider adding an explicit lifetime bound
|
LL | struct S<T: 'static>(&'static T);
| +++++++
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0310`.