Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs94
-rw-r--r--crates/ide-diagnostics/src/handlers/mutability_errors.rs21
2 files changed, 70 insertions, 45 deletions
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 5cd1be6842..ff43c64a9e 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -206,56 +206,60 @@ impl MirLowerCtx<'_> {
(current, current_else)
}
Pat::Slice { prefix, slice, suffix } => {
- 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((&mut cond_place).clone()),
- pattern.into(),
- );
- let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
- let next = self.new_basic_block();
- if slice.is_none() {
- self.set_terminator(
- current,
- TerminatorKind::SwitchInt {
- discr: Operand::Copy(place_len),
- targets: SwitchTargets::static_if(
- pattern_len as u128,
- next,
- else_target,
- ),
- },
- pattern.into(),
- );
- } else {
- let c = Operand::from_concrete_const(
- pattern_len.to_le_bytes().to_vec(),
- MemoryMap::default(),
- TyBuilder::usize(),
- );
- let discr: Place =
- self.temp(TyBuilder::bool(), current, pattern.into())?.into();
+ if mode == MatchingMode::Check {
+ // emit runtime length check for slice
+ 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,
- discr.clone(),
- Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)),
- pattern.into(),
- );
- let discr = Operand::Copy(discr);
- self.set_terminator(
- current,
- TerminatorKind::SwitchInt {
- discr,
- targets: SwitchTargets::static_if(1, next, else_target),
- },
+ place_len.clone(),
+ Rvalue::Len((&mut cond_place).clone()),
pattern.into(),
);
+ let else_target =
+ *current_else.get_or_insert_with(|| self.new_basic_block());
+ let next = self.new_basic_block();
+ if slice.is_none() {
+ self.set_terminator(
+ current,
+ TerminatorKind::SwitchInt {
+ discr: Operand::Copy(place_len),
+ targets: SwitchTargets::static_if(
+ pattern_len as u128,
+ next,
+ else_target,
+ ),
+ },
+ pattern.into(),
+ );
+ } else {
+ let c = Operand::from_concrete_const(
+ pattern_len.to_le_bytes().to_vec(),
+ MemoryMap::default(),
+ TyBuilder::usize(),
+ );
+ let discr: Place =
+ self.temp(TyBuilder::bool(), current, pattern.into())?.into();
+ self.push_assignment(
+ current,
+ discr.clone(),
+ Rvalue::CheckedBinaryOp(BinOp::Le, c, Operand::Copy(place_len)),
+ pattern.into(),
+ );
+ let discr = Operand::Copy(discr);
+ self.set_terminator(
+ current,
+ TerminatorKind::SwitchInt {
+ discr,
+ targets: SwitchTargets::static_if(1, next, else_target),
+ },
+ pattern.into(),
+ );
+ }
+ current = next;
}
- current = next;
}
for (i, &pat) in prefix.iter().enumerate() {
let next_place = (&mut cond_place).project(ProjectionElem::ConstantIndex {
diff --git a/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 8795afc2d9..f61460e317 100644
--- a/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -994,6 +994,27 @@ fn f() {
}
#[test]
+ fn slice_pattern() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized, deref_mut, slice, copy
+fn x(t: &[u8]) {
+ match t {
+ &[a, mut b] | &[a, _, mut b] => {
+ //^^^^^ 💡 weak: variable does not need to be mutable
+
+ a = 2;
+ //^^^^^ 💡 error: cannot mutate immutable variable `a`
+
+ }
+ _ => {}
+ }
+}
+ "#,
+ );
+ }
+
+ #[test]
fn boxes() {
check_diagnostics(
r#"