]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_ast_lowering/src/pat.rs
New upstream version 1.60.0+dfsg1
[rustc.git] / compiler / rustc_ast_lowering / src / pat.rs
CommitLineData
5099ac24
FG
1use crate::ImplTraitPosition;
2
dfeec247
XL
3use super::{ImplTraitContext, LoweringContext, ParamMode};
4
74b04a01 5use rustc_ast::ptr::P;
3dfed10e 6use rustc_ast::*;
f9f354fc
XL
7use rustc_data_structures::stack::ensure_sufficient_stack;
8use rustc_errors::Applicability;
dfeec247
XL
9use rustc_hir as hir;
10use rustc_hir::def::Res;
f9f354fc 11use rustc_span::symbol::Ident;
dfeec247 12use rustc_span::{source_map::Spanned, Span};
dfeec247
XL
13
14impl<'a, 'hir> LoweringContext<'a, 'hir> {
136023e0
XL
15 crate fn lower_pat(&mut self, pattern: &Pat) -> &'hir hir::Pat<'hir> {
16 self.arena.alloc(self.lower_pat_mut(pattern))
17 }
18
19 crate fn lower_pat_mut(&mut self, mut pattern: &Pat) -> hir::Pat<'hir> {
f9f354fc 20 ensure_sufficient_stack(|| {
29967ef6
XL
21 // loop here to avoid recursion
22 let node = loop {
23 match pattern.kind {
24 PatKind::Wild => break hir::PatKind::Wild,
25 PatKind::Ident(ref binding_mode, ident, ref sub) => {
26 let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
27 break self.lower_pat_ident(pattern, binding_mode, ident, lower_sub);
28 }
a2a8927a
XL
29 PatKind::Lit(ref e) => {
30 break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
31 }
17df50a5 32 PatKind::TupleStruct(ref qself, ref path, ref pats) => {
29967ef6
XL
33 let qpath = self.lower_qpath(
34 pattern.id,
17df50a5 35 qself,
29967ef6
XL
36 path,
37 ParamMode::Optional,
5099ac24 38 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
29967ef6
XL
39 );
40 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
41 break hir::PatKind::TupleStruct(qpath, pats, ddpos);
42 }
43 PatKind::Or(ref pats) => {
44 break hir::PatKind::Or(
136023e0 45 self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
29967ef6
XL
46 );
47 }
48 PatKind::Path(ref qself, ref path) => {
49 let qpath = self.lower_qpath(
50 pattern.id,
51 qself,
52 path,
53 ParamMode::Optional,
5099ac24 54 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
29967ef6
XL
55 );
56 break hir::PatKind::Path(qpath);
57 }
17df50a5 58 PatKind::Struct(ref qself, ref path, ref fields, etc) => {
29967ef6
XL
59 let qpath = self.lower_qpath(
60 pattern.id,
17df50a5 61 qself,
29967ef6
XL
62 path,
63 ParamMode::Optional,
5099ac24 64 ImplTraitContext::Disallowed(ImplTraitPosition::Path),
29967ef6 65 );
dfeec247 66
6a06907d 67 let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
29967ef6 68 hir_id: self.next_id(),
94222f64 69 ident: self.lower_ident(f.ident),
29967ef6
XL
70 pat: self.lower_pat(&f.pat),
71 is_shorthand: f.is_shorthand,
94222f64 72 span: self.lower_span(f.span),
29967ef6
XL
73 }));
74 break hir::PatKind::Struct(qpath, fs, etc);
75 }
76 PatKind::Tuple(ref pats) => {
77 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
78 break hir::PatKind::Tuple(pats, ddpos);
79 }
80 PatKind::Box(ref inner) => {
81 break hir::PatKind::Box(self.lower_pat(inner));
82 }
83 PatKind::Ref(ref inner, mutbl) => {
84 break hir::PatKind::Ref(self.lower_pat(inner), mutbl);
85 }
86 PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => {
87 break hir::PatKind::Range(
a2a8927a
XL
88 e1.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
89 e2.as_deref().map(|e| self.lower_expr_within_pat(e, true)),
29967ef6
XL
90 self.lower_range_end(end, e2.is_some()),
91 );
92 }
93 PatKind::Slice(ref pats) => break self.lower_pat_slice(pats),
94 PatKind::Rest => {
95 // If we reach here the `..` pattern is not semantically allowed.
96 break self.ban_illegal_rest_pat(pattern.span);
97 }
98 // return inner to be processed in next loop
99 PatKind::Paren(ref inner) => pattern = inner,
100 PatKind::MacCall(_) => panic!("{:?} shouldn't exist here", pattern.span),
f9f354fc 101 }
f9f354fc 102 };
dfeec247 103
29967ef6 104 self.pat_with_node_id_of(pattern, node)
f9f354fc 105 })
dfeec247
XL
106 }
107
108 fn lower_pat_tuple(
109 &mut self,
110 pats: &[P<Pat>],
111 ctx: &str,
136023e0 112 ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
dfeec247
XL
113 let mut elems = Vec::with_capacity(pats.len());
114 let mut rest = None;
115
116 let mut iter = pats.iter().enumerate();
117 for (idx, pat) in iter.by_ref() {
118 // Interpret the first `..` pattern as a sub-tuple pattern.
119 // Note that unlike for slice patterns,
120 // where `xs @ ..` is a legal sub-slice pattern,
121 // it is not a legal sub-tuple pattern.
f9f354fc
XL
122 match pat.kind {
123 // Found a sub-tuple rest pattern
124 PatKind::Rest => {
125 rest = Some((idx, pat.span));
126 break;
127 }
128 // Found a sub-tuple pattern `$binding_mode $ident @ ..`.
129 // This is not allowed as a sub-tuple pattern
130 PatKind::Ident(ref _bm, ident, Some(ref sub)) if sub.is_rest() => {
f9f354fc
XL
131 let sp = pat.span;
132 self.diagnostic()
133 .struct_span_err(
134 sp,
135 &format!("`{} @` is not allowed in a {}", ident.name, ctx),
136 )
137 .span_label(sp, "this is only allowed in slice patterns")
138 .help("remove this and bind each tuple field independently")
139 .span_suggestion_verbose(
140 sp,
141 &format!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident),
142 "..".to_string(),
143 Applicability::MaybeIncorrect,
144 )
145 .emit();
f9f354fc
XL
146 }
147 _ => {}
dfeec247 148 }
f9f354fc 149
dfeec247 150 // It was not a sub-tuple pattern so lower it normally.
136023e0 151 elems.push(self.lower_pat_mut(pat));
dfeec247
XL
152 }
153
154 for (_, pat) in iter {
155 // There was a previous sub-tuple pattern; make sure we don't allow more...
156 if pat.is_rest() {
157 // ...but there was one again, so error.
158 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
159 } else {
136023e0 160 elems.push(self.lower_pat_mut(pat));
dfeec247
XL
161 }
162 }
163
164 (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
165 }
166
167 /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
168 /// `hir::PatKind::Slice(before, slice, after)`.
169 ///
170 /// When encountering `($binding_mode $ident @)? ..` (`slice`),
171 /// this is interpreted as a sub-slice pattern semantically.
172 /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
173 fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
174 let mut before = Vec::new();
175 let mut after = Vec::new();
176 let mut slice = None;
177 let mut prev_rest_span = None;
178
179 // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
180 let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
181 let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
182 let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
183 this.pat_with_node_id_of(pat, node)
184 };
185
186 let mut iter = pats.iter();
187 // Lower all the patterns until the first occurrence of a sub-slice pattern.
188 for pat in iter.by_ref() {
189 match pat.kind {
190 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
191 PatKind::Rest => {
192 prev_rest_span = Some(pat.span);
193 slice = Some(self.pat_wild_with_node_id_of(pat));
194 break;
195 }
196 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
197 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
198 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
199 prev_rest_span = Some(sub.span);
136023e0 200 slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
dfeec247
XL
201 break;
202 }
203 // It was not a subslice pattern so lower it normally.
136023e0 204 _ => before.push(self.lower_pat_mut(pat)),
dfeec247
XL
205 }
206 }
207
208 // Lower all the patterns after the first sub-slice pattern.
209 for pat in iter {
210 // There was a previous subslice pattern; make sure we don't allow more.
211 let rest_span = match pat.kind {
212 PatKind::Rest => Some(pat.span),
213 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
214 // #69103: Lower into `binding @ _` as above to avoid ICEs.
215 after.push(lower_rest_sub(self, pat, bm, ident, sub));
216 Some(sub.span)
217 }
218 _ => None,
219 };
220 if let Some(rest_span) = rest_span {
221 // We have e.g., `[a, .., b, ..]`. That's no good, error!
222 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
223 } else {
224 // Lower the pattern normally.
136023e0 225 after.push(self.lower_pat_mut(pat));
dfeec247
XL
226 }
227 }
228
229 hir::PatKind::Slice(
230 self.arena.alloc_from_iter(before),
231 slice,
232 self.arena.alloc_from_iter(after),
233 )
234 }
235
236 fn lower_pat_ident(
237 &mut self,
238 p: &Pat,
239 binding_mode: &BindingMode,
240 ident: Ident,
241 lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
242 ) -> hir::PatKind<'hir> {
243 match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
244 // `None` can occur in body-less function signatures
ba9703b0 245 res @ (None | Some(Res::Local(_))) => {
dfeec247
XL
246 let canonical_id = match res {
247 Some(Res::Local(id)) => id,
248 _ => p.id,
249 };
250
251 hir::PatKind::Binding(
252 self.lower_binding_mode(binding_mode),
253 self.lower_node_id(canonical_id),
94222f64 254 self.lower_ident(ident),
dfeec247
XL
255 lower_sub(self),
256 )
257 }
258 Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
259 None,
260 self.arena.alloc(hir::Path {
94222f64 261 span: self.lower_span(ident.span),
dfeec247 262 res: self.lower_res(res),
94222f64 263 segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
dfeec247
XL
264 }),
265 )),
266 }
267 }
268
269 fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
270 match *b {
271 BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
272 BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
273 BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
274 BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
275 }
276 }
277
278 fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
136023e0 279 self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
dfeec247
XL
280 }
281
282 /// Construct a `Pat` with the `HirId` of `p.id` lowered.
136023e0
XL
283 fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
284 hir::Pat {
29967ef6
XL
285 hir_id: self.lower_node_id(p.id),
286 kind,
94222f64 287 span: self.lower_span(p.span),
29967ef6 288 default_binding_modes: true,
136023e0 289 }
dfeec247
XL
290 }
291
292 /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
29967ef6 293 crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
dfeec247
XL
294 self.diagnostic()
295 .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
296 .span_label(sp, &format!("can only be used once per {} pattern", ctx))
297 .span_label(prev_sp, "previously used here")
298 .emit();
299 }
300
301 /// Used to ban the `..` pattern in places it shouldn't be semantically.
302 fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
303 self.diagnostic()
304 .struct_span_err(sp, "`..` patterns are not allowed here")
305 .note("only allowed in tuple, tuple struct, and slice patterns")
306 .emit();
307
308 // We're not in a list context so `..` can be reasonably treated
309 // as `_` because it should always be valid and roughly matches the
310 // intent of `..` (notice that the rest of a single slot is that slot).
311 hir::PatKind::Wild
312 }
313
314 fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
315 match *e {
316 RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
317 // No end; so `X..` behaves like `RangeFrom`.
318 RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,
319 }
320 }
a2a8927a
XL
321
322 /// Matches `'-' lit | lit (cf. parser::Parser::parse_literal_maybe_minus)`,
323 /// or paths for ranges.
324 //
325 // FIXME: do we want to allow `expr -> pattern` conversion to create path expressions?
326 // That means making this work:
327 //
328 // ```rust,ignore (FIXME)
329 // struct S;
330 // macro_rules! m {
331 // ($a:expr) => {
332 // let $a = S;
333 // }
334 // }
335 // m!(S);
336 // ```
337 fn lower_expr_within_pat(&mut self, expr: &Expr, allow_paths: bool) -> &'hir hir::Expr<'hir> {
338 match expr.kind {
339 ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::Err => {}
340 ExprKind::Path(..) if allow_paths => {}
341 ExprKind::Unary(UnOp::Neg, ref inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
342 _ => {
343 self.diagnostic()
344 .span_err(expr.span, "arbitrary expressions aren't allowed in patterns");
345 return self.arena.alloc(self.expr_err(expr.span));
346 }
347 }
348 self.lower_expr(expr)
349 }
dfeec247 350}