diff options
| author | Guillaume Gomez <guillaume1.gomez@gmail.com> | 2023-10-30 17:33:15 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-30 17:33:15 +0100 |
| commit | 95de91b5ceae99d451cbb9fd85ec4dc9c8f7397c (patch) | |
| tree | bc2257c9a24b698f4bb374bde92ea1800f17ff54 /compiler/rustc_infer | |
| parent | 824e3677c26d7fd7687d6a7a3349f3f11c534490 (diff) | |
| parent | 8c04999226e4be90c46c370580c9e8cd7f0ccb05 (diff) | |
| download | rust-95de91b5ceae99d451cbb9fd85ec4dc9c8f7397c.tar.gz rust-95de91b5ceae99d451cbb9fd85ec4dc9c8f7397c.zip | |
Rollup merge of #117132 - estebank:issue-80194, r=petrochenkov
On object safety error, mention new enum as alternative When we encounter a `dyn Trait` that isn't object safe, look for its implementors. If there's one, mention using it directly If there are less than 9, mention the possibility of creating a new enum and using that instead. Fix #80194.
Diffstat (limited to 'compiler/rustc_infer')
| -rw-r--r-- | compiler/rustc_infer/src/traits/error_reporting/mod.rs | 64 |
1 files changed, 63 insertions, 1 deletions
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs index 7a335827f37..32966011932 100644 --- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs @@ -5,7 +5,8 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, TyCtxt}; use rustc_span::Span; use std::fmt; use std::iter; @@ -108,5 +109,66 @@ pub fn report_object_safety_error<'tcx>( violation.solution(&mut err); } } + + let impls_of = tcx.trait_impls_of(trait_def_id); + let impls = if impls_of.blanket_impls().is_empty() { + impls_of + .non_blanket_impls() + .values() + .flatten() + .filter(|def_id| { + !matches!(tcx.type_of(*def_id).instantiate_identity().kind(), ty::Dynamic(..)) + }) + .collect::<Vec<_>>() + } else { + vec![] + }; + let externally_visible = if !impls.is_empty() + && let Some(def_id) = trait_def_id.as_local() + && tcx.effective_visibilities(()).is_exported(def_id) + { + true + } else { + false + }; + match &impls[..] { + [] => {} + _ if impls.len() > 9 => {} + [only] if externally_visible => { + err.help(with_no_trimmed_paths!(format!( + "only type `{}` is seen to implement the trait in this crate, consider using it \ + directly instead", + tcx.type_of(*only).instantiate_identity(), + ))); + } + [only] => { + err.help(with_no_trimmed_paths!(format!( + "only type `{}` implements the trait, consider using it directly instead", + tcx.type_of(*only).instantiate_identity(), + ))); + } + impls => { + let types = impls + .iter() + .map(|t| { + with_no_trimmed_paths!(format!(" {}", tcx.type_of(*t).instantiate_identity(),)) + }) + .collect::<Vec<_>>(); + err.help(format!( + "the following types implement the trait, consider defining an enum where each \ + variant holds one of these types, implementing `{}` for this new enum and using \ + it instead:\n{}", + trait_str, + types.join("\n"), + )); + } + } + if externally_visible { + err.note(format!( + "`{trait_str}` can be implemented in other crates; if you want to support your users \ + passing their own types here, you can't refer to a specific type", + )); + } + err } |
