Bump rustc_pattern_analysis

This commit is contained in:
Lukas Wirth 2024-06-30 18:41:55 +02:00
parent b60b27bd22
commit d859e40db9
4 changed files with 75 additions and 91 deletions

37
Cargo.lock generated
View File

@ -616,7 +616,7 @@ dependencies = [
"oorandom", "oorandom",
"project-model", "project-model",
"ra-ap-rustc_abi", "ra-ap-rustc_abi",
"ra-ap-rustc_index 0.53.0", "ra-ap-rustc_index",
"ra-ap-rustc_pattern_analysis", "ra-ap-rustc_pattern_analysis",
"rustc-hash", "rustc-hash",
"scoped-tls", "scoped-tls",
@ -1489,21 +1489,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46" checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"ra-ap-rustc_index 0.53.0", "ra-ap-rustc_index",
"tracing", "tracing",
] ]
[[package]]
name = "ra-ap-rustc_index"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
dependencies = [
"arrayvec",
"ra-ap-rustc_index_macros 0.44.0",
"smallvec",
]
[[package]] [[package]]
name = "ra-ap-rustc_index" name = "ra-ap-rustc_index"
version = "0.53.0" version = "0.53.0"
@ -1511,22 +1500,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9" checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9"
dependencies = [ dependencies = [
"arrayvec", "arrayvec",
"ra-ap-rustc_index_macros 0.53.0", "ra-ap-rustc_index_macros",
"smallvec", "smallvec",
] ]
[[package]]
name = "ra-ap-rustc_index_macros"
version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8782aaf3a113837c533dfb1c45df91cd17e1fdd1d2f9a20c2e0d1976025c4f1f"
dependencies = [
"proc-macro2",
"quote",
"syn",
"synstructure",
]
[[package]] [[package]]
name = "ra-ap-rustc_index_macros" name = "ra-ap-rustc_index_macros"
version = "0.53.0" version = "0.53.0"
@ -1555,17 +1532,17 @@ version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135" checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135"
dependencies = [ dependencies = [
"ra-ap-rustc_index 0.53.0", "ra-ap-rustc_index",
"ra-ap-rustc_lexer", "ra-ap-rustc_lexer",
] ]
[[package]] [[package]]
name = "ra-ap-rustc_pattern_analysis" name = "ra-ap-rustc_pattern_analysis"
version = "0.44.0" version = "0.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334" checksum = "34768e1faf88c31f2e9ad57b48318a52b507dafac0cddbf01b5d63bfc0b0a365"
dependencies = [ dependencies = [
"ra-ap-rustc_index 0.44.0", "ra-ap-rustc_index",
"rustc-hash", "rustc-hash",
"rustc_apfloat", "rustc_apfloat",
"smallvec", "smallvec",

View File

@ -87,7 +87,7 @@ ra-ap-rustc_lexer = { version = "0.53.0", default-features = false }
ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false } ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false }
ra-ap-rustc_index = { version = "0.53.0", default-features = false } ra-ap-rustc_index = { version = "0.53.0", default-features = false }
ra-ap-rustc_abi = { version = "0.53.0", default-features = false } ra-ap-rustc_abi = { version = "0.53.0", default-features = false }
ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false } ra-ap-rustc_pattern_analysis = { version = "0.53.0", default-features = false }
# local crates that aren't published to crates.io. These should not have versions. # local crates that aren't published to crates.io. These should not have versions.
sourcegen = { path = "./crates/sourcegen" } sourcegen = { path = "./crates/sourcegen" }

View File

@ -51,6 +51,7 @@ pub(crate) struct Pat {
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub(crate) enum PatKind { pub(crate) enum PatKind {
Wild, Wild,
Never,
/// `x`, `ref x`, `x @ P`, etc. /// `x`, `ref x`, `x @ P`, etc.
Binding { Binding {
@ -294,6 +295,7 @@ impl HirDisplay for Pat {
fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
match &*self.kind { match &*self.kind {
PatKind::Wild => write!(f, "_"), PatKind::Wild => write!(f, "_"),
PatKind::Never => write!(f, "!"),
PatKind::Binding { name, subpattern } => { PatKind::Binding { name, subpattern } => {
write!(f, "{}", name.display(f.db.upcast()))?; write!(f, "{}", name.display(f.db.upcast()))?;
if let Some(subpattern) = subpattern { if let Some(subpattern) = subpattern {

View File

@ -4,10 +4,9 @@ use std::fmt;
use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId}; use hir_def::{DefWithBodyId, EnumId, EnumVariantId, HasModule, LocalFieldId, ModuleId, VariantId};
use once_cell::unsync::Lazy; use once_cell::unsync::Lazy;
use rustc_hash::FxHashMap; use rustc_index::IndexVec;
use rustc_pattern_analysis::{ use rustc_pattern_analysis::{
constructor::{Constructor, ConstructorSet, VariantVisibility}, constructor::{Constructor, ConstructorSet, VariantVisibility},
index::IdxContainer,
usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport}, usefulness::{compute_match_usefulness, PlaceValidity, UsefulnessReport},
Captures, PatCx, PrivateUninhabitedField, Captures, PatCx, PrivateUninhabitedField,
}; };
@ -26,10 +25,10 @@ use super::{is_box, FieldPat, Pat, PatKind};
use Constructor::*; use Constructor::*;
// Re-export r-a-specific versions of all these types. // Re-export r-a-specific versions of all these types.
pub(crate) type DeconstructedPat<'p> = pub(crate) type DeconstructedPat<'db> =
rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'p>>; rustc_pattern_analysis::pat::DeconstructedPat<MatchCheckCtx<'db>>;
pub(crate) type MatchArm<'p> = rustc_pattern_analysis::MatchArm<'p, MatchCheckCtx<'p>>; pub(crate) type MatchArm<'db> = rustc_pattern_analysis::MatchArm<'db, MatchCheckCtx<'db>>;
pub(crate) type WitnessPat<'p> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'p>>; pub(crate) type WitnessPat<'db> = rustc_pattern_analysis::pat::WitnessPat<MatchCheckCtx<'db>>;
/// [Constructor] uses this in unimplemented variants. /// [Constructor] uses this in unimplemented variants.
/// It allows porting match expressions from upstream algorithm without losing semantics. /// It allows porting match expressions from upstream algorithm without losing semantics.
@ -54,23 +53,27 @@ impl EnumVariantContiguousIndex {
} }
} }
impl rustc_index::Idx for EnumVariantContiguousIndex {
fn new(idx: usize) -> Self {
EnumVariantContiguousIndex(idx)
}
fn index(self) -> usize {
self.0
}
}
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct MatchCheckCtx<'p> { pub(crate) struct MatchCheckCtx<'db> {
module: ModuleId, module: ModuleId,
body: DefWithBodyId, body: DefWithBodyId,
pub(crate) db: &'p dyn HirDatabase, pub(crate) db: &'db dyn HirDatabase,
exhaustive_patterns: bool, exhaustive_patterns: bool,
min_exhaustive_patterns: bool, min_exhaustive_patterns: bool,
} }
#[derive(Clone)] impl<'db> MatchCheckCtx<'db> {
pub(crate) struct PatData<'p> { pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
/// Keep db around so that we can print variant names in `Debug`.
pub(crate) db: &'p dyn HirDatabase,
}
impl<'p> MatchCheckCtx<'p> {
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'p dyn HirDatabase) -> Self {
let def_map = db.crate_def_map(module.krate()); let def_map = db.crate_def_map(module.krate());
let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns"); let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
let min_exhaustive_patterns = let min_exhaustive_patterns =
@ -80,9 +83,9 @@ impl<'p> MatchCheckCtx<'p> {
pub(crate) fn compute_match_usefulness( pub(crate) fn compute_match_usefulness(
&self, &self,
arms: &[MatchArm<'p>], arms: &[MatchArm<'db>],
scrut_ty: Ty, scrut_ty: Ty,
) -> Result<UsefulnessReport<'p, Self>, ()> { ) -> Result<UsefulnessReport<'db, Self>, ()> {
// FIXME: Determine place validity correctly. For now, err on the safe side. // FIXME: Determine place validity correctly. For now, err on the safe side.
let place_validity = PlaceValidity::MaybeInvalid; let place_validity = PlaceValidity::MaybeInvalid;
// Measured to take ~100ms on modern hardware. // Measured to take ~100ms on modern hardware.
@ -101,7 +104,7 @@ impl<'p> MatchCheckCtx<'p> {
} }
fn variant_id_for_adt( fn variant_id_for_adt(
db: &'p dyn HirDatabase, db: &'db dyn HirDatabase,
ctor: &Constructor<Self>, ctor: &Constructor<Self>,
adt: hir_def::AdtId, adt: hir_def::AdtId,
) -> Option<VariantId> { ) -> Option<VariantId> {
@ -126,7 +129,7 @@ impl<'p> MatchCheckCtx<'p> {
&'a self, &'a self,
ty: &'a Ty, ty: &'a Ty,
variant: VariantId, variant: VariantId,
) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'p> { ) -> impl Iterator<Item = (LocalFieldId, Ty)> + Captures<'a> + Captures<'db> {
let (_, substs) = ty.as_adt().unwrap(); let (_, substs) = ty.as_adt().unwrap();
let field_tys = self.db.field_types(variant); let field_tys = self.db.field_types(variant);
@ -139,8 +142,8 @@ impl<'p> MatchCheckCtx<'p> {
}) })
} }
pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'p> { pub(crate) fn lower_pat(&self, pat: &Pat) -> DeconstructedPat<'db> {
let singleton = |pat: DeconstructedPat<'p>| vec![pat.at_index(0)]; let singleton = |pat: DeconstructedPat<'db>| vec![pat.at_index(0)];
let ctor; let ctor;
let mut fields: Vec<_>; let mut fields: Vec<_>;
let arity; let arity;
@ -228,6 +231,11 @@ impl<'p> MatchCheckCtx<'p> {
fields = Vec::new(); fields = Vec::new();
arity = 0; arity = 0;
} }
PatKind::Never => {
ctor = Never;
fields = Vec::new();
arity = 0;
}
PatKind::Or { pats } => { PatKind::Or { pats } => {
ctor = Or; ctor = Or;
fields = pats fields = pats
@ -238,11 +246,10 @@ impl<'p> MatchCheckCtx<'p> {
arity = pats.len(); arity = pats.len();
} }
} }
let data = PatData { db: self.db }; DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), ())
DeconstructedPat::new(ctor, fields, arity, pat.ty.clone(), data)
} }
pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'p>) -> Pat { pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'db>) -> Pat {
let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p)); let mut subpatterns = pat.iter_fields().map(|p| self.hoist_witness_pat(p));
let kind = match pat.ctor() { let kind = match pat.ctor() {
&Bool(value) => PatKind::LiteralBool { value }, &Bool(value) => PatKind::LiteralBool { value },
@ -290,6 +297,7 @@ impl<'p> MatchCheckCtx<'p> {
Slice(_) => unimplemented!(), Slice(_) => unimplemented!(),
&Str(void) => match void {}, &Str(void) => match void {},
Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild, Wildcard | NonExhaustive | Hidden | PrivateUninhabited => PatKind::Wild,
Never => PatKind::Never,
Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => { Missing | F32Range(..) | F64Range(..) | Opaque(..) | Or => {
never!("can't convert to pattern: {:?}", pat.ctor()); never!("can't convert to pattern: {:?}", pat.ctor());
PatKind::Wild PatKind::Wild
@ -299,13 +307,13 @@ impl<'p> MatchCheckCtx<'p> {
} }
} }
impl<'p> PatCx for MatchCheckCtx<'p> { impl<'db> PatCx for MatchCheckCtx<'db> {
type Error = (); type Error = ();
type Ty = Ty; type Ty = Ty;
type VariantIdx = EnumVariantContiguousIndex; type VariantIdx = EnumVariantContiguousIndex;
type StrLit = Void; type StrLit = Void;
type ArmData = (); type ArmData = ();
type PatData = PatData<'p>; type PatData = ();
fn is_exhaustive_patterns_feature_on(&self) -> bool { fn is_exhaustive_patterns_feature_on(&self) -> bool {
self.exhaustive_patterns self.exhaustive_patterns
@ -339,8 +347,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
}, },
Ref => 1, Ref => 1,
Slice(..) => unimplemented!(), Slice(..) => unimplemented!(),
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..)
| NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0, | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => 0,
Or => { Or => {
never!("The `Or` constructor doesn't have a fixed arity"); never!("The `Or` constructor doesn't have a fixed arity");
0 0
@ -402,8 +410,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
} }
}, },
Slice(_) => unreachable!("Found a `Slice` constructor in match checking"), Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..) Never | Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..)
| NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => smallvec![], | Opaque(..) | NonExhaustive | PrivateUninhabited | Hidden | Missing | Wildcard => {
smallvec![]
}
Or => { Or => {
never!("called `Fields::wildcards` on an `Or` ctor"); never!("called `Fields::wildcards` on an `Or` ctor");
smallvec![] smallvec![]
@ -442,11 +452,8 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
if enum_data.variants.is_empty() && !is_declared_nonexhaustive { if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
ConstructorSet::NoConstructors ConstructorSet::NoConstructors
} else { } else {
let mut variants = FxHashMap::with_capacity_and_hasher( let mut variants = IndexVec::with_capacity(enum_data.variants.len());
enum_data.variants.len(), for &(variant, _) in enum_data.variants.iter() {
Default::default(),
);
for (i, &(variant, _)) in enum_data.variants.iter().enumerate() {
let is_uninhabited = let is_uninhabited =
is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module); is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module);
let visibility = if is_uninhabited { let visibility = if is_uninhabited {
@ -454,13 +461,10 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
} else { } else {
VariantVisibility::Visible VariantVisibility::Visible
}; };
variants.insert(EnumVariantContiguousIndex(i), visibility); variants.push(visibility);
} }
ConstructorSet::Variants { ConstructorSet::Variants { variants, non_exhaustive: is_declared_nonexhaustive }
variants: IdxContainer(variants),
non_exhaustive: is_declared_nonexhaustive,
}
} }
} }
TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union, TyKind::Adt(AdtId(hir_def::AdtId::UnionId(_)), _) => ConstructorSet::Union,
@ -476,26 +480,27 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
fn write_variant_name( fn write_variant_name(
f: &mut fmt::Formatter<'_>, f: &mut fmt::Formatter<'_>,
pat: &rustc_pattern_analysis::pat::DeconstructedPat<Self>, _ctor: &Constructor<Self>,
_ty: &Self::Ty,
) -> fmt::Result { ) -> fmt::Result {
let db = pat.data().db; write!(f, "<write_variant_name unsupported>")
let variant = // We lack the database here ...
pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, pat.ctor(), adt)); // let variant = ty.as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(db, ctor, adt));
if let Some(variant) = variant { // if let Some(variant) = variant {
match variant { // match variant {
VariantId::EnumVariantId(v) => { // VariantId::EnumVariantId(v) => {
write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?; // write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?;
} // }
VariantId::StructId(s) => { // VariantId::StructId(s) => {
write!(f, "{}", db.struct_data(s).name.display(db.upcast()))? // write!(f, "{}", db.struct_data(s).name.display(db.upcast()))?
} // }
VariantId::UnionId(u) => { // VariantId::UnionId(u) => {
write!(f, "{}", db.union_data(u).name.display(db.upcast()))? // write!(f, "{}", db.union_data(u).name.display(db.upcast()))?
} // }
} // }
} // }
Ok(()) // Ok(())
} }
fn bug(&self, fmt: fmt::Arguments<'_>) { fn bug(&self, fmt: fmt::Arguments<'_>) {
@ -507,7 +512,7 @@ impl<'p> PatCx for MatchCheckCtx<'p> {
} }
} }
impl<'p> fmt::Debug for MatchCheckCtx<'p> { impl<'db> fmt::Debug for MatchCheckCtx<'db> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("MatchCheckCtx").finish() f.debug_struct("MatchCheckCtx").finish()
} }