]> git.lizzy.rs Git - rust.git/commitdiff
Querify object_safety_violations.
authorCamille GILLOT <gillot.camille@gmail.com>
Mon, 10 Feb 2020 18:55:49 +0000 (19:55 +0100)
committerCamille GILLOT <gillot.camille@gmail.com>
Mon, 17 Feb 2020 18:48:36 +0000 (19:48 +0100)
src/librustc/query/mod.rs
src/librustc/traits/mod.rs
src/librustc_infer/infer/error_reporting/mod.rs
src/librustc_infer/traits/error_reporting/mod.rs
src/librustc_infer/traits/error_reporting/suggestions.rs
src/librustc_infer/traits/mod.rs
src/librustc_infer/traits/object_safety.rs
src/librustc_typeck/check/cast.rs
src/librustc_typeck/check/coercion.rs
src/librustc_typeck/check/wfcheck.rs

index 5e279975d152d21d4a3f5f137ba3be771749584f..df08501f0074059180e559fedd4319eee05cc52d 100644 (file)
@@ -656,6 +656,9 @@ fn describe_as_module(def_id: DefId, tcx: TyCtxt<'_>) -> String {
         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
index c000aa7c25e974281826728805ce566ce958ff00..de2ec53e51e788a93d0734309c5b006d6cbb8d55 100644 (file)
 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;
 
@@ -737,3 +739,133 @@ fn lift_literal_to_tcx(
         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,
+}
index 77119b8618f173508c50aa331a61c4e75d6a6893..243feb16237c096e433ab81fe37844d640a6e84b 100644 (file)
@@ -52,7 +52,6 @@
 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,
 };
@@ -1618,7 +1617,7 @@ pub fn report_and_explain_type_error(
         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) => {
index 4bc8ffc3d2f43be0f5a8c35b4f5c1932edd27b88..2fc7c17897739f1a4befce0912ab0e32c946b9ee 100644 (file)
@@ -12,7 +12,6 @@
 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;
@@ -748,7 +747,7 @@ pub fn report_selection_error(
                     }
 
                     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)
                     }
 
@@ -912,7 +911,7 @@ pub fn report_selection_error(
             }
 
             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)
             }
 
index 50ae7c4fbbf6b4a33410603918467dcb4d5a8080..f1206ddf909a62f4a7bee48b00a911e6104e2570 100644 (file)
@@ -5,7 +5,6 @@
 
 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};
@@ -587,7 +586,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
                 // 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.
index 06c6d6518134893e0f7c6bb51dc836862552f9e3..64bc9f2cb926846224300898bad464aec596e3c9 100644 (file)
@@ -47,7 +47,6 @@
 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};
@@ -636,8 +635,8 @@ fn self_ty(&self) -> ty::Binder<Ty<'tcx>> {
 }
 
 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,
index d36d66e4e2555cc7940aa06bb77bc9fb982154e8..f409c22831fb5449d56540d3cfc4a0f42cf1794d 100644 (file)
 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
@@ -176,10 +46,7 @@ pub fn astconv_object_safety_violations(
     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);
 
@@ -905,6 +772,10 @@ fn contains_illegal_self_type_reference<'tcx>(
     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 };
 }
index 18f6a78804b408b5c859137c1745c5f2d6754c17..a67ceb856ce0cf9b0134b13ffb5e1d7c6b06650d 100644 (file)
@@ -45,7 +45,6 @@
 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;
 
@@ -517,7 +516,7 @@ pub fn check(mut self, fcx: &FnCtxt<'a, 'tcx>) {
     }
 
     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();
index c327a7996b6e4e8aced92af095d39b374312a5be..3720b74d92e07ad403f83e0598779efd5c7f737c 100644 (file)
@@ -66,7 +66,6 @@
 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};
@@ -1404,7 +1403,7 @@ fn add_impl_trait_explanation<'a>(
                         // 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()
                             })
                         })
                     }
index 4ffc3bf8e78fde4b551054db6be09f8edc77f232..12e6087dbafd6f8b8f28e1c16608f1d275d744e0 100644 (file)
@@ -223,7 +223,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
         _ => {}
     }
     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();