Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/mir/lower.rs')
-rw-r--r--crates/hir-ty/src/mir/lower.rs203
1 files changed, 123 insertions, 80 deletions
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index b77e2c1c80..6fe157f45c 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -8,14 +8,14 @@ use hir_def::{
body::Body,
data::adt::{StructKind, VariantData},
hir::{
- ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm,
- Pat, PatId, RecordFieldPat, RecordLitField,
+ ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
+ LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField,
},
lang_item::{LangItem, LangItemTarget},
path::Path,
- resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
+ resolver::{resolver_for_expr, HasResolver, ResolveValueResult, ValueNs},
AdtId, DefWithBodyId, EnumVariantId, GeneralConstId, HasModule, ItemContainerId, LocalFieldId,
- TraitId,
+ TraitId, TypeOrConstParamId,
};
use hir_expand::name::Name;
use la_arena::ArenaMap;
@@ -29,9 +29,10 @@ use crate::{
display::HirDisplay,
infer::{CaptureKind, CapturedItem, TypeMismatch},
inhabitedness::is_ty_uninhabited_from,
- layout::{layout_of_ty, LayoutError},
+ layout::LayoutError,
mapping::ToChalk,
static_lifetime,
+ traits::FnTrait,
utils::{generics, ClosureSubst},
Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
};
@@ -41,8 +42,6 @@ use super::*;
mod as_place;
mod pattern_matching;
-use pattern_matching::AdtPatternShape;
-
#[derive(Debug, Clone)]
struct LoopBlocks {
begin: BasicBlockId,
@@ -74,6 +73,7 @@ pub enum MirLowerError {
ConstEvalError(String, Box<ConstEvalError>),
LayoutError(LayoutError),
IncompleteExpr,
+ IncompletePattern,
/// Trying to lower a trait function, instead of an implementation
TraitFunctionDefinition(TraitId, Name),
UnresolvedName(String),
@@ -96,6 +96,9 @@ pub enum MirLowerError {
UnresolvedLabel,
UnresolvedUpvar(Place),
UnaccessableLocal,
+
+ // monomorphization errors:
+ GenericArgNotProvided(TypeOrConstParamId, Substitution),
}
impl MirLowerError {
@@ -129,9 +132,24 @@ impl MirLowerError {
e.actual.display(db),
)?;
}
+ MirLowerError::GenericArgNotProvided(id, subst) => {
+ let parent = id.parent;
+ let param = &db.generic_params(parent).type_or_consts[id.local_id];
+ writeln!(
+ f,
+ "Generic arg not provided for {}",
+ param.name().unwrap_or(&Name::missing()).display(db.upcast())
+ )?;
+ writeln!(f, "Provided args: [")?;
+ for g in subst.iter(Interner) {
+ write!(f, " {},", g.display(db).to_string())?;
+ }
+ writeln!(f, "]")?;
+ }
MirLowerError::LayoutError(_)
| MirLowerError::UnsizedTemporary(_)
| MirLowerError::IncompleteExpr
+ | MirLowerError::IncompletePattern
| MirLowerError::UnaccessableLocal
| MirLowerError::TraitFunctionDefinition(_, _)
| MirLowerError::UnresolvedName(_)
@@ -528,61 +546,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
Ok(())
})
}
- &Expr::For { iterable, pat, body, label } => {
- let into_iter_fn = self.resolve_lang_item(LangItem::IntoIterIntoIter)?
- .as_function().ok_or(MirLowerError::LangItemNotFound(LangItem::IntoIterIntoIter))?;
- let iter_next_fn = self.resolve_lang_item(LangItem::IteratorNext)?
- .as_function().ok_or(MirLowerError::LangItemNotFound(LangItem::IteratorNext))?;
- let option_some = self.resolve_lang_item(LangItem::OptionSome)?
- .as_enum_variant().ok_or(MirLowerError::LangItemNotFound(LangItem::OptionSome))?;
- let option = option_some.parent;
- let into_iter_fn_op = Operand::const_zst(
- TyKind::FnDef(
- self.db.intern_callable_def(CallableDefId::FunctionId(into_iter_fn)).into(),
- Substitution::from1(Interner, self.expr_ty_without_adjust(iterable))
- ).intern(Interner));
- let iter_next_fn_op = Operand::const_zst(
- TyKind::FnDef(
- self.db.intern_callable_def(CallableDefId::FunctionId(iter_next_fn)).into(),
- Substitution::from1(Interner, self.expr_ty_without_adjust(iterable))
- ).intern(Interner));
- let &Some(iterator_ty) = &self.infer.type_of_for_iterator.get(&expr_id) else {
- return Err(MirLowerError::TypeError("unknown for loop iterator type"));
- };
- let ref_mut_iterator_ty = TyKind::Ref(Mutability::Mut, static_lifetime(), iterator_ty.clone()).intern(Interner);
- let item_ty = &self.infer.type_of_pat[pat];
- let option_item_ty = TyKind::Adt(chalk_ir::AdtId(option.into()), Substitution::from1(Interner, item_ty.clone())).intern(Interner);
- let iterator_place: Place = self.temp(iterator_ty.clone(), current, expr_id.into())?.into();
- let option_item_place: Place = self.temp(option_item_ty.clone(), current, expr_id.into())?.into();
- let ref_mut_iterator_place: Place = self.temp(ref_mut_iterator_ty, current, expr_id.into())?.into();
- let Some(current) = self.lower_call_and_args(into_iter_fn_op, Some(iterable).into_iter(), iterator_place.clone(), current, false, expr_id.into())?
- else {
- return Ok(None);
- };
- self.push_assignment(current, ref_mut_iterator_place.clone(), Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, iterator_place), expr_id.into());
- self.lower_loop(current, place, label, expr_id.into(), |this, begin| {
- let Some(current) = this.lower_call(iter_next_fn_op, Box::new([Operand::Copy(ref_mut_iterator_place)]), option_item_place.clone(), begin, false, expr_id.into())?
- else {
- return Ok(());
- };
- let end = this.current_loop_end()?;
- let (current, _) = this.pattern_matching_variant(
- option_item_ty.clone(),
- BindingAnnotation::Unannotated,
- option_item_place.into(),
- option_some.into(),
- current,
- pat.into(),
- Some(end),
- AdtPatternShape::Tuple { args: &[pat], ellipsis: None },
- )?;
- if let Some((_, block)) = this.lower_expr_as_place(current, body, true)? {
- let block = this.pop_drop_scope(block);
- this.set_goto(block, begin, expr_id.into());
- }
- Ok(())
- })
- },
Expr::Call { callee, args, .. } => {
if let Some((func_id, generic_args)) =
self.infer.method_resolution(expr_id) {
@@ -918,6 +881,27 @@ impl<'ctx> MirLowerCtx<'ctx> {
let Some((lhs_op, current)) = self.lower_expr_to_some_operand(*lhs, current)? else {
return Ok(None);
};
+ if let hir_def::hir::BinaryOp::LogicOp(op) = op {
+ let value_to_short = match op {
+ syntax::ast::LogicOp::And => 0,
+ syntax::ast::LogicOp::Or => 1,
+ };
+ let start_of_then = self.new_basic_block();
+ self.push_assignment(start_of_then, place.clone(), lhs_op.clone().into(), expr_id.into());
+ let end_of_then = Some(start_of_then);
+ let start_of_else = self.new_basic_block();
+ let end_of_else =
+ self.lower_expr_to_place(*rhs, place, start_of_else)?;
+ self.set_terminator(
+ current,
+ TerminatorKind::SwitchInt {
+ discr: lhs_op,
+ targets: SwitchTargets::static_if(value_to_short, start_of_then, start_of_else),
+ },
+ expr_id.into(),
+ );
+ return Ok(self.merge_blocks(end_of_then, end_of_else, expr_id.into()));
+ }
let Some((rhs_op, current)) = self.lower_expr_to_some_operand(*rhs, current)? else {
return Ok(None);
};
@@ -1135,8 +1119,39 @@ impl<'ctx> MirLowerCtx<'ctx> {
Ok(())
}
+ fn lower_literal_or_const_to_operand(
+ &mut self,
+ ty: Ty,
+ loc: &LiteralOrConst,
+ ) -> Result<Operand> {
+ match loc {
+ LiteralOrConst::Literal(l) => self.lower_literal_to_operand(ty, l),
+ LiteralOrConst::Const(c) => {
+ let unresolved_name = || MirLowerError::unresolved_path(self.db, c);
+ let resolver = self.owner.resolver(self.db.upcast());
+ let pr = resolver
+ .resolve_path_in_value_ns(self.db.upcast(), c)
+ .ok_or_else(unresolved_name)?;
+ match pr {
+ ResolveValueResult::ValueNs(v) => {
+ if let ValueNs::ConstId(c) = v {
+ self.lower_const_to_operand(Substitution::empty(Interner), c.into(), ty)
+ } else {
+ not_supported!("bad path in range pattern");
+ }
+ }
+ ResolveValueResult::Partial(_, _) => {
+ not_supported!("associated constants in range pattern")
+ }
+ }
+ }
+ }
+ }
+
fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<Operand> {
- let size = layout_of_ty(self.db, &ty, self.owner.module(self.db.upcast()).krate())?
+ let size = self
+ .db
+ .layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())?
.size
.bytes_usize();
let bytes = match l {
@@ -1196,6 +1211,17 @@ impl<'ctx> MirLowerCtx<'ctx> {
span: MirSpan,
ty: Ty,
) -> Result<()> {
+ let c = self.lower_const_to_operand(subst, const_id, ty)?;
+ self.push_assignment(prev_block, place, c.into(), span);
+ Ok(())
+ }
+
+ fn lower_const_to_operand(
+ &mut self,
+ subst: Substitution,
+ const_id: GeneralConstId,
+ ty: Ty,
+ ) -> Result<Operand> {
let c = if subst.len(Interner) != 0 {
// We can't evaluate constant with substitution now, as generics are not monomorphized in lowering.
intern_const_scalar(ConstScalar::UnevaluatedConst(const_id, subst), ty)
@@ -1205,18 +1231,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
.const_eval(const_id.into(), subst)
.map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
};
- self.write_const_to_place(c, prev_block, place, span)
- }
-
- fn write_const_to_place(
- &mut self,
- c: Const,
- prev_block: BasicBlockId,
- place: Place,
- span: MirSpan,
- ) -> Result<()> {
- self.push_assignment(prev_block, place, Operand::Constant(c).into(), span);
- Ok(())
+ Ok(Operand::Constant(c))
}
fn write_bytes_to_place(
@@ -1673,8 +1688,23 @@ fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
},
(TyKind::Scalar(_), TyKind::Raw(..)) => CastKind::PointerFromExposedAddress,
(TyKind::Raw(..), TyKind::Scalar(_)) => CastKind::PointerExposeAddress,
- (TyKind::Raw(..) | TyKind::Ref(..), TyKind::Raw(..) | TyKind::Ref(..)) => {
- CastKind::PtrToPtr
+ (TyKind::Raw(_, a) | TyKind::Ref(_, _, a), TyKind::Raw(_, b) | TyKind::Ref(_, _, b)) => {
+ CastKind::Pointer(if a == b {
+ PointerCast::MutToConstPointer
+ } else if matches!(a.kind(Interner), TyKind::Slice(_) | TyKind::Str)
+ && matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Str)
+ {
+ // slice to slice cast is no-op (metadata is not touched), so we use this
+ PointerCast::MutToConstPointer
+ } else if matches!(b.kind(Interner), TyKind::Slice(_) | TyKind::Dyn(_)) {
+ PointerCast::Unsize
+ } else if matches!(a.kind(Interner), TyKind::Slice(s) if s == b) {
+ PointerCast::ArrayToPointer
+ } else {
+ // cast between two sized pointer, like *const i32 to *const i8. There is no specific variant
+ // for it in `PointerCast` so we use `MutToConstPointer`
+ PointerCast::MutToConstPointer
+ })
}
// Enum to int casts
(TyKind::Scalar(_), TyKind::Adt(..)) | (TyKind::Adt(..), TyKind::Scalar(_)) => {
@@ -1697,11 +1727,19 @@ pub fn mir_body_for_closure_query(
let TyKind::Closure(_, substs) = &infer[expr].kind(Interner) else {
implementation_error!("closure expression is not closure");
};
- let (captures, _) = infer.closure_info(&closure);
+ let (captures, kind) = infer.closure_info(&closure);
let mut ctx = MirLowerCtx::new(db, owner, &body, &infer);
// 0 is return local
ctx.result.locals.alloc(Local { ty: infer[*root].clone() });
- let closure_local = ctx.result.locals.alloc(Local { ty: infer[expr].clone() });
+ let closure_local = ctx.result.locals.alloc(Local {
+ ty: match kind {
+ FnTrait::FnOnce => infer[expr].clone(),
+ FnTrait::FnMut => TyKind::Ref(Mutability::Mut, static_lifetime(), infer[expr].clone())
+ .intern(Interner),
+ FnTrait::Fn => TyKind::Ref(Mutability::Not, static_lifetime(), infer[expr].clone())
+ .intern(Interner),
+ },
+ });
ctx.result.param_locals.push(closure_local);
let Some(sig) = ClosureSubst(substs).sig_ty().callable_sig(db) else {
implementation_error!("closure has not callable sig");
@@ -1721,6 +1759,10 @@ pub fn mir_body_for_closure_query(
}
let mut err = None;
let closure_local = ctx.result.locals.iter().nth(1).unwrap().0;
+ let closure_projection = match kind {
+ FnTrait::FnOnce => vec![],
+ FnTrait::FnMut | FnTrait::Fn => vec![ProjectionElem::Deref],
+ };
ctx.result.walk_places(|p| {
if let Some(x) = upvar_map.get(&p.local) {
let r = x.iter().find(|x| {
@@ -1743,7 +1785,8 @@ pub fn mir_body_for_closure_query(
match r {
Some(x) => {
p.local = closure_local;
- let mut next_projs = vec![PlaceElem::TupleOrClosureField(x.1)];
+ let mut next_projs = closure_projection.clone();
+ next_projs.push(PlaceElem::TupleOrClosureField(x.1));
let prev_projs = mem::take(&mut p.projection);
if x.0.kind != CaptureKind::ByValue {
next_projs.push(ProjectionElem::Deref);