Skip to content

Commit 22a1275

Browse files
authored
Unrolled build for rust-lang#123122
Rollup merge of rust-lang#123122 - surechen:fix_122714, r=fmease Fix incorrect suggestion for undeclared hrtb lifetimes in where clauses. For poly-trait-ref like `for<'a> Trait<T>` in `T: for<'a> Trait<T> + 'b { }`. We should merge the hrtb lifetimes: existed `for<'a>` and suggestion `for<'b>` or will get err: [E0316] nested quantification of lifetimes fixes rust-lang#122714
2 parents 5065123 + 4ebbb5f commit 22a1275

File tree

3 files changed

+207
-14
lines changed

3 files changed

+207
-14
lines changed

compiler/rustc_resolve/src/late/diagnostics.rs

+87-14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use rustc_ast::{
1717
};
1818
use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
1919
use rustc_data_structures::fx::FxHashSet;
20+
use rustc_data_structures::fx::FxIndexSet;
2021
use rustc_errors::{
2122
codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
2223
SuggestionStyle,
@@ -31,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
3132
use rustc_span::edition::Edition;
3233
use rustc_span::hygiene::MacroKind;
3334
use rustc_span::symbol::{kw, sym, Ident, Symbol};
34-
use rustc_span::Span;
35+
use rustc_span::{Span, DUMMY_SP};
3536

3637
use rustc_middle::ty;
3738

@@ -2714,8 +2715,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27142715
self.suggest_introducing_lifetime(
27152716
&mut err,
27162717
Some(lifetime_ref.ident.name.as_str()),
2717-
|err, _, span, message, suggestion| {
2718-
err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
2718+
|err, _, span, message, suggestion, span_suggs| {
2719+
err.multipart_suggestion_with_style(
2720+
message,
2721+
std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
2722+
Applicability::MaybeIncorrect,
2723+
if span_suggs.is_empty() {
2724+
SuggestionStyle::ShowCode
2725+
} else {
2726+
SuggestionStyle::ShowAlways
2727+
},
2728+
);
27192729
true
27202730
},
27212731
);
@@ -2726,13 +2736,20 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27262736
&self,
27272737
err: &mut Diag<'_>,
27282738
name: Option<&str>,
2729-
suggest: impl Fn(&mut Diag<'_>, bool, Span, Cow<'static, str>, String) -> bool,
2739+
suggest: impl Fn(
2740+
&mut Diag<'_>,
2741+
bool,
2742+
Span,
2743+
Cow<'static, str>,
2744+
String,
2745+
Vec<(Span, String)>,
2746+
) -> bool,
27302747
) {
27312748
let mut suggest_note = true;
27322749
for rib in self.lifetime_ribs.iter().rev() {
27332750
let mut should_continue = true;
27342751
match rib.kind {
2735-
LifetimeRibKind::Generics { binder: _, span, kind } => {
2752+
LifetimeRibKind::Generics { binder, span, kind } => {
27362753
// Avoid suggesting placing lifetime parameters on constant items unless the relevant
27372754
// feature is enabled. Suggest the parent item as a possible location if applicable.
27382755
if let LifetimeBinderKind::ConstItem = kind
@@ -2761,11 +2778,53 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27612778
| LifetimeBinderKind::PolyTrait
27622779
| LifetimeBinderKind::WhereBound
27632780
);
2781+
2782+
let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
27642783
let (span, sugg) = if span.is_empty() {
2784+
let mut binder_idents: FxIndexSet<Ident> = Default::default();
2785+
binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
2786+
2787+
// We need to special case binders in the following situation:
2788+
// Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
2789+
// T: for<'a> Trait<T> + 'b
2790+
// ^^^^^^^ remove existing inner binder `for<'a>`
2791+
// for<'a, 'b> T: Trait<T> + 'b
2792+
// ^^^^^^^^^^^ suggest outer binder `for<'a, 'b>`
2793+
if let LifetimeBinderKind::WhereBound = kind
2794+
&& let Some(ast::WherePredicate::BoundPredicate(
2795+
ast::WhereBoundPredicate { bounded_ty, bounds, .. },
2796+
)) = self.diag_metadata.current_where_predicate
2797+
&& bounded_ty.id == binder
2798+
{
2799+
for bound in bounds {
2800+
if let ast::GenericBound::Trait(poly_trait_ref, _) = bound
2801+
&& let span = poly_trait_ref
2802+
.span
2803+
.with_hi(poly_trait_ref.trait_ref.path.span.lo())
2804+
&& !span.is_empty()
2805+
{
2806+
rm_inner_binders.insert(span);
2807+
poly_trait_ref.bound_generic_params.iter().for_each(|v| {
2808+
binder_idents.insert(v.ident);
2809+
});
2810+
}
2811+
}
2812+
}
2813+
2814+
let binders_sugg = binder_idents.into_iter().enumerate().fold(
2815+
"".to_string(),
2816+
|mut binders, (i, x)| {
2817+
if i != 0 {
2818+
binders += ", ";
2819+
}
2820+
binders += x.as_str();
2821+
binders
2822+
},
2823+
);
27652824
let sugg = format!(
27662825
"{}<{}>{}",
27672826
if higher_ranked { "for" } else { "" },
2768-
name.unwrap_or("'a"),
2827+
binders_sugg,
27692828
if higher_ranked { " " } else { "" },
27702829
);
27712830
(span, sugg)
@@ -2780,24 +2839,39 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
27802839
let sugg = format!("{}, ", name.unwrap_or("'a"));
27812840
(span, sugg)
27822841
};
2842+
27832843
if higher_ranked {
27842844
let message = Cow::from(format!(
27852845
"consider making the {} lifetime-generic with a new `{}` lifetime",
27862846
kind.descr(),
27872847
name.unwrap_or("'a"),
27882848
));
2789-
should_continue = suggest(err, true, span, message, sugg);
2849+
should_continue = suggest(
2850+
err,
2851+
true,
2852+
span,
2853+
message,
2854+
sugg,
2855+
if !rm_inner_binders.is_empty() {
2856+
rm_inner_binders
2857+
.into_iter()
2858+
.map(|v| (v, "".to_string()))
2859+
.collect::<Vec<_>>()
2860+
} else {
2861+
vec![]
2862+
},
2863+
);
27902864
err.note_once(
27912865
"for more information on higher-ranked polymorphism, visit \
27922866
https://doc.rust-lang.org/nomicon/hrtb.html",
27932867
);
27942868
} else if let Some(name) = name {
27952869
let message =
27962870
Cow::from(format!("consider introducing lifetime `{name}` here"));
2797-
should_continue = suggest(err, false, span, message, sugg);
2871+
should_continue = suggest(err, false, span, message, sugg, vec![]);
27982872
} else {
27992873
let message = Cow::from("consider introducing a named lifetime parameter");
2800-
should_continue = suggest(err, false, span, message, sugg);
2874+
should_continue = suggest(err, false, span, message, sugg, vec![]);
28012875
}
28022876
}
28032877
LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
@@ -3033,11 +3107,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
30333107
self.suggest_introducing_lifetime(
30343108
err,
30353109
None,
3036-
|err, higher_ranked, span, message, intro_sugg| {
3110+
|err, higher_ranked, span, message, intro_sugg, _| {
30373111
err.multipart_suggestion_verbose(
30383112
message,
30393113
std::iter::once((span, intro_sugg))
3040-
.chain(spans_suggs.iter().cloned())
3114+
.chain(spans_suggs.clone())
30413115
.collect(),
30423116
Applicability::MaybeIncorrect,
30433117
);
@@ -3161,11 +3235,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
31613235
self.suggest_introducing_lifetime(
31623236
err,
31633237
None,
3164-
|err, higher_ranked, span, message, intro_sugg| {
3238+
|err, higher_ranked, span, message, intro_sugg, _| {
31653239
err.multipart_suggestion_verbose(
31663240
message,
31673241
std::iter::once((span, intro_sugg))
3168-
.chain(spans_suggs.iter().cloned())
3242+
.chain(spans_suggs.clone())
31693243
.collect(),
31703244
Applicability::MaybeIncorrect,
31713245
);
@@ -3309,7 +3383,6 @@ fn mk_where_bound_predicate(
33093383
poly_trait_ref: &ast::PolyTraitRef,
33103384
ty: &Ty,
33113385
) -> Option<ast::WhereBoundPredicate> {
3312-
use rustc_span::DUMMY_SP;
33133386
let modified_segments = {
33143387
let mut segments = path.segments.clone();
33153388
let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#![allow(dead_code)]
2+
3+
trait Trait1<T>
4+
where T: for<'a> Trait1<T> + 'b { } //~ ERROR use of undeclared lifetime name `'b`
5+
6+
trait Trait2<T>
7+
where
8+
T: B<'b> + for<'a> A<'a>, //~ ERROR use of undeclared lifetime name `'b`
9+
{
10+
}
11+
12+
trait Trait3<T>
13+
where
14+
T: B<'b> + for<'a> A<'a> + 'c {}
15+
//~^ ERROR use of undeclared lifetime name `'b`
16+
//~| ERROR use of undeclared lifetime name `'c`
17+
18+
trait Trait4<T>
19+
where
20+
T: for<'a> A<'a> + 'x + for<'b> B<'b>, //~ ERROR use of undeclared lifetime name `'x`
21+
{
22+
}
23+
24+
trait A<'a> {}
25+
trait B<'a> {}
26+
27+
28+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
error[E0261]: use of undeclared lifetime name `'b`
2+
--> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:4:32
3+
|
4+
LL | where T: for<'a> Trait1<T> + 'b { }
5+
| ^^ undeclared lifetime
6+
|
7+
= note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
8+
help: consider making the bound lifetime-generic with a new `'b` lifetime
9+
|
10+
LL - where T: for<'a> Trait1<T> + 'b { }
11+
LL + where for<'b, 'a> T: Trait1<T> + 'b { }
12+
|
13+
help: consider introducing lifetime `'b` here
14+
|
15+
LL | trait Trait1<'b, T>
16+
| +++
17+
18+
error[E0261]: use of undeclared lifetime name `'b`
19+
--> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:8:10
20+
|
21+
LL | T: B<'b> + for<'a> A<'a>,
22+
| ^^ undeclared lifetime
23+
|
24+
help: consider making the bound lifetime-generic with a new `'b` lifetime
25+
|
26+
LL | T: for<'b> B<'b> + for<'a> A<'a>,
27+
| +++++++
28+
help: consider making the bound lifetime-generic with a new `'b` lifetime
29+
|
30+
LL - T: B<'b> + for<'a> A<'a>,
31+
LL + for<'b, 'a> T: B<'b> + A<'a>,
32+
|
33+
help: consider introducing lifetime `'b` here
34+
|
35+
LL | trait Trait2<'b, T>
36+
| +++
37+
38+
error[E0261]: use of undeclared lifetime name `'b`
39+
--> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:10
40+
|
41+
LL | T: B<'b> + for<'a> A<'a> + 'c {}
42+
| ^^ undeclared lifetime
43+
|
44+
help: consider making the bound lifetime-generic with a new `'b` lifetime
45+
|
46+
LL | T: for<'b> B<'b> + for<'a> A<'a> + 'c {}
47+
| +++++++
48+
help: consider making the bound lifetime-generic with a new `'b` lifetime
49+
|
50+
LL - T: B<'b> + for<'a> A<'a> + 'c {}
51+
LL + for<'b, 'a> T: B<'b> + A<'a> + 'c {}
52+
|
53+
help: consider introducing lifetime `'b` here
54+
|
55+
LL | trait Trait3<'b, T>
56+
| +++
57+
58+
error[E0261]: use of undeclared lifetime name `'c`
59+
--> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:32
60+
|
61+
LL | T: B<'b> + for<'a> A<'a> + 'c {}
62+
| ^^ undeclared lifetime
63+
|
64+
help: consider making the bound lifetime-generic with a new `'c` lifetime
65+
|
66+
LL - T: B<'b> + for<'a> A<'a> + 'c {}
67+
LL + for<'c, 'a> T: B<'b> + A<'a> + 'c {}
68+
|
69+
help: consider introducing lifetime `'c` here
70+
|
71+
LL | trait Trait3<'c, T>
72+
| +++
73+
74+
error[E0261]: use of undeclared lifetime name `'x`
75+
--> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:20:24
76+
|
77+
LL | T: for<'a> A<'a> + 'x + for<'b> B<'b>,
78+
| ^^ undeclared lifetime
79+
|
80+
help: consider making the bound lifetime-generic with a new `'x` lifetime
81+
|
82+
LL - T: for<'a> A<'a> + 'x + for<'b> B<'b>,
83+
LL + for<'x, 'a, 'b> T: A<'a> + 'x + B<'b>,
84+
|
85+
help: consider introducing lifetime `'x` here
86+
|
87+
LL | trait Trait4<'x, T>
88+
| +++
89+
90+
error: aborting due to 5 previous errors
91+
92+
For more information about this error, try `rustc --explain E0261`.

0 commit comments

Comments
 (0)