From 1280961b51fb0b80867758dc5062bca3b9f0f6fe Mon Sep 17 00:00:00 2001 From: iDawer Date: Sun, 21 Nov 2021 18:15:21 +0500 Subject: [PATCH] internal: sync match checking with rust-lang/rust f31622a50 2021-11-12 --- crates/hir_ty/src/diagnostics/expr.rs | 2 +- .../match_check/deconstruct_pat.rs | 53 +++++++++++-------- .../src/diagnostics/match_check/usefulness.rs | 36 +++++++++---- 3 files changed, 57 insertions(+), 34 deletions(-) diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index 04a0125fd7..00c7b95215 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs @@ -335,7 +335,7 @@ impl ExprValidator { let report = compute_match_usefulness(&cx, &m_arms, match_expr_ty); // 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; // FIXME Report witnesses diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs index 218b48680f..acb3280329 100644 --- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs @@ -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 { match *self { Variant(id) => id.into(), @@ -556,32 +564,33 @@ impl SplitWildcard { // witness. 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 // 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 // considered exhaustive. let is_secretly_empty = enum_data.variants.is_empty() - && !cx.feature_exhaustive_patterns() + && !is_exhaustive_pat_feature && !pcx.is_top_level; - if is_secretly_empty { - smallvec![NonExhaustive] - } else if is_declared_nonexhaustive { - enum_data - .variants - .iter() - .map(|(local_id, ..)| Variant(EnumVariantId { parent: enum_id, local_id })) - .chain(Some(NonExhaustive)) - .collect() - } else if cx.feature_exhaustive_patterns() { - unimplemented!() // see MatchCheckCtx.feature_exhaustive_patterns() - } else { - enum_data - .variants - .iter() - .map(|(local_id, ..)| Variant(EnumVariantId { parent: enum_id, local_id })) - .collect() + let mut ctors: SmallVec<[_; 1]> = enum_data + .variants + .iter() + .filter(|&(_, _v)| { + // If `exhaustive_patterns` is enabled, we exclude variants known to be + // uninhabited. + let is_uninhabited = is_exhaustive_pat_feature + && unimplemented!("after MatchCheckCtx.feature_exhaustive_patterns()"); + !is_uninhabited + }) + .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::Int(..) | Scalar::Uint(..)) => unhandled(), @@ -661,9 +670,7 @@ impl SplitWildcard { Missing { nonexhaustive_enum_missing_real_variants: self .iter_missing(pcx) - .filter(|c| !c.is_non_exhaustive()) - .next() - .is_some(), + .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), } } else { Missing { nonexhaustive_enum_missing_real_variants: false } @@ -820,9 +827,9 @@ impl<'p> Fields<'p> { /// Values and patterns can be represented as a constructor applied to some fields. This represents /// a pattern in this form. -/// This also keeps track of whether the pattern has been foundreachable 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 -/// `clone_and_forget_reachability` is you're sure. +/// `clone_and_forget_reachability` if you're sure. pub(crate) struct DeconstructedPat<'p> { ctor: Constructor, fields: Fields<'p>, diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs index f519f79c76..9b00c4dccf 100644 --- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs @@ -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) +//! //! //! ----- //! @@ -402,9 +402,7 @@ impl<'p> Matrix<'p> { /// expands it. fn push(&mut self, row: PatStack<'p>) { if !row.is_empty() && row.head().is_or_pat() { - for row in row.expand_or_pat() { - self.patterns.push(row); - } + self.patterns.extend(row.expand_or_pat()); } else { self.patterns.push(row); } @@ -500,15 +498,33 @@ impl<'p> Usefulness<'p> { } else { let mut split_wildcard = SplitWildcard::new(pcx); 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 // constructor, that matches everything that can be built with // it. For example, if `ctor` is a `Constructor::Variant` for // `Option::Some`, we get the pattern `Some(_)`. - split_wildcard + let mut new: Vec> = split_wildcard .iter_missing(pcx) - .cloned() - .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) - .collect() + .filter_map(|missing_ctor| { + // Check if this variant is marked `doc(hidden)` + 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 @@ -660,7 +676,7 @@ fn is_useful<'p>( 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 is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);