Use a unique id instead of by-address indexing
This commit is contained in:
parent
8465c82b64
commit
be29cd173a
@ -9,6 +9,17 @@ use crate::TypeCx;
|
|||||||
|
|
||||||
use self::Constructor::*;
|
use self::Constructor::*;
|
||||||
|
|
||||||
|
/// A globally unique id to distinguish patterns.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub(crate) struct PatId(u32);
|
||||||
|
impl PatId {
|
||||||
|
fn new() -> Self {
|
||||||
|
use std::sync::atomic::{AtomicU32, Ordering};
|
||||||
|
static PAT_ID: AtomicU32 = AtomicU32::new(0);
|
||||||
|
PatId(PAT_ID.fetch_add(1, Ordering::SeqCst))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Values and patterns can be represented as a constructor applied to some fields. This represents
|
/// Values and patterns can be represented as a constructor applied to some fields. This represents
|
||||||
/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
|
/// a pattern in this form. A `DeconstructedPat` will almost always come from user input; the only
|
||||||
/// exception are some `Wildcard`s introduced during pattern lowering.
|
/// exception are some `Wildcard`s introduced during pattern lowering.
|
||||||
@ -24,11 +35,13 @@ pub struct DeconstructedPat<Cx: TypeCx> {
|
|||||||
/// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
|
/// Extra data to store in a pattern. `None` if the pattern is a wildcard that does not
|
||||||
/// correspond to a user-supplied pattern.
|
/// correspond to a user-supplied pattern.
|
||||||
data: Option<Cx::PatData>,
|
data: Option<Cx::PatData>,
|
||||||
|
/// Globally-unique id used to track usefulness at the level of subpatterns.
|
||||||
|
pub(crate) uid: PatId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Cx: TypeCx> DeconstructedPat<Cx> {
|
impl<Cx: TypeCx> DeconstructedPat<Cx> {
|
||||||
pub fn wildcard(ty: Cx::Ty) -> Self {
|
pub fn wildcard(ty: Cx::Ty) -> Self {
|
||||||
DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None }
|
DeconstructedPat { ctor: Wildcard, fields: Vec::new(), ty, data: None, uid: PatId::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
@ -37,7 +50,7 @@ impl<Cx: TypeCx> DeconstructedPat<Cx> {
|
|||||||
ty: Cx::Ty,
|
ty: Cx::Ty,
|
||||||
data: Cx::PatData,
|
data: Cx::PatData,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
DeconstructedPat { ctor, fields, ty, data: Some(data) }
|
DeconstructedPat { ctor, fields, ty, data: Some(data), uid: PatId::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_or_pat(&self) -> bool {
|
pub(crate) fn is_or_pat(&self) -> bool {
|
||||||
|
@ -713,10 +713,9 @@ use rustc_hash::FxHashSet;
|
|||||||
use rustc_index::bit_set::BitSet;
|
use rustc_index::bit_set::BitSet;
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
use crate::constructor::{Constructor, ConstructorSet, IntRange};
|
use crate::constructor::{Constructor, ConstructorSet, IntRange};
|
||||||
use crate::pat::{DeconstructedPat, PatOrWild, WitnessPat};
|
use crate::pat::{DeconstructedPat, PatId, PatOrWild, WitnessPat};
|
||||||
use crate::{Captures, MatchArm, TypeCx};
|
use crate::{Captures, MatchArm, TypeCx};
|
||||||
|
|
||||||
use self::ValidityConstraint::*;
|
use self::ValidityConstraint::*;
|
||||||
@ -728,36 +727,13 @@ pub fn ensure_sufficient_stack<R>(f: impl FnOnce() -> R) -> R {
|
|||||||
f()
|
f()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrapper type for by-address hashing. Comparison and hashing of the wrapped pointer type will be
|
|
||||||
/// based on the address of its contents, rather than their value.
|
|
||||||
struct ByAddress<T>(T);
|
|
||||||
|
|
||||||
impl<T: Deref> ByAddress<T> {
|
|
||||||
fn addr(&self) -> *const T::Target {
|
|
||||||
(&*self.0) as *const _
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Raw pointer hashing and comparison.
|
|
||||||
impl<T: Deref> std::hash::Hash for ByAddress<T> {
|
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
||||||
self.addr().hash(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Deref> PartialEq for ByAddress<T> {
|
|
||||||
fn eq(&self, other: &Self) -> bool {
|
|
||||||
std::ptr::eq(self.addr(), other.addr())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl<T: Deref> Eq for ByAddress<T> {}
|
|
||||||
|
|
||||||
/// Context that provides information for usefulness checking.
|
/// Context that provides information for usefulness checking.
|
||||||
struct UsefulnessCtxt<'a, 'p, Cx: TypeCx> {
|
struct UsefulnessCtxt<'a, Cx: TypeCx> {
|
||||||
/// The context for type information.
|
/// The context for type information.
|
||||||
tycx: &'a Cx,
|
tycx: &'a Cx,
|
||||||
/// Collect the patterns found useful during usefulness checking. This is used to lint
|
/// Collect the patterns found useful during usefulness checking. This is used to lint
|
||||||
/// unreachable (sub)patterns. We distinguish patterns by their address to avoid needing to
|
/// unreachable (sub)patterns.
|
||||||
/// inspect the contents. They'll all be distinct anyway since they carry a `Span`.
|
useful_subpatterns: FxHashSet<PatId>,
|
||||||
useful_subpatterns: FxHashSet<ByAddress<&'p DeconstructedPat<Cx>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context that provides information local to a place under investigation.
|
/// Context that provides information local to a place under investigation.
|
||||||
@ -1398,7 +1374,7 @@ impl<Cx: TypeCx> WitnessMatrix<Cx> {
|
|||||||
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
|
/// We can however get false negatives because exhaustiveness does not explore all cases. See the
|
||||||
/// section on relevancy at the top of the file.
|
/// section on relevancy at the top of the file.
|
||||||
fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
||||||
mcx: &mut UsefulnessCtxt<'_, 'p, Cx>,
|
mcx: &mut UsefulnessCtxt<'_, Cx>,
|
||||||
overlap_range: IntRange,
|
overlap_range: IntRange,
|
||||||
matrix: &Matrix<'p, Cx>,
|
matrix: &Matrix<'p, Cx>,
|
||||||
specialized_matrix: &Matrix<'p, Cx>,
|
specialized_matrix: &Matrix<'p, Cx>,
|
||||||
@ -1471,7 +1447,7 @@ fn collect_overlapping_range_endpoints<'p, Cx: TypeCx>(
|
|||||||
/// This is all explained at the top of the file.
|
/// This is all explained at the top of the file.
|
||||||
#[instrument(level = "debug", skip(mcx), ret)]
|
#[instrument(level = "debug", skip(mcx), ret)]
|
||||||
fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
||||||
mcx: &mut UsefulnessCtxt<'a, 'p, Cx>,
|
mcx: &mut UsefulnessCtxt<'a, Cx>,
|
||||||
matrix: &mut Matrix<'p, Cx>,
|
matrix: &mut Matrix<'p, Cx>,
|
||||||
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
|
) -> Result<WitnessMatrix<Cx>, Cx::Error> {
|
||||||
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count()));
|
||||||
@ -1598,7 +1574,7 @@ fn compute_exhaustiveness_and_usefulness<'a, 'p, Cx: TypeCx>(
|
|||||||
for row in matrix.rows() {
|
for row in matrix.rows() {
|
||||||
if row.useful {
|
if row.useful {
|
||||||
if let PatOrWild::Pat(pat) = row.head() {
|
if let PatOrWild::Pat(pat) = row.head() {
|
||||||
mcx.useful_subpatterns.insert(ByAddress(pat));
|
mcx.useful_subpatterns.insert(pat.uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1620,14 +1596,14 @@ pub enum Usefulness<'p, Cx: TypeCx> {
|
|||||||
|
|
||||||
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
|
/// Report whether this pattern was found useful, and its subpatterns that were not useful if any.
|
||||||
fn collect_pattern_usefulness<'p, Cx: TypeCx>(
|
fn collect_pattern_usefulness<'p, Cx: TypeCx>(
|
||||||
useful_subpatterns: &FxHashSet<ByAddress<&'p DeconstructedPat<Cx>>>,
|
useful_subpatterns: &FxHashSet<PatId>,
|
||||||
pat: &'p DeconstructedPat<Cx>,
|
pat: &'p DeconstructedPat<Cx>,
|
||||||
) -> Usefulness<'p, Cx> {
|
) -> Usefulness<'p, Cx> {
|
||||||
fn pat_is_useful<'p, Cx: TypeCx>(
|
fn pat_is_useful<'p, Cx: TypeCx>(
|
||||||
useful_subpatterns: &FxHashSet<ByAddress<&'p DeconstructedPat<Cx>>>,
|
useful_subpatterns: &FxHashSet<PatId>,
|
||||||
pat: &'p DeconstructedPat<Cx>,
|
pat: &'p DeconstructedPat<Cx>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if useful_subpatterns.contains(&ByAddress(pat)) {
|
if useful_subpatterns.contains(&pat.uid) {
|
||||||
true
|
true
|
||||||
} else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(useful_subpatterns, f))
|
} else if pat.is_or_pat() && pat.iter_fields().any(|f| pat_is_useful(useful_subpatterns, f))
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user