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