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.rs163
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)))
}
}