]>
Commit | Line | Data |
---|---|---|
f035d41b | 1 | //! Some helper functions for `AutoDeref` |
7cac9316 | 2 | use super::method::MethodCallee; |
f035d41b | 3 | use super::{FnCtxt, PlaceOp}; |
3157f602 | 4 | |
f035d41b | 5 | use rustc_infer::infer::InferOk; |
ba9703b0 | 6 | use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref}; |
f035d41b | 7 | use rustc_middle::ty::{self, Ty}; |
dfeec247 | 8 | use rustc_span::Span; |
f035d41b | 9 | use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind}; |
3157f602 | 10 | |
7cac9316 XL |
11 | use std::iter; |
12 | ||
f035d41b XL |
13 | impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
14 | pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { | |
1b1a35ee XL |
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) | |
3157f602 | 27 | } |
3157f602 | 28 | |
f035d41b XL |
29 | pub fn try_overloaded_deref( |
30 | &self, | |
dc9dc135 XL |
31 | span: Span, |
32 | base_ty: Ty<'tcx>, | |
f035d41b XL |
33 | ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { |
34 | self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) | |
7cac9316 XL |
35 | } |
36 | ||
37 | /// Returns the adjustment steps. | |
f035d41b XL |
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)) | |
8bb4bdeb XL |
40 | } |
41 | ||
dc9dc135 XL |
42 | pub fn adjust_steps_as_infer_ok( |
43 | &self, | |
f035d41b | 44 | autoderef: &Autoderef<'a, 'tcx>, |
dc9dc135 | 45 | ) -> InferOk<'tcx, Vec<Adjustment<'tcx>>> { |
7cac9316 | 46 | let mut obligations = vec![]; |
f035d41b XL |
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 | |
dfeec247 XL |
51 | .iter() |
52 | .map(|&(source, kind)| { | |
53 | if let AutoderefKind::Overloaded = kind { | |
f035d41b | 54 | self.try_overloaded_deref(autoderef.span(), source).and_then( |
dfeec247 XL |
55 | |InferOk { value: method, obligations: o }| { |
56 | obligations.extend(o); | |
1b1a35ee XL |
57 | if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { |
58 | Some(OverloadedDeref { | |
59 | region, | |
60 | mutbl, | |
61 | span: autoderef.overloaded_span(), | |
62 | }) | |
dfeec247 XL |
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 } | |
3157f602 | 77 | } |
3157f602 | 78 | } |