Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/lower/as_place.rs')
-rw-r--r--crates/hir-ty/src/mir/lower/as_place.rs63
1 files changed, 62 insertions, 1 deletions
diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs
index c6f4f66ada..425904850b 100644
--- a/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/crates/hir-ty/src/mir/lower/as_place.rs
@@ -1,6 +1,7 @@
//! MIR lowering for places
use super::*;
+use hir_def::FunctionId;
use hir_expand::name;
macro_rules! not_supported {
@@ -193,7 +194,24 @@ impl MirLowerCtx<'_> {
if index_ty != TyBuilder::usize()
|| !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..))
{
- not_supported!("overloaded index");
+ let Some(index_fn) = self.infer.method_resolution(expr_id) else {
+ return Err(MirLowerError::UnresolvedMethod);
+ };
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None);
+ };
+ let Some((index_operand, current)) = self.lower_expr_to_some_operand(*index, current)? else {
+ return Ok(None);
+ };
+ return self.lower_overloaded_index(
+ current,
+ base_place,
+ self.expr_ty_after_adjustments(*base),
+ self.expr_ty(expr_id),
+ index_operand,
+ expr_id.into(),
+ index_fn,
+ );
}
let Some((mut p_base, current)) =
self.lower_expr_as_place(current, *base, true)? else {
@@ -210,6 +228,49 @@ impl MirLowerCtx<'_> {
}
}
+ fn lower_overloaded_index(
+ &mut self,
+ current: BasicBlockId,
+ place: Place,
+ base_ty: Ty,
+ result_ty: Ty,
+ index_operand: Operand,
+ span: MirSpan,
+ index_fn: (FunctionId, Substitution),
+ ) -> Result<Option<(Place, BasicBlockId)>> {
+ let is_mutable = 'b: {
+ if let Some(index_mut_trait) = self.resolve_lang_item(LangItem::IndexMut)?.as_trait() {
+ if let Some(index_mut_fn) =
+ self.db.trait_data(index_mut_trait).method_by_name(&name![index_mut])
+ {
+ break 'b index_mut_fn == index_fn.0;
+ }
+ }
+ false
+ };
+ let (mutability, borrow_kind) = match is_mutable {
+ true => (Mutability::Mut, BorrowKind::Mut { allow_two_phase_borrow: false }),
+ false => (Mutability::Not, BorrowKind::Shared),
+ };
+ let base_ref = TyKind::Ref(mutability, static_lifetime(), base_ty).intern(Interner);
+ let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner);
+ let ref_place: Place = self.temp(base_ref)?.into();
+ self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span);
+ let mut result: Place = self.temp(result_ref)?.into();
+ let index_fn_op = Operand::const_zst(
+ TyKind::FnDef(
+ self.db.intern_callable_def(CallableDefId::FunctionId(index_fn.0)).into(),
+ index_fn.1,
+ )
+ .intern(Interner),
+ );
+ let Some(current) = self.lower_call(index_fn_op, vec![Operand::Copy(ref_place), index_operand], result.clone(), current, false)? else {
+ return Ok(None);
+ };
+ result.projection.push(ProjectionElem::Deref);
+ Ok(Some((result, current)))
+ }
+
fn lower_overloaded_deref(
&mut self,
current: BasicBlockId,