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