Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/infer/closure.rs105
-rw-r--r--crates/hir-ty/src/mir/lower.rs27
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs385
-rw-r--r--crates/hir-ty/src/utils.rs22
4 files changed, 238 insertions, 301 deletions
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 662f2e5fa1..754ac88bb5 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -9,10 +9,7 @@ use chalk_ir::{
};
use hir_def::{
data::adt::VariantData,
- hir::{
- Array, BinaryOp, BindingAnnotation, BindingId, CaptureBy, Expr, ExprId, Pat, PatId,
- Statement, UnaryOp,
- },
+ hir::{Array, BinaryOp, BindingId, CaptureBy, Expr, ExprId, Pat, PatId, Statement, UnaryOp},
lang_item::LangItem,
resolver::{resolver_for_expr, ResolveValueResult, ValueNs},
DefWithBodyId, FieldId, HasModule, VariantId,
@@ -28,9 +25,9 @@ use crate::{
mir::{BorrowKind, MirSpan, ProjectionElem},
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
- utils::{self, generics, pattern_matching_dereference_count, Generics},
- Adjust, Adjustment, Binders, ChalkTraitId, ClosureId, ConstValue, DynTy, FnPointer, FnSig,
- Interner, Substitution, Ty, TyExt,
+ utils::{self, generics, Generics},
+ Adjust, Adjustment, Binders, BindingMode, ChalkTraitId, ClosureId, ConstValue, DynTy,
+ FnPointer, FnSig, Interner, Substitution, Ty, TyExt,
};
use super::{Expectation, InferenceContext};
@@ -488,13 +485,7 @@ impl InferenceContext<'_> {
if let Some(initializer) = initializer {
self.walk_expr(*initializer);
if let Some(place) = self.place_of_expr(*initializer) {
- let ty = self.expr_ty(*initializer);
- self.consume_with_pat(
- place,
- ty,
- BindingAnnotation::Unannotated,
- *pat,
- );
+ self.consume_with_pat(place, *pat);
}
}
}
@@ -799,41 +790,37 @@ impl InferenceContext<'_> {
}
}
- fn consume_with_pat(
- &mut self,
- mut place: HirPlace,
- mut ty: Ty,
- mut bm: BindingAnnotation,
- pat: PatId,
- ) {
+ fn consume_with_pat(&mut self, mut place: HirPlace, pat: PatId) {
+ let cnt = self.result.pat_adjustments.get(&pat).map(|x| x.len()).unwrap_or_default();
+ place.projections = place
+ .projections
+ .iter()
+ .cloned()
+ .chain((0..cnt).map(|_| ProjectionElem::Deref))
+ .collect::<Vec<_>>()
+ .into();
match &self.body[pat] {
Pat::Missing | Pat::Wild => (),
Pat::Tuple { args, ellipsis } => {
- pattern_matching_dereference(&mut ty, &mut bm, &mut place);
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
- let subst = match ty.kind(Interner) {
- TyKind::Tuple(_, s) => s,
+ let field_count = match self.result[pat].kind(Interner) {
+ TyKind::Tuple(_, s) => s.len(Interner),
_ => return,
};
- let fields = subst.iter(Interner).map(|x| x.assert_ty_ref(Interner)).enumerate();
+ let fields = 0..field_count;
let it = al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
- for (arg, (i, ty)) in it {
+ for (arg, i) in it {
let mut p = place.clone();
p.projections.push(ProjectionElem::TupleOrClosureField(i));
- self.consume_with_pat(p, ty.clone(), bm, *arg);
+ self.consume_with_pat(p, *arg);
}
}
Pat::Or(pats) => {
for pat in pats.iter() {
- self.consume_with_pat(place.clone(), ty.clone(), bm, *pat);
+ self.consume_with_pat(place.clone(), *pat);
}
}
Pat::Record { args, .. } => {
- pattern_matching_dereference(&mut ty, &mut bm, &mut place);
- let subst = match ty.kind(Interner) {
- TyKind::Adt(_, s) => s,
- _ => return,
- };
let Some(variant) = self.result.variant_resolution_for_pat(pat) else {
return;
};
@@ -843,7 +830,6 @@ impl InferenceContext<'_> {
}
VariantId::StructId(s) => {
let vd = &*self.db.struct_data(s).variant_data;
- let field_types = self.db.field_types(variant);
for field_pat in args.iter() {
let arg = field_pat.pat;
let Some(local_id) = vd.field(&field_pat.name) else {
@@ -854,12 +840,7 @@ impl InferenceContext<'_> {
parent: variant.into(),
local_id,
}));
- self.consume_with_pat(
- p,
- field_types[local_id].clone().substitute(Interner, subst),
- bm,
- arg,
- );
+ self.consume_with_pat(p, arg);
}
}
}
@@ -870,26 +851,20 @@ impl InferenceContext<'_> {
| Pat::Path(_)
| Pat::Lit(_) => self.consume_place(place, pat.into()),
Pat::Bind { id, subpat: _ } => {
- let mode = self.body.bindings[*id].mode;
- if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
- bm = mode;
- }
- let capture_kind = match bm {
- BindingAnnotation::Unannotated | BindingAnnotation::Mutable => {
+ let mode = self.result.binding_modes[*id];
+ let capture_kind = match mode {
+ BindingMode::Move => {
self.consume_place(place, pat.into());
return;
}
- BindingAnnotation::Ref => BorrowKind::Shared,
- BindingAnnotation::RefMut => BorrowKind::Mut { allow_two_phase_borrow: false },
+ BindingMode::Ref(Mutability::Not) => BorrowKind::Shared,
+ BindingMode::Ref(Mutability::Mut) => {
+ BorrowKind::Mut { allow_two_phase_borrow: false }
+ }
};
self.add_capture(place, CaptureKind::ByRef(capture_kind), pat.into());
}
Pat::TupleStruct { path: _, args, ellipsis } => {
- pattern_matching_dereference(&mut ty, &mut bm, &mut place);
- let subst = match ty.kind(Interner) {
- TyKind::Adt(_, s) => s,
- _ => return,
- };
let Some(variant) = self.result.variant_resolution_for_pat(pat) else {
return;
};
@@ -903,29 +878,20 @@ impl InferenceContext<'_> {
let fields = vd.fields().iter();
let it =
al.iter().zip(fields.clone()).chain(ar.iter().rev().zip(fields.rev()));
- let field_types = self.db.field_types(variant);
for (arg, (i, _)) in it {
let mut p = place.clone();
p.projections.push(ProjectionElem::Field(FieldId {
parent: variant.into(),
local_id: i,
}));
- self.consume_with_pat(
- p,
- field_types[i].clone().substitute(Interner, subst),
- bm,
- *arg,
- );
+ self.consume_with_pat(p, *arg);
}
}
}
}
Pat::Ref { pat, mutability: _ } => {
- if let Some((inner, _, _)) = ty.as_reference() {
- ty = inner.clone();
- place.projections.push(ProjectionElem::Deref);
- self.consume_with_pat(place, ty, bm, *pat)
- }
+ place.projections.push(ProjectionElem::Deref);
+ self.consume_with_pat(place, *pat)
}
Pat::Box { .. } => (), // not supported
}
@@ -1054,12 +1020,3 @@ fn apply_adjusts_to_place(mut r: HirPlace, adjustments: &[Adjustment]) -> Option
}
Some(r)
}
-
-fn pattern_matching_dereference(
- cond_ty: &mut Ty,
- binding_mode: &mut BindingAnnotation,
- cond_place: &mut HirPlace,
-) {
- let cnt = pattern_matching_dereference_count(cond_ty, binding_mode);
- cond_place.projections.extend((0..cnt).map(|_| ProjectionElem::Deref));
-}
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index ebd4199835..ef94b3650b 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -478,9 +478,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
current,
None,
cond_place,
- self.expr_ty_after_adjustments(*expr),
*pat,
- BindingAnnotation::Unannotated,
)?;
self.write_bytes_to_place(
then_target,
@@ -598,16 +596,13 @@ impl<'ctx> MirLowerCtx<'ctx> {
else {
return Ok(None);
};
- let cond_ty = self.expr_ty_after_adjustments(*expr);
let mut end = None;
for MatchArm { pat, guard, expr } in arms.iter() {
let (then, mut otherwise) = self.pattern_match(
current,
None,
cond_place.clone(),
- cond_ty.clone(),
*pat,
- BindingAnnotation::Unannotated,
)?;
let then = if let &Some(guard) = guard {
let next = self.new_basic_block();
@@ -1477,9 +1472,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
span: MirSpan,
) -> Result<()> {
self.drop_scopes.last_mut().unwrap().locals.push(l);
- // FIXME: this storage dead is not neccessary, but since drop scope handling is broken, we need
- // it to avoid falso positives in mutability errors
- self.push_statement(current, StatementKind::StorageDead(l).with_span(span));
self.push_statement(current, StatementKind::StorageLive(l).with_span(span));
Ok(())
}
@@ -1508,14 +1500,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
return Ok(None);
};
current = c;
- (current, else_block) = self.pattern_match(
- current,
- None,
- init_place,
- self.expr_ty_after_adjustments(*expr_id),
- *pat,
- BindingAnnotation::Unannotated,
- )?;
+ (current, else_block) =
+ self.pattern_match(current, None, init_place, *pat)?;
match (else_block, else_branch) {
(None, _) => (),
(Some(else_block), None) => {
@@ -1595,14 +1581,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
continue;
}
}
- let r = self.pattern_match(
- current,
- None,
- local.into(),
- self.result.locals[local].ty.clone(),
- param,
- BindingAnnotation::Unannotated,
- )?;
+ let r = self.pattern_match(current, None, local.into(), param)?;
if let Some(b) = r.1 {
self.set_terminator(b, TerminatorKind::Unreachable, param.into());
}
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index ee2a0306d5..5cd1be6842 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -2,7 +2,7 @@
use hir_def::{hir::LiteralOrConst, resolver::HasResolver, AssocItemId};
-use crate::utils::pattern_matching_dereference_count;
+use crate::BindingMode;
use super::*;
@@ -18,6 +18,26 @@ pub(super) enum AdtPatternShape<'a> {
Unit,
}
+/// We need to do pattern matching in two phases: One to check if the pattern matches, and one to fill the bindings
+/// of patterns. This is necessary to prevent double moves and similar problems. For example:
+/// ```ignore
+/// struct X;
+/// match (X, 3) {
+/// (b, 2) | (b, 3) => {},
+/// _ => {}
+/// }
+/// ```
+/// If we do everything in one pass, we will move `X` to the first `b`, then we see that the second field of tuple
+/// doesn't match and we should move the `X` to the second `b` (which here is the same thing, but doesn't need to be) and
+/// it might even doesn't match the second pattern and we may want to not move `X` at all.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum MatchingMode {
+ /// Check that if this pattern matches
+ Check,
+ /// Assume that this pattern matches, fill bindings
+ Bind,
+}
+
impl MirLowerCtx<'_> {
/// It gets a `current` unterminated block, appends some statements and possibly a terminator to it to check if
/// the pattern matches and write bindings, and returns two unterminated blocks, one for the matched path (which
@@ -30,19 +50,49 @@ impl MirLowerCtx<'_> {
/// so it should be an empty block.
pub(super) fn pattern_match(
&mut self,
+ current: BasicBlockId,
+ current_else: Option<BasicBlockId>,
+ cond_place: Place,
+ pattern: PatId,
+ ) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
+ let (current, current_else) = self.pattern_match_inner(
+ current,
+ current_else,
+ cond_place.clone(),
+ pattern,
+ MatchingMode::Check,
+ )?;
+ let (current, current_else) = self.pattern_match_inner(
+ current,
+ current_else,
+ cond_place,
+ pattern,
+ MatchingMode::Bind,
+ )?;
+ Ok((current, current_else))
+ }
+
+ fn pattern_match_inner(
+ &mut self,
mut current: BasicBlockId,
mut current_else: Option<BasicBlockId>,
mut cond_place: Place,
- mut cond_ty: Ty,
pattern: PatId,
- mut binding_mode: BindingAnnotation,
+ mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
+ let cnt = self.infer.pat_adjustments.get(&pattern).map(|x| x.len()).unwrap_or_default();
+ cond_place.projection = cond_place
+ .projection
+ .iter()
+ .cloned()
+ .chain((0..cnt).map(|_| ProjectionElem::Deref))
+ .collect::<Vec<_>>()
+ .into();
Ok(match &self.body.pats[pattern] {
Pat::Missing => return Err(MirLowerError::IncompletePattern),
Pat::Wild => (current, current_else),
Pat::Tuple { args, ellipsis } => {
- pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
- let subst = match cond_ty.kind(Interner) {
+ let subst = match self.infer[pattern].kind(Interner) {
TyKind::Tuple(_, s) => s,
_ => {
return Err(MirLowerError::TypeError(
@@ -55,25 +105,31 @@ impl MirLowerCtx<'_> {
current_else,
args,
*ellipsis,
- subst.iter(Interner).enumerate().map(|(i, x)| {
- (PlaceElem::TupleOrClosureField(i), x.assert_ty_ref(Interner).clone())
- }),
- &cond_place,
- binding_mode,
+ (0..subst.len(Interner)).map(|i| PlaceElem::TupleOrClosureField(i)),
+ &(&mut cond_place),
+ mode,
)?
}
Pat::Or(pats) => {
let then_target = self.new_basic_block();
let mut finished = false;
for pat in &**pats {
- let (next, next_else) = self.pattern_match(
+ let (mut next, next_else) = self.pattern_match_inner(
current,
None,
- cond_place.clone(),
- cond_ty.clone(),
+ (&mut cond_place).clone(),
*pat,
- binding_mode,
+ MatchingMode::Check,
)?;
+ if mode == MatchingMode::Bind {
+ (next, _) = self.pattern_match_inner(
+ next,
+ None,
+ (&mut cond_place).clone(),
+ *pat,
+ MatchingMode::Bind,
+ )?;
+ }
self.set_goto(next, then_target, pattern.into());
match next_else {
Some(t) => {
@@ -86,8 +142,12 @@ impl MirLowerCtx<'_> {
}
}
if !finished {
- let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
- self.set_goto(current, ce, pattern.into());
+ if mode == MatchingMode::Bind {
+ self.set_terminator(current, TerminatorKind::Unreachable, pattern.into());
+ } else {
+ let ce = *current_else.get_or_insert_with(|| self.new_basic_block());
+ self.set_goto(current, ce, pattern.into());
+ }
}
(then_target, current_else)
}
@@ -96,19 +156,19 @@ impl MirLowerCtx<'_> {
not_supported!("unresolved variant for record");
};
self.pattern_matching_variant(
- cond_ty,
- binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Record { args: &*args },
+ mode,
)?
}
Pat::Range { start, end } => {
let mut add_check = |l: &LiteralOrConst, binop| -> Result<()> {
- let lv = self.lower_literal_or_const_to_operand(cond_ty.clone(), l)?;
+ let lv =
+ self.lower_literal_or_const_to_operand(self.infer[pattern].clone(), l)?;
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
let next = self.new_basic_block();
let discr: Place =
@@ -116,7 +176,11 @@ impl MirLowerCtx<'_> {
self.push_assignment(
current,
discr.clone(),
- Rvalue::CheckedBinaryOp(binop, lv, Operand::Copy(cond_place.clone())),
+ Rvalue::CheckedBinaryOp(
+ binop,
+ lv,
+ Operand::Copy((&mut cond_place).clone()),
+ ),
pattern.into(),
);
let discr = Operand::Copy(discr);
@@ -131,24 +195,25 @@ impl MirLowerCtx<'_> {
current = next;
Ok(())
};
- if let Some(start) = start {
- add_check(start, BinOp::Le)?;
- }
- if let Some(end) = end {
- add_check(end, BinOp::Ge)?;
+ if mode == MatchingMode::Check {
+ if let Some(start) = start {
+ add_check(start, BinOp::Le)?;
+ }
+ if let Some(end) = end {
+ add_check(end, BinOp::Ge)?;
+ }
}
(current, current_else)
}
Pat::Slice { prefix, slice, suffix } => {
- pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
- if let TyKind::Slice(_) = cond_ty.kind(Interner) {
+ if let TyKind::Slice(_) = self.infer[pattern].kind(Interner) {
let pattern_len = prefix.len() + suffix.len();
let place_len: Place =
self.temp(TyBuilder::usize(), current, pattern.into())?.into();
self.push_assignment(
current,
place_len.clone(),
- Rvalue::Len(cond_place.clone()),
+ Rvalue::Len((&mut cond_place).clone()),
pattern.into(),
);
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
@@ -193,63 +258,49 @@ impl MirLowerCtx<'_> {
current = next;
}
for (i, &pat) in prefix.iter().enumerate() {
- let next_place = cond_place.project(ProjectionElem::ConstantIndex {
+ let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: false,
});
- let cond_ty = self.infer[pat].clone();
- (current, current_else) = self.pattern_match(
- current,
- current_else,
- next_place,
- cond_ty,
- pat,
- binding_mode,
- )?;
+ (current, current_else) =
+ self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
if let Some(slice) = slice {
- if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
- let next_place = cond_place.project(ProjectionElem::Subslice {
- from: prefix.len() as u64,
- to: suffix.len() as u64,
- });
- (current, current_else) = self.pattern_match_binding(
- id,
- &mut binding_mode,
- next_place,
- (*slice).into(),
- current,
- current_else,
- )?;
+ if mode == MatchingMode::Bind {
+ if let Pat::Bind { id, subpat: _ } = self.body[*slice] {
+ let next_place = (&mut cond_place).project(ProjectionElem::Subslice {
+ from: prefix.len() as u64,
+ to: suffix.len() as u64,
+ });
+ (current, current_else) = self.pattern_match_binding(
+ id,
+ next_place,
+ (*slice).into(),
+ current,
+ current_else,
+ )?;
+ }
}
}
for (i, &pat) in suffix.iter().enumerate() {
- let next_place = cond_place.project(ProjectionElem::ConstantIndex {
+ let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
offset: i as u64,
from_end: true,
});
- let cond_ty = self.infer[pat].clone();
- (current, current_else) = self.pattern_match(
- current,
- current_else,
- next_place,
- cond_ty,
- pat,
- binding_mode,
- )?;
+ (current, current_else) =
+ self.pattern_match_inner(current, current_else, next_place, pat, mode)?;
}
(current, current_else)
}
Pat::Path(p) => match self.infer.variant_resolution_for_pat(pattern) {
Some(variant) => self.pattern_matching_variant(
- cond_ty,
- binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Unit,
+ mode,
)?,
None => {
let unresolved_name = || MirLowerError::unresolved_path(self.db, p);
@@ -270,9 +321,17 @@ impl MirLowerCtx<'_> {
}
not_supported!("path in pattern position that is not const or variant")
};
- let tmp: Place = self.temp(cond_ty.clone(), current, pattern.into())?.into();
+ let tmp: Place =
+ self.temp(self.infer[pattern].clone(), current, pattern.into())?.into();
let span = pattern.into();
- self.lower_const(c.into(), current, tmp.clone(), subst, span, cond_ty.clone())?;
+ self.lower_const(
+ c.into(),
+ current,
+ tmp.clone(),
+ subst,
+ span,
+ self.infer[pattern].clone(),
+ )?;
let tmp2: Place = self.temp(TyBuilder::bool(), current, pattern.into())?.into();
self.push_assignment(
current,
@@ -299,61 +358,58 @@ impl MirLowerCtx<'_> {
},
Pat::Lit(l) => match &self.body.exprs[*l] {
Expr::Literal(l) => {
- let c = self.lower_literal_to_operand(cond_ty, l)?;
- self.pattern_match_const(current_else, current, c, cond_place, pattern)?
+ let c = self.lower_literal_to_operand(self.infer[pattern].clone(), l)?;
+ if mode == MatchingMode::Check {
+ self.pattern_match_const(current_else, current, c, cond_place, pattern)?
+ } else {
+ (current, current_else)
+ }
}
_ => not_supported!("expression path literal"),
},
Pat::Bind { id, subpat } => {
if let Some(subpat) = subpat {
- (current, current_else) = self.pattern_match(
+ (current, current_else) = self.pattern_match_inner(
current,
current_else,
- cond_place.clone(),
- cond_ty,
+ (&mut cond_place).clone(),
*subpat,
- binding_mode,
+ mode,
)?
}
- self.pattern_match_binding(
- *id,
- &mut binding_mode,
- cond_place,
- pattern.into(),
- current,
- current_else,
- )?
+ if mode == MatchingMode::Bind {
+ self.pattern_match_binding(
+ *id,
+ cond_place,
+ pattern.into(),
+ current,
+ current_else,
+ )?
+ } else {
+ (current, current_else)
+ }
}
Pat::TupleStruct { path: _, args, ellipsis } => {
let Some(variant) = self.infer.variant_resolution_for_pat(pattern) else {
not_supported!("unresolved variant");
};
self.pattern_matching_variant(
- cond_ty,
- binding_mode,
cond_place,
variant,
current,
pattern.into(),
current_else,
AdtPatternShape::Tuple { args, ellipsis: *ellipsis },
+ mode,
)?
}
- Pat::Ref { pat, mutability: _ } => {
- if let Some((ty, _, _)) = cond_ty.as_reference() {
- cond_ty = ty.clone();
- self.pattern_match(
- current,
- current_else,
- cond_place.project(ProjectionElem::Deref),
- cond_ty,
- *pat,
- binding_mode,
- )?
- } else {
- return Err(MirLowerError::TypeError("& pattern for non reference"));
- }
- }
+ Pat::Ref { pat, mutability: _ } => self.pattern_match_inner(
+ current,
+ current_else,
+ cond_place.project(ProjectionElem::Deref),
+ *pat,
+ mode,
+ )?,
Pat::Box { .. } => not_supported!("box pattern"),
Pat::ConstBlock(_) => not_supported!("const block pattern"),
})
@@ -362,27 +418,21 @@ impl MirLowerCtx<'_> {
fn pattern_match_binding(
&mut self,
id: BindingId,
- binding_mode: &mut BindingAnnotation,
cond_place: Place,
span: MirSpan,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let target_place = self.binding_local(id)?;
- let mode = self.body.bindings[id].mode;
- if matches!(mode, BindingAnnotation::Ref | BindingAnnotation::RefMut) {
- *binding_mode = mode;
- }
+ let mode = self.infer.binding_modes[id];
self.push_storage_live(id, current)?;
self.push_assignment(
current,
target_place.into(),
- match *binding_mode {
- BindingAnnotation::Unannotated | BindingAnnotation::Mutable => {
- Operand::Copy(cond_place).into()
- }
- BindingAnnotation::Ref => Rvalue::Ref(BorrowKind::Shared, cond_place),
- BindingAnnotation::RefMut => {
+ match mode {
+ BindingMode::Move => Operand::Copy(cond_place).into(),
+ BindingMode::Ref(Mutability::Not) => Rvalue::Ref(BorrowKind::Shared, cond_place),
+ BindingMode::Ref(Mutability::Mut) => {
Rvalue::Ref(BorrowKind::Mut { allow_two_phase_borrow: false }, cond_place)
}
},
@@ -420,52 +470,48 @@ impl MirLowerCtx<'_> {
Ok((then_target, Some(else_target)))
}
- pub(super) fn pattern_matching_variant(
+ fn pattern_matching_variant(
&mut self,
- mut cond_ty: Ty,
- mut binding_mode: BindingAnnotation,
- mut cond_place: Place,
+ cond_place: Place,
variant: VariantId,
- current: BasicBlockId,
+ mut current: BasicBlockId,
span: MirSpan,
- current_else: Option<BasicBlockId>,
+ mut current_else: Option<BasicBlockId>,
shape: AdtPatternShape<'_>,
+ mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
- pattern_matching_dereference(&mut cond_ty, &mut binding_mode, &mut cond_place);
- let subst = match cond_ty.kind(Interner) {
- TyKind::Adt(_, s) => s,
- _ => return Err(MirLowerError::TypeError("non adt type matched with tuple struct")),
- };
Ok(match variant {
VariantId::EnumVariantId(v) => {
- let e = self.const_eval_discriminant(v)? as u128;
- let tmp = self.discr_temp_place(current);
- self.push_assignment(
- current,
- tmp.clone(),
- Rvalue::Discriminant(cond_place.clone()),
- span,
- );
- let next = self.new_basic_block();
- let else_target = current_else.unwrap_or_else(|| self.new_basic_block());
- self.set_terminator(
- current,
- TerminatorKind::SwitchInt {
- discr: Operand::Copy(tmp),
- targets: SwitchTargets::static_if(e, next, else_target),
- },
- span,
- );
+ if mode == MatchingMode::Check {
+ let e = self.const_eval_discriminant(v)? as u128;
+ let tmp = self.discr_temp_place(current);
+ self.push_assignment(
+ current,
+ tmp.clone(),
+ Rvalue::Discriminant(cond_place.clone()),
+ span,
+ );
+ let next = self.new_basic_block();
+ let else_target = current_else.get_or_insert_with(|| self.new_basic_block());
+ self.set_terminator(
+ current,
+ TerminatorKind::SwitchInt {
+ discr: Operand::Copy(tmp),
+ targets: SwitchTargets::static_if(e, next, *else_target),
+ },
+ span,
+ );
+ current = next;
+ }
let enum_data = self.db.enum_data(v.parent);
self.pattern_matching_variant_fields(
shape,
&enum_data.variants[v.local_id].variant_data,
variant,
- subst,
- next,
- Some(else_target),
+ current,
+ current_else,
&cond_place,
- binding_mode,
+ mode,
)?
}
VariantId::StructId(s) => {
@@ -474,11 +520,10 @@ impl MirLowerCtx<'_> {
shape,
&struct_data.variant_data,
variant,
- subst,
current,
current_else,
&cond_place,
- binding_mode,
+ mode,
)?
}
VariantId::UnionId(_) => {
@@ -492,13 +537,11 @@ impl MirLowerCtx<'_> {
shape: AdtPatternShape<'_>,
variant_data: &VariantData,
v: VariantId,
- subst: &Substitution,
current: BasicBlockId,
current_else: Option<BasicBlockId>,
cond_place: &Place,
- binding_mode: BindingAnnotation,
+ mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
- let fields_type = self.db.field_types(v);
Ok(match shape {
AdtPatternShape::Record { args } => {
let it = args
@@ -509,25 +552,16 @@ impl MirLowerCtx<'_> {
Ok((
PlaceElem::Field(FieldId { parent: v.into(), local_id: field_id }),
x.pat,
- fields_type[field_id].clone().substitute(Interner, subst),
))
})
.collect::<Result<Vec<_>>>()?;
- self.pattern_match_adt(
- current,
- current_else,
- it.into_iter(),
- cond_place,
- binding_mode,
- )?
+ self.pattern_match_adt(current, current_else, it.into_iter(), cond_place, mode)?
}
AdtPatternShape::Tuple { args, ellipsis } => {
- let fields = variant_data.fields().iter().map(|(x, _)| {
- (
- PlaceElem::Field(FieldId { parent: v.into(), local_id: x }),
- fields_type[x].clone().substitute(Interner, subst),
- )
- });
+ let fields = variant_data
+ .fields()
+ .iter()
+ .map(|(x, _)| PlaceElem::Field(FieldId { parent: v.into(), local_id: x }));
self.pattern_match_tuple_like(
current,
current_else,
@@ -535,7 +569,7 @@ impl MirLowerCtx<'_> {
ellipsis,
fields,
cond_place,
- binding_mode,
+ mode,
)?
}
AdtPatternShape::Unit => (current, current_else),
@@ -546,14 +580,14 @@ impl MirLowerCtx<'_> {
&mut self,
mut current: BasicBlockId,
mut current_else: Option<BasicBlockId>,
- args: impl Iterator<Item = (PlaceElem, PatId, Ty)>,
+ args: impl Iterator<Item = (PlaceElem, PatId)>,
cond_place: &Place,
- binding_mode: BindingAnnotation,
+ mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
- for (proj, arg, ty) in args {
+ for (proj, arg) in args {
let cond_place = cond_place.project(proj);
(current, current_else) =
- self.pattern_match(current, current_else, cond_place, ty, arg, binding_mode)?;
+ self.pattern_match_inner(current, current_else, cond_place, arg, mode)?;
}
Ok((current, current_else))
}
@@ -564,31 +598,16 @@ impl MirLowerCtx<'_> {
current_else: Option<BasicBlockId>,
args: &[PatId],
ellipsis: Option<usize>,
- fields: impl DoubleEndedIterator<Item = (PlaceElem, Ty)> + Clone,
+ fields: impl DoubleEndedIterator<Item = PlaceElem> + Clone,
cond_place: &Place,
- binding_mode: BindingAnnotation,
+ mode: MatchingMode,
) -> Result<(BasicBlockId, Option<BasicBlockId>)> {
let (al, ar) = args.split_at(ellipsis.unwrap_or(args.len()));
let it = al
.iter()
.zip(fields.clone())
.chain(ar.iter().rev().zip(fields.rev()))
- .map(|(x, y)| (y.0, *x, y.1));
- self.pattern_match_adt(current, current_else, it, cond_place, binding_mode)
+ .map(|(x, y)| (y, *x));
+ self.pattern_match_adt(current, current_else, it, cond_place, mode)
}
}
-
-fn pattern_matching_dereference(
- cond_ty: &mut Ty,
- binding_mode: &mut BindingAnnotation,
- cond_place: &mut Place,
-) {
- let cnt = pattern_matching_dereference_count(cond_ty, binding_mode);
- cond_place.projection = cond_place
- .projection
- .iter()
- .cloned()
- .chain((0..cnt).map(|_| ProjectionElem::Deref))
- .collect::<Vec<_>>()
- .into();
-}
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index 8f36188b78..681d087ede 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -7,7 +7,7 @@ use base_db::CrateId;
use chalk_ir::{
cast::Cast,
fold::{FallibleTypeFolder, Shift},
- BoundVar, DebruijnIndex, Mutability,
+ BoundVar, DebruijnIndex,
};
use either::Either;
use hir_def::{
@@ -16,7 +16,6 @@ use hir_def::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
},
- hir::BindingAnnotation,
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
type_ref::{TraitBoundModifier, TypeRef},
@@ -35,7 +34,7 @@ use crate::{
layout::{Layout, TagEncoding},
mir::pad16,
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
- Ty, TyExt, WhereClause,
+ Ty, WhereClause,
};
pub(crate) fn fn_traits(
@@ -395,23 +394,6 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
}
}
-pub(crate) fn pattern_matching_dereference_count(
- cond_ty: &mut Ty,
- binding_mode: &mut BindingAnnotation,
-) -> usize {
- let mut r = 0;
- while let Some((ty, _, mu)) = cond_ty.as_reference() {
- if mu == Mutability::Mut && *binding_mode != BindingAnnotation::Ref {
- *binding_mode = BindingAnnotation::RefMut;
- } else {
- *binding_mode = BindingAnnotation::Ref;
- }
- *cond_ty = ty.clone();
- r += 1;
- }
- r
-}
-
pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
pub(crate) db: &'a dyn HirDatabase,
}