]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_hir_analysis/src/check/autoderef.rs
Auto merge of #102783 - RalfJung:tls, r=thomcc
[rust.git] / compiler / rustc_hir_analysis / src / check / autoderef.rs
1 //! Some helper functions for `AutoDeref`
2 use super::method::MethodCallee;
3 use super::{FnCtxt, PlaceOp};
4
5 use rustc_infer::infer::InferOk;
6 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
7 use rustc_middle::ty::{self, Ty};
8 use rustc_span::Span;
9 use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
10
11 use std::iter;
12
13 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
14     pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> {
15         Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span)
16     }
17
18     /// Like `autoderef`, but provides a custom `Span` to use for calls to
19     /// an overloaded `Deref` operator
20     pub fn autoderef_overloaded_span(
21         &'a self,
22         span: Span,
23         base_ty: Ty<'tcx>,
24         overloaded_span: Span,
25     ) -> Autoderef<'a, 'tcx> {
26         Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
27     }
28
29     pub fn try_overloaded_deref(
30         &self,
31         span: Span,
32         base_ty: Ty<'tcx>,
33     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
34         self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref)
35     }
36
37     /// Returns the adjustment steps.
38     pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec<Adjustment<'tcx>> {
39         self.register_infer_ok_obligations(self.adjust_steps_as_infer_ok(autoderef))
40     }
41
42     pub fn adjust_steps_as_infer_ok(
43         &self,
44         autoderef: &Autoderef<'a, 'tcx>,
45     ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> {
46         let mut obligations = vec![];
47         let steps = autoderef.steps();
48         let targets =
49             steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(autoderef.final_ty(false)));
50         let steps: Vec<_> = steps
51             .iter()
52             .map(|&(source, kind)| {
53                 if let AutoderefKind::Overloaded = kind {
54                     self.try_overloaded_deref(autoderef.span(), source).and_then(
55                         |InferOk { value: method, obligations: o }| {
56                             obligations.extend(o);
57                             if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() {
58                                 Some(OverloadedDeref {
59                                     region,
60                                     mutbl,
61                                     span: autoderef.overloaded_span(),
62                                 })
63                             } else {
64                                 None
65                             }
66                         },
67                     )
68                 } else {
69                     None
70                 }
71             })
72             .zip(targets)
73             .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
74             .collect();
75
76         InferOk { obligations, value: steps }
77     }
78 }