about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-30 17:47:07 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2023-10-30 17:47:07 +0000
commit455cf5a4f6531598d72a7590c6f390d9296cc548 (patch)
tree153f9865b704c6ece8c38028a5f27e07461306bc /compiler
parent6d1fc53cf4f61b0dce5fc84cebae3b9fb8a45436 (diff)
downloadrust-455cf5a4f6531598d72a7590c6f390d9296cc548.tar.gz
rust-455cf5a4f6531598d72a7590c6f390d9296cc548.zip
Improve some diagnostics around `?Trait` bounds
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/bounds.rs57
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs2
2 files changed, 32 insertions, 27 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 711da6db5ac..3e700f2da86 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -8,6 +8,7 @@ use rustc_middle::ty::{self as ty, Ty, TypeVisitableExt};
 use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits;
+use smallvec::SmallVec;
 
 use crate::astconv::{
     AstConv, ConvertedBinding, ConvertedBindingKind, OnlySelfBounds, PredicateFilter,
@@ -28,15 +29,11 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         let tcx = self.tcx();
 
         // Try to find an unbound in bounds.
-        let mut unbound = None;
+        let mut unbounds: SmallVec<[_; 1]> = SmallVec::new();
         let mut search_bounds = |ast_bounds: &'tcx [hir::GenericBound<'tcx>]| {
             for ab in ast_bounds {
                 if let hir::GenericBound::Trait(ptr, hir::TraitBoundModifier::Maybe) = ab {
-                    if unbound.is_none() {
-                        unbound = Some(&ptr.trait_ref);
-                    } else {
-                        tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds { span });
-                    }
+                    unbounds.push(ptr)
                 }
             }
         };
@@ -51,33 +48,41 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             }
         }
 
+        if unbounds.len() > 1 {
+            tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds {
+                spans: unbounds.iter().map(|ptr| ptr.span).collect(),
+            });
+        }
+
         let sized_def_id = tcx.lang_items().sized_trait();
-        match (&sized_def_id, unbound) {
-            (Some(sized_def_id), Some(tpb))
-                if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
-            {
-                // There was in fact a `?Sized` bound, return without doing anything
-                return;
-            }
-            (_, Some(_)) => {
-                // There was a `?Trait` bound, but it was not `?Sized`; warn.
-                tcx.sess.span_warn(
-                    span,
-                    "default bound relaxed for a type parameter, but \
-                        this does nothing because the given bound is not \
-                        a default; only `?Sized` is supported",
-                );
-                // Otherwise, add implicitly sized if `Sized` is available.
-            }
-            _ => {
-                // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+
+        let mut seen_sized_unbound = false;
+        for unbound in unbounds {
+            if let Some(sized_def_id) = sized_def_id {
+                if unbound.trait_ref.path.res == Res::Def(DefKind::Trait, sized_def_id) {
+                    seen_sized_unbound = true;
+                    continue;
+                }
             }
+            // There was a `?Trait` bound, but it was not `?Sized`; warn.
+            tcx.sess.span_warn(
+                unbound.span,
+                "relaxing a default bound only does something for `?Sized`; \
+                all other traits are not bound by default",
+            );
         }
+
+        // If the above loop finished there was no `?Sized` bound; add implicitly sized if `Sized` is available.
         if sized_def_id.is_none() {
             // No lang item for `Sized`, so we can't add it as a bound.
             return;
         }
-        bounds.push_sized(tcx, self_ty, span);
+        if seen_sized_unbound {
+            // There was in fact a `?Sized` bound, return without doing anything
+        } else {
+            // There was no `?Sized` bound; add implicitly sized if `Sized` is available.
+            bounds.push_sized(tcx, self_ty, span);
+        }
     }
 
     /// This helper takes a *converted* parameter type (`param_ty`)
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 6a2db1d0627..dd83b5b6f2c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -96,7 +96,7 @@ pub struct CopyImplOnTypeWithDtor {
 #[diag(hir_analysis_multiple_relaxed_default_bounds, code = "E0203")]
 pub struct MultipleRelaxedDefaultBounds {
     #[primary_span]
-    pub span: Span,
+    pub spans: Vec<Span>,
 }
 
 #[derive(Diagnostic)]