]> git.lizzy.rs Git - rust.git/blob - crates/hir_ty/src/infer/pat.rs
Implement const pat inference
[rust.git] / crates / hir_ty / src / infer / pat.rs
1 //! Type inference for patterns.
2
3 use std::iter::repeat;
4 use std::sync::Arc;
5
6 use hir_def::{
7     expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
8     path::Path,
9     type_ref::Mutability,
10     FieldId,
11 };
12 use hir_expand::name::Name;
13 use test_utils::mark;
14
15 use super::{BindingMode, Expectation, InferenceContext};
16 use crate::{utils::variant_data, Substs, Ty, TypeCtor};
17
18 impl<'a> InferenceContext<'a> {
19     fn infer_tuple_struct_pat(
20         &mut self,
21         path: Option<&Path>,
22         subpats: &[PatId],
23         expected: &Ty,
24         default_bm: BindingMode,
25         id: PatId,
26         ellipsis: Option<usize>,
27     ) -> Ty {
28         let (ty, def) = self.resolve_variant(path);
29         let var_data = def.map(|it| variant_data(self.db.upcast(), it));
30         if let Some(variant) = def {
31             self.write_variant_resolution(id.into(), variant);
32         }
33         self.unify(&ty, expected);
34
35         let substs = ty.substs().unwrap_or_else(Substs::empty);
36
37         let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
38         let (pre, post) = match ellipsis {
39             Some(idx) => subpats.split_at(idx),
40             None => (&subpats[..], &[][..]),
41         };
42         let post_idx_offset = field_tys.iter().count() - post.len();
43
44         let pre_iter = pre.iter().enumerate();
45         let post_iter = (post_idx_offset..).zip(post.iter());
46         for (i, &subpat) in pre_iter.chain(post_iter) {
47             let expected_ty = var_data
48                 .as_ref()
49                 .and_then(|d| d.field(&Name::new_tuple_field(i)))
50                 .map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
51             let expected_ty = self.normalize_associated_types_in(expected_ty);
52             self.infer_pat(subpat, &expected_ty, default_bm);
53         }
54
55         ty
56     }
57
58     fn infer_record_pat(
59         &mut self,
60         path: Option<&Path>,
61         subpats: &[RecordFieldPat],
62         expected: &Ty,
63         default_bm: BindingMode,
64         id: PatId,
65     ) -> Ty {
66         let (ty, def) = self.resolve_variant(path);
67         let var_data = def.map(|it| variant_data(self.db.upcast(), it));
68         if let Some(variant) = def {
69             self.write_variant_resolution(id.into(), variant);
70         }
71
72         self.unify(&ty, expected);
73
74         let substs = ty.substs().unwrap_or_else(Substs::empty);
75
76         let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
77         for subpat in subpats {
78             let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
79             if let Some(local_id) = matching_field {
80                 let field_def = FieldId { parent: def.unwrap(), local_id };
81                 self.result.record_pat_field_resolutions.insert(subpat.pat, field_def);
82             }
83
84             let expected_ty =
85                 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
86             let expected_ty = self.normalize_associated_types_in(expected_ty);
87             self.infer_pat(subpat.pat, &expected_ty, default_bm);
88         }
89
90         ty
91     }
92
93     pub(super) fn infer_pat(
94         &mut self,
95         pat: PatId,
96         mut expected: &Ty,
97         mut default_bm: BindingMode,
98     ) -> Ty {
99         let body = Arc::clone(&self.body); // avoid borrow checker problem
100
101         if is_non_ref_pat(&body, pat) {
102             while let Some((inner, mutability)) = expected.as_reference() {
103                 expected = inner;
104                 default_bm = match default_bm {
105                     BindingMode::Move => BindingMode::Ref(mutability),
106                     BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
107                     BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
108                 }
109             }
110         } else if let Pat::Ref { .. } = &body[pat] {
111             mark::hit!(match_ergonomics_ref);
112             // When you encounter a `&pat` pattern, reset to Move.
113             // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
114             default_bm = BindingMode::Move;
115         }
116
117         // Lose mutability.
118         let default_bm = default_bm;
119         let expected = expected;
120
121         let ty = match &body[pat] {
122             &Pat::Tuple { ref args, ellipsis } => {
123                 let expectations = match expected.as_tuple() {
124                     Some(parameters) => &*parameters.0,
125                     _ => &[],
126                 };
127
128                 let (pre, post) = match ellipsis {
129                     Some(idx) => args.split_at(idx),
130                     None => (&args[..], &[][..]),
131                 };
132                 let n_uncovered_patterns = expectations.len().saturating_sub(args.len());
133                 let mut expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
134                 let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
135
136                 let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
137                 inner_tys.extend(pre.iter().zip(expectations_iter.by_ref()).map(&mut infer_pat));
138                 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
139                 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
140
141                 Ty::apply(
142                     TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
143                     Substs(inner_tys.into()),
144                 )
145             }
146             Pat::Or(ref pats) => {
147                 if let Some((first_pat, rest)) = pats.split_first() {
148                     let ty = self.infer_pat(*first_pat, expected, default_bm);
149                     for pat in rest {
150                         self.infer_pat(*pat, expected, default_bm);
151                     }
152                     ty
153                 } else {
154                     Ty::Unknown
155                 }
156             }
157             Pat::Ref { pat, mutability } => {
158                 let expectation = match expected.as_reference() {
159                     Some((inner_ty, exp_mut)) => {
160                         if *mutability != exp_mut {
161                             // FIXME: emit type error?
162                         }
163                         inner_ty
164                     }
165                     _ => &Ty::Unknown,
166                 };
167                 let subty = self.infer_pat(*pat, expectation, default_bm);
168                 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
169             }
170             Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
171                 p.as_ref(),
172                 subpats,
173                 expected,
174                 default_bm,
175                 pat,
176                 *ellipsis,
177             ),
178             Pat::Record { path: p, args: fields, ellipsis: _ } => {
179                 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
180             }
181             Pat::Path(path) => {
182                 // FIXME use correct resolver for the surrounding expression
183                 let resolver = self.resolver.clone();
184                 self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
185             }
186             Pat::Bind { mode, name: _, subpat } => {
187                 let mode = if mode == &BindingAnnotation::Unannotated {
188                     default_bm
189                 } else {
190                     BindingMode::convert(*mode)
191                 };
192                 let inner_ty = if let Some(subpat) = subpat {
193                     self.infer_pat(*subpat, expected, default_bm)
194                 } else {
195                     expected.clone()
196                 };
197                 let inner_ty = self.insert_type_vars_shallow(inner_ty);
198
199                 let bound_ty = match mode {
200                     BindingMode::Ref(mutability) => {
201                         Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone())
202                     }
203                     BindingMode::Move => inner_ty.clone(),
204                 };
205                 let bound_ty = self.resolve_ty_as_possible(bound_ty);
206                 self.write_pat_ty(pat, bound_ty);
207                 return inner_ty;
208             }
209             Pat::Slice { prefix, slice, suffix } => {
210                 let (container_ty, elem_ty) = match &expected {
211                     ty_app!(TypeCtor::Array, st) => (TypeCtor::Array, st.as_single().clone()),
212                     ty_app!(TypeCtor::Slice, st) => (TypeCtor::Slice, st.as_single().clone()),
213                     _ => (TypeCtor::Slice, Ty::Unknown),
214                 };
215
216                 for pat_id in prefix.iter().chain(suffix) {
217                     self.infer_pat(*pat_id, &elem_ty, default_bm);
218                 }
219
220                 let pat_ty = Ty::apply_one(container_ty, elem_ty);
221                 if let Some(slice_pat_id) = slice {
222                     self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
223                 }
224
225                 pat_ty
226             }
227             Pat::Wild => expected.clone(),
228             Pat::Range { start, end } => {
229                 let start_ty = self.infer_expr(*start, &Expectation::has_type(expected.clone()));
230                 let end_ty = self.infer_expr(*end, &Expectation::has_type(start_ty));
231                 end_ty
232             }
233             Pat::Lit(expr) => self.infer_expr(*expr, &Expectation::has_type(expected.clone())),
234             Pat::Box { inner } => match self.resolve_boxed_box() {
235                 Some(box_adt) => {
236                     let inner_expected = match expected.as_adt() {
237                         Some((adt, substs)) if adt == box_adt => substs.as_single(),
238                         _ => &Ty::Unknown,
239                     };
240
241                     let inner_ty = self.infer_pat(*inner, inner_expected, default_bm);
242                     Ty::apply_one(TypeCtor::Adt(box_adt), inner_ty)
243                 }
244                 None => Ty::Unknown,
245             },
246             Pat::ConstBlock(expr) => {
247                 self.infer_expr(*expr, &Expectation::has_type(expected.clone()))
248             }
249             Pat::Missing => Ty::Unknown,
250         };
251         // use a new type variable if we got Ty::Unknown here
252         let ty = self.insert_type_vars_shallow(ty);
253         if !self.unify(&ty, expected) {
254             // FIXME record mismatch, we need to change the type of self.type_mismatches for that
255         }
256         let ty = self.resolve_ty_as_possible(ty);
257         self.write_pat_ty(pat, ty.clone());
258         ty
259     }
260 }
261
262 fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool {
263     match &body[pat] {
264         Pat::Tuple { .. }
265         | Pat::TupleStruct { .. }
266         | Pat::Record { .. }
267         | Pat::Range { .. }
268         | Pat::Slice { .. } => true,
269         Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)),
270         // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented.
271         Pat::Path(..) => true,
272         Pat::ConstBlock(..) => true,
273         Pat::Lit(expr) => match body[*expr] {
274             Expr::Literal(Literal::String(..)) => false,
275             _ => true,
276         },
277         Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Box { .. } | Pat::Missing => false,
278     }
279 }