about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection/src
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2024-01-24 21:29:15 +0000
committerEsteban Küber <esteban@kuber.com.ar>2024-02-01 03:30:26 +0000
commitc4c22b0d52e9699edd02fd3a7a61965f296ba605 (patch)
treee648928fe6e6127f2522d43ef9a38ada7c8cef36 /compiler/rustc_trait_selection/src
parent11f32b73e0dc9287e305b5b9980d24aecdc8c17f (diff)
downloadrust-c4c22b0d52e9699edd02fd3a7a61965f296ba605.tar.gz
rust-c4c22b0d52e9699edd02fd3a7a61965f296ba605.zip
On E0277 be clearer about implicit `Sized` bounds on type params and assoc types
```
error[E0277]: the size for values of type `[i32]` cannot be known at compilation time
   --> f100.rs:2:33
    |
2   |     let _ = std::mem::size_of::<[i32]>();
    |                                 ^^^^^ doesn't have a size known at compile-time
    |
    = help: the trait `Sized` is not implemented for `[i32]`
note: required by an implicit `Sized` bound in `std::mem::size_of`
   --> /home/gh-estebank/rust/library/core/src/mem/mod.rs:312:22
    |
312 | pub const fn size_of<T>() -> usize {
    |                      ^ required by the implicit `Sized` requirement on this bound in `size_of`
```

Fix #120178.
Diffstat (limited to 'compiler/rustc_trait_selection/src')
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs159
1 files changed, 90 insertions, 69 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 5bab57ca56c..3060f33330e 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -3009,35 +3009,44 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         );
                     }
                 }
-                let descr = format!("required by a bound in `{item_name}`");
-                if span.is_visible(sm) {
-                    let msg = format!("required by this bound in `{short_item_name}`");
-                    multispan.push_span_label(span, msg);
-                    err.span_note(multispan, descr);
-                    if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
-                        && let ty::ClauseKind::Trait(trait_pred) = clause
-                    {
-                        let def_id = trait_pred.def_id();
-                        let visible_item = if let Some(local) = def_id.as_local() {
-                            // Check for local traits being reachable.
-                            let vis = &tcx.resolutions(()).effective_visibilities;
-                            // Account for non-`pub` traits in the root of the local crate.
-                            let is_locally_reachable = tcx.parent(def_id).is_crate_root();
-                            vis.is_reachable(local) || is_locally_reachable
-                        } else {
-                            // Check for foreign traits being reachable.
-                            tcx.visible_parent_map(()).get(&def_id).is_some()
-                        };
-                        if Some(def_id) == tcx.lang_items().sized_trait()
-                            && let Some(hir::Node::TraitItem(hir::TraitItem {
-                                ident,
-                                kind: hir::TraitItemKind::Type(bounds, None),
-                                ..
-                            })) = tcx.hir().get_if_local(item_def_id)
-                            // Do not suggest relaxing if there is an explicit `Sized` obligation.
-                            && !bounds.iter()
-                                .filter_map(|bound| bound.trait_ref())
-                                .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
+                let mut a = "a";
+                let mut this = "this";
+                let mut note = None;
+                let mut help = None;
+                if let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder()
+                    && let ty::ClauseKind::Trait(trait_pred) = clause
+                {
+                    let def_id = trait_pred.def_id();
+                    let visible_item = if let Some(local) = def_id.as_local() {
+                        // Check for local traits being reachable.
+                        let vis = &tcx.resolutions(()).effective_visibilities;
+                        // Account for non-`pub` traits in the root of the local crate.
+                        let is_locally_reachable = tcx.parent(def_id).is_crate_root();
+                        vis.is_reachable(local) || is_locally_reachable
+                    } else {
+                        // Check for foreign traits being reachable.
+                        tcx.visible_parent_map(()).get(&def_id).is_some()
+                    };
+                    if Some(def_id) == tcx.lang_items().sized_trait() {
+                        // Check if this is an implicit bound, even in foreign crates.
+                        if tcx
+                            .generics_of(item_def_id)
+                            .params
+                            .iter()
+                            .any(|param| tcx.def_span(param.def_id) == span)
+                        {
+                            a = "an implicit `Sized`";
+                            this = "the implicit `Sized` requirement on this";
+                        }
+                        if let Some(hir::Node::TraitItem(hir::TraitItem {
+                            ident,
+                            kind: hir::TraitItemKind::Type(bounds, None),
+                            ..
+                        })) = tcx.hir().get_if_local(item_def_id)
+                        // Do not suggest relaxing if there is an explicit `Sized` obligation.
+                        && !bounds.iter()
+                            .filter_map(|bound| bound.trait_ref())
+                            .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait())
                         {
                             let (span, separator) = if let [.., last] = bounds {
                                 (last.span().shrink_to_hi(), " +")
@@ -3051,52 +3060,64 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 Applicability::MachineApplicable,
                             );
                         }
-                        if let DefKind::Trait = tcx.def_kind(item_def_id)
-                            && !visible_item
-                        {
-                            err.note(format!(
-                                "`{short_item_name}` is a \"sealed trait\", because to implement \
-                                 it you also need to implement `{}`, which is not accessible; \
-                                 this is usually done to force you to use one of the provided \
-                                 types that already implement it",
-                                with_no_trimmed_paths!(tcx.def_path_str(def_id)),
-                            ));
-                            let impls_of = tcx.trait_impls_of(def_id);
-                            let impls = impls_of
-                                .non_blanket_impls()
-                                .values()
-                                .flatten()
-                                .chain(impls_of.blanket_impls().iter())
+                    }
+                    if let DefKind::Trait = tcx.def_kind(item_def_id)
+                        && !visible_item
+                    {
+                        note = Some(format!(
+                            "`{short_item_name}` is a \"sealed trait\", because to implement it \
+                             you also need to implement `{}`, which is not accessible; this is \
+                             usually done to force you to use one of the provided types that \
+                             already implement it",
+                            with_no_trimmed_paths!(tcx.def_path_str(def_id)),
+                        ));
+                        let impls_of = tcx.trait_impls_of(def_id);
+                        let impls = impls_of
+                            .non_blanket_impls()
+                            .values()
+                            .flatten()
+                            .chain(impls_of.blanket_impls().iter())
+                            .collect::<Vec<_>>();
+                        if !impls.is_empty() {
+                            let len = impls.len();
+                            let mut types = impls
+                                .iter()
+                                .map(|t| {
+                                    with_no_trimmed_paths!(format!(
+                                        "  {}",
+                                        tcx.type_of(*t).instantiate_identity(),
+                                    ))
+                                })
                                 .collect::<Vec<_>>();
-                            if !impls.is_empty() {
-                                let len = impls.len();
-                                let mut types = impls
-                                    .iter()
-                                    .map(|t| {
-                                        with_no_trimmed_paths!(format!(
-                                            "  {}",
-                                            tcx.type_of(*t).instantiate_identity(),
-                                        ))
-                                    })
-                                    .collect::<Vec<_>>();
-                                let post = if types.len() > 9 {
-                                    types.truncate(8);
-                                    format!("\nand {} others", len - 8)
-                                } else {
-                                    String::new()
-                                };
-                                err.help(format!(
-                                    "the following type{} implement{} the trait:\n{}{post}",
-                                    pluralize!(len),
-                                    if len == 1 { "s" } else { "" },
-                                    types.join("\n"),
-                                ));
-                            }
+                            let post = if types.len() > 9 {
+                                types.truncate(8);
+                                format!("\nand {} others", len - 8)
+                            } else {
+                                String::new()
+                            };
+                            help = Some(format!(
+                                "the following type{} implement{} the trait:\n{}{post}",
+                                pluralize!(len),
+                                if len == 1 { "s" } else { "" },
+                                types.join("\n"),
+                            ));
                         }
                     }
+                };
+                let descr = format!("required by {a} bound in `{item_name}`");
+                if span.is_visible(sm) {
+                    let msg = format!("required by {this} bound in `{short_item_name}`");
+                    multispan.push_span_label(span, msg);
+                    err.span_note(multispan, descr);
                 } else {
                     err.span_note(tcx.def_span(item_def_id), descr);
                 }
+                if let Some(note) = note {
+                    err.note(note);
+                }
+                if let Some(help) = help {
+                    err.help(help);
+                }
             }
             ObligationCauseCode::Coercion { source, target } => {
                 let mut file = None;