Skip to content

Commit b7e358e

Browse files
committed
Trivialize tracking of unreachable subpatterns
Phew it had been very had to make it work without a good way to identify patterns. Now it's dead easy.
1 parent b6062bd commit b7e358e

File tree

2 files changed

+95
-297
lines changed

2 files changed

+95
-297
lines changed

compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs

+60-19
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ use rustc_span::{Span, DUMMY_SP};
6262
use rustc_target::abi::{Integer, Size, VariantIdx};
6363

6464
use smallvec::{smallvec, SmallVec};
65+
use std::cell::Cell;
6566
use std::cmp::{self, max, min, Ordering};
6667
use std::fmt;
6768
use std::iter::{once, IntoIterator};
@@ -1219,21 +1220,45 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
12191220
}
12201221
}
12211222

1222-
#[derive(Clone)]
1223+
/// Values and patterns can be represented as a constructor applied to some fields. This represents
1224+
/// a pattern in this form.
1225+
/// This also keeps track of whether the pattern has been foundreachable during analysis. For this
1226+
/// reason we should be careful not to clone patterns for which we care about that. Use
1227+
/// `clone_and_forget_reachability` is you're sure.
12231228
pub(crate) struct DeconstructedPat<'p, 'tcx> {
12241229
ctor: Constructor<'tcx>,
12251230
fields: Fields<'p, 'tcx>,
12261231
ty: Ty<'tcx>,
12271232
span: Span,
1233+
reachable: Cell<bool>,
12281234
}
12291235

12301236
impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
12311237
pub(super) fn wildcard(ty: Ty<'tcx>) -> Self {
1232-
Self::new(Wildcard, Fields::empty(), ty)
1238+
Self::new(Wildcard, Fields::empty(), ty, DUMMY_SP)
12331239
}
12341240

1235-
pub(super) fn new(ctor: Constructor<'tcx>, fields: Fields<'p, 'tcx>, ty: Ty<'tcx>) -> Self {
1236-
DeconstructedPat { ctor, fields, ty, span: DUMMY_SP }
1241+
pub(super) fn new(
1242+
ctor: Constructor<'tcx>,
1243+
fields: Fields<'p, 'tcx>,
1244+
ty: Ty<'tcx>,
1245+
span: Span,
1246+
) -> Self {
1247+
DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) }
1248+
}
1249+
1250+
/// Construct a pattern that matches everything that starts with this constructor.
1251+
/// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1252+
/// `Some(_)`.
1253+
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
1254+
let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
1255+
DeconstructedPat::new(ctor, fields, pcx.ty, DUMMY_SP)
1256+
}
1257+
1258+
/// Clone this value. This method emphasizes that cloning loses reachability information and
1259+
/// should be done carefully.
1260+
pub(super) fn clone_and_forget_reachability(&self) -> Self {
1261+
DeconstructedPat::new(self.ctor.clone(), self.fields, self.ty, self.span)
12371262
}
12381263

12391264
pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self {
@@ -1332,12 +1357,9 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13321357
// So here, the constructor for a `"foo"` pattern is `&` (represented by
13331358
// `Single`), and has one field. That field has constructor `Str(value)` and no
13341359
// fields.
1335-
let subpattern = DeconstructedPat {
1336-
ctor: Str(value),
1337-
fields: Fields::empty(),
1338-
ty: t, // `t` is `str`, not `&str`
1339-
span: pat.span,
1340-
};
1360+
// Note: `t` is `str`, not `&str`.
1361+
let subpattern =
1362+
DeconstructedPat::new(Str(value), Fields::empty(), t, pat.span);
13411363
ctor = Single;
13421364
fields = Fields::singleton(cx, subpattern)
13431365
}
@@ -1386,7 +1408,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
13861408
fields = Fields::from_iter(cx, pats.into_iter().map(mkpat));
13871409
}
13881410
}
1389-
DeconstructedPat { ctor, fields, ty: pat.ty, span: pat.span }
1411+
DeconstructedPat::new(ctor, fields, pat.ty, pat.span)
13901412
}
13911413

13921414
pub(crate) fn to_pat(&self, cx: &MatchCheckCtxt<'p, 'tcx>) -> Pat<'tcx> {
@@ -1475,14 +1497,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
14751497
Pat { ty: self.ty, span: DUMMY_SP, kind: Box::new(pat) }
14761498
}
14771499

1478-
/// Construct a pattern that matches everything that starts with this constructor.
1479-
// For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get the pattern
1480-
// `Some(_)`.
1481-
pub(super) fn wild_from_ctor(pcx: PatCtxt<'_, 'p, 'tcx>, ctor: Constructor<'tcx>) -> Self {
1482-
let fields = Fields::wildcards(pcx.cx, pcx.ty, &ctor);
1483-
DeconstructedPat::new(ctor, fields, pcx.ty)
1484-
}
1485-
14861500
pub(super) fn is_or_pat(&self) -> bool {
14871501
matches!(self.ctor, Or)
14881502
}
@@ -1543,6 +1557,33 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
15431557
_ => self.fields.iter_patterns().collect(),
15441558
}
15451559
}
1560+
1561+
/// We keep track for each pattern if it was ever reachable during the analysis. This is used
1562+
/// with `unreachable_spans` to report unreachable subpatterns arising from or patterns.
1563+
pub(super) fn set_reachable(&self) {
1564+
self.reachable.set(true)
1565+
}
1566+
pub(super) fn is_reachable(&self) -> bool {
1567+
self.reachable.get()
1568+
}
1569+
1570+
/// Report the spans of subpatterns that were not reachable, if any.
1571+
pub(super) fn unreachable_spans(&self) -> Vec<Span> {
1572+
let mut spans = Vec::new();
1573+
self.collect_unreachable_spans(&mut spans);
1574+
spans
1575+
}
1576+
1577+
fn collect_unreachable_spans(&self, spans: &mut Vec<Span>) {
1578+
// We don't look at subpatterns if we already reported the whole pattern as unreachable.
1579+
if !self.is_reachable() {
1580+
spans.push(self.span);
1581+
} else {
1582+
for p in self.iter_fields() {
1583+
p.collect_unreachable_spans(spans);
1584+
}
1585+
}
1586+
}
15461587
}
15471588

15481589
/// This is mostly copied from the `Pat` impl. This is best effort and not good enough for a

0 commit comments

Comments
 (0)