Skip to content

Commit 0918dc4

Browse files
committed
or-patterns: middle/dead: remove top_pats_hack.
Also tweak walkers on `Pat`.
1 parent 370fbcc commit 0918dc4

File tree

3 files changed

+100
-95
lines changed

3 files changed

+100
-95
lines changed

src/librustc/hir/mod.rs

+42-20
Original file line numberDiff line numberDiff line change
@@ -882,39 +882,61 @@ impl fmt::Debug for Pat {
882882

883883
impl Pat {
884884
// FIXME(#19596) this is a workaround, but there should be a better way
885-
fn walk_<G>(&self, it: &mut G) -> bool
886-
where G: FnMut(&Pat) -> bool
887-
{
885+
fn walk_short_(&self, it: &mut impl FnMut(&Pat) -> bool) -> bool {
888886
if !it(self) {
889887
return false;
890888
}
891889

890+
use PatKind::*;
892891
match &self.node {
893-
PatKind::Binding(.., Some(p)) => p.walk_(it),
894-
PatKind::Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_(it)),
895-
PatKind::TupleStruct(_, s, _) | PatKind::Tuple(s, _) | PatKind::Or(s) => {
896-
s.iter().all(|p| p.walk_(it))
897-
}
898-
PatKind::Box(s) | PatKind::Ref(s, _) => s.walk_(it),
899-
PatKind::Slice(before, slice, after) => {
892+
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => true,
893+
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_short_(it),
894+
Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
895+
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
896+
Slice(before, slice, after) => {
900897
before.iter()
901898
.chain(slice.iter())
902899
.chain(after.iter())
903-
.all(|p| p.walk_(it))
900+
.all(|p| p.walk_short_(it))
904901
}
905-
PatKind::Wild |
906-
PatKind::Lit(_) |
907-
PatKind::Range(..) |
908-
PatKind::Binding(..) |
909-
PatKind::Path(_) => {
910-
true
902+
}
903+
}
904+
905+
/// Walk the pattern in left-to-right order,
906+
/// short circuiting (with `.all(..)`) if `false` is returned.
907+
///
908+
/// Note that when visiting e.g. `Tuple(ps)`,
909+
/// if visiting `ps[0]` returns `false`,
910+
/// then `ps[1]` will not be visited.
911+
pub fn walk_short(&self, mut it: impl FnMut(&Pat) -> bool) -> bool {
912+
self.walk_short_(&mut it)
913+
}
914+
915+
// FIXME(#19596) this is a workaround, but there should be a better way
916+
fn walk_(&self, it: &mut impl FnMut(&Pat) -> bool) {
917+
if !it(self) {
918+
return;
919+
}
920+
921+
use PatKind::*;
922+
match &self.node {
923+
Wild | Lit(_) | Range(..) | Binding(.., None) | Path(_) => {},
924+
Box(s) | Ref(s, _) | Binding(.., Some(s)) => s.walk_(it),
925+
Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
926+
TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
927+
Slice(before, slice, after) => {
928+
before.iter()
929+
.chain(slice.iter())
930+
.chain(after.iter())
931+
.for_each(|p| p.walk_(it))
911932
}
912933
}
913934
}
914935

915-
pub fn walk<F>(&self, mut it: F) -> bool
916-
where F: FnMut(&Pat) -> bool
917-
{
936+
/// Walk the pattern in left-to-right order.
937+
///
938+
/// If `it(pat)` returns `false`, the children are not visited.
939+
pub fn walk(&self, mut it: impl FnMut(&Pat) -> bool) {
918940
self.walk_(&mut it)
919941
}
920942
}

src/librustc/hir/pat_util.rs

+51-61
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ impl hir::Pat {
6666

6767
/// Call `f` on every "binding" in a pattern, e.g., on `a` in
6868
/// `match foo() { Some(a) => (), None => () }`
69-
pub fn each_binding<F>(&self, mut f: F)
70-
where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
71-
{
69+
pub fn each_binding(&self, mut f: impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident)) {
7270
self.walk(|p| {
7371
if let PatKind::Binding(binding_mode, _, ident, _) = p.node {
7472
f(binding_mode, p.hir_id, p.span, ident);
@@ -81,59 +79,53 @@ impl hir::Pat {
8179
/// `match foo() { Some(a) => (), None => () }`.
8280
///
8381
/// When encountering an or-pattern `p_0 | ... | p_n` only `p_0` will be visited.
84-
pub fn each_binding_or_first<F>(&self, c: &mut F)
85-
where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
86-
{
87-
match &self.node {
88-
PatKind::Binding(bm, _, ident, sub) => {
89-
c(*bm, self.hir_id, self.span, *ident);
90-
sub.iter().for_each(|p| p.each_binding_or_first(c));
91-
}
92-
PatKind::Or(ps) => ps[0].each_binding_or_first(c),
93-
PatKind::Struct(_, fs, _) => fs.iter().for_each(|f| f.pat.each_binding_or_first(c)),
94-
PatKind::TupleStruct(_, ps, _) | PatKind::Tuple(ps, _) => {
95-
ps.iter().for_each(|p| p.each_binding_or_first(c));
96-
}
97-
PatKind::Box(p) | PatKind::Ref(p, _) => p.each_binding_or_first(c),
98-
PatKind::Slice(before, slice, after) => {
99-
before.iter()
100-
.chain(slice.iter())
101-
.chain(after.iter())
102-
.for_each(|p| p.each_binding_or_first(c));
82+
pub fn each_binding_or_first(
83+
&self,
84+
f: &mut impl FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident),
85+
) {
86+
self.walk(|p| match &p.node {
87+
PatKind::Or(ps) => {
88+
ps[0].each_binding_or_first(f);
89+
false
90+
},
91+
PatKind::Binding(bm, _, ident, _) => {
92+
f(*bm, p.hir_id, p.span, *ident);
93+
true
10394
}
104-
PatKind::Wild | PatKind::Lit(_) | PatKind::Range(..) | PatKind::Path(_) => {}
105-
}
95+
_ => true,
96+
})
10697
}
10798

10899
/// Checks if the pattern contains any patterns that bind something to
109100
/// an ident, e.g., `foo`, or `Foo(foo)` or `foo @ Bar(..)`.
110101
pub fn contains_bindings(&self) -> bool {
111-
let mut contains_bindings = false;
112-
self.walk(|p| {
113-
if let PatKind::Binding(..) = p.node {
114-
contains_bindings = true;
115-
false // there's at least one binding, can short circuit now.
116-
} else {
117-
true
118-
}
119-
});
120-
contains_bindings
102+
self.satisfies(|p| match p.node {
103+
PatKind::Binding(..) => true,
104+
_ => false,
105+
})
121106
}
122107

123108
/// Checks if the pattern contains any patterns that bind something to
124109
/// an ident or wildcard, e.g., `foo`, or `Foo(_)`, `foo @ Bar(..)`,
125110
pub fn contains_bindings_or_wild(&self) -> bool {
126-
let mut contains_bindings = false;
127-
self.walk(|p| {
128-
match p.node {
129-
PatKind::Binding(..) | PatKind::Wild => {
130-
contains_bindings = true;
131-
false // there's at least one binding/wildcard, can short circuit now.
132-
}
133-
_ => true
111+
self.satisfies(|p| match p.node {
112+
PatKind::Binding(..) | PatKind::Wild => true,
113+
_ => false,
114+
})
115+
}
116+
117+
/// Checks if the pattern satisfies the given predicate on some sub-pattern.
118+
fn satisfies(&self, pred: impl Fn(&Self) -> bool) -> bool {
119+
let mut satisfies = false;
120+
self.walk_short(|p| {
121+
if pred(p) {
122+
satisfies = true;
123+
false // Found one, can short circuit now.
124+
} else {
125+
true
134126
}
135127
});
136-
contains_bindings
128+
satisfies
137129
}
138130

139131
pub fn simple_ident(&self) -> Option<ast::Ident> {
@@ -147,20 +139,20 @@ impl hir::Pat {
147139
/// Returns variants that are necessary to exist for the pattern to match.
148140
pub fn necessary_variants(&self) -> Vec<DefId> {
149141
let mut variants = vec![];
150-
self.walk(|p| {
151-
match p.node {
152-
PatKind::Path(hir::QPath::Resolved(_, ref path)) |
153-
PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
154-
PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
155-
match path.res {
156-
Res::Def(DefKind::Variant, id) => variants.push(id),
157-
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id) => variants.push(id),
158-
_ => ()
159-
}
142+
self.walk(|p| match &p.node {
143+
PatKind::Or(_) => false,
144+
PatKind::Path(hir::QPath::Resolved(_, path)) |
145+
PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..) |
146+
PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
147+
if let Res::Def(DefKind::Variant, id)
148+
| Res::Def(DefKind::Ctor(CtorOf::Variant, ..), id)
149+
= path.res
150+
{
151+
variants.push(id);
160152
}
161-
_ => ()
153+
true
162154
}
163-
true
155+
_ => true,
164156
});
165157
variants.sort();
166158
variants.dedup();
@@ -176,14 +168,12 @@ impl hir::Pat {
176168
let mut result = None;
177169
self.each_binding(|annotation, _, _, _| {
178170
match annotation {
179-
hir::BindingAnnotation::Ref => {
180-
match result {
181-
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
182-
_ => (),
183-
}
171+
hir::BindingAnnotation::Ref => match result {
172+
None | Some(hir::MutImmutable) => result = Some(hir::MutImmutable),
173+
_ => {}
184174
}
185175
hir::BindingAnnotation::RefMut => result = Some(hir::MutMutable),
186-
_ => (),
176+
_ => {}
187177
}
188178
});
189179
result

src/librustc/middle/dead.rs

+7-14
Original file line numberDiff line numberDiff line change
@@ -259,20 +259,13 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> {
259259
}
260260

261261
fn visit_arm(&mut self, arm: &'tcx hir::Arm) {
262-
let pats = arm.top_pats_hack();
263-
if let [pat] = pats {
264-
let variants = pat.necessary_variants();
265-
266-
// Inside the body, ignore constructions of variants
267-
// necessary for the pattern to match. Those construction sites
268-
// can't be reached unless the variant is constructed elsewhere.
269-
let len = self.ignore_variant_stack.len();
270-
self.ignore_variant_stack.extend_from_slice(&variants);
271-
intravisit::walk_arm(self, arm);
272-
self.ignore_variant_stack.truncate(len);
273-
} else {
274-
intravisit::walk_arm(self, arm);
275-
}
262+
// Inside the body, ignore constructions of variants
263+
// necessary for the pattern to match. Those construction sites
264+
// can't be reached unless the variant is constructed elsewhere.
265+
let len = self.ignore_variant_stack.len();
266+
self.ignore_variant_stack.extend(arm.pat.necessary_variants());
267+
intravisit::walk_arm(self, arm);
268+
self.ignore_variant_stack.truncate(len);
276269
}
277270

278271
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {

0 commit comments

Comments
 (0)