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
use super::method::MethodCallee;
use super::{FnCtxt, PlaceOp};
use rustc_infer::infer::InferOk;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
use std::iter;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
}
pub fn try_overloaded_deref(
&self,
span: Span,
base_ty: Ty<'tcx>,
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
}
pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
}
pub fn adjust_steps_as_infer_ok(
&self,
autoderef: &Autoderef<'a, 'tcx>,
) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
let mut obligations = vec![];
let steps = autoderef.steps();
let targets =
steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
let steps: Vec<_> = steps
.iter()
.map(|&(source, kind)| {
if let AutoderefKind::Overloaded = kind {
self.try_overloaded_deref(autoderef.span(), source).and_then(
|InferOk { value: method, obligations: o }| {
obligations.extend(o);
if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
Some(OverloadedDeref { region, mutbl, span: autoderef.span() })
} else {
None
}
},
)
} else {
None
}
})
.zip(targets)
.map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
.collect();
InferOk { obligations, value: steps }
}
}