diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs index 8476929eaeced..aa54d1ae7b9d1 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; // 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 6f0f180b4274b..4d643c09e54bc 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1559,25 +1559,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 4be4372c0393a..0b01c4efcdbd4 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 a9ffb5542b6df..9fc907da2653e 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 9bc3d398f7290..cca40ff1ce6a6 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 e48aab6f46f4b..3a80e720e8c4b 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 a09fad3b6b78a..b3808eae1ad11 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 e5f18778f43e6..7be864c301b15 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 0000000000000..4d6c4354e2bdc --- /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(&self, _f: impl FnOnce() -> T) -> T { + unimplemented!() + } +} +impl Future for RunUntil<'_, T> { + type Output = T::Output; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + 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 31f642ea66418..a6f8ba65ab51a 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 2808fc35e2a1b..8857e77d8983d 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`.