Repository: rust-analyzer/rust-analyzer
Pull request #5990 (2020-09-12 19:22:51)

Implement box patterns


Patch:
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 30ac12a12e..9ea3d52915 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -835,8 +835,12 @@ impl ExprCollector<'_> {
 
                 Pat::Missing
             }
+            ast::Pat::BoxPat(boxpat) => {
+                let inner = self.collect_pat_opt(boxpat.pat());
+                Pat::Box { inner }
+            }
             // FIXME: implement
-            ast::Pat::BoxPat(_) | ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
+            ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing,
         };
         let ptr = AstPtr::new(&pat);
         self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index c94b3a36f5..dc975d42f8 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -395,6 +395,7 @@ pub enum Pat {
     Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
     TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> },
     Ref { pat: PatId, mutability: Mutability },
+    Box { inner: PatId },
 }
 
 impl Pat {
@@ -415,6 +416,7 @@ impl Pat {
             Pat::Record { args, .. } => {
                 args.iter().map(|f| f.pat).for_each(f);
             }
+            Pat::Box { inner } => f(*inner),
         }
     }
 }
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index dde38bc397..cde2ab82b6 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -209,6 +209,18 @@ impl<'a> InferenceContext<'a> {
                 end_ty
             }
             Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())),
+            Pat::Box { inner } => match self.resolve_boxed_box() {
+                Some(box_adt) => {
+                    let inner_expected = match expected.as_adt() {
+                        Some((adt, substs)) if adt == box_adt => substs.as_single(),
+                        _ => &Ty::Unknown,
+                    };
+
+                    let inner_ty = self.infer_pat(*inner, inner_expected, default_bm);
+                    Ty::apply_one(TypeCtor::Adt(box_adt), inner_ty)
+                }
+                None => Ty::Unknown,
+            },
             Pat::Missing => Ty::Unknown,
         };
         // use a new type variable if we got Ty::Unknown here
@@ -236,6 +248,6 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
             Expr::Literal(Literal::String(..)) => false,
             _ => true,
         },
-        Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
+        Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
     }
 }


Test patch:
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index aeb191c79a..6a965ac4fa 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -654,3 +654,28 @@ fn slice_tail_pattern() {
         "#]],
     );
 }
+
+#[test]
+fn box_pattern() {
+    check_infer(
+        r#"
+        #[lang = "owned_box"]
+        pub struct Box<T>(T);
+
+        fn foo(params: Box<i32>) {
+            match params {
+                box integer => {}
+            }
+        }
+        "#,
+        expect![[r#"
+            52..58 'params': Box<i32>
+            70..124 '{     ...   } }': ()
+            76..122 'match ...     }': ()
+            82..88 'params': Box<i32>
+            99..110 'box integer': Box<i32>
+            103..110 'integer': i32
+            114..116 '{}': ()
+        "#]],
+    );
+}