From cf94bdc0742c13e2a0cac864c478b8626b266e1b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:11:38 +0200 Subject: Merging upstream version 1.66.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_hir_typeck/src/autoderef.rs | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 compiler/rustc_hir_typeck/src/autoderef.rs (limited to 'compiler/rustc_hir_typeck/src/autoderef.rs') diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs new file mode 100644 index 000000000..59c366ad7 --- /dev/null +++ b/compiler/rustc_hir_typeck/src/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>> { + self.try_overloaded_place_op(span, base_ty, &[], PlaceOp::Deref) + } + + /// Returns the adjustment steps. + pub fn adjust_steps(&self, autoderef: &Autoderef<'a, 'tcx>) -> Vec> { + 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>> { + 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 } + } +} -- cgit v1.2.3