Hack out effects support for old solver
This commit is contained in:
parent
3f1be1ec7e
commit
8b7b8e5f56
37 changed files with 302 additions and 192 deletions
152
compiler/rustc_trait_selection/src/traits/effects.rs
Normal file
152
compiler/rustc_trait_selection/src/traits/effects.rs
Normal file
|
@ -0,0 +1,152 @@
|
|||
use rustc_hir as hir;
|
||||
use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt};
|
||||
use rustc_infer::traits::{ImplSource, Obligation, PredicateObligation};
|
||||
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
|
||||
use rustc_middle::{span_bug, ty};
|
||||
use rustc_type_ir::solve::NoSolution;
|
||||
use thin_vec::ThinVec;
|
||||
|
||||
use super::SelectionContext;
|
||||
|
||||
pub type HostEffectObligation<'tcx> = Obligation<'tcx, ty::HostEffectPredicate<'tcx>>;
|
||||
|
||||
pub enum EvaluationFailure {
|
||||
Ambiguous,
|
||||
NoSolution,
|
||||
}
|
||||
|
||||
pub fn evaluate_host_effect_obligation<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||
if selcx.infcx.intercrate {
|
||||
span_bug!(
|
||||
obligation.cause.span,
|
||||
"should not select host obligation in old solver in intercrate mode"
|
||||
);
|
||||
}
|
||||
|
||||
match evaluate_host_effect_from_bounds(selcx, obligation) {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
||||
Err(EvaluationFailure::NoSolution) => {}
|
||||
}
|
||||
|
||||
match evaluate_host_effect_from_selection_candiate(selcx, obligation) {
|
||||
Ok(result) => return Ok(result),
|
||||
Err(EvaluationFailure::Ambiguous) => return Err(EvaluationFailure::Ambiguous),
|
||||
Err(EvaluationFailure::NoSolution) => {}
|
||||
}
|
||||
|
||||
Err(EvaluationFailure::NoSolution)
|
||||
}
|
||||
|
||||
fn match_candidate<'tcx>(
|
||||
infcx: &InferCtxt<'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
candidate: ty::Binder<'tcx, ty::HostEffectPredicate<'tcx>>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, NoSolution> {
|
||||
if !candidate.skip_binder().host.satisfies(obligation.predicate.host) {
|
||||
return Err(NoSolution);
|
||||
}
|
||||
|
||||
let candidate = infcx.instantiate_binder_with_fresh_vars(
|
||||
obligation.cause.span,
|
||||
BoundRegionConversionTime::HigherRankedType,
|
||||
candidate,
|
||||
);
|
||||
|
||||
let mut nested = infcx
|
||||
.at(&obligation.cause, obligation.param_env)
|
||||
.eq(DefineOpaqueTypes::Yes, obligation.predicate.trait_ref, candidate.trait_ref)?
|
||||
.into_obligations();
|
||||
|
||||
for nested in &mut nested {
|
||||
nested.set_depth_from_parent(obligation.recursion_depth);
|
||||
}
|
||||
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
fn evaluate_host_effect_from_bounds<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||
let infcx = selcx.infcx;
|
||||
let drcx = DeepRejectCtxt::relate_rigid_rigid(selcx.tcx());
|
||||
let mut candidate = None;
|
||||
|
||||
for predicate in obligation.param_env.caller_bounds() {
|
||||
let bound_predicate = predicate.kind();
|
||||
if let ty::ClauseKind::HostEffect(data) = predicate.kind().skip_binder() {
|
||||
let data = bound_predicate.rebind(data);
|
||||
if data.skip_binder().trait_ref.def_id != obligation.predicate.trait_ref.def_id {
|
||||
continue;
|
||||
}
|
||||
|
||||
if !drcx.args_may_unify(
|
||||
obligation.predicate.trait_ref.args,
|
||||
data.skip_binder().trait_ref.args,
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let is_match = infcx.probe(|_| match_candidate(infcx, obligation, data).is_ok());
|
||||
|
||||
if is_match {
|
||||
if candidate.is_some() {
|
||||
return Err(EvaluationFailure::Ambiguous);
|
||||
} else {
|
||||
candidate = Some(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(data) = candidate {
|
||||
Ok(match_candidate(infcx, obligation, data)
|
||||
.expect("candidate matched before, so it should match again"))
|
||||
} else {
|
||||
Err(EvaluationFailure::NoSolution)
|
||||
}
|
||||
}
|
||||
|
||||
fn evaluate_host_effect_from_selection_candiate<'tcx>(
|
||||
selcx: &mut SelectionContext<'_, 'tcx>,
|
||||
obligation: &HostEffectObligation<'tcx>,
|
||||
) -> Result<ThinVec<PredicateObligation<'tcx>>, EvaluationFailure> {
|
||||
let tcx = selcx.tcx();
|
||||
selcx.infcx.commit_if_ok(|_| {
|
||||
match selcx.select(&obligation.with(tcx, obligation.predicate.trait_ref)) {
|
||||
Ok(None) => Err(EvaluationFailure::Ambiguous),
|
||||
Err(_) => Err(EvaluationFailure::NoSolution),
|
||||
Ok(Some(source)) => match source {
|
||||
ImplSource::UserDefined(impl_) => {
|
||||
if tcx.constness(impl_.impl_def_id) != hir::Constness::Const {
|
||||
return Err(EvaluationFailure::NoSolution);
|
||||
}
|
||||
|
||||
let mut nested = impl_.nested;
|
||||
nested.extend(
|
||||
tcx.const_conditions(impl_.impl_def_id)
|
||||
.instantiate(tcx, impl_.args)
|
||||
.into_iter()
|
||||
.map(|(trait_ref, _)| {
|
||||
obligation.with(
|
||||
tcx,
|
||||
trait_ref.to_host_effect_clause(tcx, obligation.predicate.host),
|
||||
)
|
||||
}),
|
||||
);
|
||||
|
||||
for nested in &mut nested {
|
||||
nested.set_depth_from_parent(obligation.recursion_depth);
|
||||
}
|
||||
|
||||
Ok(nested)
|
||||
}
|
||||
_ => Err(EvaluationFailure::NoSolution),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
|
@ -17,6 +17,7 @@ use rustc_middle::ty::{self, Binder, Const, GenericArgsRef, TypeVisitableExt};
|
|||
use thin_vec::ThinVec;
|
||||
use tracing::{debug, debug_span, instrument};
|
||||
|
||||
use super::effects::{self, HostEffectObligation};
|
||||
use super::project::{self, ProjectAndUnifyResult};
|
||||
use super::select::SelectionContext;
|
||||
use super::{
|
||||
|
@ -402,8 +403,13 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
|
|||
)
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
|
||||
ProcessResult::Changed(Default::default())
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
|
||||
let host_obligation = obligation.with(infcx.tcx, data);
|
||||
|
||||
self.process_host_obligation(
|
||||
host_obligation,
|
||||
&mut pending_obligation.stalled_on,
|
||||
)
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => {
|
||||
|
@ -854,6 +860,27 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn process_host_obligation(
|
||||
&mut self,
|
||||
host_obligation: HostEffectObligation<'tcx>,
|
||||
stalled_on: &mut Vec<TyOrConstInferVar>,
|
||||
) -> ProcessResult<PendingPredicateObligation<'tcx>, FulfillmentErrorCode<'tcx>> {
|
||||
match effects::evaluate_host_effect_obligation(&mut self.selcx, &host_obligation) {
|
||||
Ok(nested) => ProcessResult::Changed(mk_pending(nested)),
|
||||
Err(effects::EvaluationFailure::Ambiguous) => {
|
||||
stalled_on.clear();
|
||||
stalled_on.extend(args_infer_vars(
|
||||
&self.selcx,
|
||||
ty::Binder::dummy(host_obligation.predicate.trait_ref.args),
|
||||
));
|
||||
ProcessResult::Unchanged
|
||||
}
|
||||
Err(effects::EvaluationFailure::NoSolution) => {
|
||||
ProcessResult::Error(FulfillmentErrorCode::Select(SelectionError::Unimplemented))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the set of inference variables contained in `args`.
|
||||
|
|
|
@ -6,6 +6,7 @@ pub mod auto_trait;
|
|||
pub(crate) mod coherence;
|
||||
pub mod const_evaluatable;
|
||||
mod dyn_compatibility;
|
||||
pub mod effects;
|
||||
mod engine;
|
||||
mod fulfill;
|
||||
pub mod misc;
|
||||
|
|
|
@ -49,7 +49,7 @@ use crate::infer::{InferCtxt, InferOk, TypeFreshener};
|
|||
use crate::solve::InferCtxtSelectExt as _;
|
||||
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
|
||||
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
|
||||
use crate::traits::{ProjectionCacheKey, Unimplemented};
|
||||
use crate::traits::{ProjectionCacheKey, Unimplemented, effects};
|
||||
|
||||
mod _match;
|
||||
mod candidate_assembly;
|
||||
|
@ -645,11 +645,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
self.evaluate_trait_predicate_recursively(previous_stack, obligation)
|
||||
}
|
||||
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(..)) => {
|
||||
// FIXME(effects): It should be relatively straightforward to implement
|
||||
// old trait solver support for `HostEffect` bounds; or at least basic
|
||||
// support for them.
|
||||
todo!()
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(data)) => {
|
||||
self.infcx.enter_forall(bound_predicate.rebind(data), |data| {
|
||||
match effects::evaluate_host_effect_obligation(
|
||||
self,
|
||||
&obligation.with(self.tcx(), data),
|
||||
) {
|
||||
Ok(nested) => {
|
||||
self.evaluate_predicates_recursively(previous_stack, nested)
|
||||
}
|
||||
Err(effects::EvaluationFailure::Ambiguous) => Ok(EvaluatedToAmbig),
|
||||
Err(effects::EvaluationFailure::NoSolution) => Ok(EvaluatedToErr),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
ty::PredicateKind::Subtype(p) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue