Skip to main content

rustc_hir_typeck/
autoderef.rs

1//! Some helper functions for `AutoDeref`.
2
3use 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, DerefAdjustKind, 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    /// Returns the adjustment steps.
30    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: ::alloc::vec::Vec::new()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()));
46        let steps: Vec<_> = steps
47            .iter()
48            .map(|&(source, kind)| match kind {
49                AutoderefKind::Overloaded => {
50                    self.try_overloaded_deref(autoderef.span(), source)
51                        .and_then(|InferOk { value: method, obligations: o }| {
52                            obligations.extend(o);
53                            // FIXME: we should assert the sig is &T here... there's no reason for this to be fallible.
54                            if let ty::Ref(_, _, mutbl) = *method.sig.output().kind() {
55                                Some(DerefAdjustKind::Overloaded(OverloadedDeref {
56                                    mutbl,
57                                    span: autoderef.span(),
58                                }))
59                            } else {
60                                None
61                            }
62                        })
63                        .unwrap_or(DerefAdjustKind::Builtin)
64                }
65                AutoderefKind::Builtin => DerefAdjustKind::Builtin,
66            })
67            .zip_eq(targets)
68            .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
69            .collect();
70
71        InferOk { obligations, value: steps }
72    }
73}