diff options
| author | Matthias Krüger <matthias.krueger@famsik.de> | 2024-07-24 22:22:16 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-07-24 22:22:16 +0200 |
| commit | 2ff33bb1df6ef62a8f325887324cecf4b00f5087 (patch) | |
| tree | 4bfcdc377a72009800454a4ea58f58813b1d37c2 /compiler/rustc_middle | |
| parent | ed5dfed535b4be3a7ab0f4c0d73f274a7fe6165a (diff) | |
| parent | e13eb37eeb3ccb447f33496fe86d77498558d2d5 (diff) | |
| download | rust-2ff33bb1df6ef62a8f325887324cecf4b00f5087.tar.gz rust-2ff33bb1df6ef62a8f325887324cecf4b00f5087.zip | |
Rollup merge of #127717 - gurry:127441-stray-impl-sugg, r=compiler-errors
Fix malformed suggestion for repeated maybe unsized bounds Fixes #127441 Now when we encounter something like `foo(a : impl ?Sized + ?Sized)`, instead of suggesting removal of both bounds and leaving `foo(a: impl )` behind, we suggest changing the first bound to `Sized` and removing the second bound, resulting in `foo(a: impl Sized)`. Although the issue was reported for impl trait types, it also occurred with regular param bounds. So if we encounter `foo<T: ?Sized + ?Sized>(a: T)` we now detect that all the bounds are `?Sized` and therefore emit the suggestion to remove the entire predicate `: ?Sized + ?Sized` resulting in `foo<T>(a: T)`. Lastly, if we encounter a situation where some of the bounds are something other than `?Sized`, then we emit separate removal suggestions for each `?Sized` bound. E.g. if we see `foo(a: impl ?Sized + Bar + ?Sized)` or `foo<T: ?Sized + Bar + ?Sized>(a: T)` we emit suggestions such that the user will be left with `foo(a : impl Bar)` or `foo<T: Bar>(a: T)` respectively.
Diffstat (limited to 'compiler/rustc_middle')
| -rw-r--r-- | compiler/rustc_middle/src/ty/diagnostics.rs | 69 |
1 files changed, 49 insertions, 20 deletions
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index f479b18c7c4..f2261f4a43b 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -188,31 +188,60 @@ fn suggest_changing_unsized_bound( continue; }; - for (pos, bound) in predicate.bounds.iter().enumerate() { - let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound else { - continue; - }; - if poly.trait_ref.trait_def_id() != def_id { - continue; - } - if predicate.origin == PredicateOrigin::ImplTrait && predicate.bounds.len() == 1 { - // For `impl ?Sized` with no other bounds, suggest `impl Sized` instead. - let bound_span = bound.span(); - if bound_span.can_be_used_for_suggestions() { - let question_span = bound_span.with_hi(bound_span.lo() + BytePos(1)); - suggestions.push(( + let unsized_bounds = predicate + .bounds + .iter() + .enumerate() + .filter(|(_, bound)| { + if let hir::GenericBound::Trait(poly, hir::TraitBoundModifier::Maybe) = bound + && poly.trait_ref.trait_def_id() == def_id + { + true + } else { + false + } + }) + .collect::<Vec<_>>(); + + if unsized_bounds.is_empty() { + continue; + } + + let mut push_suggestion = |sp, msg| suggestions.push((sp, String::new(), msg)); + + if predicate.bounds.len() == unsized_bounds.len() { + // All the bounds are unsized bounds, e.g. + // `T: ?Sized + ?Sized` or `_: impl ?Sized + ?Sized`, + // so in this case: + // - if it's an impl trait predicate suggest changing the + // the first bound to sized and removing the rest + // - Otherwise simply suggest removing the entire predicate + if predicate.origin == PredicateOrigin::ImplTrait { + let first_bound = unsized_bounds[0].1; + let first_bound_span = first_bound.span(); + if first_bound_span.can_be_used_for_suggestions() { + let question_span = + first_bound_span.with_hi(first_bound_span.lo() + BytePos(1)); + push_suggestion( question_span, - String::new(), SuggestChangingConstraintsMessage::ReplaceMaybeUnsizedWithSized, - )); + ); + + for (pos, _) in unsized_bounds.iter().skip(1) { + let sp = generics.span_for_bound_removal(where_pos, *pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } } } else { + let sp = generics.span_for_predicate_removal(where_pos); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); + } + } else { + // Some of the bounds are other than unsized. + // So push separate removal suggestion for each unsized bound + for (pos, _) in unsized_bounds { let sp = generics.span_for_bound_removal(where_pos, pos); - suggestions.push(( - sp, - String::new(), - SuggestChangingConstraintsMessage::RemoveMaybeUnsized, - )); + push_suggestion(sp, SuggestChangingConstraintsMessage::RemoveMaybeUnsized); } } } |
