about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-10-22 20:26:11 +0000
committerbors <bors@rust-lang.org>2023-10-22 20:26:11 +0000
commit10872952c03947124f8ccda7d7aa7930b7da32fe (patch)
tree0a0ff616e323403796c4cbec2058b0b455057b5c
parent7c11399b6bc5cf7a0b12a506a4b155a4be0458ee (diff)
parent8b82ea4f51b0288a2e318aca352cee6df06e244e (diff)
downloadrust-10872952c03947124f8ccda7d7aa7930b7da32fe.tar.gz
rust-10872952c03947124f8ccda7d7aa7930b7da32fe.zip
Auto merge of #15789 - HKalbasi:unused-var, r=HKalbasi
Store binding mode for each instance of a binding independently

fix #15787
-rw-r--r--crates/hir-ty/src/consteval/tests.rs14
-rw-r--r--crates/hir-ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir-ty/src/infer.rs14
-rw-r--r--crates/hir-ty/src/infer/closure.rs6
-rw-r--r--crates/hir-ty/src/infer/pat.rs2
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs5
-rw-r--r--crates/hir/src/source_analyzer.rs4
-rw-r--r--crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs15
8 files changed, 53 insertions, 9 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 7ad3659a4f6..b395e7f4a81 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1159,6 +1159,20 @@ fn pattern_matching_slice() {
         "#,
         33213,
     );
+    check_number(
+        r#"
+    //- minicore: slice, index, coerce_unsized, copy
+    const fn f(mut slice: &[u32]) -> usize {
+        slice = match slice {
+            [0, rest @ ..] | rest => rest,
+        };
+        slice.len()
+    }
+    const GOAL: usize = f(&[]) + f(&[10]) + f(&[0, 100])
+        + f(&[1000, 1000, 1000]) + f(&[0, 57, 34, 46, 10000, 10000]);
+        "#,
+        10,
+    );
 }
 
 #[test]
diff --git a/crates/hir-ty/src/diagnostics/match_check.rs b/crates/hir-ty/src/diagnostics/match_check.rs
index f8cdeaa5e35..2e04bbfee83 100644
--- a/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/crates/hir-ty/src/diagnostics/match_check.rs
@@ -147,7 +147,7 @@ impl<'a> PatCtxt<'a> {
             }
 
             hir_def::hir::Pat::Bind { id, subpat, .. } => {
-                let bm = self.infer.binding_modes[id];
+                let bm = self.infer.binding_modes[pat];
                 ty = &self.infer[id];
                 let name = &self.body.bindings[id].name;
                 match (bm, ty.kind(Interner)) {
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 78d3c667a1f..3d5ed1f93c0 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -420,7 +420,19 @@ pub struct InferenceResult {
     standard_types: InternedStandardTypes,
     /// Stores the types which were implicitly dereferenced in pattern binding modes.
     pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
-    pub binding_modes: ArenaMap<BindingId, BindingMode>,
+    /// Stores the binding mode (`ref` in `let ref x = 2`) of bindings.
+    ///
+    /// This one is tied to the `PatId` instead of `BindingId`, because in some rare cases, a binding in an
+    /// or pattern can have multiple binding modes. For example:
+    /// ```
+    /// fn foo(mut slice: &[u32]) -> usize {
+    ///    slice = match slice {
+    ///        [0, rest @ ..] | rest => rest,
+    ///    };
+    /// }
+    /// ```
+    /// the first `rest` has implicit `ref` binding mode, but the second `rest` binding mode is `move`.
+    pub binding_modes: ArenaMap<PatId, BindingMode>,
     pub expr_adjustments: FxHashMap<ExprId, Vec<Adjustment>>,
     pub(crate) closure_info: FxHashMap<ClosureId, (Vec<CapturedItem>, FnTrait)>,
     // FIXME: remove this field
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 13d6b5643ac..0805e20447a 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -679,7 +679,7 @@ impl InferenceContext<'_> {
             | Pat::Range { .. } => {
                 update_result(CaptureKind::ByRef(BorrowKind::Shared));
             }
-            Pat::Bind { id, .. } => match self.result.binding_modes[*id] {
+            Pat::Bind { id, .. } => match self.result.binding_modes[p] {
                 crate::BindingMode::Move => {
                     if self.is_ty_copy(self.result.type_of_binding[*id].clone()) {
                         update_result(CaptureKind::ByRef(BorrowKind::Shared));
@@ -838,8 +838,8 @@ impl InferenceContext<'_> {
             | Pat::ConstBlock(_)
             | Pat::Path(_)
             | Pat::Lit(_) => self.consume_place(place, pat.into()),
-            Pat::Bind { id, subpat: _ } => {
-                let mode = self.result.binding_modes[*id];
+            Pat::Bind { id: _, subpat: _ } => {
+                let mode = self.result.binding_modes[pat];
                 let capture_kind = match mode {
                     BindingMode::Move => {
                         self.consume_place(place, pat.into());
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 4e28ec06023..7ff12e5b7f8 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -421,7 +421,7 @@ impl InferenceContext<'_> {
         } else {
             BindingMode::convert(mode)
         };
-        self.result.binding_modes.insert(binding, mode);
+        self.result.binding_modes.insert(pat, mode);
 
         let inner_ty = match subpat {
             Some(subpat) => self.infer_pat(subpat, &expected, default_bm),
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index 270f75ad967..1120bb1c112 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -284,6 +284,7 @@ impl MirLowerCtx<'_> {
                             );
                             (current, current_else) = self.pattern_match_binding(
                                 id,
+                                *slice,
                                 next_place,
                                 (*slice).into(),
                                 current,
@@ -395,6 +396,7 @@ impl MirLowerCtx<'_> {
                 if mode == MatchingMode::Bind {
                     self.pattern_match_binding(
                         *id,
+                        pattern,
                         cond_place,
                         pattern.into(),
                         current,
@@ -431,13 +433,14 @@ impl MirLowerCtx<'_> {
     fn pattern_match_binding(
         &mut self,
         id: BindingId,
+        pat: PatId,
         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.infer.binding_modes[id];
+        let mode = self.infer.binding_modes[pat];
         self.push_storage_live(id, current)?;
         self.push_assignment(
             current,
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8d8ba48ad92..55c2f8324c6 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -236,9 +236,9 @@ impl SourceAnalyzer {
         _db: &dyn HirDatabase,
         pat: &ast::IdentPat,
     ) -> Option<BindingMode> {
-        let binding_id = self.binding_id_of_pat(pat)?;
+        let id = self.pat_id(&pat.clone().into())?;
         let infer = self.infer.as_ref()?;
-        infer.binding_modes.get(binding_id).map(|bm| match bm {
+        infer.binding_modes.get(id).map(|bm| match bm {
             hir_ty::BindingMode::Move => BindingMode::Move,
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Mut) => BindingMode::Ref(Mutability::Mut),
             hir_ty::BindingMode::Ref(hir_ty::Mutability::Not) => {
diff --git a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
index 20175b3fd53..886aefeb575 100644
--- a/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
+++ b/crates/ide-diagnostics/src/handlers/moved_out_of_ref.rs
@@ -175,4 +175,19 @@ fn main() {
             "#,
         );
     }
+
+    #[test]
+    fn regression_15787() {
+        check_diagnostics(
+            r#"
+//- minicore: coerce_unsized, slice, copy
+fn foo(mut slice: &[u32]) -> usize {
+    slice = match slice {
+        [0, rest @ ..] | rest => rest,
+    };
+    slice.len()
+}
+"#,
+        );
+    }
 }