1use std::sync::Arc;
2
3use rustc_ast::ptr::P;
4use rustc_ast::*;
5use rustc_data_structures::stack::ensure_sufficient_stack;
6use rustc_hir::def::{DefKind, Res};
7use rustc_hir::{self as hir, LangItem};
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::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);
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 matches!(
110 etc,
111 ast::PatFieldsRest::Rest | ast::PatFieldsRest::Recovered(_)
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, mutbl) => {
126 break hir::PatKind::Ref(self.lower_pat(inner), *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, cond) => {
136 break hir::PatKind::Guard(self.lower_pat(inner), self.lower_expr(cond));
137 }
138 PatKind::Slice(pats) => break self.lower_pat_slice(pats),
139 PatKind::Rest => {
140 break self.ban_illegal_rest_pat(pattern.span);
142 }
143 PatKind::Paren(inner) => pattern = inner,
145 PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
146 PatKind::Err(guar) => break hir::PatKind::Err(*guar),
147 }
148 };
149
150 self.pat_with_node_id_of(pattern, node, pat_hir_id)
151 })
152 }
153
154 fn lower_pat_tuple(
155 &mut self,
156 pats: &[P<Pat>],
157 ctx: &str,
158 ) -> (&'hir [hir::Pat<'hir>], hir::DotDotPos) {
159 let mut elems = Vec::with_capacity(pats.len());
160 let mut rest = None;
161
162 let mut iter = pats.iter().enumerate();
163 for (idx, pat) in iter.by_ref() {
164 match &pat.kind {
169 PatKind::Rest => {
171 rest = Some((idx, pat.span));
172 break;
173 }
174 PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
177 let sp = pat.span;
178 self.dcx().emit_err(SubTupleBinding {
179 span: sp,
180 ident_name: ident.name,
181 ident: *ident,
182 ctx,
183 });
184 }
185 _ => {}
186 }
187
188 elems.push(self.lower_pat_mut(pat));
190 }
191
192 for (_, pat) in iter {
193 if pat.is_rest() {
195 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
197 } else {
198 elems.push(self.lower_pat_mut(pat));
199 }
200 }
201
202 (self.arena.alloc_from_iter(elems), hir::DotDotPos::new(rest.map(|(ddpos, _)| ddpos)))
203 }
204
205 fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
212 let mut before = Vec::new();
213 let mut after = Vec::new();
214 let mut slice = None;
215 let mut prev_rest_span = None;
216
217 let lower_rest_sub = |this: &mut Self, pat: &Pat, &ann, &ident, sub: &Pat| {
219 let sub_hir_id = this.lower_node_id(sub.id);
220 let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub, sub_hir_id));
221 let pat_hir_id = this.lower_node_id(pat.id);
222 let node = this.lower_pat_ident(pat, ann, ident, pat_hir_id, lower_sub);
223 this.pat_with_node_id_of(pat, node, pat_hir_id)
224 };
225
226 let mut iter = pats.iter();
227 for pat in iter.by_ref() {
229 match &pat.kind {
230 PatKind::Rest => {
232 prev_rest_span = Some(pat.span);
233 let hir_id = self.lower_node_id(pat.id);
234 slice = Some(self.pat_wild_with_node_id_of(pat, hir_id));
235 break;
236 }
237 PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
240 prev_rest_span = Some(sub.span);
241 slice = Some(self.arena.alloc(lower_rest_sub(self, pat, ann, ident, sub)));
242 break;
243 }
244 _ => before.push(self.lower_pat_mut(pat)),
246 }
247 }
248
249 for pat in iter {
251 let rest_span = match &pat.kind {
253 PatKind::Rest => Some(pat.span),
254 PatKind::Ident(ann, ident, Some(sub)) if sub.is_rest() => {
255 after.push(lower_rest_sub(self, pat, ann, ident, sub));
257 Some(sub.span)
258 }
259 _ => None,
260 };
261 if let Some(rest_span) = rest_span {
262 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
264 } else {
265 after.push(self.lower_pat_mut(pat));
267 }
268 }
269
270 hir::PatKind::Slice(
271 self.arena.alloc_from_iter(before),
272 slice,
273 self.arena.alloc_from_iter(after),
274 )
275 }
276
277 fn lower_pat_ident(
278 &mut self,
279 p: &Pat,
280 annotation: BindingMode,
281 ident: Ident,
282 hir_id: hir::HirId,
283 lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
284 ) -> hir::PatKind<'hir> {
285 match self.resolver.get_partial_res(p.id).map(|d| d.expect_full_res()) {
286 res @ (None | Some(Res::Local(_))) => {
288 let binding_id = match res {
289 Some(Res::Local(id)) => {
290 if id == p.id {
294 self.ident_and_label_to_local_id.insert(id, hir_id.local_id);
295 hir_id
296 } else {
297 hir::HirId {
298 owner: self.current_hir_id_owner,
299 local_id: self.ident_and_label_to_local_id[&id],
300 }
301 }
302 }
303 _ => {
304 self.ident_and_label_to_local_id.insert(p.id, hir_id.local_id);
305 hir_id
306 }
307 };
308 hir::PatKind::Binding(
309 annotation,
310 binding_id,
311 self.lower_ident(ident),
312 lower_sub(self),
313 )
314 }
315 Some(res) => {
316 let res = self.lower_res(res);
317 let span = self.lower_span(ident.span);
318 hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
319 kind: hir::PatExprKind::Path(hir::QPath::Resolved(
320 None,
321 self.arena.alloc(hir::Path {
322 span,
323 res,
324 segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
325 }),
326 )),
327 hir_id: self.next_id(),
328 span,
329 }))
330 }
331 }
332 }
333
334 fn pat_wild_with_node_id_of(&mut self, p: &Pat, hir_id: hir::HirId) -> &'hir hir::Pat<'hir> {
335 self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild, hir_id))
336 }
337
338 fn pat_with_node_id_of(
340 &mut self,
341 p: &Pat,
342 kind: hir::PatKind<'hir>,
343 hir_id: hir::HirId,
344 ) -> hir::Pat<'hir> {
345 hir::Pat { hir_id, kind, span: self.lower_span(p.span), default_binding_modes: true }
346 }
347
348 pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
350 self.dcx().emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
351 }
352
353 fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
355 self.dcx().emit_err(MisplacedDoubleDot { span: sp });
356
357 hir::PatKind::Wild
361 }
362
363 fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
364 match *e {
365 RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
366 RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
368 }
369 }
370
371 fn lower_expr_within_pat(
387 &mut self,
388 expr: &Expr,
389 allow_paths: bool,
390 ) -> &'hir hir::PatExpr<'hir> {
391 let span = self.lower_span(expr.span);
392 let err = |guar| hir::PatExprKind::Lit {
393 lit: self.arena.alloc(respan(span, LitKind::Err(guar))),
394 negated: false,
395 };
396 let kind = match &expr.kind {
397 ExprKind::Lit(lit) => {
398 hir::PatExprKind::Lit { lit: self.lower_lit(lit, span), negated: false }
399 }
400 ExprKind::ConstBlock(c) => hir::PatExprKind::ConstBlock(self.lower_const_block(c)),
401 ExprKind::IncludedBytes(bytes) => hir::PatExprKind::Lit {
402 lit: self
403 .arena
404 .alloc(respan(span, LitKind::ByteStr(Arc::clone(bytes), StrStyle::Cooked))),
405 negated: false,
406 },
407 ExprKind::Err(guar) => err(*guar),
408 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 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 });
427 err(guar)
428 }
429 };
430 self.arena.alloc(hir::PatExpr { hir_id: self.lower_node_id(expr.id), span, kind })
431 }
432
433 pub(crate) fn lower_ty_pat(
434 &mut self,
435 pattern: &TyPat,
436 base_type: Span,
437 ) -> &'hir hir::TyPat<'hir> {
438 self.arena.alloc(self.lower_ty_pat_mut(pattern, base_type))
439 }
440
441 fn lower_ty_pat_mut(&mut self, pattern: &TyPat, base_type: Span) -> hir::TyPat<'hir> {
442 let pat_hir_id = self.lower_node_id(pattern.id);
444 let node = match &pattern.kind {
445 TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
446 e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
447 self.lower_ty_pat_range_end(
448 hir::LangItem::RangeMin,
449 span.shrink_to_lo(),
450 base_type,
451 )
452 }),
453 e2.as_deref()
454 .map(|e| match end {
455 RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
456 RangeEnd::Excluded => self.lower_excluded_range_end(e),
457 })
458 .unwrap_or_else(|| {
459 self.lower_ty_pat_range_end(
460 hir::LangItem::RangeMax,
461 span.shrink_to_hi(),
462 base_type,
463 )
464 }),
465 ),
466 TyPatKind::Err(guar) => hir::TyPatKind::Err(*guar),
467 };
468
469 hir::TyPat { hir_id: pat_hir_id, kind: node, span: self.lower_span(pattern.span) }
470 }
471
472 fn lower_excluded_range_end(&mut self, e: &AnonConst) -> &'hir hir::ConstArg<'hir> {
475 let span = self.lower_span(e.value.span);
476 let unstable_span = self.mark_span_with_reason(
477 DesugaringKind::PatTyRange,
478 span,
479 Some(Arc::clone(&self.allow_pattern_type)),
480 );
481 let anon_const = self.with_new_scopes(span, |this| {
482 let def_id = this.local_def_id(e.id);
483 let hir_id = this.lower_node_id(e.id);
484 let body = this.lower_body(|this| {
485 let kind = hir::ExprKind::Path(this.make_lang_item_qpath(
487 hir::LangItem::RangeSub,
488 unstable_span,
489 None,
490 ));
491 let fn_def = this.arena.alloc(hir::Expr { hir_id: this.next_id(), kind, span });
492 let args = this.arena.alloc([this.lower_expr_mut(&e.value)]);
493 (
494 &[],
495 hir::Expr {
496 hir_id: this.next_id(),
497 kind: hir::ExprKind::Call(fn_def, args),
498 span,
499 },
500 )
501 });
502 hir::AnonConst { def_id, hir_id, body, span }
503 });
504 self.arena.alloc(hir::ConstArg {
505 hir_id: self.next_id(),
506 kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
507 })
508 }
509
510 fn lower_ty_pat_range_end(
514 &mut self,
515 lang_item: LangItem,
516 span: Span,
517 base_type: Span,
518 ) -> &'hir hir::ConstArg<'hir> {
519 let parent_def_id = self.current_hir_id_owner.def_id;
520 let node_id = self.next_node_id();
521
522 let def_id = self.create_def(parent_def_id, node_id, None, DefKind::AnonConst, span);
527 let hir_id = self.lower_node_id(node_id);
528
529 let unstable_span = self.mark_span_with_reason(
530 DesugaringKind::PatTyRange,
531 self.lower_span(span),
532 Some(Arc::clone(&self.allow_pattern_type)),
533 );
534 let span = self.lower_span(base_type);
535
536 let path_expr = hir::Expr {
537 hir_id: self.next_id(),
538 kind: hir::ExprKind::Path(self.make_lang_item_qpath(lang_item, unstable_span, None)),
539 span,
540 };
541
542 let ct = self.with_new_scopes(span, |this| {
543 self.arena.alloc(hir::AnonConst {
544 def_id,
545 hir_id,
546 body: this.lower_body(|_this| (&[], path_expr)),
547 span,
548 })
549 });
550 let hir_id = self.next_id();
551 self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
552 }
553}