Skip to content

Commit 1d7e818

Browse files
committed
Auto merge of #69242 - cjgillot:object_violations, r=Zoxc
Querify object_safety_violations. Split from #69076 r? @Zoxc
2 parents 8aa9d20 + 310f470 commit 1d7e818

File tree

12 files changed

+153
-156
lines changed

12 files changed

+153
-156
lines changed

src/librustc/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ rustc_queries! {
661661
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(key) }
662662
cache_on_disk_if { true }
663663
}
664-
query is_object_safe(key: DefId) -> bool {
664+
query object_safety_violations(key: DefId) -> Vec<traits::ObjectSafetyViolation> {
665665
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
666666
}
667667

src/librustc/traits/mod.rs

+132
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ use crate::ty::{self, AdtKind, List, Ty, TyCtxt};
1616
use rustc_hir as hir;
1717
use rustc_hir::def_id::DefId;
1818
use rustc_span::{Span, DUMMY_SP};
19+
use smallvec::SmallVec;
1920
use syntax::ast;
2021

22+
use std::borrow::Cow;
2123
use std::fmt::Debug;
2224
use std::rc::Rc;
2325

@@ -737,3 +739,133 @@ where
737739
tcx: TyCtxt<'tcx>,
738740
) -> Option<Self::LiftedLiteral>;
739741
}
742+
743+
#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
744+
pub enum ObjectSafetyViolation {
745+
/// `Self: Sized` declared on the trait.
746+
SizedSelf(SmallVec<[Span; 1]>),
747+
748+
/// Supertrait reference references `Self` an in illegal location
749+
/// (e.g., `trait Foo : Bar<Self>`).
750+
SupertraitSelf(SmallVec<[Span; 1]>),
751+
752+
/// Method has something illegal.
753+
Method(ast::Name, MethodViolationCode, Span),
754+
755+
/// Associated const.
756+
AssocConst(ast::Name, Span),
757+
}
758+
759+
impl ObjectSafetyViolation {
760+
pub fn error_msg(&self) -> Cow<'static, str> {
761+
match *self {
762+
ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
763+
ObjectSafetyViolation::SupertraitSelf(ref spans) => {
764+
if spans.iter().any(|sp| *sp != DUMMY_SP) {
765+
"it uses `Self` as a type parameter in this".into()
766+
} else {
767+
"it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
768+
.into()
769+
}
770+
}
771+
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
772+
format!("associated function `{}` has no `self` parameter", name).into()
773+
}
774+
ObjectSafetyViolation::Method(
775+
name,
776+
MethodViolationCode::ReferencesSelfInput(_),
777+
DUMMY_SP,
778+
) => format!("method `{}` references the `Self` type in its parameters", name).into(),
779+
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
780+
format!("method `{}` references the `Self` type in this parameter", name).into()
781+
}
782+
ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
783+
format!("method `{}` references the `Self` type in its return type", name).into()
784+
}
785+
ObjectSafetyViolation::Method(
786+
name,
787+
MethodViolationCode::WhereClauseReferencesSelf,
788+
_,
789+
) => {
790+
format!("method `{}` references the `Self` type in its `where` clause", name).into()
791+
}
792+
ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
793+
format!("method `{}` has generic type parameters", name).into()
794+
}
795+
ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
796+
format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
797+
}
798+
ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
799+
format!("it contains associated `const` `{}`", name).into()
800+
}
801+
ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
802+
}
803+
}
804+
805+
pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
806+
Some(match *self {
807+
ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {
808+
return None;
809+
}
810+
ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
811+
format!(
812+
"consider turning `{}` into a method by giving it a `&self` argument or \
813+
constraining it so it does not apply to trait objects",
814+
name
815+
),
816+
sugg.map(|(sugg, sp)| (sugg.to_string(), sp)),
817+
),
818+
ObjectSafetyViolation::Method(
819+
name,
820+
MethodViolationCode::UndispatchableReceiver,
821+
span,
822+
) => (
823+
format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
824+
.into(),
825+
Some(("&Self".to_string(), span)),
826+
),
827+
ObjectSafetyViolation::AssocConst(name, _)
828+
| ObjectSafetyViolation::Method(name, ..) => {
829+
(format!("consider moving `{}` to another trait", name), None)
830+
}
831+
})
832+
}
833+
834+
pub fn spans(&self) -> SmallVec<[Span; 1]> {
835+
// When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
836+
// diagnostics use a `note` instead of a `span_label`.
837+
match self {
838+
ObjectSafetyViolation::SupertraitSelf(spans)
839+
| ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
840+
ObjectSafetyViolation::AssocConst(_, span)
841+
| ObjectSafetyViolation::Method(_, _, span)
842+
if *span != DUMMY_SP =>
843+
{
844+
smallvec![*span]
845+
}
846+
_ => smallvec![],
847+
}
848+
}
849+
}
850+
851+
/// Reasons a method might not be object-safe.
852+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
853+
pub enum MethodViolationCode {
854+
/// e.g., `fn foo()`
855+
StaticMethod(Option<(&'static str, Span)>),
856+
857+
/// e.g., `fn foo(&self, x: Self)`
858+
ReferencesSelfInput(usize),
859+
860+
/// e.g., `fn foo(&self) -> Self`
861+
ReferencesSelfOutput,
862+
863+
/// e.g., `fn foo(&self) where Self: Clone`
864+
WhereClauseReferencesSelf,
865+
866+
/// e.g., `fn foo<A>()`
867+
Generic,
868+
869+
/// the method's receiver (`self` argument) can't be dispatched on
870+
UndispatchableReceiver,
871+
}

src/librustc/ty/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -3081,6 +3081,10 @@ impl<'tcx> TyCtxt<'tcx> {
30813081
};
30823082
(ident, scope)
30833083
}
3084+
3085+
pub fn is_object_safe(self, key: DefId) -> bool {
3086+
self.object_safety_violations(key).is_empty()
3087+
}
30843088
}
30853089

30863090
#[derive(Clone, HashStable)]

src/librustc_incremental/persist/dirty_clean.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const BASE_STRUCT: &[&str] =
7878
const BASE_TRAIT_DEF: &[&str] = &[
7979
label_strs::associated_item_def_ids,
8080
label_strs::generics_of,
81-
label_strs::is_object_safe,
81+
label_strs::object_safety_violations,
8282
label_strs::predicates_of,
8383
label_strs::specialization_graph_of,
8484
label_strs::trait_def,

src/librustc_infer/infer/error_reporting/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa
5252
use crate::infer::opaque_types;
5353
use crate::infer::{self, SuppressRegionErrors};
5454
use crate::traits::error_reporting::report_object_safety_error;
55-
use crate::traits::object_safety_violations;
5655
use crate::traits::{
5756
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
5857
};
@@ -1618,7 +1617,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
16181617
let failure_code = trace.cause.as_failure_code(terr);
16191618
let mut diag = match failure_code {
16201619
FailureCode::Error0038(did) => {
1621-
let violations = object_safety_violations(self.tcx, did);
1620+
let violations = self.tcx.object_safety_violations(did);
16221621
report_object_safety_error(self.tcx, span, did, violations)
16231622
}
16241623
FailureCode::Error0317(failure_str) => {

src/librustc_infer/traits/error_reporting/mod.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ use super::{
1212
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
1313
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
1414
use crate::infer::{self, InferCtxt, TyCtxtInferExt};
15-
use crate::traits::object_safety_violations;
1615
use rustc::mir::interpret::ErrorHandled;
1716
use rustc::session::DiagnosticMessageId;
1817
use rustc::ty::error::ExpectedFound;
@@ -748,7 +747,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
748747
}
749748

750749
ty::Predicate::ObjectSafe(trait_def_id) => {
751-
let violations = object_safety_violations(self.tcx, trait_def_id);
750+
let violations = self.tcx.object_safety_violations(trait_def_id);
752751
report_object_safety_error(self.tcx, span, trait_def_id, violations)
753752
}
754753

@@ -912,7 +911,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
912911
}
913912

914913
TraitNotObjectSafe(did) => {
915-
let violations = object_safety_violations(self.tcx, did);
914+
let violations = self.tcx.object_safety_violations(did);
916915
report_object_safety_error(self.tcx, span, did, violations)
917916
}
918917

src/librustc_infer/traits/error_reporting/suggestions.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use super::{
55

66
use crate::infer::InferCtxt;
77
use crate::traits::error_reporting::suggest_constraining_type_param;
8-
use crate::traits::object_safety::object_safety_violations;
98

109
use rustc::ty::TypeckTables;
1110
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
@@ -587,7 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
587586
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
588587
predicates
589588
.principal_def_id()
590-
.map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty())
589+
.map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
591590
}
592591
// We only want to suggest `impl Trait` to `dyn Trait`s.
593592
// For example, `fn foo() -> str` needs to be filtered out.

src/librustc_infer/traits/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ pub use self::engine::{TraitEngine, TraitEngineExt};
4747
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
4848
pub use self::object_safety::astconv_object_safety_violations;
4949
pub use self::object_safety::is_vtable_safe_method;
50-
pub use self::object_safety::object_safety_violations;
5150
pub use self::object_safety::MethodViolationCode;
5251
pub use self::object_safety::ObjectSafetyViolation;
5352
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
@@ -636,8 +635,8 @@ impl<'tcx> TraitObligation<'tcx> {
636635
}
637636

638637
pub fn provide(providers: &mut ty::query::Providers<'_>) {
638+
object_safety::provide(providers);
639639
*providers = ty::query::Providers {
640-
is_object_safe: object_safety::is_object_safe_provider,
641640
specialization_graph_of: specialize::specialization_graph_provider,
642641
specializes: specialize::specializes,
643642
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,

0 commit comments

Comments
 (0)