Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/autoderef.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/autoderef.rs | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/crates/hir-ty/src/infer/autoderef.rs b/crates/hir-ty/src/infer/autoderef.rs new file mode 100644 index 0000000000..77b1ae6a94 --- /dev/null +++ b/crates/hir-ty/src/infer/autoderef.rs @@ -0,0 +1,54 @@ +//! Autoderef helpers for inference. + +use std::iter; + +use crate::{ + Adjust, Adjustment, OverloadedDeref, + autoderef::{Autoderef, AutoderefKind}, + infer::unify::InferenceTable, + next_solver::{ + Ty, + infer::{InferOk, traits::PredicateObligations}, + mapping::NextSolverToChalk, + }, +}; + +impl<'db> InferenceTable<'db> { + pub(crate) fn autoderef(&mut self, base_ty: Ty<'db>) -> Autoderef<'_, 'db> { + Autoderef::new(self, base_ty) + } +} + +impl<'db> Autoderef<'_, 'db> { + /// Returns the adjustment steps. + pub(crate) fn adjust_steps(mut self) -> Vec<Adjustment> { + let infer_ok = self.adjust_steps_as_infer_ok(); + self.table.register_infer_ok(infer_ok) + } + + pub(crate) fn adjust_steps_as_infer_ok(&mut self) -> InferOk<'db, Vec<Adjustment>> { + let steps = self.steps(); + if steps.is_empty() { + return InferOk { obligations: PredicateObligations::new(), value: vec![] }; + } + + let targets = steps.iter().skip(1).map(|&(ty, _)| ty).chain(iter::once(self.final_ty())); + let steps: Vec<_> = steps + .iter() + .map(|&(_source, kind)| { + if let AutoderefKind::Overloaded = kind { + Some(OverloadedDeref(Some(chalk_ir::Mutability::Not))) + } else { + None + } + }) + .zip(targets) + .map(|(autoderef, target)| Adjustment { + kind: Adjust::Deref(autoderef), + target: target.to_chalk(self.table.interner), + }) + .collect(); + + InferOk { obligations: self.take_obligations(), value: steps } + } +} |