Skip to content

Commit 5508f46

Browse files
committed
Use DroplessArena when allocating ResolvedPats
Fix tuple handling in `match_same_arms`
1 parent b37317b commit 5508f46

File tree

3 files changed

+86
-59
lines changed

3 files changed

+86
-59
lines changed

clippy_lints/src/doc.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -637,12 +637,6 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
637637
loop {
638638
match parser.parse_item(ForceCollect::No) {
639639
Ok(Some(item)) => match &item.kind {
640-
// Tests with one of these items are ignored
641-
ItemKind::Static(..)
642-
| ItemKind::Const(..)
643-
| ItemKind::ExternCrate(..)
644-
| ItemKind::ForeignMod(..) => return false,
645-
// We found a main function ...
646640
ItemKind::Fn(box Fn {
647641
sig, body: Some(block), ..
648642
}) if item.ident.name == sym::main => {
@@ -661,8 +655,13 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, span: Span) {
661655
return false;
662656
}
663657
},
664-
// Another function was found; this case is ignored too
665-
ItemKind::Fn(..) => return false,
658+
// Tests with one of these items are ignored
659+
ItemKind::Static(..)
660+
| ItemKind::Const(..)
661+
| ItemKind::ExternCrate(..)
662+
| ItemKind::ForeignMod(..)
663+
// Another function was found; this case is ignored
664+
| ItemKind::Fn(..) => return false,
666665
_ => {},
667666
},
668667
Ok(None) => break,

clippy_lints/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
// FIXME: switch to something more ergonomic here, once available.
2525
// (Currently there is no way to opt into sysroot crates without `extern crate`.)
26+
extern crate rustc_arena;
2627
extern crate rustc_ast;
2728
extern crate rustc_ast_pretty;
2829
extern crate rustc_attr;

clippy_lints/src/matches/match_same_arms.rs

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
22
use clippy_utils::source::snippet;
33
use clippy_utils::{path_to_local, search_same, SpanlessEq, SpanlessHash};
4+
use core::iter;
5+
use rustc_arena::DroplessArena;
46
use rustc_ast::ast::LitKind;
57
use rustc_hir::def_id::DefId;
68
use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdSet, Pat, PatKind, RangeEnd};
79
use rustc_lint::LateContext;
10+
use rustc_middle::ty;
811
use rustc_span::Symbol;
912
use std::collections::hash_map::Entry;
1013

@@ -17,7 +20,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
1720
h.finish()
1821
};
1922

20-
let resolved_pats: Vec<_> = arms.iter().map(|a| ResolvedPat::from_pat(cx, a.pat)).collect();
23+
let arena = DroplessArena::default();
24+
let resolved_pats: Vec<_> = arms.iter().map(|a| ResolvedPat::from_pat(cx, &arena, a.pat)).collect();
2125

2226
// The furthast forwards a pattern can move without semantic changes
2327
let forwards_blocking_idxs: Vec<_> = resolved_pats
@@ -128,21 +132,22 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
128132
}
129133
}
130134

131-
#[derive(Debug)]
132-
enum ResolvedPat<'hir> {
135+
#[derive(Clone, Copy)]
136+
enum ResolvedPat<'hir, 'arena> {
133137
Wild,
134-
Struct(Option<DefId>, Vec<(Symbol, ResolvedPat<'hir>)>),
135-
Sequence(Option<DefId>, Vec<ResolvedPat<'hir>>, Option<usize>),
136-
Or(Vec<ResolvedPat<'hir>>),
138+
Struct(Option<DefId>, &'arena [(Symbol, Self)]),
139+
Tuple(Option<DefId>, &'arena [Self]),
140+
Or(&'arena [Self]),
137141
Path(Option<DefId>),
138142
LitStr(Symbol),
139143
LitBytes(&'hir [u8]),
140144
LitInt(u128),
141145
LitBool(bool),
142146
Range(PatRange),
147+
Slice(&'arena [Self], &'arena [Self], bool),
143148
}
144149

145-
#[derive(Debug)]
150+
#[derive(Clone, Copy)]
146151
struct PatRange {
147152
start: u128,
148153
end: u128,
@@ -177,28 +182,66 @@ impl PatRange {
177182
}
178183
}
179184

180-
impl<'hir> ResolvedPat<'hir> {
181-
fn from_pat(cx: &LateContext<'_>, pat: &'hir Pat<'_>) -> Self {
185+
#[allow(clippy::similar_names)]
186+
impl<'hir, 'arena> ResolvedPat<'hir, 'arena> {
187+
#[allow(clippy::too_many_lines)]
188+
fn from_pat(cx: &LateContext<'_>, arena: &'arena DroplessArena, pat: &'hir Pat<'_>) -> Self {
182189
match pat.kind {
183190
PatKind::Wild | PatKind::Binding(.., None) => Self::Wild,
184-
PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => Self::from_pat(cx, pat),
191+
PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
192+
Self::from_pat(cx, arena, pat)
193+
},
185194
PatKind::Struct(ref path, fields, _) => {
186-
let mut fields: Vec<_> = fields
187-
.iter()
188-
.map(|f| (f.ident.name, Self::from_pat(cx, f.pat)))
189-
.collect();
195+
let fields =
196+
arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat))));
190197
fields.sort_by_key(|&(name, _)| name);
191198
Self::Struct(cx.qpath_res(path, pat.hir_id).opt_def_id(), fields)
192199
},
193-
PatKind::TupleStruct(ref path, pats, wild_idx) => Self::Sequence(
194-
cx.qpath_res(path, pat.hir_id).opt_def_id(),
195-
pats.iter().map(|pat| Self::from_pat(cx, pat)).collect(),
196-
wild_idx,
197-
),
198-
PatKind::Or(pats) => Self::Or(pats.iter().map(|pat| Self::from_pat(cx, pat)).collect()),
200+
PatKind::TupleStruct(ref path, pats, wild_idx) => {
201+
let adt = match cx.typeck_results().pat_ty(pat).ty_adt_def() {
202+
Some(x) => x,
203+
None => return Self::Wild,
204+
};
205+
let (var_id, variant) = if adt.is_enum() {
206+
match cx.qpath_res(path, pat.hir_id).opt_def_id() {
207+
Some(x) => (Some(x), adt.variant_with_ctor_id(x)),
208+
None => return Self::Wild,
209+
}
210+
} else {
211+
(None, adt.non_enum_variant())
212+
};
213+
let (front, back) = match wild_idx {
214+
Some(i) => pats.split_at(i),
215+
None => (pats, [].as_slice()),
216+
};
217+
let pats = arena.alloc_from_iter(
218+
front
219+
.iter()
220+
.map(|pat| Self::from_pat(cx, arena, pat))
221+
.chain(iter::repeat_with(|| Self::Wild).take(variant.fields.len() - pats.len()))
222+
.chain(back.iter().map(|pat| Self::from_pat(cx, arena, pat))),
223+
);
224+
Self::Tuple(var_id, pats)
225+
},
226+
PatKind::Or(pats) => Self::Or(arena.alloc_from_iter(pats.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
199227
PatKind::Path(ref path) => Self::Path(cx.qpath_res(path, pat.hir_id).opt_def_id()),
200228
PatKind::Tuple(pats, wild_idx) => {
201-
Self::Sequence(None, pats.iter().map(|pat| Self::from_pat(cx, pat)).collect(), wild_idx)
229+
let field_count = match cx.typeck_results().pat_ty(pat).kind() {
230+
ty::Tuple(subs) => subs.len(),
231+
_ => return Self::Wild,
232+
};
233+
let (front, back) = match wild_idx {
234+
Some(i) => pats.split_at(i),
235+
None => (pats, [].as_slice()),
236+
};
237+
let pats = arena.alloc_from_iter(
238+
front
239+
.iter()
240+
.map(|pat| Self::from_pat(cx, arena, pat))
241+
.chain(iter::repeat_with(|| Self::Wild).take(field_count - pats.len()))
242+
.chain(back.iter().map(|pat| Self::from_pat(cx, arena, pat))),
243+
);
244+
Self::Tuple(None, pats)
202245
},
203246
PatKind::Lit(e) => match &e.kind {
204247
ExprKind::Lit(lit) => match lit.node {
@@ -239,23 +282,22 @@ impl<'hir> ResolvedPat<'hir> {
239282
};
240283
Self::Range(PatRange { start, end, bounds })
241284
},
242-
PatKind::Slice(pats, wild, pats2) => Self::Sequence(
243-
None,
244-
pats.iter()
245-
.chain(pats2.iter())
246-
.map(|pat| Self::from_pat(cx, pat))
247-
.collect(),
248-
wild.map(|_| pats.len()),
285+
PatKind::Slice(front, wild_pat, back) => Self::Slice(
286+
arena.alloc_from_iter(front.iter().map(|pat| Self::from_pat(cx, arena, pat))),
287+
arena.alloc_from_iter(back.iter().map(|pat| Self::from_pat(cx, arena, pat))),
288+
wild_pat.is_some(),
249289
),
250290
}
251291
}
252292

253293
/// Checks if two patterns overlap in the values they can match assuming they are for the same
254294
/// type.
255295
fn can_also_match(&self, other: &Self) -> bool {
256-
match (self, other) {
296+
match (*self, *other) {
257297
(Self::Wild, _) | (_, Self::Wild) => true,
258-
(Self::Or(pats), other) | (other, Self::Or(pats)) => pats.iter().any(|pat| pat.can_also_match(other)),
298+
(Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => {
299+
pats.iter().any(|pat| pat.can_also_match(other))
300+
},
259301
(Self::Struct(lpath, lfields), Self::Struct(rpath, rfields)) => {
260302
if lpath != rpath {
261303
return false;
@@ -287,39 +329,24 @@ impl<'hir> ResolvedPat<'hir> {
287329
}
288330
true
289331
},
290-
(Self::Sequence(lpath, lpats, lwild_idx), Self::Sequence(rpath, rpats, rwild_idx)) => {
332+
(Self::Tuple(lpath, lpats), Self::Tuple(rpath, rpats)) => {
291333
if lpath != rpath {
292334
return false;
293335
}
294-
295-
let (lpats_start, lpats_end) = lwild_idx
296-
.or(*rwild_idx)
297-
.map_or((&**lpats, [].as_slice()), |idx| lpats.split_at(idx));
298-
let (rpats_start, rpats_end) = rwild_idx
299-
.or(*lwild_idx)
300-
.map_or((&**rpats, [].as_slice()), |idx| rpats.split_at(idx));
301-
302-
lpats_start
303-
.iter()
304-
.zip(rpats_start.iter())
305-
.all(|(lpat, rpat)| lpat.can_also_match(rpat))
306-
// `lpats_end` and `rpats_end` lengths may be disjointed, so start from the end and ignore any
307-
// extras.
308-
&& lpats_end
336+
lpats
309337
.iter()
310-
.rev()
311-
.zip(rpats_end.iter().rev())
338+
.zip(rpats.iter())
312339
.all(|(lpat, rpat)| lpat.can_also_match(rpat))
313340
},
314341
(Self::Path(x), Self::Path(y)) => x == y,
315342
(Self::LitStr(x), Self::LitStr(y)) => x == y,
316343
(Self::LitBytes(x), Self::LitBytes(y)) => x == y,
317344
(Self::LitInt(x), Self::LitInt(y)) => x == y,
318345
(Self::LitBool(x), Self::LitBool(y)) => x == y,
319-
(Self::Range(x), Self::Range(y)) => x.overlaps(y),
320-
(Self::Range(range), Self::LitInt(x)) | (Self::LitInt(x), Self::Range(range)) => range.contains(*x),
346+
(Self::Range(ref x), Self::Range(ref y)) => x.overlaps(y),
347+
(Self::Range(ref range), Self::LitInt(x)) | (Self::LitInt(x), Self::Range(ref range)) => range.contains(x),
321348

322-
// Todo: Lit* with Path, Range with Path, LitBytes with Sequence
349+
// Todo: Lit* with Path, Range with Path, LitBytes with Slice, Slice with Slice
323350
_ => true,
324351
}
325352
}

0 commit comments

Comments
 (0)