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.rs96
1 files changed, 72 insertions, 24 deletions
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 936b56a021..8f28d62db0 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -6,7 +6,8 @@ use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
body::Body,
expr::{
- Array, BindingAnnotation, ExprId, LabelId, Literal, MatchArm, Pat, PatId, RecordLitField,
+ Array, BindingAnnotation, BindingId, ExprId, LabelId, Literal, MatchArm, Pat, PatId,
+ RecordLitField,
},
layout::LayoutError,
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
@@ -30,7 +31,7 @@ struct LoopBlocks {
struct MirLowerCtx<'a> {
result: MirBody,
owner: DefWithBodyId,
- binding_locals: ArenaMap<PatId, LocalId>,
+ binding_locals: ArenaMap<BindingId, LocalId>,
current_loop_blocks: Option<LoopBlocks>,
discr_temp: Option<Place>,
db: &'a dyn HirDatabase,
@@ -43,7 +44,9 @@ pub enum MirLowerError {
ConstEvalError(Box<ConstEvalError>),
LayoutError(LayoutError),
IncompleteExpr,
- UnresolvedName,
+ UnresolvedName(String),
+ UnresolvedMethod,
+ UnresolvedField,
MissingFunctionDefinition,
TypeError(&'static str),
NotSupported(String),
@@ -222,22 +225,23 @@ impl MirLowerCtx<'_> {
match &self.body.exprs[expr_id] {
Expr::Missing => Err(MirLowerError::IncompleteExpr),
Expr::Path(p) => {
+ let unresolved_name = || MirLowerError::UnresolvedName("".to_string());
let resolver = resolver_for_expr(self.db.upcast(), self.owner, expr_id);
let pr = resolver
.resolve_path_in_value_ns(self.db.upcast(), p.mod_path())
- .ok_or(MirLowerError::UnresolvedName)?;
+ .ok_or_else(unresolved_name)?;
let pr = match pr {
ResolveValueResult::ValueNs(v) => v,
ResolveValueResult::Partial(..) => {
return match self
.infer
.assoc_resolutions_for_expr(expr_id)
- .ok_or(MirLowerError::UnresolvedName)?
+ .ok_or_else(unresolved_name)?
.0
//.ok_or(ConstEvalError::SemanticError("unresolved assoc item"))?
{
hir_def::AssocItemId::ConstId(c) => self.lower_const(c, current, place),
- _ => return Err(MirLowerError::UnresolvedName),
+ _ => return Err(unresolved_name()),
};
}
};
@@ -394,7 +398,7 @@ impl MirLowerCtx<'_> {
}
Expr::MethodCall { receiver, args, .. } => {
let (func_id, generic_args) =
- self.infer.method_resolution(expr_id).ok_or(MirLowerError::UnresolvedName)?;
+ self.infer.method_resolution(expr_id).ok_or(MirLowerError::UnresolvedMethod)?;
let ty = chalk_ir::TyKind::FnDef(
CallableDefId::FunctionId(func_id).to_chalk(self.db),
generic_args,
@@ -476,7 +480,7 @@ impl MirLowerCtx<'_> {
let variant_id = self
.infer
.variant_resolution_for_expr(expr_id)
- .ok_or(MirLowerError::UnresolvedName)?;
+ .ok_or_else(|| MirLowerError::UnresolvedName("".to_string()))?;
let subst = match self.expr_ty(expr_id).kind(Interner) {
TyKind::Adt(_, s) => s.clone(),
_ => not_supported!("Non ADT record literal"),
@@ -487,7 +491,7 @@ impl MirLowerCtx<'_> {
let mut operands = vec![None; variant_data.fields().len()];
for RecordLitField { name, expr } in fields.iter() {
let field_id =
- variant_data.field(name).ok_or(MirLowerError::UnresolvedName)?;
+ variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
let op;
(op, current) = self.lower_expr_to_some_operand(*expr, current)?;
operands[u32::from(field_id.into_raw()) as usize] = Some(op);
@@ -509,7 +513,7 @@ impl MirLowerCtx<'_> {
not_supported!("Union record literal with more than one field");
};
let local_id =
- variant_data.field(name).ok_or(MirLowerError::UnresolvedName)?;
+ variant_data.field(name).ok_or(MirLowerError::UnresolvedField)?;
let mut place = place;
place
.projection
@@ -529,7 +533,7 @@ impl MirLowerCtx<'_> {
let field = self
.infer
.field_resolution(expr_id)
- .ok_or(MirLowerError::UnresolvedName)?;
+ .ok_or(MirLowerError::UnresolvedField)?;
current_place.projection.push(ProjectionElem::Field(field));
}
self.push_assignment(current, place, Operand::Copy(current_place).into());
@@ -962,8 +966,9 @@ impl MirLowerCtx<'_> {
}
(then_target, Some(else_target))
}
- Pat::Bind { mode, name: _, subpat } => {
- let target_place = self.binding_locals[pattern];
+ Pat::Bind { id, subpat } => {
+ let target_place = self.binding_locals[*id];
+ let mode = self.body.bindings[*id].mode;
if let Some(subpat) = subpat {
(current, current_else) = self.pattern_match(
current,
@@ -975,7 +980,7 @@ impl MirLowerCtx<'_> {
)?
}
if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
- binding_mode = *mode;
+ binding_mode = mode;
}
self.push_assignment(
current,
@@ -1189,17 +1194,40 @@ pub fn lower_to_mir(
let mut locals = Arena::new();
// 0 is return local
locals.alloc(Local { mutability: Mutability::Mut, ty: infer[root_expr].clone() });
- let mut create_local_of_path = |p: PatId| {
- // FIXME: mutablity is broken
- locals.alloc(Local { mutability: Mutability::Not, ty: infer[p].clone() })
+ let mut binding_locals: ArenaMap<BindingId, LocalId> = ArenaMap::new();
+ let param_locals: ArenaMap<PatId, LocalId> = if let DefWithBodyId::FunctionId(fid) = owner {
+ let substs = TyBuilder::placeholder_subst(db, fid);
+ let callable_sig = db.callable_item_signature(fid.into()).substitute(Interner, &substs);
+ // 1 to param_len is for params
+ body.params
+ .iter()
+ .zip(callable_sig.params().iter())
+ .map(|(&x, ty)| {
+ let local_id = locals.alloc(Local { mutability: Mutability::Not, ty: ty.clone() });
+ if let Pat::Bind { id, subpat: None } = body[x] {
+ if matches!(
+ body.bindings[id].mode,
+ BindingAnnotation::Unannotated | BindingAnnotation::Mutable
+ ) {
+ binding_locals.insert(id, local_id);
+ }
+ }
+ (x, local_id)
+ })
+ .collect()
+ } else {
+ if !body.params.is_empty() {
+ return Err(MirLowerError::TypeError("Unexpected parameter for non function body"));
+ }
+ ArenaMap::new()
};
- // 1 to param_len is for params
- let mut binding_locals: ArenaMap<PatId, LocalId> =
- body.params.iter().map(|&x| (x, create_local_of_path(x))).collect();
// and then rest of bindings
- for (pat_id, _) in body.pats.iter() {
- if !binding_locals.contains_idx(pat_id) {
- binding_locals.insert(pat_id, create_local_of_path(pat_id));
+ for (id, _) in body.bindings.iter() {
+ if !binding_locals.contains_idx(id) {
+ binding_locals.insert(
+ id,
+ locals.alloc(Local { mutability: Mutability::Not, ty: infer[id].clone() }),
+ );
}
}
let mir = MirBody { basic_blocks, locals, start_block, owner, arg_count: body.params.len() };
@@ -1213,7 +1241,27 @@ pub fn lower_to_mir(
current_loop_blocks: None,
discr_temp: None,
};
- let b = ctx.lower_expr_to_place(root_expr, return_slot().into(), start_block)?;
+ let mut current = start_block;
+ for &param in &body.params {
+ if let Pat::Bind { id, .. } = body[param] {
+ if param_locals[param] == ctx.binding_locals[id] {
+ continue;
+ }
+ }
+ let r = ctx.pattern_match(
+ current,
+ None,
+ param_locals[param].into(),
+ ctx.result.locals[param_locals[param]].ty.clone(),
+ param,
+ BindingAnnotation::Unannotated,
+ )?;
+ if let Some(b) = r.1 {
+ ctx.set_terminator(b, Terminator::Unreachable);
+ }
+ current = r.0;
+ }
+ let b = ctx.lower_expr_to_place(root_expr, return_slot().into(), current)?;
ctx.result.basic_blocks[b].terminator = Some(Terminator::Return);
Ok(ctx.result)
}