summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_infer/src/traits/error_reporting/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer/src/traits/error_reporting/mod.rs')
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs108
1 files changed, 108 insertions, 0 deletions
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
new file mode 100644
index 000000000..95b6c4ce1
--- /dev/null
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -0,0 +1,108 @@
+use super::ObjectSafetyViolation;
+
+use crate::infer::InferCtxt;
+use rustc_data_structures::fx::FxHashSet;
+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_span::Span;
+use std::fmt;
+use std::iter;
+
+impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
+ pub fn report_extra_impl_obligation(
+ &self,
+ error_span: Span,
+ impl_item_def_id: LocalDefId,
+ trait_item_def_id: DefId,
+ requirement: &dyn fmt::Display,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ error_span,
+ E0276,
+ "impl has stricter requirements than trait"
+ );
+
+ if let Some(span) = self.tcx.hir().span_if_local(trait_item_def_id) {
+ let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
+ err.span_label(span, format!("definition of `{}` from trait", item_name));
+ }
+
+ err.span_label(error_span, format!("impl has extra requirement {}", requirement));
+
+ err
+ }
+}
+
+pub fn report_object_safety_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ trait_def_id: DefId,
+ violations: &[ObjectSafetyViolation],
+) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let trait_str = tcx.def_path_str(trait_def_id);
+ let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
+ hir::Node::Item(item) => Some(item.ident.span),
+ _ => None,
+ });
+ let mut err = struct_span_err!(
+ tcx.sess,
+ span,
+ E0038,
+ "the trait `{}` cannot be made into an object",
+ trait_str
+ );
+ err.span_label(span, format!("`{}` cannot be made into an object", trait_str));
+
+ let mut reported_violations = FxHashSet::default();
+ let mut multi_span = vec![];
+ let mut messages = vec![];
+ for violation in violations {
+ if let ObjectSafetyViolation::SizedSelf(sp) = &violation && !sp.is_empty() {
+ // Do not report `SizedSelf` without spans pointing at `SizedSelf` obligations
+ // with a `Span`.
+ reported_violations.insert(ObjectSafetyViolation::SizedSelf(vec![].into()));
+ }
+ if reported_violations.insert(violation.clone()) {
+ let spans = violation.spans();
+ let msg = if trait_span.is_none() || spans.is_empty() {
+ format!("the trait cannot be made into an object because {}", violation.error_msg())
+ } else {
+ format!("...because {}", violation.error_msg())
+ };
+ if spans.is_empty() {
+ err.note(&msg);
+ } else {
+ for span in spans {
+ multi_span.push(span);
+ messages.push(msg.clone());
+ }
+ }
+ }
+ }
+ let has_multi_span = !multi_span.is_empty();
+ let mut note_span = MultiSpan::from_spans(multi_span.clone());
+ if let (Some(trait_span), true) = (trait_span, has_multi_span) {
+ note_span.push_span_label(trait_span, "this trait cannot be made into an object...");
+ }
+ for (span, msg) in iter::zip(multi_span, messages) {
+ note_span.push_span_label(span, msg);
+ }
+ err.span_note(
+ note_span,
+ "for a trait to be \"object safe\" it needs to allow building a vtable to allow the call \
+ to be resolvable dynamically; for more information visit \
+ <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
+ );
+ if trait_span.is_some() {
+ let mut reported_violations: Vec<_> = reported_violations.into_iter().collect();
+ reported_violations.sort();
+ for violation in reported_violations {
+ // Only provide the help if its a local trait, otherwise it's not actionable.
+ violation.solution(&mut err);
+ }
+ }
+ err
+}