internal: sync match checking with rust-lang/rust f31622a50 2021-11-12

This commit is contained in:
iDawer 2021-11-21 18:15:21 +05:00
parent deb05930ef
commit 1280961b51
3 changed files with 57 additions and 34 deletions

View file

@ -335,7 +335,7 @@ impl ExprValidator {
let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty); let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty);
// FIXME Report unreacheble arms // FIXME Report unreacheble arms
// https://github.com/rust-lang/rust/blob/25c15cdbe/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200-L201 // https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/check_match.rs#L200
let witnesses = report.non_exhaustiveness_witnesses; let witnesses = report.non_exhaustiveness_witnesses;
// FIXME Report witnesses // FIXME Report witnesses

View file

@ -332,6 +332,14 @@ impl Constructor {
} }
} }
pub(super) fn is_unstable_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool {
false //FIXME: implement this
}
pub(super) fn is_doc_hidden_variant(&self, _pcx: PatCtxt<'_, '_>) -> bool {
false //FIXME: implement this
}
fn variant_id_for_adt(&self, adt: hir_def::AdtId) -> VariantId { fn variant_id_for_adt(&self, adt: hir_def::AdtId) -> VariantId {
match *self { match *self {
Variant(id) => id.into(), Variant(id) => id.into(),
@ -556,32 +564,33 @@ impl SplitWildcard {
// witness. // witness.
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty);
let is_exhaustive_pat_feature = cx.feature_exhaustive_patterns();
// If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it
// as though it had an "unknown" constructor to avoid exposing its emptiness. The // as though it had an "unknown" constructor to avoid exposing its emptiness. The
// exception is if the pattern is at the top level, because we want empty matches to be // exception is if the pattern is at the top level, because we want empty matches to be
// considered exhaustive. // considered exhaustive.
let is_secretly_empty = enum_data.variants.is_empty() let is_secretly_empty = enum_data.variants.is_empty()
&& !cx.feature_exhaustive_patterns() && !is_exhaustive_pat_feature
&& !pcx.is_top_level; && !pcx.is_top_level;
if is_secretly_empty { let mut ctors: SmallVec<[_; 1]> = enum_data
smallvec![NonExhaustive]
} else if is_declared_nonexhaustive {
enum_data
.variants .variants
.iter() .iter()
.map(|(local_id, ..)| Variant(EnumVariantId { parent: enum_id, local_id })) .filter(|&(_, _v)| {
.chain(Some(NonExhaustive)) // If `exhaustive_patterns` is enabled, we exclude variants known to be
.collect() // uninhabited.
} else if cx.feature_exhaustive_patterns() { let is_uninhabited = is_exhaustive_pat_feature
unimplemented!() // see MatchCheckCtx.feature_exhaustive_patterns() && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()");
} else { !is_uninhabited
enum_data })
.variants .map(|(local_id, _)| Variant(EnumVariantId { parent: enum_id, local_id }))
.iter() .collect();
.map(|(local_id, ..)| Variant(EnumVariantId { parent: enum_id, local_id }))
.collect() if is_secretly_empty || is_declared_nonexhaustive {
ctors.push(NonExhaustive);
} }
ctors
} }
TyKind::Scalar(Scalar::Char) => unhandled(), TyKind::Scalar(Scalar::Char) => unhandled(),
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(), TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
@ -661,9 +670,7 @@ impl SplitWildcard {
Missing { Missing {
nonexhaustive_enum_missing_real_variants: self nonexhaustive_enum_missing_real_variants: self
.iter_missing(pcx) .iter_missing(pcx)
.filter(|c| !c.is_non_exhaustive()) .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))),
.next()
.is_some(),
} }
} else { } else {
Missing { nonexhaustive_enum_missing_real_variants: false } Missing { nonexhaustive_enum_missing_real_variants: false }
@ -822,7 +829,7 @@ impl<'p> Fields<'p> {
/// a pattern in this form. /// a pattern in this form.
/// This also keeps track of whether the pattern has been found reachable during analysis. For this /// This also keeps track of whether the pattern has been found reachable during analysis. For this
/// reason we should be careful not to clone patterns for which we care about that. Use /// reason we should be careful not to clone patterns for which we care about that. Use
/// `clone_and_forget_reachability` is you're sure. /// `clone_and_forget_reachability` if you're sure.
pub(crate) struct DeconstructedPat<'p> { pub(crate) struct DeconstructedPat<'p> {
ctor: Constructor, ctor: Constructor,
fields: Fields<'p>, fields: Fields<'p>,

View file

@ -1,5 +1,5 @@
//! Based on rust-lang/rust (last sync 68b76a483 2021-10-01) //! Based on rust-lang/rust (last sync f31622a50 2021-11-12)
//! <https://github.com/rust-lang/rust/blob/68b76a483/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs> //! <https://github.com/rust-lang/rust/blob/f31622a50/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs>
//! //!
//! ----- //! -----
//! //!
@ -402,9 +402,7 @@ impl<'p> Matrix<'p> {
/// expands it. /// expands it.
fn push(&mut self, row: PatStack<'p>) { fn push(&mut self, row: PatStack<'p>) {
if !row.is_empty() && row.head().is_or_pat() { if !row.is_empty() && row.head().is_or_pat() {
for row in row.expand_or_pat() { self.patterns.extend(row.expand_or_pat());
self.patterns.push(row);
}
} else { } else {
self.patterns.push(row); self.patterns.push(row);
} }
@ -500,15 +498,33 @@ impl<'p> Usefulness<'p> {
} else { } else {
let mut split_wildcard = SplitWildcard::new(pcx); let mut split_wildcard = SplitWildcard::new(pcx);
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
// This lets us know if we skipped any variants because they are marked
// `doc(hidden)` or they are unstable feature gate (only stdlib types).
let mut hide_variant_show_wild = false;
// Construct for each missing constructor a "wild" version of this // Construct for each missing constructor a "wild" version of this
// constructor, that matches everything that can be built with // constructor, that matches everything that can be built with
// it. For example, if `ctor` is a `Constructor::Variant` for // it. For example, if `ctor` is a `Constructor::Variant` for
// `Option::Some`, we get the pattern `Some(_)`. // `Option::Some`, we get the pattern `Some(_)`.
split_wildcard let mut new: Vec<DeconstructedPat<'_>> = split_wildcard
.iter_missing(pcx) .iter_missing(pcx)
.cloned() .filter_map(|missing_ctor| {
.map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) // Check if this variant is marked `doc(hidden)`
.collect() if missing_ctor.is_doc_hidden_variant(pcx)
|| missing_ctor.is_unstable_variant(pcx)
{
hide_variant_show_wild = true;
return None;
}
Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()))
})
.collect();
if hide_variant_show_wild {
new.push(DeconstructedPat::wildcard(pcx.ty.clone()))
}
new
}; };
witnesses witnesses
@ -660,7 +676,7 @@ fn is_useful<'p>(
return ret; return ret;
} }
assert!(rows.iter().all(|r| r.len() == v.len())); debug_assert!(rows.iter().all(|r| r.len() == v.len()));
let ty = v.head().ty(); let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);