Skip to content

Commit bb5afb4

Browse files
committed
use a struct abstraction in check_match
1 parent b69cca6 commit bb5afb4

File tree

1 file changed

+94
-60
lines changed

1 file changed

+94
-60
lines changed

src/librustc_const_eval/check_match.rs

Lines changed: 94 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,55 @@ pub const DUMMY_WILD_PAT: &'static Pat = &Pat {
5252
span: DUMMY_SP
5353
};
5454

55-
struct Matrix<'a, 'tcx>(Vec<Vec<(&'a Pat, Option<Ty<'tcx>>)>>);
55+
pub const DUMMY_WILD_PATTERN : Pattern<'static, 'static> = Pattern {
56+
pat: DUMMY_WILD_PAT,
57+
pattern_ty: None
58+
};
59+
60+
#[derive(Copy, Clone)]
61+
pub struct Pattern<'a, 'tcx> {
62+
pat: &'a Pat,
63+
pattern_ty: Option<Ty<'tcx>>
64+
}
65+
66+
impl<'a, 'tcx> Pattern<'a, 'tcx> {
67+
fn as_raw(self) -> &'a Pat {
68+
let mut pat = self.pat;
69+
70+
while let PatKind::Binding(.., Some(ref s)) = pat.node {
71+
pat = s;
72+
}
73+
74+
return pat;
75+
}
76+
77+
78+
/// Checks for common cases of "catchall" patterns that may not be intended as such.
79+
fn is_catchall(self, dm: &DefMap) -> bool {
80+
fn is_catchall(dm: &DefMap, pat: &Pat) -> bool {
81+
match pat.node {
82+
PatKind::Binding(.., None) => true,
83+
PatKind::Binding(.., Some(ref s)) => is_catchall(dm, s),
84+
PatKind::Ref(ref s, _) => is_catchall(dm, s),
85+
PatKind::Tuple(ref v, _) => v.iter().all(|p|is_catchall(dm, &p)),
86+
_ => false
87+
}
88+
}
89+
is_catchall(dm, self.pat)
90+
}
91+
92+
fn span(self) -> Span {
93+
self.pat.span
94+
}
95+
}
96+
97+
struct Matrix<'a, 'tcx>(Vec<Vec<Pattern<'a, 'tcx>>>);
98+
99+
impl<'a, 'tcx> fmt::Debug for Pattern<'a, 'tcx> {
100+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
101+
write!(f, "{}: {:?}", pat_to_string(self.pat), self.pattern_ty)
102+
}
103+
}
56104

57105
/// Pretty-printer for matrices of patterns, example:
58106
/// ++++++++++++++++++++++++++
@@ -72,9 +120,7 @@ impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
72120

73121
let &Matrix(ref m) = self;
74122
let pretty_printed_matrix: Vec<Vec<String>> = m.iter().map(|row| {
75-
row.iter()
76-
.map(|&(pat,ty)| format!("{}: {:?}", pat_to_string(&pat), ty))
77-
.collect::<Vec<String>>()
123+
row.iter().map(|pat| format!("{:?}", pat)).collect()
78124
}).collect();
79125

80126
let column_count = m.iter().map(|row| row.len()).max().unwrap_or(0);
@@ -100,9 +146,8 @@ impl<'a, 'tcx> fmt::Debug for Matrix<'a, 'tcx> {
100146
}
101147
}
102148

103-
impl<'a, 'tcx> FromIterator<Vec<(&'a Pat, Option<Ty<'tcx>>)>> for Matrix<'a, 'tcx> {
104-
fn from_iter<T: IntoIterator<Item=Vec<(&'a Pat, Option<Ty<'tcx>>)>>>(iter: T)
105-
-> Self
149+
impl<'a, 'tcx> FromIterator<Vec<Pattern<'a, 'tcx>>> for Matrix<'a, 'tcx> {
150+
fn from_iter<T: IntoIterator<Item=Vec<Pattern<'a, 'tcx>>>>(iter: T) -> Self
106151
{
107152
Matrix(iter.into_iter().collect())
108153
}
@@ -349,8 +394,8 @@ fn check_arms(cx: &MatchCheckCtxt,
349394
err.span_label(pat.span, &format!("this is an unreachable pattern"));
350395
// if we had a catchall pattern, hint at that
351396
for row in &seen.0 {
352-
if pat_is_catchall(&cx.tcx.def_map.borrow(), row[0].0) {
353-
span_note!(err, row[0].0.span,
397+
if row[0].is_catchall(&cx.tcx.def_map.borrow()) {
398+
span_note!(err, row[0].span(),
354399
"this pattern matches any value");
355400
}
356401
}
@@ -374,29 +419,11 @@ fn check_arms(cx: &MatchCheckCtxt,
374419
}
375420
}
376421

377-
/// Checks for common cases of "catchall" patterns that may not be intended as such.
378-
fn pat_is_catchall(dm: &DefMap, p: &Pat) -> bool {
379-
match p.node {
380-
PatKind::Binding(.., None) => true,
381-
PatKind::Binding(.., Some(ref s)) => pat_is_catchall(dm, &s),
382-
PatKind::Ref(ref s, _) => pat_is_catchall(dm, &s),
383-
PatKind::Tuple(ref v, _) => v.iter().all(|p| pat_is_catchall(dm, &p)),
384-
_ => false
385-
}
386-
}
387-
388-
fn raw_pat(p: &Pat) -> &Pat {
389-
match p.node {
390-
PatKind::Binding(.., Some(ref s)) => raw_pat(&s),
391-
_ => p
392-
}
393-
}
394-
395422
fn check_exhaustive<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
396423
sp: Span,
397424
matrix: &Matrix<'a, 'tcx>,
398425
source: hir::MatchSource) {
399-
match is_useful(cx, matrix, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
426+
match is_useful(cx, matrix, &[DUMMY_WILD_PATTERN], ConstructWitness) {
400427
UsefulWithWitness(pats) => {
401428
let witnesses = if pats.is_empty() {
402429
vec![DUMMY_WILD_PAT]
@@ -655,7 +682,7 @@ impl Constructor {
655682
fn missing_constructors(cx: &MatchCheckCtxt, &Matrix(ref rows): &Matrix,
656683
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
657684
let used_constructors: Vec<Constructor> = rows.iter()
658-
.flat_map(|row| pat_constructors(cx, row[0].0, left_ty, max_slice_length))
685+
.flat_map(|row| pat_constructors(cx, row[0], left_ty, max_slice_length))
659686
.collect();
660687
all_constructors(cx, left_ty, max_slice_length)
661688
.into_iter()
@@ -695,7 +722,7 @@ fn all_constructors(_cx: &MatchCheckCtxt, left_ty: Ty,
695722
// So it assumes that v is non-empty.
696723
fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
697724
matrix: &Matrix<'a, 'tcx>,
698-
v: &[(&Pat, Option<Ty<'tcx>>)],
725+
v: &[Pattern<'a, 'tcx>],
699726
witness: WitnessPreference)
700727
-> Usefulness {
701728
let &Matrix(ref rows) = matrix;
@@ -710,20 +737,22 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
710737
return NotUseful;
711738
}
712739
assert!(rows.iter().all(|r| r.len() == v.len()));
713-
let left_ty = match rows.iter().filter_map(|r| r[0].1).next().or_else(|| v[0].1) {
740+
let left_ty = match rows.iter().filter_map(|r| r[0].pattern_ty).next()
741+
.or_else(|| v[0].pattern_ty)
742+
{
714743
Some(ty) => ty,
715744
None => {
716745
// all patterns are wildcards - we can pick any type we want
717746
cx.tcx.types.bool
718747
}
719748
};
720749

721-
let max_slice_length = rows.iter().filter_map(|row| match row[0].0.node {
750+
let max_slice_length = rows.iter().filter_map(|row| match row[0].pat.node {
722751
PatKind::Slice(ref before, _, ref after) => Some(before.len() + after.len()),
723752
_ => None
724753
}).max().map_or(0, |v| v + 1);
725754

726-
let constructors = pat_constructors(cx, v[0].0, left_ty, max_slice_length);
755+
let constructors = pat_constructors(cx, v[0], left_ty, max_slice_length);
727756
debug!("is_useful - pat_constructors = {:?} left_ty = {:?}", constructors,
728757
left_ty);
729758
if constructors.is_empty() {
@@ -749,7 +778,7 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
749778
}).find(|result| result != &NotUseful).unwrap_or(NotUseful)
750779
} else {
751780
let matrix = rows.iter().filter_map(|r| {
752-
match raw_pat(r[0].0).node {
781+
match r[0].as_raw().node {
753782
PatKind::Binding(..) | PatKind::Wild => Some(r[1..].to_vec()),
754783
_ => None,
755784
}
@@ -777,7 +806,7 @@ fn is_useful<'a, 'tcx>(cx: &MatchCheckCtxt<'a, 'tcx>,
777806
fn is_useful_specialized<'a, 'tcx>(
778807
cx: &MatchCheckCtxt<'a, 'tcx>,
779808
&Matrix(ref m): &Matrix<'a, 'tcx>,
780-
v: &[(&Pat, Option<Ty<'tcx>>)],
809+
v: &[Pattern<'a, 'tcx>],
781810
ctor: Constructor,
782811
lty: Ty<'tcx>,
783812
witness: WitnessPreference) -> Usefulness
@@ -801,18 +830,18 @@ fn is_useful_specialized<'a, 'tcx>(
801830
///
802831
/// On the other hand, a wild pattern and an identifier pattern cannot be
803832
/// specialized in any way.
804-
fn pat_constructors(cx: &MatchCheckCtxt, p: &Pat,
833+
fn pat_constructors(cx: &MatchCheckCtxt, p: Pattern,
805834
left_ty: Ty, max_slice_length: usize) -> Vec<Constructor> {
806-
let pat = raw_pat(p);
835+
let pat = p.as_raw();
807836
match pat.node {
808837
PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..) =>
809838
match cx.tcx.expect_def(pat.id) {
810839
Def::Variant(id) | Def::VariantCtor(id, ..) => vec![Variant(id)],
811840
Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) |
812841
Def::TyAlias(..) | Def::AssociatedTy(..) => vec![Single],
813842
Def::Const(..) | Def::AssociatedConst(..) =>
814-
span_bug!(pat.span, "const pattern should've been rewritten"),
815-
def => span_bug!(pat.span, "pat_constructors: unexpected definition {:?}", def),
843+
span_bug!(p.span(), "const pattern should've been rewritten"),
844+
def => span_bug!(p.span(), "pat_constructors: unexpected definition {:?}", def),
816845
},
817846
PatKind::Lit(ref expr) =>
818847
vec![ConstantValue(eval_const_expr(cx.tcx, &expr))],
@@ -881,15 +910,18 @@ fn range_covered_by_constructor(tcx: TyCtxt, span: Span,
881910

882911
fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
883912
pat: &'a Pat)
884-
-> (&'a Pat, Option<Ty<'tcx>>)
913+
-> Pattern<'a, 'tcx>
885914
{
886915
let pat_ty = cx.tcx.pat_ty(pat);
887-
(pat, Some(match pat.node {
888-
PatKind::Binding(hir::BindByRef(..), ..) => {
889-
pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty
890-
}
891-
_ => pat_ty
892-
}))
916+
Pattern {
917+
pat: pat,
918+
pattern_ty: Some(match pat.node {
919+
PatKind::Binding(hir::BindByRef(..), ..) => {
920+
pat_ty.builtin_deref(false, ty::NoPreference).unwrap().ty
921+
}
922+
_ => pat_ty
923+
})
924+
}
893925
}
894926

895927
/// This is the main specialization step. It expands the first pattern in the given row
@@ -902,20 +934,19 @@ fn wrap_pat<'a, 'b, 'tcx>(cx: &MatchCheckCtxt<'b, 'tcx>,
902934
/// fields filled with wild patterns.
903935
pub fn specialize<'a, 'b, 'tcx>(
904936
cx: &MatchCheckCtxt<'b, 'tcx>,
905-
r: &[(&'a Pat, Option<Ty<'tcx>>)],
937+
r: &[Pattern<'a, 'tcx>],
906938
constructor: &Constructor, col: usize, arity: usize)
907-
-> Option<Vec<(&'a Pat, Option<Ty<'tcx>>)>>
939+
-> Option<Vec<Pattern<'a, 'tcx>>>
908940
{
909-
let pat = raw_pat(r[col].0);
941+
let pat = r[col].as_raw();
910942
let &Pat {
911943
id: pat_id, ref node, span: pat_span
912944
} = pat;
913945
let wpat = |pat: &'a Pat| wrap_pat(cx, pat);
914-
let dummy_pat = (DUMMY_WILD_PAT, None);
915946

916-
let head: Option<Vec<(&Pat, Option<Ty>)>> = match *node {
947+
let head: Option<Vec<Pattern>> = match *node {
917948
PatKind::Binding(..) | PatKind::Wild =>
918-
Some(vec![dummy_pat; arity]),
949+
Some(vec![DUMMY_WILD_PATTERN; arity]),
919950

920951
PatKind::Path(..) => {
921952
match cx.tcx.expect_def(pat_id) {
@@ -942,7 +973,7 @@ pub fn specialize<'a, 'b, 'tcx>(
942973
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| {
943974
wpat(p)
944975
}).collect();
945-
pats.extend(repeat((DUMMY_WILD_PAT, None)).take(arity - args.len()));
976+
pats.extend(repeat(DUMMY_WILD_PATTERN).take(arity - args.len()));
946977
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
947978
Some(pats)
948979
}
@@ -961,7 +992,7 @@ pub fn specialize<'a, 'b, 'tcx>(
961992
Some(variant.fields.iter().map(|sf| {
962993
match pattern_fields.iter().find(|f| f.node.name == sf.name) {
963994
Some(ref f) => wpat(&f.node.pat),
964-
_ => dummy_pat
995+
_ => DUMMY_WILD_PATTERN
965996
}
966997
}).collect())
967998
} else {
@@ -971,7 +1002,7 @@ pub fn specialize<'a, 'b, 'tcx>(
9711002

9721003
PatKind::Tuple(ref args, Some(ddpos)) => {
9731004
let mut pats: Vec<_> = args[..ddpos].iter().map(|p| wpat(p)).collect();
974-
pats.extend(repeat(dummy_pat).take(arity - args.len()));
1005+
pats.extend(repeat(DUMMY_WILD_PATTERN).take(arity - args.len()));
9751006
pats.extend(args[ddpos..].iter().map(|p| wpat(p)));
9761007
Some(pats)
9771008
}
@@ -982,12 +1013,15 @@ pub fn specialize<'a, 'b, 'tcx>(
9821013
Some(vec![wpat(&**inner)]),
9831014

9841015
PatKind::Lit(ref expr) => {
985-
match r[col].1 {
1016+
match r[col].pattern_ty {
9861017
Some(&ty::TyS { sty: ty::TyRef(_, mt), .. }) => {
9871018
// HACK: handle string literals. A string literal pattern
9881019
// serves both as an unary reference pattern and as a
9891020
// nullary value pattern, depending on the type.
990-
Some(vec![(pat, Some(mt.ty))])
1021+
Some(vec![Pattern {
1022+
pat: pat,
1023+
pattern_ty: Some(mt.ty)
1024+
}])
9911025
}
9921026
Some(ty) => {
9931027
assert_eq!(constructor_arity(cx, constructor, ty), 0);
@@ -1023,14 +1057,14 @@ pub fn specialize<'a, 'b, 'tcx>(
10231057
// Fixed-length vectors.
10241058
Some(
10251059
before.iter().map(|p| wpat(p)).chain(
1026-
repeat(dummy_pat).take(arity - pat_len).chain(
1060+
repeat(DUMMY_WILD_PATTERN).take(arity - pat_len).chain(
10271061
after.iter().map(|p| wpat(p))
10281062
)).collect())
10291063
},
10301064
Slice(length) if pat_len <= length && slice.is_some() => {
10311065
Some(
10321066
before.iter().map(|p| wpat(p)).chain(
1033-
repeat(dummy_pat).take(arity - pat_len).chain(
1067+
repeat(DUMMY_WILD_PATTERN).take(arity - pat_len).chain(
10341068
after.iter().map(|p| wpat(p))
10351069
)).collect())
10361070
}
@@ -1105,7 +1139,7 @@ fn is_refutable<A, F>(cx: &MatchCheckCtxt, pat: &Pat, refutable: F) -> Option<A>
11051139
F: FnOnce(&Pat) -> A,
11061140
{
11071141
let pats = Matrix(vec!(vec!(wrap_pat(cx, pat))));
1108-
match is_useful(cx, &pats, &[(DUMMY_WILD_PAT, None)], ConstructWitness) {
1142+
match is_useful(cx, &pats, &[DUMMY_WILD_PATTERN], ConstructWitness) {
11091143
UsefulWithWitness(pats) => Some(refutable(&pats[0])),
11101144
NotUseful => None,
11111145
Useful => bug!()

0 commit comments

Comments
 (0)