Repository: rust-analyzer/rust-analyzer (rust)

Issue:
No type inference for slice patterns
Minimal reproduction:

```rust
let xs: &[f64] = &[0.0];
match xs {
    &[x] => {
        x; // {unknown}
    }
    _ => {}
}
```

Pull request description:
Type inference for slice patterns
Fixes #3043 

Notes to reviewer:

1. This only works if `expected` is `Ty::Apply`. I'm not sure of the implications of this.
1. This only works if the slice pattern only has a prefix. I think this means it doesn't work for subslice patterns, which are currently only available behind a feature flag.

Patch:
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
index 0934520d70..62aafd508e 100644
--- a/crates/ra_hir_def/src/path/lower.rs
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -101,12 +101,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
                 break;
             }
             ast::PathSegmentKind::SuperKw => {
-                let nested_super_count = if let PathKind::Super(n) = kind {
-                    n
-                } else {
-                    0
-                };
-                kind = PathKind::Super(nested_super_count + 1);
+                kind = PathKind::Super(1);
+                break;
             }
         }
         path = match qualifier(&path) {
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
index 278d5196e7..b6d1125e20 100644
--- a/crates/ra_hir_def/src/path/lower/lower_use.rs
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -103,13 +103,10 @@ fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) ->
             ModPath::from_segments(PathKind::Super(0), iter::empty())
         }
         ast::PathSegmentKind::SuperKw => {
-            let nested_super_count = match prefix.map(|p| p.kind) {
-                Some(PathKind::Super(n)) => n,
-                Some(_) => return None,
-                None => 0,
-            };
-
-            ModPath::from_segments(PathKind::Super(nested_super_count + 1), iter::empty())
+            if prefix.is_some() {
+                return None;
+            }
+            ModPath::from_segments(PathKind::Super(1), iter::empty())
         }
         ast::PathSegmentKind::Type { .. } => {
             // not allowed in imports
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index bf8ea192b7..623e525993 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -185,6 +185,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
                 self.write_pat_ty(pat, bound_ty);
                 return inner_ty;
             }
+            Pat::Slice { prefix, slice: _slice, suffix } => {
+                let (container_ty, elem_ty) = match &expected {
+                    ty_app!(TypeCtor::Array, st) => {
+                        (TypeCtor::Array, st.as_single().clone())
+                    },
+                    ty_app!(TypeCtor::Slice, st) => {
+                        (TypeCtor::Slice, st.as_single().clone())
+                    },
+                    _ => (TypeCtor::Slice, Ty::Unknown),
+                };
+
+                for pat_id in prefix.iter().chain(suffix) {
+                    self.infer_pat(*pat_id, &elem_ty, default_bm);
+                }
+
+                Ty::apply_one(container_ty, elem_ty)
+            }
             _ => Ty::Unknown,
         };
         // use a new type variable if we got Ty::Unknown here
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index 9145aa183d..a6e0158b2a 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -545,43 +545,4 @@ mod tests {
         "###
         )
     }
-
-    #[test]
-    fn test_super_super_completion() {
-        assert_debug_snapshot!(
-        do_ref_completion(
-                r"
-                mod a {
-                    const A: usize = 0;
-
-                    mod b {
-                        const B: usize = 0;
-
-                        mod c {
-                            use super::super::<|>
-                        }
-                    }
-                }
-                ",
-        ),
-            @r###"
-        [
-            CompletionItem {
-                label: "A",
-                source_range: [217; 217),
-                delete: [217; 217),
-                insert: "A",
-                kind: Const,
-            },
-            CompletionItem {
-                label: "b",
-                source_range: [217; 217),
-                delete: [217; 217),
-                insert: "b",
-                kind: Module,
-            },
-        ]
-        "###
-        );
-    }
 }


Test patch:
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index dda5ed699c..82f0f835c8 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -65,42 +65,6 @@ fn crate_def_map_smoke_test() {
     "###)
 }
 
-#[test]
-fn crate_def_map_super_super() {
-    let map = def_map(
-        "
-        //- /lib.rs
-        mod a {
-            const A: usize = 0;
-
-            mod b {
-                const B: usize = 0;
-
-                mod c {
-                    use super::super::*;
-                }
-            }
-        }
-        ",
-    );
-    assert_snapshot!(map, @r###"
-        ⋮crate
-        ⋮a: t
-        ⋮
-        ⋮crate::a
-        ⋮A: v
-        ⋮b: t
-        ⋮
-        ⋮crate::a::b
-        ⋮B: v
-        ⋮c: t
-        ⋮
-        ⋮crate::a::b::c
-        ⋮A: v
-        ⋮b: t
-    "###)
-}
-
 #[test]
 fn bogus_paths() {
     covers!(bogus_paths);
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 81d00c2afb..76aa320246 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -53,8 +53,9 @@ fn test(x: &i32) {
     [140; 141) 'g': {unknown}
     [144; 145) 'e': {unknown}
     [158; 205) 'if let...     }': ()
-    [165; 170) '[val]': {unknown}
-    [173; 176) 'opt': {unknown}
+    [165; 170) '[val]': [{unknown}]
+    [166; 169) 'val': {unknown}
+    [173; 176) 'opt': [{unknown}]
     [177; 205) '{     ...     }': ()
     [191; 192) 'h': {unknown}
     [195; 198) 'val': {unknown}
@@ -136,6 +137,94 @@ fn test() {
     );
 }
 
+#[test]
+fn infer_pattern_match_slice() {
+    assert_snapshot!(
+        infer(r#"
+fn test() {
+    let slice: &[f64] = &[0.0];
+    match slice {
+        &[] => {},
+        &[a] => {
+            a;
+        },
+        &[b, c] => {
+            b;
+            c;
+        }
+        _ => {}
+    }
+}
+"#),
+    @r###"
+    [11; 210) '{     ...   } }': ()
+    [21; 26) 'slice': &[f64]
+    [37; 43) '&[0.0]': &[f64; _]
+    [38; 43) '[0.0]': [f64; _]
+    [39; 42) '0.0': f64
+    [49; 208) 'match ...     }': ()
+    [55; 60) 'slice': &[f64]
+    [71; 74) '&[]': &[f64]
+    [72; 74) '[]': [f64]
+    [78; 80) '{}': ()
+    [90; 94) '&[a]': &[f64]
+    [91; 94) '[a]': [f64]
+    [92; 93) 'a': f64
+    [98; 124) '{     ...     }': ()
+    [112; 113) 'a': f64
+    [134; 141) '&[b, c]': &[f64]
+    [135; 141) '[b, c]': [f64]
+    [136; 137) 'b': f64
+    [139; 140) 'c': f64
+    [145; 186) '{     ...     }': ()
+    [159; 160) 'b': f64
+    [174; 175) 'c': f64
+    [195; 196) '_': &[f64]
+    [200; 202) '{}': ()
+    "###
+    );
+}
+
+#[test]
+fn infer_pattern_match_arr() {
+    assert_snapshot!(
+        infer(r#"
+fn test() {
+    let arr: [f64; 2] = [0.0, 1.0];
+    match arr {
+        [1.0, a] => {
+            a;
+        },
+        [b, c] => {
+            b;
+            c;
+        }
+    }
+}
+"#),
+    @r###"
+    [11; 180) '{     ...   } }': ()
+    [21; 24) 'arr': [f64; _]
+    [37; 47) '[0.0, 1.0]': [f64; _]
+    [38; 41) '0.0': f64
+    [43; 46) '1.0': f64
+    [53; 178) 'match ...     }': ()
+    [59; 62) 'arr': [f64; _]
+    [73; 81) '[1.0, a]': [f64; _]
+    [74; 77) '1.0': f64
+    [79; 80) 'a': f64
+    [85; 111) '{     ...     }': ()
+    [99; 100) 'a': f64
+    [121; 127) '[b, c]': [f64; _]
+    [122; 123) 'b': f64
+    [125; 126) 'c': f64
+    [131; 172) '{     ...     }': ()
+    [145; 146) 'b': f64
+    [160; 161) 'c': f64
+    "###
+    );
+}
+
 #[test]
 fn infer_adt_pattern() {
     assert_snapshot!(