]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast_lowering/src/pat.rs
Add more information to `impl Trait` deny error
[rust.git] / compiler / rustc_ast_lowering / src / pat.rs
1 use crate::ImplTraitPosition;
2
3 use super::{ImplTraitContext, LoweringContext, ParamMode};
4
5 use rustc_ast::ptr::P;
6 use rustc_ast::*;
7 use rustc_data_structures::stack::ensure_sufficient_stack;
8 use rustc_errors::Applicability;
9 use rustc_hir as hir;
10 use rustc_hir::def::Res;
11 use rustc_span::symbol::Ident;
12 use rustc_span::{source_map::Spanned, Span};
13
14 impl<'a, 'hir> LoweringContext<'a, 'hir> {
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> {
20         ensure_sufficient_stack(|| {
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                     }
29                     PatKind::Lit(ref e) => {
30                         break hir::PatKind::Lit(self.lower_expr_within_pat(e, false));
31                     }
32                     PatKind::TupleStruct(ref qself, ref path, ref pats) => {
33                         let qpath = self.lower_qpath(
34                             pattern.id,
35                             qself,
36                             path,
37                             ParamMode::Optional,
38                             ImplTraitContext::Disallowed(ImplTraitPosition::Path),
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(
45                             self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat_mut(x))),
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,
54                             ImplTraitContext::Disallowed(ImplTraitPosition::Path),
55                         );
56                         break hir::PatKind::Path(qpath);
57                     }
58                     PatKind::Struct(ref qself, ref path, ref fields, etc) => {
59                         let qpath = self.lower_qpath(
60                             pattern.id,
61                             qself,
62                             path,
63                             ParamMode::Optional,
64                             ImplTraitContext::Disallowed(ImplTraitPosition::Path),
65                         );
66
67                         let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::PatField {
68                             hir_id: self.next_id(),
69                             ident: self.lower_ident(f.ident),
70                             pat: self.lower_pat(&f.pat),
71                             is_shorthand: f.is_shorthand,
72                             span: self.lower_span(f.span),
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(
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)),
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),
101                 }
102             };
103
104             self.pat_with_node_id_of(pattern, node)
105         })
106     }
107
108     fn lower_pat_tuple(
109         &mut self,
110         pats: &[P<Pat>],
111         ctx: &str,
112     ) -> (&'hir [hir::Pat<'hir>], Option<usize>) {
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.
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() => {
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();
146                 }
147                 _ => {}
148             }
149
150             // It was not a sub-tuple pattern so lower it normally.
151             elems.push(self.lower_pat_mut(pat));
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 {
160                 elems.push(self.lower_pat_mut(pat));
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);
200                     slice = Some(self.arena.alloc(lower_rest_sub(self, pat, bm, ident, sub)));
201                     break;
202                 }
203                 // It was not a subslice pattern so lower it normally.
204                 _ => before.push(self.lower_pat_mut(pat)),
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.
225                 after.push(self.lower_pat_mut(pat));
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
245             res @ (None | Some(Res::Local(_))) => {
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),
254                     self.lower_ident(ident),
255                     lower_sub(self),
256                 )
257             }
258             Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
259                 None,
260                 self.arena.alloc(hir::Path {
261                     span: self.lower_span(ident.span),
262                     res: self.lower_res(res),
263                     segments: arena_vec![self; hir::PathSegment::from_ident(self.lower_ident(ident))],
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> {
279         self.arena.alloc(self.pat_with_node_id_of(p, hir::PatKind::Wild))
280     }
281
282     /// Construct a `Pat` with the `HirId` of `p.id` lowered.
283     fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> hir::Pat<'hir> {
284         hir::Pat {
285             hir_id: self.lower_node_id(p.id),
286             kind,
287             span: self.lower_span(p.span),
288             default_binding_modes: true,
289         }
290     }
291
292     /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
293     crate fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
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     }
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     }
350 }