1 use crate::infer::canonical::query_response;
2 use crate::infer::{InferCtxt, InferOk};
4 use crate::traits::query::type_op::TypeOpOutput;
5 use crate::traits::query::Fallible;
6 use rustc_infer::infer::region_constraints::RegionConstraintData;
7 use rustc_span::source_map::DUMMY_SP;
11 pub struct CustomTypeOp<F, G> {
16 impl<F, G> CustomTypeOp<F, G> {
17 pub fn new<'tcx, R>(closure: F, description: G) -> Self
19 F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
22 CustomTypeOp { closure, description }
26 impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
28 F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
32 /// We can't do any custom error reporting for `CustomTypeOp`, so
33 /// we can use `!` to enforce that the implementation never provides it.
36 /// Processes the operation and all resulting obligations,
37 /// returning the final result along with any region constraints
38 /// (they will be given over to the NLL region solver).
39 fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
40 if cfg!(debug_assertions) {
41 info!("fully_perform({:?})", self);
44 Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0)
48 impl<F, G> fmt::Debug for CustomTypeOp<F, G>
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{}", (self.description)())
57 /// Executes `op` and then scrapes out all the "old style" region
58 /// constraints that result, creating query-region-constraints.
59 pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
60 infcx: &InferCtxt<'tcx>,
61 op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
62 ) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
63 // During NLL, we expect that nobody will register region
64 // obligations **except** as part of a custom type op (and, at the
65 // end of each custom type op, we scrape out the region
66 // obligations that resulted). So this vector should be empty on
68 let pre_obligations = infcx.take_registered_region_obligations();
70 pre_obligations.is_empty(),
71 "scrape_region_constraints: incoming region obligations = {:#?}",
75 let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
76 let errors = traits::fully_solve_obligations(infcx, obligations);
77 if !errors.is_empty() {
78 infcx.tcx.sess.diagnostic().delay_span_bug(
80 &format!("errors selecting obligation during MIR typeck: {:?}", errors),
84 let region_obligations = infcx.take_registered_region_obligations();
86 let region_constraint_data = infcx.take_and_reset_region_constraints();
88 let region_constraints = query_response::make_query_region_constraints(
92 .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()))
93 .map(|(ty, r, cc)| (infcx.resolve_vars_if_possible(ty), r, cc)),
94 ®ion_constraint_data,
97 if region_constraints.is_empty() {
99 TypeOpOutput { output: value, constraints: None, error_info: None },
100 region_constraint_data,
106 constraints: Some(infcx.tcx.arena.alloc(region_constraints)),
109 region_constraint_data,