query is_object_safe(key: DefId) -> bool {
desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
}
+ query object_safety_violations(key: DefId) -> Vec<traits::ObjectSafetyViolation> {
+ desc { |tcx| "determine object safety of trait `{}`", tcx.def_path_str(key) }
+ }
/// Gets the ParameterEnvironment for a given item; this environment
/// will be in "user-facing" mode, meaning that it is suitabe for
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_span::{Span, DUMMY_SP};
+use smallvec::SmallVec;
use syntax::ast;
+use std::borrow::Cow;
use std::fmt::Debug;
use std::rc::Rc;
tcx: TyCtxt<'tcx>,
) -> Option<Self::LiftedLiteral>;
}
+
+#[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum ObjectSafetyViolation {
+ /// `Self: Sized` declared on the trait.
+ SizedSelf(SmallVec<[Span; 1]>),
+
+ /// Supertrait reference references `Self` an in illegal location
+ /// (e.g., `trait Foo : Bar<Self>`).
+ SupertraitSelf(SmallVec<[Span; 1]>),
+
+ /// Method has something illegal.
+ Method(ast::Name, MethodViolationCode, Span),
+
+ /// Associated const.
+ AssocConst(ast::Name, Span),
+}
+
+impl ObjectSafetyViolation {
+ pub fn error_msg(&self) -> Cow<'static, str> {
+ match *self {
+ ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
+ ObjectSafetyViolation::SupertraitSelf(ref spans) => {
+ if spans.iter().any(|sp| *sp != DUMMY_SP) {
+ "it uses `Self` as a type parameter in this".into()
+ } else {
+ "it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
+ .into()
+ }
+ }
+ ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
+ format!("associated function `{}` has no `self` parameter", name).into()
+ }
+ ObjectSafetyViolation::Method(
+ name,
+ MethodViolationCode::ReferencesSelfInput(_),
+ DUMMY_SP,
+ ) => format!("method `{}` references the `Self` type in its parameters", name).into(),
+ ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
+ format!("method `{}` references the `Self` type in this parameter", name).into()
+ }
+ ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
+ format!("method `{}` references the `Self` type in its return type", name).into()
+ }
+ ObjectSafetyViolation::Method(
+ name,
+ MethodViolationCode::WhereClauseReferencesSelf,
+ _,
+ ) => {
+ format!("method `{}` references the `Self` type in its `where` clause", name).into()
+ }
+ ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
+ format!("method `{}` has generic type parameters", name).into()
+ }
+ ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
+ format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
+ }
+ ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
+ format!("it contains associated `const` `{}`", name).into()
+ }
+ ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
+ }
+ }
+
+ pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
+ Some(match *self {
+ ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {
+ return None;
+ }
+ ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
+ format!(
+ "consider turning `{}` into a method by giving it a `&self` argument or \
+ constraining it so it does not apply to trait objects",
+ name
+ ),
+ sugg.map(|(sugg, sp)| (sugg.to_string(), sp)),
+ ),
+ ObjectSafetyViolation::Method(
+ name,
+ MethodViolationCode::UndispatchableReceiver,
+ span,
+ ) => (
+ format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
+ .into(),
+ Some(("&Self".to_string(), span)),
+ ),
+ ObjectSafetyViolation::AssocConst(name, _)
+ | ObjectSafetyViolation::Method(name, ..) => {
+ (format!("consider moving `{}` to another trait", name), None)
+ }
+ })
+ }
+
+ pub fn spans(&self) -> SmallVec<[Span; 1]> {
+ // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
+ // diagnostics use a `note` instead of a `span_label`.
+ match self {
+ ObjectSafetyViolation::SupertraitSelf(spans)
+ | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
+ ObjectSafetyViolation::AssocConst(_, span)
+ | ObjectSafetyViolation::Method(_, _, span)
+ if *span != DUMMY_SP =>
+ {
+ smallvec![*span]
+ }
+ _ => smallvec![],
+ }
+ }
+}
+
+/// Reasons a method might not be object-safe.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+pub enum MethodViolationCode {
+ /// e.g., `fn foo()`
+ StaticMethod(Option<(&'static str, Span)>),
+
+ /// e.g., `fn foo(&self, x: Self)`
+ ReferencesSelfInput(usize),
+
+ /// e.g., `fn foo(&self) -> Self`
+ ReferencesSelfOutput,
+
+ /// e.g., `fn foo(&self) where Self: Clone`
+ WhereClauseReferencesSelf,
+
+ /// e.g., `fn foo<A>()`
+ Generic,
+
+ /// the method's receiver (`self` argument) can't be dispatched on
+ UndispatchableReceiver,
+}
use crate::infer::opaque_types;
use crate::infer::{self, SuppressRegionErrors};
use crate::traits::error_reporting::report_object_safety_error;
-use crate::traits::object_safety_violations;
use crate::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
};
let failure_code = trace.cause.as_failure_code(terr);
let mut diag = match failure_code {
FailureCode::Error0038(did) => {
- let violations = object_safety_violations(self.tcx, did);
+ let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations)
}
FailureCode::Error0317(failure_str) => {
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{self, InferCtxt, TyCtxtInferExt};
-use crate::traits::object_safety_violations;
use rustc::mir::interpret::ErrorHandled;
use rustc::session::DiagnosticMessageId;
use rustc::ty::error::ExpectedFound;
}
ty::Predicate::ObjectSafe(trait_def_id) => {
- let violations = object_safety_violations(self.tcx, trait_def_id);
+ let violations = self.tcx.object_safety_violations(trait_def_id);
report_object_safety_error(self.tcx, span, trait_def_id, violations)
}
}
TraitNotObjectSafe(did) => {
- let violations = object_safety_violations(self.tcx, did);
+ let violations = self.tcx.object_safety_violations(did);
report_object_safety_error(self.tcx, span, did, violations)
}
use crate::infer::InferCtxt;
use crate::traits::error_reporting::suggest_constraining_type_param;
-use crate::traits::object_safety::object_safety_violations;
use rustc::ty::TypeckTables;
use rustc::ty::{self, AdtKind, DefIdTree, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
// If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
predicates
.principal_def_id()
- .map_or(true, |def_id| object_safety_violations(self.tcx, def_id).is_empty())
+ .map_or(true, |def_id| self.tcx.object_safety_violations(def_id).is_empty())
}
// We only want to suggest `impl Trait` to `dyn Trait`s.
// For example, `fn foo() -> str` needs to be filtered out.
pub use self::fulfill::{FulfillmentContext, PendingPredicateObligation};
pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
-pub use self::object_safety::object_safety_violations;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
}
pub fn provide(providers: &mut ty::query::Providers<'_>) {
+ object_safety::provide(providers);
*providers = ty::query::Providers {
- is_object_safe: object_safety::is_object_safe_provider,
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
use rustc_hir::def_id::DefId;
use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
use rustc_span::symbol::Symbol;
-use rustc_span::{Span, DUMMY_SP};
-use smallvec::{smallvec, SmallVec};
-use syntax::ast;
+use rustc_span::Span;
+use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::iter::{self};
+use std::iter;
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
-pub enum ObjectSafetyViolation {
- /// `Self: Sized` declared on the trait.
- SizedSelf(SmallVec<[Span; 1]>),
-
- /// Supertrait reference references `Self` an in illegal location
- /// (e.g., `trait Foo : Bar<Self>`).
- SupertraitSelf(SmallVec<[Span; 1]>),
-
- /// Method has something illegal.
- Method(ast::Name, MethodViolationCode, Span),
-
- /// Associated const.
- AssocConst(ast::Name, Span),
-}
-
-impl ObjectSafetyViolation {
- pub fn error_msg(&self) -> Cow<'static, str> {
- match *self {
- ObjectSafetyViolation::SizedSelf(_) => "it requires `Self: Sized`".into(),
- ObjectSafetyViolation::SupertraitSelf(ref spans) => {
- if spans.iter().any(|sp| *sp != DUMMY_SP) {
- "it uses `Self` as a type parameter in this".into()
- } else {
- "it cannot use `Self` as a type parameter in a supertrait or `where`-clause"
- .into()
- }
- }
- ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(_), _) => {
- format!("associated function `{}` has no `self` parameter", name).into()
- }
- ObjectSafetyViolation::Method(
- name,
- MethodViolationCode::ReferencesSelfInput(_),
- DUMMY_SP,
- ) => format!("method `{}` references the `Self` type in its parameters", name).into(),
- ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfInput(_), _) => {
- format!("method `{}` references the `Self` type in this parameter", name).into()
- }
- ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelfOutput, _) => {
- format!("method `{}` references the `Self` type in its return type", name).into()
- }
- ObjectSafetyViolation::Method(
- name,
- MethodViolationCode::WhereClauseReferencesSelf,
- _,
- ) => {
- format!("method `{}` references the `Self` type in its `where` clause", name).into()
- }
- ObjectSafetyViolation::Method(name, MethodViolationCode::Generic, _) => {
- format!("method `{}` has generic type parameters", name).into()
- }
- ObjectSafetyViolation::Method(name, MethodViolationCode::UndispatchableReceiver, _) => {
- format!("method `{}`'s `self` parameter cannot be dispatched on", name).into()
- }
- ObjectSafetyViolation::AssocConst(name, DUMMY_SP) => {
- format!("it contains associated `const` `{}`", name).into()
- }
- ObjectSafetyViolation::AssocConst(..) => "it contains this associated `const`".into(),
- }
- }
-
- pub fn solution(&self) -> Option<(String, Option<(String, Span)>)> {
- Some(match *self {
- ObjectSafetyViolation::SizedSelf(_) | ObjectSafetyViolation::SupertraitSelf(_) => {
- return None;
- }
- ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod(sugg), _) => (
- format!(
- "consider turning `{}` into a method by giving it a `&self` argument or \
- constraining it so it does not apply to trait objects",
- name
- ),
- sugg.map(|(sugg, sp)| (sugg.to_string(), sp)),
- ),
- ObjectSafetyViolation::Method(
- name,
- MethodViolationCode::UndispatchableReceiver,
- span,
- ) => (
- format!("consider changing method `{}`'s `self` parameter to be `&self`", name)
- .into(),
- Some(("&Self".to_string(), span)),
- ),
- ObjectSafetyViolation::AssocConst(name, _)
- | ObjectSafetyViolation::Method(name, ..) => {
- (format!("consider moving `{}` to another trait", name), None)
- }
- })
- }
-
- pub fn spans(&self) -> SmallVec<[Span; 1]> {
- // When `span` comes from a separate crate, it'll be `DUMMY_SP`. Treat it as `None` so
- // diagnostics use a `note` instead of a `span_label`.
- match self {
- ObjectSafetyViolation::SupertraitSelf(spans)
- | ObjectSafetyViolation::SizedSelf(spans) => spans.clone(),
- ObjectSafetyViolation::AssocConst(_, span)
- | ObjectSafetyViolation::Method(_, _, span)
- if *span != DUMMY_SP =>
- {
- smallvec![*span]
- }
- _ => smallvec![],
- }
- }
-}
-
-/// Reasons a method might not be object-safe.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
-pub enum MethodViolationCode {
- /// e.g., `fn foo()`
- StaticMethod(Option<(&'static str, Span)>),
-
- /// e.g., `fn foo(&self, x: Self)`
- ReferencesSelfInput(usize),
-
- /// e.g., `fn foo(&self) -> Self`
- ReferencesSelfOutput,
-
- /// e.g., `fn foo(&self) where Self: Clone`
- WhereClauseReferencesSelf,
-
- /// e.g., `fn foo<A>()`
- Generic,
-
- /// the method's receiver (`self` argument) can't be dispatched on
- UndispatchableReceiver,
-}
+pub use crate::traits::{MethodViolationCode, ObjectSafetyViolation};
/// Returns the object safety violations that affect
/// astconv -- currently, `Self` in supertraits. This is needed
violations
}
-pub fn object_safety_violations(
- tcx: TyCtxt<'_>,
- trait_def_id: DefId,
-) -> Vec<ObjectSafetyViolation> {
+fn object_safety_violations(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Vec<ObjectSafetyViolation> {
debug_assert!(tcx.generics_of(trait_def_id).has_self);
debug!("object_safety_violations: {:?}", trait_def_id);
error
}
-pub(super) fn is_object_safe_provider(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
- object_safety_violations(tcx, trait_def_id).is_empty()
+fn is_object_safe(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
+ tcx.object_safety_violations(trait_def_id).is_empty()
+}
+
+pub fn provide(providers: &mut ty::query::Providers<'_>) {
+ *providers = ty::query::Providers { is_object_safe, object_safety_violations, ..*providers };
}
use rustc_hir as hir;
use rustc_infer::traits;
use rustc_infer::traits::error_reporting::report_object_safety_error;
-use rustc_infer::traits::object_safety_violations;
use rustc_span::Span;
use syntax::ast;
}
fn report_object_unsafe_cast(&self, fcx: &FnCtxt<'a, 'tcx>, did: DefId) {
- let violations = object_safety_violations(fcx.tcx, did);
+ let violations = fcx.tcx.object_safety_violations(did);
let mut err = report_object_safety_error(fcx.tcx, self.cast_span, did, violations);
err.note(&format!("required by cast to type '{}'", fcx.ty_to_string(self.cast_ty)));
err.emit();
use rustc_hir::def_id::DefId;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{Coercion, InferOk, InferResult};
-use rustc_infer::traits::object_safety_violations;
use rustc_infer::traits::{self, ObligationCause, ObligationCauseCode};
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
// Are of this `impl Trait`'s traits object safe?
is_object_safe = bounds.iter().all(|bound| {
bound.trait_def_id().map_or(false, |def_id| {
- object_safety_violations(fcx.tcx, def_id).is_empty()
+ fcx.tcx.object_safety_violations(def_id).is_empty()
})
})
}
_ => {}
}
if !trait_should_be_self.is_empty() {
- if rustc_infer::traits::object_safety_violations(tcx, trait_def_id).is_empty() {
+ if tcx.object_safety_violations(trait_def_id).is_empty() {
return;
}
let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();