1 use super::{ImplTraitContext, LoweringContext, ParamMode};
4 use rustc_hir::def::Res;
5 use rustc_span::{source_map::Spanned, Span};
9 impl<'a, 'hir> LoweringContext<'a, 'hir> {
10 crate fn lower_pat(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
11 let node = match p.kind {
12 PatKind::Wild => hir::PatKind::Wild,
13 PatKind::Ident(ref binding_mode, ident, ref sub) => {
14 let lower_sub = |this: &mut Self| sub.as_ref().map(|s| this.lower_pat(&*s));
15 let node = self.lower_pat_ident(p, binding_mode, ident, lower_sub);
18 PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
19 PatKind::TupleStruct(ref path, ref pats) => {
20 let qpath = self.lower_qpath(
25 ImplTraitContext::disallowed(),
27 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple struct");
28 hir::PatKind::TupleStruct(qpath, pats, ddpos)
30 PatKind::Or(ref pats) => {
31 hir::PatKind::Or(self.arena.alloc_from_iter(pats.iter().map(|x| self.lower_pat(x))))
33 PatKind::Path(ref qself, ref path) => {
34 let qpath = self.lower_qpath(
39 ImplTraitContext::disallowed(),
41 hir::PatKind::Path(qpath)
43 PatKind::Struct(ref path, ref fields, etc) => {
44 let qpath = self.lower_qpath(
49 ImplTraitContext::disallowed(),
52 let fs = self.arena.alloc_from_iter(fields.iter().map(|f| hir::FieldPat {
53 hir_id: self.next_id(),
55 pat: self.lower_pat(&f.pat),
56 is_shorthand: f.is_shorthand,
59 hir::PatKind::Struct(qpath, fs, etc)
61 PatKind::Tuple(ref pats) => {
62 let (pats, ddpos) = self.lower_pat_tuple(pats, "tuple");
63 hir::PatKind::Tuple(pats, ddpos)
65 PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
66 PatKind::Ref(ref inner, mutbl) => hir::PatKind::Ref(self.lower_pat(inner), mutbl),
67 PatKind::Range(ref e1, ref e2, Spanned { node: ref end, .. }) => hir::PatKind::Range(
68 e1.as_deref().map(|e| self.lower_expr(e)),
69 e2.as_deref().map(|e| self.lower_expr(e)),
70 self.lower_range_end(end, e2.is_some()),
72 PatKind::Slice(ref pats) => self.lower_pat_slice(pats),
74 // If we reach here the `..` pattern is not semantically allowed.
75 self.ban_illegal_rest_pat(p.span)
77 PatKind::Paren(ref inner) => return self.lower_pat(inner),
78 PatKind::Mac(_) => panic!("Shouldn't exist here"),
81 self.pat_with_node_id_of(p, node)
88 ) -> (&'hir [&'hir hir::Pat<'hir>], Option<usize>) {
89 let mut elems = Vec::with_capacity(pats.len());
92 let mut iter = pats.iter().enumerate();
93 for (idx, pat) in iter.by_ref() {
94 // Interpret the first `..` pattern as a sub-tuple pattern.
95 // Note that unlike for slice patterns,
96 // where `xs @ ..` is a legal sub-slice pattern,
97 // it is not a legal sub-tuple pattern.
99 rest = Some((idx, pat.span));
102 // It was not a sub-tuple pattern so lower it normally.
103 elems.push(self.lower_pat(pat));
106 for (_, pat) in iter {
107 // There was a previous sub-tuple pattern; make sure we don't allow more...
109 // ...but there was one again, so error.
110 self.ban_extra_rest_pat(pat.span, rest.unwrap().1, ctx);
112 elems.push(self.lower_pat(pat));
116 (self.arena.alloc_from_iter(elems), rest.map(|(ddpos, _)| ddpos))
119 /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
120 /// `hir::PatKind::Slice(before, slice, after)`.
122 /// When encountering `($binding_mode $ident @)? ..` (`slice`),
123 /// this is interpreted as a sub-slice pattern semantically.
124 /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
125 fn lower_pat_slice(&mut self, pats: &[P<Pat>]) -> hir::PatKind<'hir> {
126 let mut before = Vec::new();
127 let mut after = Vec::new();
128 let mut slice = None;
129 let mut prev_rest_span = None;
131 // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
132 let lower_rest_sub = |this: &mut Self, pat, bm, ident, sub| {
133 let lower_sub = |this: &mut Self| Some(this.pat_wild_with_node_id_of(sub));
134 let node = this.lower_pat_ident(pat, bm, ident, lower_sub);
135 this.pat_with_node_id_of(pat, node)
138 let mut iter = pats.iter();
139 // Lower all the patterns until the first occurrence of a sub-slice pattern.
140 for pat in iter.by_ref() {
142 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
144 prev_rest_span = Some(pat.span);
145 slice = Some(self.pat_wild_with_node_id_of(pat));
148 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
149 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
150 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
151 prev_rest_span = Some(sub.span);
152 slice = Some(lower_rest_sub(self, pat, bm, ident, sub));
155 // It was not a subslice pattern so lower it normally.
156 _ => before.push(self.lower_pat(pat)),
160 // Lower all the patterns after the first sub-slice pattern.
162 // There was a previous subslice pattern; make sure we don't allow more.
163 let rest_span = match pat.kind {
164 PatKind::Rest => Some(pat.span),
165 PatKind::Ident(ref bm, ident, Some(ref sub)) if sub.is_rest() => {
166 // #69103: Lower into `binding @ _` as above to avoid ICEs.
167 after.push(lower_rest_sub(self, pat, bm, ident, sub));
172 if let Some(rest_span) = rest_span {
173 // We have e.g., `[a, .., b, ..]`. That's no good, error!
174 self.ban_extra_rest_pat(rest_span, prev_rest_span.unwrap(), "slice");
176 // Lower the pattern normally.
177 after.push(self.lower_pat(pat));
182 self.arena.alloc_from_iter(before),
184 self.arena.alloc_from_iter(after),
191 binding_mode: &BindingMode,
193 lower_sub: impl FnOnce(&mut Self) -> Option<&'hir hir::Pat<'hir>>,
194 ) -> hir::PatKind<'hir> {
195 match self.resolver.get_partial_res(p.id).map(|d| d.base_res()) {
196 // `None` can occur in body-less function signatures
197 res @ None | res @ Some(Res::Local(_)) => {
198 let canonical_id = match res {
199 Some(Res::Local(id)) => id,
203 hir::PatKind::Binding(
204 self.lower_binding_mode(binding_mode),
205 self.lower_node_id(canonical_id),
210 Some(res) => hir::PatKind::Path(hir::QPath::Resolved(
212 self.arena.alloc(hir::Path {
214 res: self.lower_res(res),
215 segments: arena_vec![self; hir::PathSegment::from_ident(ident)],
221 fn lower_binding_mode(&mut self, b: &BindingMode) -> hir::BindingAnnotation {
223 BindingMode::ByValue(Mutability::Not) => hir::BindingAnnotation::Unannotated,
224 BindingMode::ByRef(Mutability::Not) => hir::BindingAnnotation::Ref,
225 BindingMode::ByValue(Mutability::Mut) => hir::BindingAnnotation::Mutable,
226 BindingMode::ByRef(Mutability::Mut) => hir::BindingAnnotation::RefMut,
230 fn pat_wild_with_node_id_of(&mut self, p: &Pat) -> &'hir hir::Pat<'hir> {
231 self.pat_with_node_id_of(p, hir::PatKind::Wild)
234 /// Construct a `Pat` with the `HirId` of `p.id` lowered.
235 fn pat_with_node_id_of(&mut self, p: &Pat, kind: hir::PatKind<'hir>) -> &'hir hir::Pat<'hir> {
236 self.arena.alloc(hir::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span })
239 /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
240 fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
242 .struct_span_err(sp, &format!("`..` can only be used once per {} pattern", ctx))
243 .span_label(sp, &format!("can only be used once per {} pattern", ctx))
244 .span_label(prev_sp, "previously used here")
248 /// Used to ban the `..` pattern in places it shouldn't be semantically.
249 fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
251 .struct_span_err(sp, "`..` patterns are not allowed here")
252 .note("only allowed in tuple, tuple struct, and slice patterns")
255 // We're not in a list context so `..` can be reasonably treated
256 // as `_` because it should always be valid and roughly matches the
257 // intent of `..` (notice that the rest of a single slot is that slot).
261 fn lower_range_end(&mut self, e: &RangeEnd, has_end: bool) -> hir::RangeEnd {
263 RangeEnd::Excluded if has_end => hir::RangeEnd::Excluded,
264 // No end; so `X..` behaves like `RangeFrom`.
265 RangeEnd::Excluded | RangeEnd::Included(_) => hir::RangeEnd::Included,