about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_hir/src/hir.rs24
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs69
-rw-r--r--tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs39
-rw-r--r--tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr192
4 files changed, 295 insertions, 29 deletions
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index d57fad6ba4c..0f1b2bec6c6 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -723,7 +723,7 @@ impl<'hir> Generics<'hir> {
         )
     }
 
-    fn span_for_predicate_removal(&self, pos: usize) -> Span {
+    pub fn span_for_predicate_removal(&self, pos: usize) -> Span {
         let predicate = &self.predicates[pos];
         let span = predicate.span();
 
@@ -766,15 +766,21 @@ impl<'hir> Generics<'hir> {
             return self.span_for_predicate_removal(predicate_pos);
         }
 
-        let span = bounds[bound_pos].span();
-        if bound_pos == 0 {
-            // where T: ?Sized + Bar, Foo: Bar,
-            //          ^^^^^^^^^
-            span.to(bounds[1].span().shrink_to_lo())
+        let bound_span = bounds[bound_pos].span();
+        if bound_pos < bounds.len() - 1 {
+            // If there's another bound after the current bound
+            // include the following '+' e.g.:
+            //
+            //  `T: Foo + CurrentBound + Bar`
+            //            ^^^^^^^^^^^^^^^
+            bound_span.to(bounds[bound_pos + 1].span().shrink_to_lo())
         } else {
-            // where T: Bar + ?Sized, Foo: Bar,
-            //             ^^^^^^^^^
-            bounds[bound_pos - 1].span().shrink_to_hi().to(span)
+            // If the current bound is the last bound
+            // include the preceding '+' E.g.:
+            //
+            //  `T: Foo + Bar + CurrentBound`
+            //               ^^^^^^^^^^^^^^^
+            bound_span.with_lo(bounds[bound_pos - 1].span().hi())
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 4bf22337991..3a5cb22be38 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);
             }
         }
     }
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
new file mode 100644
index 00000000000..e6d7f74880f
--- /dev/null
+++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.rs
@@ -0,0 +1,39 @@
+// Regression test for #127441
+
+// Tests that we make the correct suggestion
+// in case there are more than one `?Sized`
+// bounds on a function parameter
+
+use std::fmt::Debug;
+
+fn foo1<T: ?Sized>(a: T) {}
+//~^ ERROR he size for values of type `T` cannot be known at compilation time
+
+fn foo2<T: ?Sized + ?Sized>(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `T` cannot be known at compilation time
+
+fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR he size for values of type `T` cannot be known at compilation time
+
+fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `T` cannot be known at compilation time
+
+fn foo5(_: impl ?Sized) {}
+//~^ ERROR the size for values of type `impl ?Sized` cannot be known at compilation time
+
+fn foo6(_: impl ?Sized + ?Sized) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation tim
+
+fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
+
+fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+//~^ ERROR type parameter has more than one relaxed default bound, only one is supported
+//~| ERROR the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
+
+fn main() {}
diff --git a/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
new file mode 100644
index 00000000000..3e8f45ee9fc
--- /dev/null
+++ b/tests/ui/trait-bounds/bad-suggestionf-for-repeated-unsized-bound-127441.stderr
@@ -0,0 +1,192 @@
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:12
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
+   |            ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:12
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+   |            ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:12
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+   |            ^^^^^^           ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:17
+   |
+LL | fn foo6(_: impl ?Sized + ?Sized) {}
+   |                 ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:17
+   |
+LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+   |                 ^^^^^^   ^^^^^^
+
+error[E0203]: type parameter has more than one relaxed default bound, only one is supported
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:17
+   |
+LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+   |                 ^^^^^^           ^^^^^^
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:9:20
+   |
+LL | fn foo1<T: ?Sized>(a: T) {}
+   |         -          ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn foo1<T: ?Sized>(a: T) {}
+LL + fn foo1<T>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo1<T: ?Sized>(a: &T) {}
+   |                       +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:12:29
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: T) {}
+   |         -                   ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider removing the `?Sized` bound to make the type parameter `Sized`
+   |
+LL - fn foo2<T: ?Sized + ?Sized>(a: T) {}
+LL + fn foo2<T>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo2<T: ?Sized + ?Sized>(a: &T) {}
+   |                                +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:16:37
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+   |         -                           ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo3<T: ?Sized + ?Sized + Debug>(a: T) {}
+LL + fn foo3<T: Debug>(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo3<T: ?Sized + ?Sized + Debug>(a: &T) {}
+   |                                        +
+
+error[E0277]: the size for values of type `T` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:20:38
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+   |         -                            ^ doesn't have a size known at compile-time
+   |         |
+   |         this type parameter needs to be `Sized`
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo4<T: ?Sized + Debug + ?Sized >(a: T) {}
+LL + fn foo4<T: Debug >(a: T) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo4<T: ?Sized + Debug + ?Sized >(a: &T) {}
+   |                                         +
+
+error[E0277]: the size for values of type `impl ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:24:9
+   |
+LL | fn foo5(_: impl ?Sized) {}
+   |         ^  ----------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider replacing `?Sized` with `Sized`
+   |
+LL - fn foo5(_: impl ?Sized) {}
+LL + fn foo5(_: impl Sized) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo5(_: &impl ?Sized) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:27:9
+   |
+LL | fn foo6(_: impl ?Sized + ?Sized) {}
+   |         ^  -------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo6(_: impl ?Sized + ?Sized) {}
+LL + fn foo6(_: impl Sized) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo6(_: &impl ?Sized + ?Sized) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + ?Sized + Debug` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:31:9
+   |
+LL | fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+   |         ^  ---------------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo7(_: impl ?Sized + ?Sized + Debug) {}
+LL + fn foo7(_: impl Debug) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo7(_: &impl ?Sized + ?Sized + Debug) {}
+   |            +
+
+error[E0277]: the size for values of type `impl ?Sized + Debug + ?Sized` cannot be known at compilation time
+  --> $DIR/bad-suggestionf-for-repeated-unsized-bound-127441.rs:35:9
+   |
+LL | fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+   |         ^  ---------------------------- this type parameter needs to be `Sized`
+   |         |
+   |         doesn't have a size known at compile-time
+   |
+   = help: unsized fn params are gated as an unstable feature
+help: consider restricting type parameters
+   |
+LL - fn foo8(_: impl ?Sized + Debug + ?Sized ) {}
+LL + fn foo8(_: impl Debug ) {}
+   |
+help: function arguments must have a statically known size, borrowed types always have a known size
+   |
+LL | fn foo8(_: &impl ?Sized + Debug + ?Sized ) {}
+   |            +
+
+error: aborting due to 14 previous errors
+
+Some errors have detailed explanations: E0203, E0277.
+For more information about an error, try `rustc --explain E0203`.