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, p
: &Pat
) -> &'hir hir
::Pat
<'hir
> {
14 ensure_sufficient_stack(|| {
15 let node
= match p
.kind
{
16 PatKind
::Wild
=> hir
::PatKind
::Wild
,
17 PatKind
::Ident(ref binding_mode
, ident
, ref sub
) => {
18 let lower_sub
= |this
: &mut Self| sub
.as_ref().map(|s
| this
.lower_pat(&*s
));
19 let node
= self.lower_pat_ident(p
, binding_mode
, ident
, lower_sub
);
22 PatKind
::Lit(ref e
) => hir
::PatKind
::Lit(self.lower_expr(e
)),
23 PatKind
::TupleStruct(ref path
, ref pats
) => {
24 let qpath
= self.lower_qpath(
29 ImplTraitContext
::disallowed(),
31 let (pats
, ddpos
) = self.lower_pat_tuple(pats
, "tuple struct");
32 hir
::PatKind
::TupleStruct(qpath
, pats
, ddpos
)
34 PatKind
::Or(ref pats
) => hir
::PatKind
::Or(
35 self.arena
.alloc_from_iter(pats
.iter().map(|x
| self.lower_pat(x
))),
37 PatKind
::Path(ref qself
, ref path
) => {
38 let qpath
= self.lower_qpath(
43 ImplTraitContext
::disallowed(),
45 hir
::PatKind
::Path(qpath
)
47 PatKind
::Struct(ref path
, ref fields
, etc
) => {
48 let qpath
= self.lower_qpath(
53 ImplTraitContext
::disallowed(),
56 let fs
= self.arena
.alloc_from_iter(fields
.iter().map(|f
| hir
::FieldPat
{
57 hir_id
: self.next_id(),
59 pat
: self.lower_pat(&f
.pat
),
60 is_shorthand
: f
.is_shorthand
,
63 hir
::PatKind
::Struct(qpath
, fs
, etc
)
65 PatKind
::Tuple(ref pats
) => {
66 let (pats
, ddpos
) = self.lower_pat_tuple(pats
, "tuple");
67 hir
::PatKind
::Tuple(pats
, ddpos
)
69 PatKind
::Box(ref inner
) => hir
::PatKind
::Box(self.lower_pat(inner
)),
70 PatKind
::Ref(ref inner
, mutbl
) => hir
::PatKind
::Ref(self.lower_pat(inner
), mutbl
),
71 PatKind
::Range(ref e1
, ref e2
, Spanned { node: ref end, .. }
) => {
73 e1
.as_deref().map(|e
| self.lower_expr(e
)),
74 e2
.as_deref().map(|e
| self.lower_expr(e
)),
75 self.lower_range_end(end
, e2
.is_some()),
78 PatKind
::Slice(ref pats
) => self.lower_pat_slice(pats
),
80 // If we reach here the `..` pattern is not semantically allowed.
81 self.ban_illegal_rest_pat(p
.span
)
83 // FIXME: consider not using recursion to lower this.
84 PatKind
::Paren(ref inner
) => return self.lower_pat(inner
),
85 PatKind
::MacCall(_
) => panic
!("{:?} shouldn't exist here", p
.span
),
88 self.pat_with_node_id_of(p
, node
)
96 ) -> (&'hir
[&'hir hir
::Pat
<'hir
>], Option
<usize>) {
97 let mut elems
= Vec
::with_capacity(pats
.len());
100 let mut iter
= pats
.iter().enumerate();
101 for (idx
, pat
) in iter
.by_ref() {
102 // Interpret the first `..` pattern as a sub-tuple pattern.
103 // Note that unlike for slice patterns,
104 // where `xs @ ..` is a legal sub-slice pattern,
105 // it is not a legal sub-tuple pattern.
107 // Found a sub-tuple rest pattern
109 rest
= Some((idx
, pat
.span
));
112 // Found a sub-tuple pattern `$binding_mode $ident @ ..`.
113 // This is not allowed as a sub-tuple pattern
114 PatKind
::Ident(ref _bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
119 &format
!("`{} @` is not allowed in a {}", ident
.name
, ctx
),
121 .span_label(sp
, "this is only allowed in slice patterns")
122 .help("remove this and bind each tuple field independently")
123 .span_suggestion_verbose(
125 &format
!("if you don't need to use the contents of {}, discard the tuple's remaining fields", ident
),
127 Applicability
::MaybeIncorrect
,
134 // It was not a sub-tuple pattern so lower it normally.
135 elems
.push(self.lower_pat(pat
));
138 for (_
, pat
) in iter
{
139 // There was a previous sub-tuple pattern; make sure we don't allow more...
141 // ...but there was one again, so error.
142 self.ban_extra_rest_pat(pat
.span
, rest
.unwrap().1, ctx
);
144 elems
.push(self.lower_pat(pat
));
148 (self.arena
.alloc_from_iter(elems
), rest
.map(|(ddpos
, _
)| ddpos
))
151 /// Lower a slice pattern of form `[pat_0, ..., pat_n]` into
152 /// `hir::PatKind::Slice(before, slice, after)`.
154 /// When encountering `($binding_mode $ident @)? ..` (`slice`),
155 /// this is interpreted as a sub-slice pattern semantically.
156 /// Patterns that follow, which are not like `slice` -- or an error occurs, are in `after`.
157 fn lower_pat_slice(&mut self, pats
: &[P
<Pat
>]) -> hir
::PatKind
<'hir
> {
158 let mut before
= Vec
::new();
159 let mut after
= Vec
::new();
160 let mut slice
= None
;
161 let mut prev_rest_span
= None
;
163 // Lowers `$bm $ident @ ..` to `$bm $ident @ _`.
164 let lower_rest_sub
= |this
: &mut Self, pat
, bm
, ident
, sub
| {
165 let lower_sub
= |this
: &mut Self| Some(this
.pat_wild_with_node_id_of(sub
));
166 let node
= this
.lower_pat_ident(pat
, bm
, ident
, lower_sub
);
167 this
.pat_with_node_id_of(pat
, node
)
170 let mut iter
= pats
.iter();
171 // Lower all the patterns until the first occurrence of a sub-slice pattern.
172 for pat
in iter
.by_ref() {
174 // Found a sub-slice pattern `..`. Record, lower it to `_`, and stop here.
176 prev_rest_span
= Some(pat
.span
);
177 slice
= Some(self.pat_wild_with_node_id_of(pat
));
180 // Found a sub-slice pattern `$binding_mode $ident @ ..`.
181 // Record, lower it to `$binding_mode $ident @ _`, and stop here.
182 PatKind
::Ident(ref bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
183 prev_rest_span
= Some(sub
.span
);
184 slice
= Some(lower_rest_sub(self, pat
, bm
, ident
, sub
));
187 // It was not a subslice pattern so lower it normally.
188 _
=> before
.push(self.lower_pat(pat
)),
192 // Lower all the patterns after the first sub-slice pattern.
194 // There was a previous subslice pattern; make sure we don't allow more.
195 let rest_span
= match pat
.kind
{
196 PatKind
::Rest
=> Some(pat
.span
),
197 PatKind
::Ident(ref bm
, ident
, Some(ref sub
)) if sub
.is_rest() => {
198 // #69103: Lower into `binding @ _` as above to avoid ICEs.
199 after
.push(lower_rest_sub(self, pat
, bm
, ident
, sub
));
204 if let Some(rest_span
) = rest_span
{
205 // We have e.g., `[a, .., b, ..]`. That's no good, error!
206 self.ban_extra_rest_pat(rest_span
, prev_rest_span
.unwrap(), "slice");
208 // Lower the pattern normally.
209 after
.push(self.lower_pat(pat
));
214 self.arena
.alloc_from_iter(before
),
216 self.arena
.alloc_from_iter(after
),
223 binding_mode
: &BindingMode
,
225 lower_sub
: impl FnOnce(&mut Self) -> Option
<&'hir hir
::Pat
<'hir
>>,
226 ) -> hir
::PatKind
<'hir
> {
227 match self.resolver
.get_partial_res(p
.id
).map(|d
| d
.base_res()) {
228 // `None` can occur in body-less function signatures
229 res @
(None
| Some(Res
::Local(_
))) => {
230 let canonical_id
= match res
{
231 Some(Res
::Local(id
)) => id
,
235 hir
::PatKind
::Binding(
236 self.lower_binding_mode(binding_mode
),
237 self.lower_node_id(canonical_id
),
242 Some(res
) => hir
::PatKind
::Path(hir
::QPath
::Resolved(
244 self.arena
.alloc(hir
::Path
{
246 res
: self.lower_res(res
),
247 segments
: arena_vec
![self; hir
::PathSegment
::from_ident(ident
)],
253 fn lower_binding_mode(&mut self, b
: &BindingMode
) -> hir
::BindingAnnotation
{
255 BindingMode
::ByValue(Mutability
::Not
) => hir
::BindingAnnotation
::Unannotated
,
256 BindingMode
::ByRef(Mutability
::Not
) => hir
::BindingAnnotation
::Ref
,
257 BindingMode
::ByValue(Mutability
::Mut
) => hir
::BindingAnnotation
::Mutable
,
258 BindingMode
::ByRef(Mutability
::Mut
) => hir
::BindingAnnotation
::RefMut
,
262 fn pat_wild_with_node_id_of(&mut self, p
: &Pat
) -> &'hir hir
::Pat
<'hir
> {
263 self.pat_with_node_id_of(p
, hir
::PatKind
::Wild
)
266 /// Construct a `Pat` with the `HirId` of `p.id` lowered.
267 fn pat_with_node_id_of(&mut self, p
: &Pat
, kind
: hir
::PatKind
<'hir
>) -> &'hir hir
::Pat
<'hir
> {
268 self.arena
.alloc(hir
::Pat { hir_id: self.lower_node_id(p.id), kind, span: p.span }
)
271 /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
272 fn ban_extra_rest_pat(&self, sp
: Span
, prev_sp
: Span
, ctx
: &str) {
274 .struct_span_err(sp
, &format
!("`..` can only be used once per {} pattern", ctx
))
275 .span_label(sp
, &format
!("can only be used once per {} pattern", ctx
))
276 .span_label(prev_sp
, "previously used here")
280 /// Used to ban the `..` pattern in places it shouldn't be semantically.
281 fn ban_illegal_rest_pat(&self, sp
: Span
) -> hir
::PatKind
<'hir
> {
283 .struct_span_err(sp
, "`..` patterns are not allowed here")
284 .note("only allowed in tuple, tuple struct, and slice patterns")
287 // We're not in a list context so `..` can be reasonably treated
288 // as `_` because it should always be valid and roughly matches the
289 // intent of `..` (notice that the rest of a single slot is that slot).
293 fn lower_range_end(&mut self, e
: &RangeEnd
, has_end
: bool
) -> hir
::RangeEnd
{
295 RangeEnd
::Excluded
if has_end
=> hir
::RangeEnd
::Excluded
,
296 // No end; so `X..` behaves like `RangeFrom`.
297 RangeEnd
::Excluded
| RangeEnd
::Included(_
) => hir
::RangeEnd
::Included
,