]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_ty/src/infer/pat.rs
Merge #11461
[rust.git] / crates / hir_ty / src / infer / pat.rs
index df438d2ac4c333715818e02554f1d3315448b47b..9821815ca33c3f28d59472f734d0a1f6f4266798 100644 (file)
@@ -1,20 +1,22 @@
 //! Type inference for patterns.
 
-use std::iter::repeat;
-use std::sync::Arc;
+use std::{iter::repeat, sync::Arc};
 
 use chalk_ir::Mutability;
 use hir_def::{
     expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
     path::Path,
+    type_ref::ConstScalar,
 };
 use hir_expand::name::Name;
 
-use super::{BindingMode, Expectation, InferenceContext, TypeMismatch};
 use crate::{
-    infer::{Adjust, Adjustment, AutoBorrow},
+    infer::{
+        Adjust, Adjustment, AutoBorrow, BindingMode, Expectation, InferenceContext, TypeMismatch,
+    },
     lower::lower_to_chalk_mutability,
-    static_lifetime, Interner, Substitution, Ty, TyBuilder, TyExt, TyKind,
+    static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
+    TyKind,
 };
 
 impl<'a> InferenceContext<'a> {
@@ -35,7 +37,7 @@ fn infer_tuple_struct_pat(
         self.unify(&ty, expected);
 
         let substs =
-            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
+            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
 
         let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
         let (pre, post) = match ellipsis {
@@ -51,7 +53,7 @@ fn infer_tuple_struct_pat(
                 .as_ref()
                 .and_then(|d| d.field(&Name::new_tuple_field(i)))
                 .map_or(self.err_ty(), |field| {
-                    field_tys[field].clone().substitute(&Interner, &substs)
+                    field_tys[field].clone().substitute(Interner, &substs)
                 });
             let expected_ty = self.normalize_associated_types_in(expected_ty);
             self.infer_pat(subpat, &expected_ty, default_bm);
@@ -77,13 +79,13 @@ fn infer_record_pat(
         self.unify(&ty, expected);
 
         let substs =
-            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
+            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
 
         let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
         for subpat in subpats {
             let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
             let expected_ty = matching_field.map_or(self.err_ty(), |field| {
-                field_tys[field].clone().substitute(&Interner, &substs)
+                field_tys[field].clone().substitute(Interner, &substs)
             });
             let expected_ty = self.normalize_associated_types_in(expected_ty);
             self.infer_pat(subpat.pat, &expected_ty, default_bm);
@@ -134,7 +136,7 @@ pub(super) fn infer_pat(
         let ty = match &body[pat] {
             Pat::Tuple { args, ellipsis } => {
                 let expectations = match expected.as_tuple() {
-                    Some(parameters) => &*parameters.as_slice(&Interner),
+                    Some(parameters) => &*parameters.as_slice(Interner),
                     _ => &[],
                 };
 
@@ -146,7 +148,7 @@ pub(super) fn infer_pat(
                 };
                 let err_ty = self.err_ty();
                 let mut expectations_iter =
-                    expectations.iter().map(|a| a.assert_ty_ref(&Interner)).chain(repeat(&err_ty));
+                    expectations.iter().map(|a| a.assert_ty_ref(Interner)).chain(repeat(&err_ty));
                 let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
 
                 let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
@@ -154,8 +156,8 @@ pub(super) fn infer_pat(
                 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
                 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
 
-                TyKind::Tuple(inner_tys.len(), Substitution::from_iter(&Interner, inner_tys))
-                    .intern(&Interner)
+                TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
+                    .intern(Interner)
             }
             Pat::Or(pats) => {
                 if let Some((first_pat, rest)) = pats.split_first() {
@@ -180,7 +182,7 @@ pub(super) fn infer_pat(
                     _ => self.result.standard_types.unknown.clone(),
                 };
                 let subty = self.infer_pat(*pat, &expectation, default_bm);
-                TyKind::Ref(mutability, static_lifetime(), subty).intern(&Interner)
+                TyKind::Ref(mutability, static_lifetime(), subty).intern(Interner)
             }
             Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
                 p.as_deref(),
@@ -204,17 +206,18 @@ pub(super) fn infer_pat(
                 } else {
                     BindingMode::convert(*mode)
                 };
-                let inner_ty = if let Some(subpat) = subpat {
-                    self.infer_pat(*subpat, &expected, default_bm)
-                } else {
-                    expected
+                self.result.pat_binding_modes.insert(pat, mode);
+
+                let inner_ty = match subpat {
+                    Some(subpat) => self.infer_pat(*subpat, &expected, default_bm),
+                    None => expected,
                 };
                 let inner_ty = self.insert_type_vars_shallow(inner_ty);
 
                 let bound_ty = match mode {
                     BindingMode::Ref(mutability) => {
                         TyKind::Ref(mutability, static_lifetime(), inner_ty.clone())
-                            .intern(&Interner)
+                            .intern(Interner)
                     }
                     BindingMode::Move => inner_ty.clone(),
                 };
@@ -222,39 +225,50 @@ pub(super) fn infer_pat(
                 return inner_ty;
             }
             Pat::Slice { prefix, slice, suffix } => {
-                let elem_ty = match expected.kind(&Interner) {
+                let elem_ty = match expected.kind(Interner) {
                     TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
                     _ => self.err_ty(),
                 };
 
-                for pat_id in prefix.iter().chain(suffix) {
-                    self.infer_pat(*pat_id, &elem_ty, default_bm);
+                for &pat_id in prefix.iter().chain(suffix.iter()) {
+                    self.infer_pat(pat_id, &elem_ty, default_bm);
+                }
+
+                if let &Some(slice_pat_id) = slice {
+                    let rest_pat_ty = match expected.kind(Interner) {
+                        TyKind::Array(_, length) => {
+                            let length = match length.data(Interner).value {
+                                ConstValue::Concrete(ConcreteConst {
+                                    interned: ConstScalar::Usize(length),
+                                }) => length.checked_sub((prefix.len() + suffix.len()) as u64),
+                                _ => None,
+                            };
+                            TyKind::Array(elem_ty.clone(), crate::consteval::usize_const(length))
+                        }
+                        _ => TyKind::Slice(elem_ty.clone()),
+                    }
+                    .intern(Interner);
+                    self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm);
                 }
 
-                let pat_ty = match expected.kind(&Interner) {
+                match expected.kind(Interner) {
                     TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()),
                     _ => TyKind::Slice(elem_ty),
                 }
-                .intern(&Interner);
-                if let Some(slice_pat_id) = slice {
-                    self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
-                }
-
-                pat_ty
+                .intern(Interner)
             }
             Pat::Wild => expected.clone(),
             Pat::Range { start, end } => {
                 let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone()));
-                let end_ty = self.infer_expr(*end, &Expectation::has_type(start_ty));
-                end_ty
+                self.infer_expr(*end, &Expectation::has_type(start_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_ty, alloc_ty) = match expected.as_adt() {
                         Some((adt, subst)) if adt == box_adt => (
-                            subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
-                            subst.as_slice(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
+                            subst.at(Interner, 0).assert_ty_ref(Interner).clone(),
+                            subst.as_slice(Interner).get(1).and_then(|a| a.ty(Interner).cloned()),
                         ),
                         _ => (self.result.standard_types.unknown.clone(), None),
                     };
@@ -297,10 +311,7 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
         // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
         Pat::Path(..) => true,
         Pat::ConstBlock(..) => true,
-        Pat::Lit(expr) => match body[*expr] {
-            Expr::Literal(Literal::String(..)) => false,
-            _ => true,
-        },
+        Pat::Lit(expr) => !matches!(body[*expr], Expr::Literal(Literal::String(..))),
         Pat::Bind {
             mode: BindingAnnotation::Mutable | BindingAnnotation::Unannotated,
             subpat: Some(subpat),