rustc_hir_typeck/
autoderef.rs
1use std::iter;
4
5use itertools::Itertools;
6use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
7use rustc_infer::infer::InferOk;
8use rustc_infer::traits::PredicateObligations;
9use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
10use rustc_middle::ty::{self, Ty};
11use rustc_span::Span;
12
13use super::method::MethodCallee;
14use super::{FnCtxt, PlaceOp};
15
16impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
17 pub(crate) fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
18 Autoderef::new(self, self.param_env, self.body_id, span, base_ty)
19 }
20
21 pub(crate) fn try_overloaded_deref(
22 &self,
23 span: Span,
24 base_ty: Ty<'tcx>,
25 ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
26 self.try_overloaded_place_op(span, base_ty, None, PlaceOp::Deref)
27 }
28
29 pub(crate) fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
31 self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
32 }
33
34 pub(crate) fn adjust_steps_as_infer_ok(
35 &self,
36 autoderef: &Autoderef<'a, 'tcx>,
37 ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
38 let steps = autoderef.steps();
39 if steps.is_empty() {
40 return InferOk { obligations: PredicateObligations::new(), value: vec![] };
41 }
42
43 let mut obligations = PredicateObligations::new();
44 let targets =
45 steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
46 let steps: Vec<_> = steps
47 .iter()
48 .map(|&(source, kind)| {
49 if let AutoderefKind::Overloaded = kind {
50 self.try_overloaded_deref(autoderef.span(), source).and_then(
51 |InferOk { value: method, obligations: o }| {
52 obligations.extend(o);
53 if let ty::Ref(_, _, mutbl) = *method.sig.output().kind() {
55 Some(OverloadedDeref { mutbl, span: autoderef.span() })
56 } else {
57 None
58 }
59 },
60 )
61 } else {
62 None
63 }
64 })
65 .zip_eq(targets)
66 .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
67 .collect();
68
69 InferOk { obligations, value: steps }
70 }
71}