about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src/check/autoderef.rs
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-09-27 10:45:57 +0000
committerbors <bors@rust-lang.org>2022-09-27 10:45:57 +0000
commit57ee5cf5a93923dae9c98bffb11545fc3a31368d (patch)
treeabd98065e805dca388767b651ae60673397fea9d /compiler/rustc_hir_analysis/src/check/autoderef.rs
parentd9297d22ad9edc2b56f0dd8734c1187a0c88be69 (diff)
parent1fc86a63f451b81606e4787692517dc613f333db (diff)
downloadrust-57ee5cf5a93923dae9c98bffb11545fc3a31368d.tar.gz
rust-57ee5cf5a93923dae9c98bffb11545fc3a31368d.zip
Auto merge of #102306 - lcnr:rustc_hir_analysis, r=compiler-errors
rename rustc_typeck to rustc_hir_analysis

first part of https://github.com/rust-lang/compiler-team/issues/529

r? `@compiler-errors`
Diffstat (limited to 'compiler/rustc_hir_analysis/src/check/autoderef.rs')
-rw-r--r--compiler/rustc_hir_analysis/src/check/autoderef.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/compiler/rustc_hir_analysis/src/check/autoderef.rs b/compiler/rustc_hir_analysis/src/check/autoderef.rs
new file mode 100644
index 00000000000..59c366ad7d7
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/check/autoderef.rs
@@ -0,0 +1,78 @@
+//! Some helper functions for `AutoDeref`
+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, span)
+    }
+
+    /// Like `autoderef`, but provides a custom `Span` to use for calls to
+    /// an overloaded `Deref` operator
+    pub fn autoderef_overloaded_span(
+        &'a self,
+        span: Span,
+        base_ty: Ty<'tcx>,
+        overloaded_span: Span,
+    ) -> Autoderef<'a, 'tcx> {
+        Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span)
+    }
+
+    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)
+    }
+
+    /// Returns the adjustment steps.
+    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.overloaded_span(),
+                                })
+                            } else {
+                                None
+                            }
+                        },
+                    )
+                } else {
+                    None
+                }
+            })
+            .zip(targets)
+            .map(|(autoderef, target)| Adjustment { kind: Adjust::Deref(autoderef), target })
+            .collect();
+
+        InferOk { obligations, value: steps }
+    }
+}