1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use infer::{InferCtxt, InferOk};
use std::fmt;
use traits::query::Fallible;
use infer::canonical::query_result;
use infer::canonical::QueryRegionConstraint;
use std::rc::Rc;
use syntax::codemap::DUMMY_SP;
use traits::{ObligationCause, TraitEngine, TraitEngineExt};
pub struct CustomTypeOp<F, G> {
closure: F,
description: G,
}
impl<F, G> CustomTypeOp<F, G> {
pub fn new<'gcx, 'tcx, R>(closure: F, description: G) -> Self
where
F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
CustomTypeOp {
closure,
description,
}
}
}
impl<'gcx, 'tcx, F, R, G> super::TypeOp<'gcx, 'tcx> for CustomTypeOp<F, G>
where
F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'gcx, 'tcx>) -> Fallible<InferOk<'tcx, R>>,
G: Fn() -> String,
{
type Output = R;
fn fully_perform(
self,
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
) -> Fallible<(Self::Output, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
scrape_region_constraints(infcx, || Ok((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)())
}
}
fn scrape_region_constraints<'gcx, 'tcx, R>(
infcx: &InferCtxt<'_, 'gcx, 'tcx>,
op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
) -> Fallible<(R, Option<Rc<Vec<QueryRegionConstraint<'tcx>>>>)> {
let mut fulfill_cx = TraitEngine::new(infcx.tcx);
let dummy_body_id = ObligationCause::dummy().body_id;
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 outlives =
query_result::make_query_outlives(infcx.tcx, region_obligations, ®ion_constraint_data);
if outlives.is_empty() {
Ok((value, None))
} else {
Ok((value, Some(Rc::new(outlives))))
}
}