1use std::sync::Arc;
2
3use rustc_ast::*;
4use rustc_data_structures::stack::ensure_sufficient_stack;
5use rustc_hir::def::{DefKind, Res};
6use rustc_hir::{self as hir, LangItem, Target};
7use rustc_middle::span_bug;
8use rustc_span::{DesugaringKind, Ident, Span, Spanned, respan};
9
10use super::errors::{
11 ArbitraryExpressionInPattern, ExtraDoubleDot, MisplacedDoubleDot, SubTupleBinding,
12};
13use super::{ImplTraitContext, LoweringContext, ParamMode, ResolverAstLoweringExt};
14use crate::{AllowReturnTypeNotation, ImplTraitPosition};
15
16impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
17 pub(crate) fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
18 self.arena.alloc(self.lower_pat_mut(pattern))
19 }
20
21 fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
22 ensure_sufficient_stack(|| {
23 let pat_hir_id = self.lower_node_id(pattern.id);
25 let node = loop {
26 match &pattern.kind {
27 PatKind::Missing => break hir::PatKind::Missing,
28 PatKind::Wild => break hir::PatKind::Wild,
29 PatKind::Never => break hir::PatKind::Never,
30 PatKind::Ident(binding_mode, ident, sub) => {
31 let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(s));
32 break self.lower_pat_ident(
33 pattern,
34 *binding_mode,
35 *ident,
36 pat_hir_id,
37 lower_sub,
38 );
39 }
40 PatKind::Expr(e) => {
41 break hir::PatKind::Expr(self.lower_expr_within_pat(e, false));
42 }
43 PatKind::TupleStruct(qself, path, pats) => {
44 let qpath = self.lower_qpath(
45 pattern.id,
46 qself,
47 path,
48 ParamMode::Optional,
49 AllowReturnTypeNotation::No,
50 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
51 None,
52 );
53 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
54 break hir::PatKind::TupleStruct(qpath, pats, ddpos);
55 }
56 PatKind::Or(pats) => {
57 break hir::PatKind::Or(
58 self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
59 );
60 }
61 PatKind::Path(qself, path) => {
62 let qpath = self.lower_qpath(
63 pattern.id,
64 qself,
65 path,
66 ParamMode::Optional,
67 AllowReturnTypeNotation::No,
68 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
69 None,
70 );
71 let kind = hir::PatExprKind::Path(qpath);
72 let span = self.lower_span(pattern.span);
73 let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind };
74 let expr = self.arena.alloc(expr);
75 return hir::Pat {
76 hir_id: self.next_id(),
77 kind: hir::PatKind::Expr(expr),
78 span,
79 default_binding_modes: true,
80 };
81 }
82 PatKind::Struct(qself, path, fields, etc) => {
83 let qpath = self.lower_qpath(
84 pattern.id,
85 qself,
86 path,
87 ParamMode::Optional,
88 AllowReturnTypeNotation::No,
89 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
90 None,
91 );
92
93 let fs = self.arena.alloc_from_iter(fields.iter().map(|f| {
94 let hir_id = self.lower_node_id(f.id);
95 self.lower_attrs(hir_id, &f.attrs, f.span, Target::PatField);
96
97 hir::PatField {
98 hir_id,
99 ident: self.lower_ident(f.ident),
100 pat: self.lower_pat(&f.pat),
101 is_shorthand: f.is_shorthand,
102 span: self.lower_span(f.span),
103 }
104 }));
105 break hir::PatKind::Struct(
106 qpath,
107 fs,
108 match etc {
109 ast::PatFieldsRest::Rest(sp) => Some(self.lower_span(*sp)),
110 ast::PatFieldsRest::Recovered(_) => Some(Span::default()),
111 _ => None,
112 },
113 );
114 }
115 PatKind::Tuple(pats) => {
116 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
117 break hir::PatKind::Tuple(pats, ddpos);
118 }
119 PatKind::Box(inner) => {
120 break hir::PatKind::Box(self.lower_pat(inner));
121 }
122 PatKind::Deref(inner) => {
123 break hir::PatKind::Deref(self.lower_pat(inner));
124 }
125 PatKind::Ref(inner, pinned, mutbl) => {
126 break hir::PatKind::Ref(self.lower_pat(inner), *pinned, *mutbl);
127 }
128 PatKind::Range(e1, e2, Spanned { node: end, .. }) => {
129 break hir::PatKind::Range(
130 e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
131 e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
132 self.lower_range_end(end, e2.is_some()),
133 );
134 }
135 PatKind::Guard(inner, guard) => {
136 break hir::PatKind::Guard(
137 self.lower_pat(inner),
138 self.lower_expr(&guard.cond),
139 );
140 }
141 PatKind::Slice(pats) => break self.lower_pat_slice(pats),
142 PatKind::Rest => {
143 break self.ban_illegal_rest_pat(pattern.span);
145 }
146 PatKind::Paren(inner) => pattern = inner,
148 PatKind::MacCall(_) => {
149 {
::core::panicking::panic_fmt(format_args!("{0:#?} shouldn\'t exist here",
pattern));
}panic!("{pattern:#?} shouldn't exist here")
150 }
151 PatKind::Err(guar) => break hir::PatKind::Err(*guar),
152 }
153 };
154
155 self.pat_with_node_id_of(pattern, node, pat_hir_id)
156 })
157 }
158
159 fn lower_pat_tuple(
160 &mut self,
161 pats: &[Pat],
162 ctx: &str,
163 ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
164 let mut elems = Vec::with_capacity(pats.len());
165 let mut rest = None;
166
167 let mut iter = pats.iter().enumerate();
168 for (idx, pat) in iter.by_ref() {
169 match &pat.kind {
174 PatKind::Rest => {
176 rest = Some((idx, pat.span));
177 break;
178 }
179 PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
182 let sp = pat.span;
183 self.dcx().emit_err(SubTupleBinding {
184 span: sp,
185 ident_name: ident.name,
186 ident: *ident,
187 ctx,
188 });
189 }
190 _ => {}
191 }
192
193 elems.push(self.lower_pat_mut(pat));
195 }
196
197 for (_, pat) in iter {
198 if pat.is_rest() {
200 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
202 } else {
203 elems.push(self.lower_pat_mut(pat));
204 }
205 }
206
207 (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
208 }
209
210 fn lower_pat_slice(&mut self, pats: &[Pat]) -> hir::PatKind<'hir> {
217 let mut before = Vec::new();
218 let mut after = Vec::new();
219 let mut slice = None;
220 let mut prev_rest_span = None;
221
222 let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| {
224 let sub_hir_id = this.lower_node_id(sub.id);
225 let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id));
226 let pat_hir_id = this.lower_node_id(pat.id);
227 let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub);
228 this.pat_with_node_id_of(pat, node, pat_hir_id)
229 };
230
231 let mut iter = pats.iter();
232 for pat in iter.by_ref() {
234 match &pat.kind {
235 PatKind::Rest => {
237 prev_rest_span = Some(pat.span);
238 let hir_id = self.lower_node_id(pat.id);
239 slice = Some(self.pat_wild_with_node_id_of(pat, hir_id));
240 break;
241 }
242 PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
245 prev_rest_span = Some(sub.span);
246 slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
247 break;
248 }
249 _ => before.push(self.lower_pat_mut(pat)),
251 }
252 }
253
254 for pat in iter {
256 let rest_span = match &pat.kind {
258 PatKind::Rest => Some(pat.span),
259 PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
260 after.push(lower_rest_sub(self, pat, ann, ident, sub));
262 Some(sub.span)
263 }
264 _ => None,
265 };
266 if let Some(rest_span) = rest_span {
267 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
269 } else {
270 after.push(self.lower_pat_mut(pat));
272 }
273 }
274
275 hir::PatKind::Slice(
276 self.arena.alloc_from_iter(before),
277 slice,
278 self.arena.alloc_from_iter(after),
279 )
280 }
281
282 fn lower_pat_ident(
283 &mut self,
284 p: &Pat,
285 annotation: BindingMode,
286 ident: Ident,
287 hir_id: hir::HirId,
288 lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
289 ) -> hir::PatKind<'hir> {
290 match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
291 res @ (None | Some(Res::Local(_))) => {
293 let binding_id = match res {
294 Some(Res::Local(id)) => {
295 if id == p.id {
299 self.ident_and_label_to_local_id.insert(id, hir_id.local_id);
300 hir_id
301 } else {
302 hir::HirId {
303 owner: self.current_hir_id_owner,
304 local_id: self.ident_and_label_to_local_id[&id],
305 }
306 }
307 }
308 _ => {
309 self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id);
310 hir_id
311 }
312 };
313 hir::PatKind::Binding(
314 annotation,
315 binding_id,
316 self.lower_ident(ident),
317 lower_sub(self),
318 )
319 }
320 Some(res) => {
321 let res = self.lower_res(res);
322 let span = self.lower_span(ident.span);
323 hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
324 kind: hir::PatExprKind::Path(hir::QPath::Resolved(
325 None,
326 self.arena.alloc(hir::Path {
327 span,
328 res,
329 segments: self.arena.alloc_from_iter([hir::PathSegment::new(self.lower_ident(ident),
self.next_id(), res)])arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
330 }),
331 )),
332 hir_id: self.next_id(),
333 span,
334 }))
335 }
336 }
337 }
338
339 fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> {
340 self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id))
341 }
342
343 fn pat_with_node_id_of(
345 &mut self,
346 p: &Pat,
347 kind: hir::PatKind<'hir>,
348 hir_id: hir::HirId,
349 ) -> hir::Pat<'hir> {
350 hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true }
351 }
352
353 pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
355 self.dcx().emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
356 }
357
358 fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
360 self.dcx().emit_err(MisplacedDoubleDot { span: sp });
361
362 hir::PatKind::Wild
366 }
367
368 fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
369 match *e {
370 RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
371 RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
373 }
374 }
375
376 fn lower_expr_within_pat(
392 &mut self,
393 expr: &Expr,
394 allow_paths: bool,
395 ) -> &'hir hir::PatExpr<'hir> {
396 let span = self.lower_span(expr.span);
397 let err =
398 |guar| hir::PatExprKind::Lit { lit: respan(span, LitKind::Err(guar)), negated: false };
399 let kind = match &expr.kind {
400 ExprKind::Lit(lit) => {
401 hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
402 }
403 ExprKind::IncludedBytes(byte_sym) => hir::PatExprKind::Lit {
404 lit: respan(span, LitKind::ByteStr(*byte_sym, StrStyle::Cooked)),
405 negated: false,
406 },
407 ExprKind::Err(guar) => err(*guar),
408 ExprKind::Dummy => ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("lowered ExprKind::Dummy"))span_bug!(span, "lowered ExprKind::Dummy"),
409 ExprKind::Path(qself, path) if allow_paths => hir::PatExprKind::Path(self.lower_qpath(
410 expr.id,
411 qself,
412 path,
413 ParamMode::Optional,
414 AllowReturnTypeNotation::No,
415 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
416 None,
417 )),
418 ExprKind::Unary(UnOp::Neg, inner) if let ExprKind::Lit(lit) = &inner.kind => {
419 hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: true }
420 }
421 _ => {
422 let is_const_block = #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::ConstBlock(_) => true,
_ => false,
}matches!(expr.kind, ExprKind::ConstBlock(_));
423 let pattern_from_macro = expr.is_approximately_pattern()
424 || #[allow(non_exhaustive_omitted_patterns)] match expr.peel_parens().kind {
ExprKind::Binary(Spanned { node: BinOpKind::BitOr, .. }, ..) => true,
_ => false,
}matches!(
425 expr.peel_parens().kind,
426 ExprKind::Binary(Spanned { node: BinOpKind::BitOr, .. }, ..)
427 );
428 let guar = self.dcx().emit_err(ArbitraryExpressionInPattern {
429 span,
430 pattern_from_macro_note: pattern_from_macro,
431 const_block_in_pattern_help: is_const_block,
432 });
433 err(guar)
434 }
435 };
436 self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
437 }
438
439 pub(crate) fn lower_ty_pat(
440 &mut self,
441 pattern: &TyPat,
442 base_type: Span,
443 ) -> &'hir hir::TyPat<'hir> {
444 self.arena.alloc(self.lower_ty_pat_mut(pattern, base_type))
445 }
446
447 fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'hir> {
448 let pat_hir_id = self.lower_node_id(pattern.id);
450 let node = match &pattern.kind {
451 TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
452 e1.as_deref()
453 .map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
454 .unwrap_or_else(|| {
455 self.lower_ty_pat_range_end(
456 hir::LangItem::RangeMin,
457 span.shrink_to_lo(),
458 base_type,
459 )
460 }),
461 e2.as_deref()
462 .map(|e| match end {
463 RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
464 RangeEnd::Excluded => self.lower_excluded_range_end(e),
465 })
466 .unwrap_or_else(|| {
467 self.lower_ty_pat_range_end(
468 hir::LangItem::RangeMax,
469 span.shrink_to_hi(),
470 base_type,
471 )
472 }),
473 ),
474 TyPatKind::NotNull => hir::TyPatKind::NotNull,
475 TyPatKind::Or(variants) => {
476 hir::TyPatKind::Or(self.arena.alloc_from_iter(
477 variants.iter().map(|pat| self.lower_ty_pat_mut(pat, base_type)),
478 ))
479 }
480 TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar),
481 };
482
483 hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) }
484 }
485
486 fn lower_excluded_range_end(&mut self, e: &AnonConst) -> &'hir hir::ConstArg<'hir> {
489 let span = self.lower_span(e.value.span);
490 let unstable_span = self.mark_span_with_reason(
491 DesugaringKind::PatTyRange,
492 span,
493 Some(Arc::clone(&self.allow_pattern_type)),
494 );
495 let anon_const = self.with_new_scopes(span, |this| {
496 let def_id = this.local_def_id(e.id);
497 let hir_id = this.lower_node_id(e.id);
498 let body = this.lower_body(|this| {
499 let kind = hir::ExprKind::Path(this.make_lang_item_qpath(
501 hir::LangItem::RangeSub,
502 unstable_span,
503 None,
504 ));
505 let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span });
506 let args = this.arena.alloc([this.lower_expr_mut(&e.value)]);
507 (
508 &[],
509 hir::Expr {
510 hir_id: this.next_id(),
511 kind: hir::ExprKind::Call(fn_def, args),
512 span,
513 },
514 )
515 });
516 hir::AnonConst { def_id, hir_id, body, span }
517 });
518 self.arena.alloc(hir::ConstArg {
519 hir_id: self.next_id(),
520 kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
521 span,
522 })
523 }
524
525 fn lower_ty_pat_range_end(
529 &mut self,
530 lang_item: LangItem,
531 span: Span,
532 base_type: Span,
533 ) -> &'hir hir::ConstArg<'hir> {
534 let node_id = self.next_node_id();
535
536 let def_id = self.create_def(node_id, None, DefKind::AnonConst, span);
541 let hir_id = self.lower_node_id(node_id);
542
543 let unstable_span = self.mark_span_with_reason(
544 DesugaringKind::PatTyRange,
545 self.lower_span(span),
546 Some(Arc::clone(&self.allow_pattern_type)),
547 );
548 let span = self.lower_span(base_type);
549
550 let path_expr = hir::Expr {
551 hir_id: self.next_id(),
552 kind: hir::ExprKind::Path(self.make_lang_item_qpath(lang_item, unstable_span, None)),
553 span,
554 };
555
556 let ct = self.with_new_scopes(span, |this| {
557 self.arena.alloc(hir::AnonConst {
558 def_id,
559 hir_id,
560 body: this.lower_body(|_this| (&[], path_expr)),
561 span,
562 })
563 });
564 let hir_id = self.next_id();
565 self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
566 }
567}