]> git.lizzy.rs Git - rust.git/blob - src/librustc/traits/query/type_op/custom.rs
Rollup merge of #51765 - jonas-schievink:patch-1, r=KodrAus
[rust.git] / src / librustc / traits / query / type_op / custom.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use infer::{InferCtxt, InferOk};
12 use std::fmt;
13 use traits::query::Fallible;
14
15 use infer::canonical::query_result;
16 use infer::canonical::QueryRegionConstraint;
17 use std::rc::Rc;
18 use syntax::codemap::DUMMY_SP;
19 use traits::{ObligationCause, TraitEngine, TraitEngineExt};
20
21 pub struct CustomTypeOp<F, G> {
22     closure: F,
23     description: G,
24 }
25
26 impl<F, G> CustomTypeOp<F, G> {
27     pub fn new<'gcx, 'tcx, R>(closure: F, description: G) -> Self
28     where
29         F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
30         G: Fn() -> String,
31     {
32         CustomTypeOp {
33             closure,
34             description,
35         }
36     }
37 }
38
39 impl<'gcx, 'tcx, F, R, G> super::TypeOp<'gcx, 'tcx> for CustomTypeOp<F, G>
40 where
41     F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'gcx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
42     G: Fn() -> String,
43 {
44     type Output = R;
45
46     /// Processes the operation and all resulting obligations,
47     /// returning the final result along with any region constraints
48     /// (they will be given over to the NLL region solver).
49     fn fully_perform(
50         self,
51         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
52     ) -> Fallible<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
53         if cfg!(debug_assertions) {
54             info!("fully_perform({:?})", self);
55         }
56
57         scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?))
58     }
59 }
60
61 impl<F, G> fmt::Debug for CustomTypeOp<F, G>
62 where
63     G: Fn() -> String,
64 {
65     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
66         write!(f, "{}", (self.description)())
67     }
68 }
69
70 /// Executes `op` and then scrapes out all the "old style" region
71 /// constraints that result, creating query-region-constraints.
72 fn scrape_region_constraints<'gcx, 'tcx, R>(
73     infcx: &InferCtxt<'_, 'gcx, 'tcx>,
74     op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
75 ) -> Fallible<(R, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
76     let mut fulfill_cx = TraitEngine::new(infcx.tcx);
77     let dummy_body_id = ObligationCause::dummy().body_id;
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
92     let outlives =
93         query_result::make_query_outlives(infcx.tcx, region_obligations, &region_constraint_data);
94
95     if outlives.is_empty() {
96         Ok((value, None))
97     } else {
98         Ok((value, Some(Rc::new(outlives))))
99     }
100 }