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