]> git.proxmox.com Git - rustc.git/blame - src/librustc_infer/traits/query/type_op/custom.rs
New upstream version 1.43.0+dfsg1
[rustc.git] / src / librustc_infer / traits / query / type_op / custom.rs
CommitLineData
9fa01778 1use crate::infer::{InferCtxt, InferOk};
9fa01778 2use crate::traits::query::Fallible;
dfeec247 3use std::fmt;
8faf50e0 4
9fa01778 5use crate::infer::canonical::query_response;
dc9dc135 6use crate::infer::canonical::QueryRegionConstraints;
9fa01778 7use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt};
dfeec247
XL
8use rustc_span::source_map::DUMMY_SP;
9use std::rc::Rc;
8faf50e0
XL
10
11pub struct CustomTypeOp<F, G> {
12 closure: F,
13 description: G,
14}
15
16impl<F, G> CustomTypeOp<F, G> {
dc9dc135 17 pub fn new<'tcx, R>(closure: F, description: G) -> Self
8faf50e0 18 where
dc9dc135 19 F: FnOnce(&InferCtxt<'_, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
8faf50e0
XL
20 G: Fn() -> String,
21 {
dfeec247 22 CustomTypeOp { closure, description }
8faf50e0
XL
23 }
24}
25
dc9dc135 26impl<'tcx, F, R, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
8faf50e0 27where
dc9dc135 28 F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
8faf50e0
XL
29 G: Fn() -> String,
30{
31 type Output = R;
32
33 /// Processes the operation and all resulting obligations,
34 /// returning the final result along with any region constraints
35 /// (they will be given over to the NLL region solver).
36 fn fully_perform(
37 self,
dc9dc135
XL
38 infcx: &InferCtxt<'_, 'tcx>,
39 ) -> Fallible<(Self::Output, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
8faf50e0
XL
40 if cfg!(debug_assertions) {
41 info!("fully_perform({:?})", self);
42 }
43
44 scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
45 }
46}
47
48impl<F, G> fmt::Debug for CustomTypeOp<F, G>
49where
50 G: Fn() -> String,
51{
0bf4aa26 52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8faf50e0
XL
53 write!(f, "{}", (self.description)())
54 }
55}
56
57/// Executes `op` and then scrapes out all the "old style" region
58/// constraints that result, creating query-region-constraints.
dc9dc135
XL
59fn scrape_region_constraints<'tcx, R>(
60 infcx: &InferCtxt<'_, 'tcx>,
8faf50e0 61 op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
dc9dc135 62) -> Fallible<(R, Option<Rc<QueryRegionConstraints<'tcx>>>)> {
8faf50e0
XL
63 let mut fulfill_cx = TraitEngine::new(infcx.tcx);
64 let dummy_body_id = ObligationCause::dummy().body_id;
65
66 // During NLL, we expect that nobody will register region
67 // obligations **except** as part of a custom type op (and, at the
68 // end of each custom type op, we scrape out the region
69 // obligations that resulted). So this vector should be empty on
70 // entry.
71 let pre_obligations = infcx.take_registered_region_obligations();
72 assert!(
73 pre_obligations.is_empty(),
74 "scrape_region_constraints: incoming region obligations = {:#?}",
75 pre_obligations,
76 );
77
78 let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
79 debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id));
80 fulfill_cx.register_predicate_obligations(infcx, obligations);
81 if let Err(e) = fulfill_cx.select_all_or_error(infcx) {
82 infcx.tcx.sess.diagnostic().delay_span_bug(
83 DUMMY_SP,
84 &format!("errors selecting obligation during MIR typeck: {:?}", e),
85 );
86 }
87
88 let region_obligations = infcx.take_registered_region_obligations();
89
90 let region_constraint_data = infcx.take_and_reset_region_constraints();
91
dc9dc135 92 let region_constraints = query_response::make_query_region_constraints(
b7449926
XL
93 infcx.tcx,
94 region_obligations
95 .iter()
96 .map(|(_, r_o)| (r_o.sup_type, r_o.sub_region))
dc9dc135 97 .map(|(ty, r)| (infcx.resolve_vars_if_possible(&ty), r)),
b7449926
XL
98 &region_constraint_data,
99 );
8faf50e0 100
dc9dc135 101 if region_constraints.is_empty() {
8faf50e0
XL
102 Ok((value, None))
103 } else {
dc9dc135 104 Ok((value, Some(Rc::new(region_constraints))))
8faf50e0
XL
105 }
106}