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.rs | 163 |
1 files changed, 132 insertions, 31 deletions
diff --git a/crates/hir-ty/src/mir/lower/as_place.rs b/crates/hir-ty/src/mir/lower/as_place.rs index fe8147dcd3..d2c8d9a089 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::{lang_item::lang_attr, FunctionId}; use hir_expand::name; macro_rules! not_supported { @@ -15,8 +16,8 @@ impl MirLowerCtx<'_> { expr_id: ExprId, prev_block: BasicBlockId, ) -> Result<Option<(Place, BasicBlockId)>> { - let ty = self.expr_ty(expr_id); - let place = self.temp(ty)?; + let ty = self.expr_ty_without_adjust(expr_id); + let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = self.lower_expr_to_place_without_adjust(expr_id, place.into(), prev_block)? else { return Ok(None); }; @@ -29,9 +30,11 @@ impl MirLowerCtx<'_> { prev_block: BasicBlockId, adjustments: &[Adjustment], ) -> Result<Option<(Place, BasicBlockId)>> { - let ty = - adjustments.last().map(|x| x.target.clone()).unwrap_or_else(|| self.expr_ty(expr_id)); - let place = self.temp(ty)?; + let ty = adjustments + .last() + .map(|x| x.target.clone()) + .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)); + let place = self.temp(ty, prev_block, expr_id.into())?; let Some(current) = self.lower_expr_to_place_with_adjust(expr_id, place.into(), prev_block, adjustments)? else { return Ok(None); }; @@ -62,7 +65,7 @@ impl MirLowerCtx<'_> { )? else { return Ok(None); }; - x.0.projection.push(ProjectionElem::Deref); + x.0 = x.0.project(ProjectionElem::Deref); Ok(Some(x)) } Adjust::Deref(Some(od)) => { @@ -79,7 +82,7 @@ impl MirLowerCtx<'_> { r, rest.last() .map(|x| x.target.clone()) - .unwrap_or_else(|| self.expr_ty(expr_id)), + .unwrap_or_else(|| self.expr_ty_without_adjust(expr_id)), last.target.clone(), expr_id.into(), match od.0 { @@ -125,35 +128,74 @@ impl MirLowerCtx<'_> { match &self.body.exprs[expr_id] { Expr::Path(p) => { let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id); - let Some(pr) = resolver.resolve_path_in_value_ns(self.db.upcast(), p.mod_path()) else { - return Err(MirLowerError::unresolved_path(self.db, p)); - }; - let pr = match pr { - ResolveValueResult::ValueNs(v) => v, - ResolveValueResult::Partial(..) => return try_rvalue(self), + let Some(pr) = resolver.resolve_path_in_value_ns_fully(self.db.upcast(), p) else { + return try_rvalue(self); }; match pr { ValueNs::LocalBinding(pat_id) => { - Ok(Some((self.result.binding_locals[pat_id].into(), current))) + Ok(Some((self.binding_local(pat_id)?.into(), current))) + } + ValueNs::StaticId(s) => { + let ty = self.expr_ty_without_adjust(expr_id); + let ref_ty = + TyKind::Ref(Mutability::Not, static_lifetime(), ty).intern(Interner); + let temp: Place = self.temp(ref_ty, current, expr_id.into())?.into(); + self.push_assignment( + current, + temp.clone(), + Operand::Static(s).into(), + expr_id.into(), + ); + Ok(Some((temp.project(ProjectionElem::Deref), current))) } _ => try_rvalue(self), } } Expr::UnaryOp { expr, op } => match op { - hir_def::expr::UnaryOp::Deref => { - if !matches!( - self.expr_ty(*expr).kind(Interner), - TyKind::Ref(..) | TyKind::Raw(..) - ) { - let Some(_) = self.lower_expr_as_place(current, *expr, true)? else { + hir_def::hir::UnaryOp::Deref => { + let is_builtin = match self.expr_ty_without_adjust(*expr).kind(Interner) { + TyKind::Ref(..) | TyKind::Raw(..) => true, + TyKind::Adt(id, _) => { + if let Some(lang_item) = lang_attr(self.db.upcast(), id.0) { + lang_item == LangItem::OwnedBox + } else { + false + } + } + _ => false, + }; + if !is_builtin { + let Some((p, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - not_supported!("explicit overloaded deref"); + return self.lower_overloaded_deref( + current, + p, + self.expr_ty_after_adjustments(*expr), + self.expr_ty_without_adjust(expr_id), + expr_id.into(), + 'b: { + if let Some((f, _)) = self.infer.method_resolution(expr_id) { + if let Some(deref_trait) = + self.resolve_lang_item(LangItem::DerefMut)?.as_trait() + { + if let Some(deref_fn) = self + .db + .trait_data(deref_trait) + .method_by_name(&name![deref_mut]) + { + break 'b deref_fn == f; + } + } + } + false + }, + ); } let Some((mut r, current)) = self.lower_expr_as_place(current, *expr, true)? else { return Ok(None); }; - r.projection.push(ProjectionElem::Deref); + r = r.project(ProjectionElem::Deref); Ok(Some((r, current))) } _ => try_rvalue(self), @@ -169,25 +211,84 @@ impl MirLowerCtx<'_> { let base_ty = self.expr_ty_after_adjustments(*base); let index_ty = self.expr_ty_after_adjustments(*index); if index_ty != TyBuilder::usize() - || !matches!(base_ty.kind(Interner), TyKind::Array(..) | TyKind::Slice(..)) + || !matches!( + base_ty.strip_reference().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("[overloaded index]".to_string())); + }; + 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, + base_ty, + self.expr_ty_without_adjust(expr_id), + index_operand, + expr_id.into(), + index_fn, + ); } + let adjusts = self + .infer + .expr_adjustments + .get(base) + .and_then(|x| x.split_last()) + .map(|x| x.1) + .unwrap_or(&[]); let Some((mut p_base, current)) = - self.lower_expr_as_place(current, *base, true)? else { + self.lower_expr_as_place_with_adjust(current, *base, true, adjusts)? + else { return Ok(None); }; - let l_index = self.temp(self.expr_ty_after_adjustments(*index))?; + let l_index = + self.temp(self.expr_ty_after_adjustments(*index), current, expr_id.into())?; let Some(current) = self.lower_expr_to_place(*index, l_index.into(), current)? else { return Ok(None); }; - p_base.projection.push(ProjectionElem::Index(l_index)); + p_base = p_base.project(ProjectionElem::Index(l_index)); Ok(Some((p_base, current))) } _ => try_rvalue(self), } } + 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 mutability = match base_ty.as_reference() { + Some((_, _, mutability)) => mutability, + None => Mutability::Not, + }; + let result_ref = TyKind::Ref(mutability, static_lifetime(), result_ty).intern(Interner); + let mut result: Place = self.temp(result_ref, current, span)?.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, Box::new([Operand::Copy(place), index_operand]), result.clone(), current, false, span)? else { + return Ok(None); + }; + result = result.project(ProjectionElem::Deref); + Ok(Some((result, current))) + } + fn lower_overloaded_deref( &mut self, current: BasicBlockId, @@ -209,7 +310,7 @@ impl MirLowerCtx<'_> { }; let ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), source_ty.clone()).intern(Interner); let target_ty_ref = TyKind::Ref(chalk_mut, static_lifetime(), target_ty).intern(Interner); - let ref_place: Place = self.temp(ty_ref)?.into(); + let ref_place: Place = self.temp(ty_ref, current, span)?.into(); self.push_assignment(current, ref_place.clone(), Rvalue::Ref(borrow_kind, place), span); let deref_trait = self .resolve_lang_item(trait_lang_item)? @@ -227,11 +328,11 @@ impl MirLowerCtx<'_> { ) .intern(Interner), ); - let mut result: Place = self.temp(target_ty_ref)?.into(); - let Some(current) = self.lower_call(deref_fn_op, vec![Operand::Copy(ref_place)], result.clone(), current, false)? else { + let mut result: Place = self.temp(target_ty_ref, current, span)?.into(); + let Some(current) = self.lower_call(deref_fn_op, Box::new([Operand::Copy(ref_place)]), result.clone(), current, false, span)? else { return Ok(None); }; - result.projection.push(ProjectionElem::Deref); + result = result.project(ProjectionElem::Deref); Ok(Some((result, current))) } } |