109 lines
3.5 KiB
Rust
109 lines
3.5 KiB
Rust
use crate::infer::{InferCtxt, InferOk};
|
|
use crate::traits::query::Fallible;
|
|
use std::fmt;
|
|
|
|
use crate::infer::canonical::query_response;
|
|
use crate::infer::canonical::QueryRegionConstraints;
|
|
use crate::traits::engine::TraitEngineExt as _;
|
|
use crate::traits::{ObligationCause, TraitEngine};
|
|
use rustc_infer::traits::TraitEngineExt as _;
|
|
use rustc_span::source_map::DUMMY_SP;
|
|
use std::rc::Rc;
|
|
|
|
pub struct CustomTypeOp<F, G> {
|
|
closure: F,
|
|
description: G,
|
|
}
|
|
|
|
impl<F, G> CustomTypeOp<F, G> {
|
|
pub fn new<'tcx, R>(closure: F, description: G) -> Self
|
|
where
|
|
F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
|
|
G: Fn() -> String,
|
|
{
|
|
CustomTypeOp { closure, description }
|
|
}
|
|
}
|
|
|
|
impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
|
|
where
|
|
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
|
|
G: Fn() -> String,
|
|
{
|
|
type Output = R;
|
|
|
|
/// Processes the operation and all resulting obligations,
|
|
/// returning the final result along with any region constraints
|
|
/// (they will be given over to the NLL region solver).
|
|
fn fully_perform(
|
|
self,
|
|
infcx: &InferCtxt<'_, 'tcx>,
|
|
) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
|
|
if cfg!(debug_assertions) {
|
|
info!("fully_perform({:?})", self);
|
|
}
|
|
|
|
scrape_region_constraints(infcx, || (self.closure)(infcx))
|
|
}
|
|
}
|
|
|
|
impl<F, G> fmt::Debug for CustomTypeOp<F, G>
|
|
where
|
|
G: Fn() -> String,
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
write!(f, "{}", (self.description)())
|
|
}
|
|
}
|
|
|
|
/// Executes `op` and then scrapes out all the "old style" region
|
|
/// constraints that result, creating query-region-constraints.
|
|
fn scrape_region_constraints<'tcx, R>(
|
|
infcx: &InferCtxt<'_, 'tcx>,
|
|
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
|
|
) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
|
|
let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
|
|
let dummy_body_id = ObligationCause::dummy().body_id;
|
|
|
|
// During NLL, we expect that nobody will register region
|
|
// obligations **except** as part of a custom type op (and, at the
|
|
// end of each custom type op, we scrape out the region
|
|
// obligations that resulted). So this vector should be empty on
|
|
// entry.
|
|
let pre_obligations = infcx.take_registered_region_obligations();
|
|
assert!(
|
|
pre_obligations.is_empty(),
|
|
"scrape_region_constraints: incoming region obligations = {:#?}",
|
|
pre_obligations,
|
|
);
|
|
|
|
let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
|
|
debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
|
|
fulfill_cx.register_predicate_obligations(infcx, obligations);
|
|
if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
|
|
infcx.tcx.sess.diagnostic().delay_span_bug(
|
|
DUMMY_SP,
|
|
&format!("errors selecting obligation during MIR typeck: {:?}", e),
|
|
);
|
|
}
|
|
|
|
let region_obligations = infcx.take_registered_region_obligations();
|
|
|
|
let region_constraint_data = infcx.take_and_reset_region_constraints();
|
|
|
|
let region_constraints = query_response::make_query_region_constraints(
|
|
infcx.tcx,
|
|
region_obligations
|
|
.iter()
|
|
.map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
|
|
.map(|(ty, r)| (infcx.resolve_vars_if_possible(ty), r)),
|
|
®ion_constraint_data,
|
|
);
|
|
|
|
if region_constraints.is_empty() {
|
|
Ok((value, None))
|
|
} else {
|
|
Ok((value, Some(Rc::new(region_constraints))))
|
|
}
|
|
}
|