1 use super::{ImplTraitContext, LoweringContext, ParamMode}
;
5 use rustc_data_structures
::stack
::ensure_sufficient_stack
;
6 use rustc_errors
::Applicability
;
8 use rustc_hir
::def
::Res
;
9 use rustc_span
::symbol
::Ident
;
10 use rustc_span
::{source_map::Spanned, Span}
;
12 impl<'a
, 'hir
> LoweringContext
<'a
, 'hir
> {
13 crate fn lower_pat(&mut self, mut pattern
: &Pat
) -> &'hir hir
::Pat
<'hir
> {
14 ensure_sufficient_stack(|| {
15 // loop here to avoid recursion
18 PatKind
::Wild
=> break hir
::PatKind
::Wild
,
19 PatKind
::Ident(ref binding_mode
, ident
, ref sub
) => {
20 let lower_sub
= |this
: &mut Self| sub
.as_ref().map(|s
| this
.lower_pat(&*s
));
21 break self.lower_pat_ident(pattern
, binding_mode
, ident
, lower_sub
);
23 PatKind
::Lit(ref e
) => break hir
::PatKind
::Lit(self.lower_expr(e
)),
24 PatKind
::TupleStruct(ref path
, ref pats
) => {
25 let qpath
= self.lower_qpath(
30 ImplTraitContext
::disallowed(),
32 let (pats
, ddpos
) = self.lower_pat_tuple(pats
, "tuple struct");
33 break hir
::PatKind
::TupleStruct(qpath
, pats
, ddpos
);
35 PatKind
::Or(ref pats
) => {
36 break hir
::PatKind
::Or(
37 self.arena
.alloc_from_iter(pats
.iter().map(|x
| self.lower_pat(x
))),
40 PatKind
::Path(ref qself
, ref path
) => {
41 let qpath
= self.lower_qpath(
46 ImplTraitContext
::disallowed(),
48 break hir
::PatKind
::Path(qpath
);
50 PatKind
::Struct(ref path
, ref fields
, etc
) => {
51 let qpath
= self.lower_qpath(
56 ImplTraitContext
::disallowed(),
59 let fs
= self.arena
.alloc_from_iter(fields
.iter().map(|f
| hir
::PatField
{
60 hir_id
: self.next_id(),
62 pat
: self.lower_pat(&f
.pat
),
63 is_shorthand
: f
.is_shorthand
,
66 break hir
::PatKind
::Struct(qpath
, fs
, etc
);
68 PatKind
::Tuple(ref pats
) => {
69 let (pats
, ddpos
) = self.lower_pat_tuple(pats
, "tuple");
70 break hir
::PatKind
::Tuple(pats
, ddpos
);
72 PatKind
::Box(ref inner
) => {
73 break hir
::PatKind
::Box(self.lower_pat(inner
));
75 PatKind
::Ref(ref inner
, mutbl
) => {
76 break hir
::PatKind
::Ref(self.lower_pat(inner
), mutbl
);
78 PatKind
::Range(ref e1
, ref e2
, Spanned { node: ref end, .. }
) => {
79 break hir
::PatKind
::Range(
80 e1
.as_deref().map(|e
| self.lower_expr(e
)),
81 e2
.as_deref().map(|e
| self.lower_expr(e
)),
82 self.lower_range_end(end
, e2
.is_some()),
85 PatKind
::Slice(ref pats
) => break self.lower_pat_slice(pats
),
87 // If we reach here the `..` pattern is not semantically allowed.
88 break self.ban_illegal_rest_pat(pattern
.span
);
90 // return inner to be processed in next loop
91 PatKind
::Paren(ref inner
) => pattern
= inner
,
92 PatKind
::MacCall(_
) => panic
!("{:?} shouldn't exist here", pattern
.span
),
96 self.pat_with_node_id_of(pattern
, node
)
104 ) -> (&'hir
[&'hir hir
::Pat
<'hir
>], Option
<usize>) {
105 let mut elems
= Vec
::with_capacity(pats
.len());
108 let mut iter
= pats
.iter().enumerate();
109 for (idx
, pat
) in iter
.by_ref() {
110 // Interpret the first `..` pattern as a sub-tuple pattern.
111 // Note that unlike for slice patterns,
112 // where `xs @ ..` is a legal sub-slice pattern,
113 // it is not a legal sub-tuple pattern.
115 // Found a sub-tuple rest pattern
117 rest
= Some((idx
, pat
.span
));
120 // Found a sub-tuple pattern `$binding_mode $ident @ ..`.
121 // This is not allowed as a sub-tuple pattern
122 PatKind
::Ident(ref _bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
127 &format
!("`{} @` is not allowed in a {}", ident
.name
, ctx
),
129 .span_label(sp
, "this is only allowed in slice patterns")
130 .help("remove this and bind each tuple field independently")
131 .span_suggestion_verbose(
133 &format
!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident
),
135 Applicability
::MaybeIncorrect
,
142 // It was not a sub-tuple pattern so lower it normally.
143 elems
.push(self.lower_pat(pat
));
146 for (_
, pat
) in iter
{
147 // There was a previous sub-tuple pattern; make sure we don't allow more...
149 // ...but there was one again, so error.
150 self.ban_extra_rest_pat(pat
.span
, rest
.unwrap().1, ctx
);
152 elems
.push(self.lower_pat(pat
));
156 (self.arena
.alloc_from_iter(elems
), rest
.map(|(ddpos
, _
)| ddpos
))
159 /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
160 /// `hir::PatKind::Slice(before, slice, after)`.
162 /// When encountering `($binding_mode $ident @)? ..` (`slice`),
163 /// this is interpreted as a sub-slice pattern semantically.
164 /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
165 fn lower_pat_slice(&mut self, pats
: &[P
<Pat
>]) -> hir
::PatKind
<'hir
> {
166 let mut before
= Vec
::new();
167 let mut after
= Vec
::new();
168 let mut slice
= None
;
169 let mut prev_rest_span
= None
;
171 // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
172 let lower_rest_sub
= |this
: &mut Self, pat
, bm
, ident
, sub
| {
173 let lower_sub
= |this
: &mut Self| Some(this
.pat_wild_with_node_id_of(sub
));
174 let node
= this
.lower_pat_ident(pat
, bm
, ident
, lower_sub
);
175 this
.pat_with_node_id_of(pat
, node
)
178 let mut iter
= pats
.iter();
179 // Lower all the patterns until the first occurrence of a sub-slice pattern.
180 for pat
in iter
.by_ref() {
182 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
184 prev_rest_span
= Some(pat
.span
);
185 slice
= Some(self.pat_wild_with_node_id_of(pat
));
188 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
189 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
190 PatKind
::Ident(ref bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
191 prev_rest_span
= Some(sub
.span
);
192 slice
= Some(lower_rest_sub(self, pat
, bm
, ident
, sub
));
195 // It was not a subslice pattern so lower it normally.
196 _
=> before
.push(self.lower_pat(pat
)),
200 // Lower all the patterns after the first sub-slice pattern.
202 // There was a previous subslice pattern; make sure we don't allow more.
203 let rest_span
= match pat
.kind
{
204 PatKind
::Rest
=> Some(pat
.span
),
205 PatKind
::Ident(ref bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
206 // #69103: Lower into `binding @ _` as above to avoid ICEs.
207 after
.push(lower_rest_sub(self, pat
, bm
, ident
, sub
));
212 if let Some(rest_span
) = rest_span
{
213 // We have e.g., `[a, .., b, ..]`. That's no good, error!
214 self.ban_extra_rest_pat(rest_span
, prev_rest_span
.unwrap(), "slice");
216 // Lower the pattern normally.
217 after
.push(self.lower_pat(pat
));
222 self.arena
.alloc_from_iter(before
),
224 self.arena
.alloc_from_iter(after
),
231 binding_mode
: &BindingMode
,
233 lower_sub
: impl FnOnce(&mut Self) -> Option
<&'hir hir
::Pat
<'hir
>>,
234 ) -> hir
::PatKind
<'hir
> {
235 match self.resolver
.get_partial_res(p
.id
).map(|d
| d
.base_res()) {
236 // `None` can occur in body-less function signatures
237 res @
(None
| Some(Res
::Local(_
))) => {
238 let canonical_id
= match res
{
239 Some(Res
::Local(id
)) => id
,
243 hir
::PatKind
::Binding(
244 self.lower_binding_mode(binding_mode
),
245 self.lower_node_id(canonical_id
),
250 Some(res
) => hir
::PatKind
::Path(hir
::QPath
::Resolved(
252 self.arena
.alloc(hir
::Path
{
254 res
: self.lower_res(res
),
255 segments
: arena_vec
![self; hir
::PathSegment
::from_ident(ident
)],
261 fn lower_binding_mode(&mut self, b
: &BindingMode
) -> hir
::BindingAnnotation
{
263 BindingMode
::ByValue(Mutability
::Not
) => hir
::BindingAnnotation
::Unannotated
,
264 BindingMode
::ByRef(Mutability
::Not
) => hir
::BindingAnnotation
::Ref
,
265 BindingMode
::ByValue(Mutability
::Mut
) => hir
::BindingAnnotation
::Mutable
,
266 BindingMode
::ByRef(Mutability
::Mut
) => hir
::BindingAnnotation
::RefMut
,
270 fn pat_wild_with_node_id_of(&mut self, p
: &Pat
) -> &'hir hir
::Pat
<'hir
> {
271 self.pat_with_node_id_of(p
, hir
::PatKind
::Wild
)
274 /// Construct a `Pat` with the `HirId` of `p.id` lowered.
275 fn pat_with_node_id_of(&mut self, p
: &Pat
, kind
: hir
::PatKind
<'hir
>) -> &'hir hir
::Pat
<'hir
> {
276 self.arena
.alloc(hir
::Pat
{
277 hir_id
: self.lower_node_id(p
.id
),
280 default_binding_modes
: true,
284 /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
285 crate fn ban_extra_rest_pat(&self, sp
: Span
, prev_sp
: Span
, ctx
: &str) {
287 .struct_span_err(sp
, &format
!("`..` can only be used once per {} pattern", ctx
))
288 .span_label(sp
, &format
!("can only be used once per {} pattern", ctx
))
289 .span_label(prev_sp
, "previously used here")
293 /// Used to ban the `..` pattern in places it shouldn't be semantically.
294 fn ban_illegal_rest_pat(&self, sp
: Span
) -> hir
::PatKind
<'hir
> {
296 .struct_span_err(sp
, "`..` patterns are not allowed here")
297 .note("only allowed in tuple, tuple struct, and slice patterns")
300 // We're not in a list context so `..` can be reasonably treated
301 // as `_` because it should always be valid and roughly matches the
302 // intent of `..` (notice that the rest of a single slot is that slot).
306 fn lower_range_end(&mut self, e
: &RangeEnd
, has_end
: bool
) -> hir
::RangeEnd
{
308 RangeEnd
::Excluded
if has_end
=> hir
::RangeEnd
::Excluded
,
309 // No end; so `X..` behaves like `RangeFrom`.
310 RangeEnd
::Excluded
| RangeEnd
::Included(_
) => hir
::RangeEnd
::Included
,