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