Skip to content

Commit 8956c1e

Browse files
committed
Factor out witness reconstruction
1 parent b7fa9f1 commit 8956c1e

File tree

1 file changed

+131
-89
lines changed

1 file changed

+131
-89
lines changed

src/librustc_mir/hair/pattern/_match.rs

Lines changed: 131 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,82 @@ pub enum Usefulness<'tcx> {
792792
}
793793

794794
impl<'tcx> Usefulness<'tcx> {
795+
fn new_useful(preference: WitnessPreference) -> Self {
796+
match preference {
797+
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
798+
LeaveOutWitness => Useful,
799+
}
800+
}
801+
795802
fn is_useful(&self) -> bool {
796803
match *self {
797804
NotUseful => false,
798805
_ => true,
799806
}
800807
}
808+
809+
fn apply_constructor(
810+
self,
811+
cx: &MatchCheckCtxt<'_, 'tcx>,
812+
ctor: &Constructor<'tcx>,
813+
ty: Ty<'tcx>,
814+
) -> Self {
815+
match self {
816+
UsefulWithWitness(witnesses) => UsefulWithWitness(
817+
witnesses
818+
.into_iter()
819+
.map(|witness| witness.apply_constructor(cx, &ctor, ty))
820+
.collect(),
821+
),
822+
x => x,
823+
}
824+
}
825+
826+
fn apply_wildcard(self, ty: Ty<'tcx>) -> Self {
827+
match self {
828+
UsefulWithWitness(witnesses) => {
829+
let wild = Pat { ty, span: DUMMY_SP, kind: box PatKind::Wild };
830+
UsefulWithWitness(
831+
witnesses
832+
.into_iter()
833+
.map(|mut witness| {
834+
witness.0.push(wild.clone());
835+
witness
836+
})
837+
.collect(),
838+
)
839+
}
840+
x => x,
841+
}
842+
}
843+
844+
fn apply_missing_ctors(
845+
self,
846+
cx: &MatchCheckCtxt<'_, 'tcx>,
847+
ty: Ty<'tcx>,
848+
missing_ctors: &MissingConstructors<'tcx>,
849+
) -> Self {
850+
match self {
851+
UsefulWithWitness(witnesses) => {
852+
let new_patterns: Vec<_> =
853+
missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, ty)).collect();
854+
// Add the new patterns to each witness
855+
UsefulWithWitness(
856+
witnesses
857+
.into_iter()
858+
.flat_map(|witness| {
859+
new_patterns.iter().map(move |pat| {
860+
let mut witness = witness.clone();
861+
witness.0.push(pat.clone());
862+
witness
863+
})
864+
})
865+
.collect(),
866+
)
867+
}
868+
x => x,
869+
}
870+
}
801871
}
802872

803873
#[derive(Copy, Clone, Debug)]
@@ -1399,10 +1469,7 @@ pub fn is_useful<'p, 'a, 'tcx>(
13991469
// the type of the tuple we're checking is inhabited or not.
14001470
if v.is_empty() {
14011471
return if rows.is_empty() {
1402-
match witness_preference {
1403-
ConstructWitness => UsefulWithWitness(vec![Witness(vec![])]),
1404-
LeaveOutWitness => Useful,
1405-
}
1472+
Usefulness::new_useful(witness_preference)
14061473
} else {
14071474
NotUseful
14081475
};
@@ -1527,79 +1594,62 @@ pub fn is_useful<'p, 'a, 'tcx>(
15271594
} else {
15281595
let matrix = matrix.specialize_wildcard();
15291596
let v = v.to_tail();
1530-
match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
1531-
UsefulWithWitness(witnesses) => {
1532-
let cx = &*cx;
1533-
// In this case, there's at least one "free"
1534-
// constructor that is only matched against by
1535-
// wildcard patterns.
1536-
//
1537-
// There are 2 ways we can report a witness here.
1538-
// Commonly, we can report all the "free"
1539-
// constructors as witnesses, e.g., if we have:
1540-
//
1541-
// ```
1542-
// enum Direction { N, S, E, W }
1543-
// let Direction::N = ...;
1544-
// ```
1545-
//
1546-
// we can report 3 witnesses: `S`, `E`, and `W`.
1547-
//
1548-
// However, there are 2 cases where we don't want
1549-
// to do this and instead report a single `_` witness:
1550-
//
1551-
// 1) If the user is matching against a non-exhaustive
1552-
// enum, there is no point in enumerating all possible
1553-
// variants, because the user can't actually match
1554-
// against them themselves, e.g., in an example like:
1555-
// ```
1556-
// let err: io::ErrorKind = ...;
1557-
// match err {
1558-
// io::ErrorKind::NotFound => {},
1559-
// }
1560-
// ```
1561-
// we don't want to show every possible IO error,
1562-
// but instead have `_` as the witness (this is
1563-
// actually *required* if the user specified *all*
1564-
// IO errors, but is probably what we want in every
1565-
// case).
1566-
//
1567-
// 2) If the user didn't actually specify a constructor
1568-
// in this arm, e.g., in
1569-
// ```
1570-
// let x: (Direction, Direction, bool) = ...;
1571-
// let (_, _, false) = x;
1572-
// ```
1573-
// we don't want to show all 16 possible witnesses
1574-
// `(<direction-1>, <direction-2>, true)` - we are
1575-
// satisfied with `(_, _, true)`. In this case,
1576-
// `used_ctors` is empty.
1577-
let new_patterns = if is_non_exhaustive || missing_ctors.all_ctors_are_missing()
1578-
{
1579-
// All constructors are unused. Add a wild pattern
1580-
// rather than each individual constructor.
1581-
vec![Pat { ty: pcx.ty, span: DUMMY_SP, kind: box PatKind::Wild }]
1582-
} else {
1583-
// Construct for each missing constructor a "wild" version of this
1584-
// constructor, that matches everything that can be built with
1585-
// it. For example, if `ctor` is a `Constructor::Variant` for
1586-
// `Option::Some`, we get the pattern `Some(_)`.
1587-
missing_ctors.iter().map(|ctor| ctor.apply_wildcards(cx, pcx.ty)).collect()
1588-
};
1589-
// Add the new patterns to each witness
1590-
let new_witnesses = witnesses
1591-
.into_iter()
1592-
.flat_map(|witness| {
1593-
new_patterns.iter().map(move |pat| {
1594-
let mut witness = witness.clone();
1595-
witness.0.push(pat.clone());
1596-
witness
1597-
})
1598-
})
1599-
.collect();
1600-
UsefulWithWitness(new_witnesses)
1601-
}
1602-
result => result,
1597+
let usefulness = is_useful(cx, &matrix, &v, witness_preference, hir_id);
1598+
1599+
// In this case, there's at least one "free"
1600+
// constructor that is only matched against by
1601+
// wildcard patterns.
1602+
//
1603+
// There are 2 ways we can report a witness here.
1604+
// Commonly, we can report all the "free"
1605+
// constructors as witnesses, e.g., if we have:
1606+
//
1607+
// ```
1608+
// enum Direction { N, S, E, W }
1609+
// let Direction::N = ...;
1610+
// ```
1611+
//
1612+
// we can report 3 witnesses: `S`, `E`, and `W`.
1613+
//
1614+
// However, there are 2 cases where we don't want
1615+
// to do this and instead report a single `_` witness:
1616+
//
1617+
// 1) If the user is matching against a non-exhaustive
1618+
// enum, there is no point in enumerating all possible
1619+
// variants, because the user can't actually match
1620+
// against them themselves, e.g., in an example like:
1621+
// ```
1622+
// let err: io::ErrorKind = ...;
1623+
// match err {
1624+
// io::ErrorKind::NotFound => {},
1625+
// }
1626+
// ```
1627+
// we don't want to show every possible IO error,
1628+
// but instead have `_` as the witness (this is
1629+
// actually *required* if the user specified *all*
1630+
// IO errors, but is probably what we want in every
1631+
// case).
1632+
//
1633+
// 2) If the user didn't actually specify a constructor
1634+
// in this arm, e.g., in
1635+
// ```
1636+
// let x: (Direction, Direction, bool) = ...;
1637+
// let (_, _, false) = x;
1638+
// ```
1639+
// we don't want to show all 16 possible witnesses
1640+
// `(<direction-1>, <direction-2>, true)` - we are
1641+
// satisfied with `(_, _, true)`. In this case,
1642+
// `used_ctors` is empty.
1643+
if is_non_exhaustive || missing_ctors.all_ctors_are_missing() {
1644+
// All constructors are unused. Add a wild pattern
1645+
// rather than each individual constructor.
1646+
usefulness.apply_wildcard(pcx.ty)
1647+
} else {
1648+
// Construct for each missing constructor a "wild" version of this
1649+
// constructor, that matches everything that can be built with
1650+
// it. For example, if `ctor` is a `Constructor::Variant` for
1651+
// `Option::Some`, we get the pattern `Some(_)`.
1652+
usefulness.apply_missing_ctors(cx, pcx.ty, &missing_ctors)
16031653
}
16041654
}
16051655
}
@@ -1621,18 +1671,10 @@ fn is_useful_specialized<'p, 'a, 'tcx>(
16211671
let ctor_wild_subpatterns_owned: Vec<_> = ctor.wildcard_subpatterns(cx, lty).collect();
16221672
let ctor_wild_subpatterns: Vec<_> = ctor_wild_subpatterns_owned.iter().collect();
16231673
let matrix = matrix.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns);
1624-
match v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns) {
1625-
Some(v) => match is_useful(cx, &matrix, &v, witness_preference, hir_id) {
1626-
UsefulWithWitness(witnesses) => UsefulWithWitness(
1627-
witnesses
1628-
.into_iter()
1629-
.map(|witness| witness.apply_constructor(cx, &ctor, lty))
1630-
.collect(),
1631-
),
1632-
result => result,
1633-
},
1634-
None => NotUseful,
1635-
}
1674+
v.specialize_constructor(cx, &ctor, &ctor_wild_subpatterns)
1675+
.map(|v| is_useful(cx, &matrix, &v, witness_preference, hir_id))
1676+
.map(|u| u.apply_constructor(cx, &ctor, lty))
1677+
.unwrap_or(NotUseful)
16361678
}
16371679

16381680
/// Determines the constructors that the given pattern can be specialized to.

0 commit comments

Comments
 (0)