use rustc_data_structures::obligation_forest::{Error, ForestObligation, Outcome};
use rustc_data_structures::obligation_forest::{ObligationForest, ObligationProcessor};
use rustc_infer::traits::ProjectionCacheKey;
-use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation};
+use rustc_infer::traits::{SelectionError, TraitEngine, TraitObligation};
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Binder, Const, Ty, TypeVisitable};
+use rustc_middle::ty::{self, Binder, Const, TypeVisitable};
use std::marker::PhantomData;
use super::const_evaluatable;
use super::CodeProjectionError;
use super::CodeSelectionError;
use super::EvaluationResult;
+use super::PredicateObligation;
use super::Unimplemented;
use super::{FulfillmentError, FulfillmentErrorCode};
-use super::{ObligationCause, PredicateObligation};
use crate::traits::project::PolyProjectionObligation;
use crate::traits::project::ProjectionCacheKeyExt as _;
}
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
- /// "Normalize" a projection type `<SomeType as SomeTrait>::X` by
- /// creating a fresh type variable `$0` as well as a projection
- /// predicate `<SomeType as SomeTrait>::X == $0`. When the
- /// inference engine runs, it will attempt to find an impl of
- /// `SomeTrait` or a where-clause that lets us unify `$0` with
- /// something concrete. If this fails, we'll unify `$0` with
- /// `projection_ty` again.
- #[instrument(level = "debug", skip(self, infcx, param_env, cause))]
- fn normalize_projection_type(
- &mut self,
- infcx: &InferCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- projection_ty: ty::ProjectionTy<'tcx>,
- cause: ObligationCause<'tcx>,
- ) -> Ty<'tcx> {
- debug_assert!(!projection_ty.has_escaping_bound_vars());
-
- // FIXME(#20304) -- cache
-
- let mut selcx = SelectionContext::new(infcx);
- let mut obligations = vec![];
- let normalized_ty = project::normalize_projection_type(
- &mut selcx,
- param_env,
- projection_ty,
- cause,
- 0,
- &mut obligations,
- );
- self.register_predicate_obligations(infcx, obligations);
-
- debug!(?normalized_ty);
-
- normalized_ty.ty().unwrap()
- }
-
fn register_predicate_obligation(
&mut self,
infcx: &InferCtxt<'tcx>,
// Evaluation will discard candidates using the leak check.
// This means we need to pass it the bound version of our
// predicate.
- ty::PredicateKind::Trait(trait_ref) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(trait_ref)) => {
let trait_obligation = obligation.with(infcx.tcx, binder.rebind(trait_ref));
self.process_trait_obligation(
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateKind::Projection(data) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(data)) => {
let project_obligation = obligation.with(infcx.tcx, binder.rebind(data));
self.process_projection_obligation(
&mut pending_obligation.stalled_on,
)
}
- ty::PredicateKind::RegionOutlives(_)
- | ty::PredicateKind::TypeOutlives(_)
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(_))
+ | ty::PredicateKind::Clause(ty::Clause::TypeOutlives(_))
| ty::PredicateKind::WellFormed(_)
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(..)
}
},
Some(pred) => match pred {
- ty::PredicateKind::Trait(data) => {
+ ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
let trait_obligation = obligation.with(infcx.tcx, Binder::dummy(data));
self.process_trait_obligation(
)
}
- ty::PredicateKind::RegionOutlives(data) => {
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(data)) => {
if infcx.considering_regions {
infcx.region_outlives_predicate(&obligation.cause, Binder::dummy(data));
}
ProcessResult::Changed(vec![])
}
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(t_a, r_b)) => {
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ t_a,
+ r_b,
+ ))) => {
if infcx.considering_regions {
infcx.register_region_obligation_with_cause(t_a, r_b, &obligation.cause);
}
ProcessResult::Changed(vec![])
}
- ty::PredicateKind::Projection(ref data) => {
+ ty::PredicateKind::Clause(ty::Clause::Projection(ref data)) => {
let project_obligation = obligation.with(infcx.tcx, Binder::dummy(*data));
self.process_projection_obligation(
}
ty::PredicateKind::ConstEquate(c1, c2) => {
+ let tcx = self.selcx.tcx();
assert!(
- self.selcx.tcx().features().generic_const_exprs,
+ tcx.features().generic_const_exprs,
"`ConstEquate` without a feature gate: {c1:?} {c2:?}",
);
- debug!(?c1, ?c2, "equating consts");
// FIXME: we probably should only try to unify abstract constants
// if the constants depend on generic parameters.
//
// Let's just see where this breaks :shrug:
- if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) =
- (c1.kind(), c2.kind())
{
- if infcx.try_unify_abstract_consts(a, b, obligation.param_env) {
- return ProcessResult::Changed(vec![]);
+ let c1 = tcx.expand_abstract_consts(c1);
+ let c2 = tcx.expand_abstract_consts(c2);
+ debug!("equating consts:\nc1= {:?}\nc2= {:?}", c1, c2);
+
+ use rustc_hir::def::DefKind;
+ use ty::ConstKind::Unevaluated;
+ match (c1.kind(), c2.kind()) {
+ (Unevaluated(a), Unevaluated(b))
+ if a.def.did == b.def.did
+ && tcx.def_kind(a.def.did) == DefKind::AssocConst =>
+ {
+ if let Ok(new_obligations) = infcx
+ .at(&obligation.cause, obligation.param_env)
+ .trace(c1, c2)
+ .eq(a.substs, b.substs)
+ {
+ return ProcessResult::Changed(mk_pending(
+ new_obligations.into_obligations(),
+ ));
+ }
+ }
+ (_, Unevaluated(_)) | (Unevaluated(_), _) => (),
+ (_, _) => {
+ if let Ok(new_obligations) =
+ infcx.at(&obligation.cause, obligation.param_env).eq(c1, c2)
+ {
+ return ProcessResult::Changed(mk_pending(
+ new_obligations.into_obligations(),
+ ));
+ }
+ }
}
}
.at(&obligation.cause, obligation.param_env)
.eq(c1, c2)
{
- Ok(_) => ProcessResult::Changed(vec![]),
+ Ok(inf_ok) => {
+ ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
+ }
Err(err) => ProcessResult::Error(
FulfillmentErrorCode::CodeConstEquateError(
ExpectedFound::new(true, c1, c2),