about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs2
-rw-r--r--compiler/rustc_middle/src/query/mod.rs19
-rw-r--r--compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs6
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs45
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs41
-rw-r--r--compiler/rustc_typeck/src/check/cast.rs5
-rw-r--r--compiler/rustc_typeck/src/check/upvar.rs59
-rw-r--r--src/test/incremental/issue-86753.rs50
-rw-r--r--src/test/ui/issues/issue-73886.stderr4
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs14
11 files changed, 142 insertions, 108 deletions
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 8476929eaec..aa54d1ae7b9 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -285,7 +285,7 @@ pub type DepNode = rustc_query_system::dep_graph::DepNode<DepKind>;
 // required that their size stay the same, but we don't want to change
 // it inadvertently. This assert just ensures we're aware of any change.
 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
-static_assert_size!(DepNode, 18);
+static_assert_size!(DepNode, 17);
 
 #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
 static_assert_size!(DepNode, 24);
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index c4b990faed0..9a2f1149316 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1555,25 +1555,6 @@ rustc_queries! {
         desc { "evaluating trait selection obligation `{}`", goal.value }
     }
 
-    /// Evaluates whether the given type implements the given trait
-    /// in the given environment.
-    ///
-    /// The inputs are:
-    ///
-    /// - the def-id of the trait
-    /// - the self type
-    /// - the *other* type parameters of the trait, excluding the self-type
-    /// - the parameter environment
-    ///
-    /// FIXME. If the type, trait, or environment has inference variables,
-    /// this yields `EvaluatedToUnknown`. It should be refactored
-    /// to use canonicalization, really.
-    query type_implements_trait(
-        key: (DefId, Ty<'tcx>, SubstsRef<'tcx>, ty::ParamEnv<'tcx>, )
-    ) -> traits::EvaluationResult {
-        desc { "evaluating `type_implements_trait` `{:?}`", key }
-    }
-
     /// Do not call this query directly: part of the `Eq` type-op
     query type_op_ascribe_user_type(
         goal: CanonicalTypeOpAscribeUserTypeGoal<'tcx>
diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
index 4be4372c039..0b01c4efcdb 100644
--- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs
@@ -13,6 +13,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_param, Ty};
 use rustc_span::source_map::DesugaringKind;
 use rustc_span::symbol::sym;
 use rustc_span::{Span, DUMMY_SP};
+use rustc_trait_selection::infer::InferCtxtExt;
 
 use crate::dataflow::drop_flag_effects;
 use crate::dataflow::indexes::{MoveOutIndex, MovePathIndex};
@@ -1330,8 +1331,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
             // to avoid panics
             if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator) {
-                if tcx
-                    .type_implements_trait((iter_trait, return_ty, ty_params, self.param_env))
+                if self
+                    .infcx
+                    .type_implements_trait(iter_trait, return_ty, ty_params, self.param_env)
                     .must_apply_modulo_regions()
                 {
                     if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index a9ffb5542b6..9fc907da265 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -1,13 +1,18 @@
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::outlives_bounds::InferCtxtExt as _;
 use crate::traits::{self, TraitEngine, TraitEngineExt};
 
 use rustc_hir as hir;
+use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::infer::canonical::{Canonical, CanonicalizedQueryResponse, QueryResponse};
 use rustc_middle::traits::query::Fallible;
+use rustc_middle::ty::subst::SubstsRef;
+use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::WithConstness;
 use rustc_middle::ty::{self, Ty, TypeFoldable};
 use rustc_span::{Span, DUMMY_SP};
 
@@ -32,8 +37,22 @@ pub trait InferCtxtExt<'tcx> {
     ) -> InferOk<'tcx, T>
     where
         T: TypeFoldable<'tcx>;
-}
 
+    /// Check whether a `ty` implements given trait(trait_def_id).
+    /// The inputs are:
+    ///
+    /// - the def-id of the trait
+    /// - the self type
+    /// - the *other* type parameters of the trait, excluding the self-type
+    /// - the parameter environment
+    fn type_implements_trait(
+        &self,
+        trait_def_id: DefId,
+        ty: Ty<'tcx>,
+        params: SubstsRef<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> traits::EvaluationResult;
+}
 impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
     fn type_is_copy_modulo_regions(
         &self,
@@ -79,6 +98,30 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'cx, 'tcx> {
         );
         InferOk { value, obligations }
     }
+
+    fn type_implements_trait(
+        &self,
+        trait_def_id: DefId,
+        ty: Ty<'tcx>,
+        params: SubstsRef<'tcx>,
+        param_env: ty::ParamEnv<'tcx>,
+    ) -> traits::EvaluationResult {
+        debug!(
+            "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
+            trait_def_id, ty, params, param_env
+        );
+
+        let trait_ref =
+            ty::TraitRef { def_id: trait_def_id, substs: self.tcx.mk_substs_trait(ty, params) };
+
+        let obligation = traits::Obligation {
+            cause: traits::ObligationCause::dummy(),
+            param_env,
+            recursion_depth: 0,
+            predicate: trait_ref.without_const().to_predicate(self.tcx),
+        };
+        self.evaluate_obligation_no_overflow(&obligation)
+    }
 }
 
 pub trait InferCtxtBuilderExt<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 9bc3d398f72..cca40ff1ce6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -28,6 +28,7 @@ use rustc_target::spec::abi;
 use std::fmt;
 
 use super::InferCtxtPrivExt;
+use crate::infer::InferCtxtExt as _;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 
@@ -2349,12 +2350,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
                 }
                 let self_ty = self.tcx.erase_regions(self_ty);
 
-                let impls_future = self.tcx.type_implements_trait((
+                let impls_future = self.type_implements_trait(
                     future_trait,
                     self_ty.skip_binder(),
                     ty::List::empty(),
                     obligation.param_env,
-                ));
+                );
 
                 let item_def_id = self
                     .tcx
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index e48aab6f46f..3a80e720e8c 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -31,7 +31,7 @@ use rustc_hir::def_id::DefId;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::{
-    self, GenericParamDefKind, ParamEnv, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
+    self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry, WithConstness,
     COMMON_VTABLE_ENTRIES,
 };
 use rustc_span::Span;
@@ -541,44 +541,6 @@ fn vtable_trait_first_method_offset<'tcx>(
     vtable_base
 }
 
-/// Check whether a `ty` implements given trait(trait_def_id).
-/// See query definition for details.
-fn type_implements_trait<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    key: (
-        DefId,    // trait_def_id,
-        Ty<'tcx>, // type
-        SubstsRef<'tcx>,
-        ParamEnv<'tcx>,
-    ),
-) -> EvaluationResult {
-    let (trait_def_id, ty, params, param_env) = key;
-
-    debug!(
-        "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
-        trait_def_id, ty, params, param_env
-    );
-
-    let trait_ref = ty::TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, params) };
-
-    // FIXME(#86868): If there are inference variables anywhere, just give up and assume
-    // we don't know the answer. This works around the ICEs that would result from
-    // using those inference variables within the `infer_ctxt` we create below.
-    // Really we should be using canonicalized variables, or perhaps removing
-    // this query altogether.
-    if (trait_ref, param_env).needs_infer() {
-        return EvaluationResult::EvaluatedToUnknown;
-    }
-
-    let obligation = Obligation {
-        cause: ObligationCause::dummy(),
-        param_env,
-        recursion_depth: 0,
-        predicate: trait_ref.without_const().to_predicate(tcx),
-    };
-    tcx.infer_ctxt().enter(|infcx| infcx.evaluate_obligation_no_overflow(&obligation))
-}
-
 pub fn provide(providers: &mut ty::query::Providers) {
     object_safety::provide(providers);
     structural_match::provide(providers);
@@ -587,7 +549,6 @@ pub fn provide(providers: &mut ty::query::Providers) {
         specializes: specialize::specializes,
         codegen_fulfill_obligation: codegen::codegen_fulfill_obligation,
         vtable_entries,
-        type_implements_trait,
         subst_and_check_impossible_predicates,
         mir_abstract_const: |tcx, def_id| {
             let def_id = def_id.expect_local();
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index a09fad3b6b7..b3808eae1ad 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -45,6 +45,7 @@ use rustc_session::lint;
 use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
+use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 
@@ -441,8 +442,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             let expr_ty = fcx.tcx.erase_regions(expr_ty);
                             let ty_params = fcx.tcx.mk_substs_trait(expr_ty, &[]);
                             if fcx
-                                .tcx
-                                .type_implements_trait((from_trait, ty, ty_params, fcx.param_env))
+                                .infcx
+                                .type_implements_trait(from_trait, ty, ty_params, fcx.param_env)
                                 .must_apply_modulo_regions()
                             {
                                 label = false;
diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs
index e5f18778f43..7be864c301b 100644
--- a/compiler/rustc_typeck/src/check/upvar.rs
+++ b/compiler/rustc_typeck/src/check/upvar.rs
@@ -42,13 +42,11 @@ use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
 use rustc_infer::infer::UpvarRegion;
 use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection, ProjectionKind};
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{
-    self, ClosureSizeProfileData, TraitRef, Ty, TyCtxt, TypeckResults, UpvarSubsts,
-};
+use rustc_middle::ty::{self, ClosureSizeProfileData, Ty, TyCtxt, TypeckResults, UpvarSubsts};
 use rustc_session::lint;
 use rustc_span::sym;
 use rustc_span::{MultiSpan, Span, Symbol};
-use rustc_trait_selection::traits::{Obligation, ObligationCause};
+use rustc_trait_selection::infer::InferCtxtExt;
 
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_index::vec::Idx;
@@ -578,29 +576,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         reasons
     }
 
-    /// Returns true if `ty` may implement `trait_def_id`
-    fn ty_impls_trait(
-        &self,
-        ty: Ty<'tcx>,
-        cause: &ObligationCause<'tcx>,
-        trait_def_id: DefId,
-    ) -> bool {
-        use crate::rustc_middle::ty::ToPredicate;
-        use crate::rustc_middle::ty::WithConstness;
-        use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
-        let tcx = self.infcx.tcx;
-
-        let trait_ref = TraitRef { def_id: trait_def_id, substs: tcx.mk_substs_trait(ty, &[]) };
-
-        let obligation = Obligation::new(
-            cause.clone(),
-            self.param_env,
-            trait_ref.without_const().to_predicate(tcx),
-        );
-
-        self.infcx.predicate_may_hold(&obligation)
-    }
-
     /// Returns true if migration is needed for trait for the provided var_hir_id
     fn need_2229_migrations_for_trait(
         &self,
@@ -618,10 +593,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let ty = self.infcx.resolve_vars_if_possible(self.node_ty(var_hir_id));
 
-        let cause = ObligationCause::misc(self.tcx.hir().span(var_hir_id), self.body_id);
-
         let obligation_should_hold = check_trait
-            .map(|check_trait| self.ty_impls_trait(ty, &cause, check_trait))
+            .map(|check_trait| {
+                self.infcx
+                    .type_implements_trait(
+                        check_trait,
+                        ty,
+                        self.tcx.mk_substs_trait(ty, &[]),
+                        self.param_env,
+                    )
+                    .must_apply_modulo_regions()
+            })
             .unwrap_or(false);
 
         // Check whether catpured fields also implement the trait
@@ -630,7 +612,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let ty = capture.place.ty();
 
             let obligation_holds_for_capture = check_trait
-                .map(|check_trait| self.ty_impls_trait(ty, &cause, check_trait))
+                .map(|check_trait| {
+                    self.infcx
+                        .type_implements_trait(
+                            check_trait,
+                            ty,
+                            self.tcx.mk_substs_trait(ty, &[]),
+                            self.param_env,
+                        )
+                        .must_apply_modulo_regions()
+                })
                 .unwrap_or(false);
 
             if !obligation_holds_for_capture && obligation_should_hold {
@@ -961,13 +952,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let is_drop_defined_for_ty = |ty: Ty<'tcx>| {
             let drop_trait = self.tcx.require_lang_item(hir::LangItem::Drop, Some(closure_span));
             let ty_params = self.tcx.mk_substs_trait(base_path_ty, &[]);
-            self.tcx
-                .type_implements_trait((
+            self.infcx
+                .type_implements_trait(
                     drop_trait,
                     ty,
                     ty_params,
                     self.tcx.param_env(closure_def_id.expect_local()),
-                ))
+                )
                 .must_apply_modulo_regions()
         };
 
diff --git a/src/test/incremental/issue-86753.rs b/src/test/incremental/issue-86753.rs
new file mode 100644
index 00000000000..4d6c4354e2b
--- /dev/null
+++ b/src/test/incremental/issue-86753.rs
@@ -0,0 +1,50 @@
+// edition:2018
+// revisions: rpass1
+
+
+// Regression test for #86753. The `type_implements_trait` query (since moved to a method)
+// was encountering an ICE during incremental testing when hashing its arguments.
+#![warn(rust_2021_compatibility)]
+
+use std::future::Future;
+use std::pin::Pin;
+use std::task::{Poll, Context};
+
+struct LocalSet {}
+struct RunUntil<'a, F> {
+    _local_set: &'a LocalSet,
+    _future: F,
+}
+impl<'a, F> RunUntil<'a, F> {
+    fn project<'pin>(self: Pin<&'pin mut Self>) -> Projection<'pin, 'a, F> {
+        unimplemented!()
+    }
+}
+
+struct Projection<'pin, 'a, F>
+where
+    RunUntil<'a, F>: 'pin,
+{
+    pub local_set: &'pin mut &'a LocalSet,
+    pub future: Pin<&'pin mut F>,
+}
+
+impl LocalSet {
+    fn with<T>(&self, _f: impl FnOnce() -> T) -> T {
+        unimplemented!()
+    }
+}
+impl<T: Future> Future for RunUntil<'_, T> {
+    type Output = T::Output;
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        let me = self.project();
+        me.local_set.with(|| {
+            let _ = cx.waker();
+            let f = me.future;
+            let _ = f.poll(cx);
+            Poll::Pending
+        })
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-73886.stderr b/src/test/ui/issues/issue-73886.stderr
index 31f642ea664..a6f8ba65ab5 100644
--- a/src/test/ui/issues/issue-73886.stderr
+++ b/src/test/ui/issues/issue-73886.stderr
@@ -8,7 +8,9 @@ error[E0605]: non-primitive cast: `u32` as `Option<_>`
   --> $DIR/issue-73886.rs:4:13
    |
 LL |     let _ = 7u32 as Option<_>;
-   |             ^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
+   |             ^^^^^^^^^^^^^^^^^ help: consider using the `From` trait instead: `Option<_>::from(7u32)`
+   |
+   = note: an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object
 
 error: aborting due to 2 previous errors
 
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 2808fc35e2a..8857e77d898 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -15,6 +15,7 @@ use rustc_span::sym;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::normalize::AtExt;
+use rustc_trait_selection::infer::InferCtxtExt;
 
 use crate::{match_def_path, must_use_attr};
 
@@ -112,6 +113,7 @@ pub fn has_iter_method(cx: &LateContext<'_>, probably_ref_ty: Ty<'_>) -> Option<
 }
 
 /// Checks whether a type implements a trait.
+/// The function returns false in case the type contains an inference variable.
 /// See also `get_trait_def_id`.
 pub fn implements_trait<'tcx>(
     cx: &LateContext<'tcx>,
@@ -119,18 +121,18 @@ pub fn implements_trait<'tcx>(
     trait_id: DefId,
     ty_params: &[GenericArg<'tcx>],
 ) -> bool {
-    // Do not check on infer_types to avoid panic in evaluate_obligation.
-    if ty.has_infer_types() {
-        return false;
-    }
+    // Clippy shouldn't have infer types
+    assert!(!ty.needs_infer());
+
     let ty = cx.tcx.erase_regions(ty);
     if ty.has_escaping_bound_vars() {
         return false;
     }
     let ty_params = cx.tcx.mk_substs(ty_params.iter());
-    cx.tcx
-        .type_implements_trait((trait_id, ty, ty_params, cx.param_env))
+    cx.tcx.infer_ctxt().enter(|infcx|
+        infcx.type_implements_trait(trait_id, ty, ty_params, cx.param_env)
         .must_apply_modulo_regions()
+    )
 }
 
 /// Checks whether this type implements `Drop`.