1
Fork 0

Tweak "object unsafe" errors

Fix #77598.
This commit is contained in:
Esteban Küber 2020-10-15 17:23:45 -07:00
parent 9832374f6e
commit ae0e3d0511
57 changed files with 720 additions and 442 deletions

View file

@ -13,7 +13,7 @@ use super::elaborate_predicates;
use crate::infer::TyCtxtInferExt;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{self, Obligation, ObligationCause};
use rustc_errors::{Applicability, FatalError};
use rustc_errors::FatalError;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts, Subst};
@ -21,7 +21,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitor, WithConstnes
use rustc_middle::ty::{Predicate, ToPredicate};
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
use rustc_span::Span;
use rustc_span::{MultiSpan, Span};
use smallvec::SmallVec;
use std::array;
@ -112,33 +112,35 @@ fn object_safety_violations_for_trait(
tcx.def_path_str(trait_def_id)
));
let node = tcx.hir().get_if_local(trait_def_id);
let msg = if let Some(hir::Node::Item(item)) = node {
err.span_label(
let mut spans = MultiSpan::from_span(*span);
if let Some(hir::Node::Item(item)) = node {
spans.push_span_label(
item.ident.span,
"this trait cannot be made into an object...",
"this trait cannot be made into an object...".into(),
);
spans.push_span_label(
*span,
format!("...because {}", violation.error_msg()),
);
format!("...because {}", violation.error_msg())
} else {
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
)
spans.push_span_label(
*span,
format!(
"the trait cannot be made into an object because {}",
violation.error_msg()
),
);
};
err.span_label(*span, &msg);
match (node, violation.solution()) {
(Some(_), Some((note, None))) => {
err.help(&note);
}
(Some(_), Some((note, Some((sugg, span))))) => {
err.span_suggestion(
span,
&note,
sugg,
Applicability::MachineApplicable,
);
}
// Only provide the help if its a local trait, otherwise it's not actionable.
_ => {}
err.span_note(
spans,
"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 node.is_some() {
// Only provide the help if its a local trait, otherwise it's not
violation.solution(&mut err);
}
err.emit();
},
@ -385,6 +387,8 @@ fn virtual_call_violation_for_method<'tcx>(
trait_def_id: DefId,
method: &ty::AssocItem,
) -> Option<MethodViolationCode> {
let sig = tcx.fn_sig(method.def_id);
// The method's first parameter must be named `self`
if !method.fn_has_self_parameter {
// We'll attempt to provide a structured suggestion for `Self: Sized`.
@ -395,11 +399,21 @@ fn virtual_call_violation_for_method<'tcx>(
[.., pred] => (", Self: Sized", pred.span().shrink_to_hi()),
},
);
return Some(MethodViolationCode::StaticMethod(sugg));
// Get the span pointing at where the `self` receiver should be.
let sm = tcx.sess.source_map();
let self_span = method.ident.span.to(tcx
.hir()
.span_if_local(method.def_id)
.unwrap_or_else(|| sm.next_point(method.ident.span))
.shrink_to_hi());
let self_span = sm.span_through_char(self_span, '(').shrink_to_hi();
return Some(MethodViolationCode::StaticMethod(
sugg,
self_span,
!sig.inputs().skip_binder().is_empty(),
));
}
let sig = tcx.fn_sig(method.def_id);
for (i, input_ty) in sig.skip_binder().inputs()[1..].iter().enumerate() {
if contains_illegal_self_type_reference(tcx, trait_def_id, input_ty) {
return Some(MethodViolationCode::ReferencesSelfInput(i));