Make type_implements_trait not a query
This commit is contained in:
parent
969a6c2481
commit
8ef5212eff
@ -1559,25 +1559,6 @@
|
||||
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>
|
||||
|
@ -13,6 +13,7 @@
|
||||
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 @@ fn try_report_cannot_return_reference_to_local(
|
||||
|
||||
// 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) {
|
||||
|
@ -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 @@ fn partially_normalize_associated_types_in<T>(
|
||||
) -> 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 @@ fn partially_normalize_associated_types_in<T>(
|
||||
);
|
||||
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> {
|
||||
|
@ -28,6 +28,7 @@
|
||||
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 @@ fn suggest_await_before_try(
|
||||
}
|
||||
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
|
||||
|
@ -31,7 +31,7 @@
|
||||
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();
|
||||
|
@ -45,6 +45,7 @@
|
||||
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 @@ fn report_cast_error(&self, fcx: &FnCtxt<'a, 'tcx>, e: CastError) {
|
||||
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;
|
||||
|
@ -42,13 +42,11 @@
|
||||
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 @@ fn compute_2229_migrations_reasons(
|
||||
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 @@ fn need_2229_migrations_for_trait(
|
||||
|
||||
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 @@ fn need_2229_migrations_for_trait(
|
||||
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 @@ fn has_significant_drop_outside_of_captures(
|
||||
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()
|
||||
};
|
||||
|
||||
|
50
src/test/incremental/issue-86753.rs
Normal file
50
src/test/incremental/issue-86753.rs
Normal file
@ -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() {}
|
@ -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
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
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`.
|
||||
|
Loading…
Reference in New Issue
Block a user