1mod pat_util;
9
10pub(crate) mod pat_analysis;
11
12use hir_def::{
13 AdtId, EnumVariantId, LocalFieldId, Lookup, VariantId,
14 expr_store::{Body, path::Path},
15 hir::PatId,
16 item_tree::FieldsShape,
17 signatures::{StructSignature, UnionSignature},
18};
19use hir_expand::name::Name;
20use rustc_type_ir::inherent::IntoKind;
21use span::Edition;
22use stdx::{always, never, variance::PhantomCovariantLifetime};
23
24use crate::{
25 BindingMode, ByRef, InferenceResult,
26 db::HirDatabase,
27 display::{HirDisplay, HirDisplayError, HirFormatter},
28 next_solver::{GenericArgs, Mutability, Ty, TyKind},
29};
30
31use self::pat_util::EnumerateAndAdjustIterator;
32
33#[derive(Clone, Debug)]
34pub(crate) enum PatternError {
35 Unimplemented,
36 UnexpectedType,
37 UnresolvedVariant,
38 MissingField,
39 ExtraFields,
40}
41
42#[derive(Clone, Debug, PartialEq)]
43pub(crate) struct FieldPat<'db> {
44 pub(crate) field: LocalFieldId,
45 pub(crate) pattern: Pat<'db>,
46}
47
48#[derive(Clone, Debug, PartialEq)]
49pub(crate) struct Pat<'db> {
50 pub(crate) ty: Ty<'db>,
51 pub(crate) kind: Box<PatKind<'db>>,
52}
53
54#[derive(Clone, Debug, PartialEq)]
56pub(crate) enum PatKind<'db> {
57 Wild,
58 Never,
59
60 Binding {
62 name: Name,
63 subpattern: Option<Pat<'db>>,
64 },
65
66 Variant {
69 substs: GenericArgs<'db>,
70 enum_variant: EnumVariantId,
71 subpatterns: Vec<FieldPat<'db>>,
72 },
73
74 Leaf {
77 subpatterns: Vec<FieldPat<'db>>,
78 },
79
80 Deref {
82 subpattern: Pat<'db>,
83 },
84
85 LiteralBool {
87 value: bool,
88 },
89
90 Or {
93 pats: Vec<Pat<'db>>,
94 },
95}
96
97pub(crate) struct PatCtxt<'a, 'db> {
98 db: &'db dyn HirDatabase,
99 infer: &'db InferenceResult<'db>,
100 body: &'a Body,
101 pub(crate) errors: Vec<PatternError>,
102}
103
104impl<'a, 'db> PatCtxt<'a, 'db> {
105 pub(crate) fn new(
106 db: &'db dyn HirDatabase,
107 infer: &'db InferenceResult<'db>,
108 body: &'a Body,
109 ) -> Self {
110 Self { db, infer, body, errors: Vec::new() }
111 }
112
113 pub(crate) fn lower_pattern(&mut self, pat: PatId) -> Pat<'db> {
114 let unadjusted_pat = self.lower_pattern_unadjusted(pat);
120 self.infer.pat_adjustments.get(&pat).map(|it| &**it).unwrap_or_default().iter().rev().fold(
121 unadjusted_pat,
122 |subpattern, ref_ty| Pat {
123 ty: ref_ty.source.as_ref(),
124 kind: Box::new(PatKind::Deref { subpattern }),
125 },
126 )
127 }
128
129 fn lower_pattern_unadjusted(&mut self, pat: PatId) -> Pat<'db> {
130 let mut ty = self.infer.pat_ty(pat);
131 let variant = self.infer.variant_resolution_for_pat(pat);
132
133 let kind = match self.body[pat] {
134 hir_def::hir::Pat::Wild => PatKind::Wild,
135
136 hir_def::hir::Pat::Lit(expr) => self.lower_lit(expr),
137
138 hir_def::hir::Pat::Path(ref path) => {
139 return self.lower_path(pat, path);
140 }
141
142 hir_def::hir::Pat::Tuple { ref args, ellipsis } => {
143 let arity = match ty.kind() {
144 TyKind::Tuple(tys) => tys.len(),
145 _ => {
146 never!("unexpected type for tuple pattern: {:?}", ty);
147 self.errors.push(PatternError::UnexpectedType);
148 return Pat { ty, kind: PatKind::Wild.into() };
149 }
150 };
151 let subpatterns = self.lower_tuple_subpats(args, arity, ellipsis);
152 PatKind::Leaf { subpatterns }
153 }
154
155 hir_def::hir::Pat::Bind { id, subpat, .. } => {
156 let bm = self.infer.binding_modes[pat];
157 ty = self.infer.binding_ty(id);
158 let name = &self.body[id].name;
159 match (bm, ty.kind()) {
160 (BindingMode(ByRef::Yes(_), _), TyKind::Ref(_, rty, _)) => ty = rty,
161 (BindingMode(ByRef::Yes(_), _), _) => {
162 never!(
163 "`ref {}` has wrong type {:?}",
164 name.display(self.db, Edition::LATEST),
165 ty
166 );
167 self.errors.push(PatternError::UnexpectedType);
168 return Pat { ty, kind: PatKind::Wild.into() };
169 }
170 _ => (),
171 }
172 PatKind::Binding { name: name.clone(), subpattern: self.lower_opt_pattern(subpat) }
173 }
174
175 hir_def::hir::Pat::TupleStruct { ref args, ellipsis, .. } if variant.is_some() => {
176 let expected_len = variant.unwrap().fields(self.db).fields().len();
177 let subpatterns = self.lower_tuple_subpats(args, expected_len, ellipsis);
178 self.lower_variant_or_leaf(pat, ty, subpatterns)
179 }
180
181 hir_def::hir::Pat::Record { ref args, .. } if variant.is_some() => {
182 let variant_data = variant.unwrap().fields(self.db);
183 let subpatterns = args
184 .iter()
185 .map(|field| {
186 variant_data.field(&field.name).map(|lfield_id| FieldPat {
188 field: lfield_id,
189 pattern: self.lower_pattern(field.pat),
190 })
191 })
192 .collect();
193 match subpatterns {
194 Some(subpatterns) => self.lower_variant_or_leaf(pat, ty, subpatterns),
195 None => {
196 self.errors.push(PatternError::MissingField);
197 PatKind::Wild
198 }
199 }
200 }
201 hir_def::hir::Pat::TupleStruct { .. } | hir_def::hir::Pat::Record { .. } => {
202 self.errors.push(PatternError::UnresolvedVariant);
203 PatKind::Wild
204 }
205
206 hir_def::hir::Pat::Or(ref pats) => PatKind::Or { pats: self.lower_patterns(pats) },
207
208 _ => {
209 self.errors.push(PatternError::Unimplemented);
210 PatKind::Wild
211 }
212 };
213
214 Pat { ty, kind: Box::new(kind) }
215 }
216
217 fn lower_tuple_subpats(
218 &mut self,
219 pats: &[PatId],
220 expected_len: usize,
221 ellipsis: Option<u32>,
222 ) -> Vec<FieldPat<'db>> {
223 if pats.len() > expected_len {
224 self.errors.push(PatternError::ExtraFields);
225 return Vec::new();
226 }
227
228 pats.iter()
229 .enumerate_and_adjust(expected_len, ellipsis.map(|it| it as usize))
230 .map(|(i, &subpattern)| FieldPat {
231 field: LocalFieldId::from_raw((i as u32).into()),
232 pattern: self.lower_pattern(subpattern),
233 })
234 .collect()
235 }
236
237 fn lower_patterns(&mut self, pats: &[PatId]) -> Vec<Pat<'db>> {
238 pats.iter().map(|&p| self.lower_pattern(p)).collect()
239 }
240
241 fn lower_opt_pattern(&mut self, pat: Option<PatId>) -> Option<Pat<'db>> {
242 pat.map(|p| self.lower_pattern(p))
243 }
244
245 fn lower_variant_or_leaf(
246 &mut self,
247 pat: PatId,
248 ty: Ty<'db>,
249 subpatterns: Vec<FieldPat<'db>>,
250 ) -> PatKind<'db> {
251 match self.infer.variant_resolution_for_pat(pat) {
252 Some(variant_id) => {
253 if let VariantId::EnumVariantId(enum_variant) = variant_id {
254 let substs = match ty.kind() {
255 TyKind::Adt(_, substs) => substs,
256 kind => {
257 always!(
258 matches!(kind, TyKind::FnDef(..) | TyKind::Error(_)),
259 "inappropriate type for def: {:?}",
260 ty
261 );
262 self.errors.push(PatternError::UnexpectedType);
263 return PatKind::Wild;
264 }
265 };
266 PatKind::Variant { substs, enum_variant, subpatterns }
267 } else {
268 PatKind::Leaf { subpatterns }
269 }
270 }
271 None => {
272 self.errors.push(PatternError::UnresolvedVariant);
273 PatKind::Wild
274 }
275 }
276 }
277
278 fn lower_path(&mut self, pat: PatId, _path: &Path) -> Pat<'db> {
279 let ty = self.infer.pat_ty(pat);
280
281 let pat_from_kind = |kind| Pat { ty, kind: Box::new(kind) };
282
283 match self.infer.variant_resolution_for_pat(pat) {
284 Some(_) => pat_from_kind(self.lower_variant_or_leaf(pat, ty, Vec::new())),
285 None => {
286 self.errors.push(PatternError::UnresolvedVariant);
287 pat_from_kind(PatKind::Wild)
288 }
289 }
290 }
291
292 fn lower_lit(&mut self, expr: hir_def::hir::ExprId) -> PatKind<'db> {
293 use hir_def::hir::{Expr, Literal::Bool};
294
295 match self.body[expr] {
296 Expr::Literal(Bool(value)) => PatKind::LiteralBool { value },
297 _ => {
298 self.errors.push(PatternError::Unimplemented);
299 PatKind::Wild
300 }
301 }
302 }
303}
304
305impl<'db> HirDisplay<'db> for Pat<'db> {
306 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
307 match &*self.kind {
308 PatKind::Wild => write!(f, "_"),
309 PatKind::Never => write!(f, "!"),
310 PatKind::Binding { name, subpattern } => {
311 write!(f, "{}", name.display(f.db, f.edition()))?;
312 if let Some(subpattern) = subpattern {
313 write!(f, " @ ")?;
314 subpattern.hir_fmt(f)?;
315 }
316 Ok(())
317 }
318 PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
319 let variant = match *self.kind {
320 PatKind::Variant { enum_variant, .. } => Some(VariantId::from(enum_variant)),
321 _ => self.ty.as_adt().and_then(|(adt, _)| match adt {
322 AdtId::StructId(s) => Some(s.into()),
323 AdtId::UnionId(u) => Some(u.into()),
324 AdtId::EnumId(_) => None,
325 }),
326 };
327
328 if let Some(variant) = variant {
329 match variant {
330 VariantId::EnumVariantId(v) => {
331 let loc = v.lookup(f.db);
332 write!(f, "{}", loc.name.display(f.db, f.edition()))?;
333 }
334 VariantId::StructId(s) => write!(
335 f,
336 "{}",
337 StructSignature::of(f.db, s).name.display(f.db, f.edition())
338 )?,
339 VariantId::UnionId(u) => write!(
340 f,
341 "{}",
342 UnionSignature::of(f.db, u).name.display(f.db, f.edition())
343 )?,
344 };
345
346 let variant_data = variant.fields(f.db);
347 if variant_data.shape == FieldsShape::Record {
348 write!(f, " {{ ")?;
349
350 let mut printed = 0;
351 let subpats = subpatterns
352 .iter()
353 .filter(|p| !matches!(*p.pattern.kind, PatKind::Wild))
354 .map(|p| {
355 printed += 1;
356 WriteWith::new(|f| {
357 write!(
358 f,
359 "{}: ",
360 variant_data.fields()[p.field]
361 .name
362 .display(f.db, f.edition())
363 )?;
364 p.pattern.hir_fmt(f)
365 })
366 });
367 f.write_joined(subpats, ", ")?;
368
369 if printed < variant_data.fields().len() {
370 write!(f, "{}..", if printed > 0 { ", " } else { "" })?;
371 }
372
373 return write!(f, " }}");
374 }
375 }
376
377 let num_fields =
378 variant.map_or(subpatterns.len(), |v| v.fields(f.db).fields().len());
379 if num_fields != 0 || variant.is_none() {
380 write!(f, "(")?;
381 let subpats = (0..num_fields).map(|i| {
382 WriteWith::new(move |f| {
383 let fid = LocalFieldId::from_raw((i as u32).into());
384 if let Some(p) = subpatterns.get(i)
385 && p.field == fid
386 {
387 return p.pattern.hir_fmt(f);
388 }
389 if let Some(p) = subpatterns.iter().find(|p| p.field == fid) {
390 p.pattern.hir_fmt(f)
391 } else {
392 write!(f, "_")
393 }
394 })
395 });
396 f.write_joined(subpats, ", ")?;
397 if let (TyKind::Tuple(..), 1) = (self.ty.kind(), num_fields) {
398 write!(f, ",")?;
399 }
400 write!(f, ")")?;
401 }
402
403 Ok(())
404 }
405 PatKind::Deref { subpattern } => {
406 match self.ty.kind() {
407 TyKind::Ref(.., mutbl) => {
408 write!(f, "&{}", if mutbl == Mutability::Mut { "mut " } else { "" })?
409 }
410 _ => never!("{:?} is a bad Deref pattern type", self.ty),
411 }
412 subpattern.hir_fmt(f)
413 }
414 PatKind::LiteralBool { value } => write!(f, "{value}"),
415 PatKind::Or { pats } => f.write_joined(pats.iter(), " | "),
416 }
417 }
418}
419
420struct WriteWith<'db, F>(F, PhantomCovariantLifetime<'db>)
421where
422 F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>;
423
424impl<'db, F> WriteWith<'db, F>
425where
426 F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
427{
428 fn new(f: F) -> Self {
429 Self(f, PhantomCovariantLifetime::new())
430 }
431}
432
433impl<'db, F> HirDisplay<'db> for WriteWith<'db, F>
434where
435 F: Fn(&mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError>,
436{
437 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result<(), HirDisplayError> {
438 (self.0)(f)
439 }
440}