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