about summary refs log tree commit diff
diff options
context:
space:
mode:
-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 5cd1be68424..ff43c64a9e6 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 8795afc2d97..f61460e317f 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#"