Split enum variants out of enum_data query
This commit is contained in:
parent
1835bc2a87
commit
176981ef49
21 changed files with 74 additions and 52 deletions
|
|
@ -56,12 +56,16 @@ bitflags! {
|
|||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumData {
|
||||
pub name: Name,
|
||||
pub variants: Box<[(EnumVariantId, Name)]>,
|
||||
pub repr: Option<ReprOptions>,
|
||||
pub visibility: RawVisibility,
|
||||
pub rustc_has_incoherent_inherent_impls: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariants {
|
||||
pub variants: Box<[(EnumVariantId, Name)]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct EnumVariantData {
|
||||
pub name: Name,
|
||||
|
|
@ -203,28 +207,16 @@ impl StructData {
|
|||
}
|
||||
}
|
||||
|
||||
impl EnumData {
|
||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||
impl EnumVariants {
|
||||
pub(crate) fn enum_variants_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumVariants> {
|
||||
let loc = e.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let rustc_has_incoherent_inherent_impls = item_tree
|
||||
.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
|
||||
.by_key(&sym::rustc_has_incoherent_inherent_impls)
|
||||
.exists();
|
||||
|
||||
let enum_ = &item_tree[loc.id.value];
|
||||
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
Arc::new(EnumVariants {
|
||||
variants: loc.container.def_map(db).enum_definitions[&e]
|
||||
.iter()
|
||||
.map(|&id| (id, item_tree[id.lookup(db).id.value].name.clone()))
|
||||
.collect(),
|
||||
repr,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
rustc_has_incoherent_inherent_impls,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -233,13 +225,6 @@ impl EnumData {
|
|||
Some(id)
|
||||
}
|
||||
|
||||
pub fn variant_body_type(&self) -> IntegerType {
|
||||
match self.repr {
|
||||
Some(ReprOptions { int: Some(builtin), .. }) => builtin,
|
||||
_ => IntegerType::Pointer(true),
|
||||
}
|
||||
}
|
||||
|
||||
// [Adopted from rustc](https://github.com/rust-lang/rust/blob/bd53aa3bf7a24a70d763182303bd75e5fc51a9af/compiler/rustc_middle/src/ty/adt.rs#L446-L448)
|
||||
pub fn is_payload_free(&self, db: &dyn DefDatabase) -> bool {
|
||||
self.variants.iter().all(|(v, _)| {
|
||||
|
|
@ -262,6 +247,35 @@ impl EnumData {
|
|||
}
|
||||
}
|
||||
|
||||
impl EnumData {
|
||||
pub(crate) fn enum_data_query(db: &dyn DefDatabase, e: EnumId) -> Arc<EnumData> {
|
||||
let loc = e.lookup(db);
|
||||
let krate = loc.container.krate;
|
||||
let item_tree = loc.id.item_tree(db);
|
||||
let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
|
||||
let rustc_has_incoherent_inherent_impls = item_tree
|
||||
.attrs(db, loc.container.krate, ModItem::from(loc.id.value).into())
|
||||
.by_key(&sym::rustc_has_incoherent_inherent_impls)
|
||||
.exists();
|
||||
|
||||
let enum_ = &item_tree[loc.id.value];
|
||||
|
||||
Arc::new(EnumData {
|
||||
name: enum_.name.clone(),
|
||||
repr,
|
||||
visibility: item_tree[enum_.visibility].clone(),
|
||||
rustc_has_incoherent_inherent_impls,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn variant_body_type(&self) -> IntegerType {
|
||||
match self.repr {
|
||||
Some(ReprOptions { int: Some(builtin), .. }) => builtin,
|
||||
_ => IntegerType::Pointer(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl EnumVariantData {
|
||||
#[inline]
|
||||
pub(crate) fn enum_variant_data_query(
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ use triomphe::Arc;
|
|||
use crate::{
|
||||
attr::{Attrs, AttrsWithOwner},
|
||||
data::{
|
||||
adt::{EnumData, EnumVariantData, StructData, VariantData},
|
||||
adt::{EnumData, EnumVariantData, EnumVariants, StructData, VariantData},
|
||||
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
|
||||
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
|
||||
},
|
||||
|
|
@ -167,6 +167,9 @@ pub trait DefDatabase:
|
|||
#[salsa::invoke_actual(EnumData::enum_data_query)]
|
||||
fn enum_data(&self, e: EnumId) -> Arc<EnumData>;
|
||||
|
||||
#[salsa::invoke_actual(EnumVariants::enum_variants_query)]
|
||||
fn enum_variants(&self, e: EnumId) -> Arc<EnumVariants>;
|
||||
|
||||
#[salsa::transparent]
|
||||
#[salsa::invoke_actual(EnumVariantData::enum_variant_data_query)]
|
||||
fn enum_variant_data(&self, id: EnumVariantId) -> Arc<EnumVariantData>;
|
||||
|
|
|
|||
|
|
@ -801,7 +801,7 @@ pub(crate) fn adt_datum_query(
|
|||
}
|
||||
hir_def::AdtId::EnumId(id) => {
|
||||
let variants = db
|
||||
.enum_data(id)
|
||||
.enum_variants(id)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(variant_id, _)| variant_id_to_fields(variant_id.into()))
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
let value = match prev_idx {
|
||||
Some(prev_idx) => {
|
||||
1 + db.const_eval_discriminant(
|
||||
db.enum_data(loc.parent).variants[prev_idx as usize].0,
|
||||
db.enum_variants(loc.parent).variants[prev_idx as usize].0,
|
||||
)?
|
||||
}
|
||||
_ => 0,
|
||||
|
|
|
|||
|
|
@ -394,7 +394,7 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
/// Check incorrect names for enum variants.
|
||||
fn validate_enum_variants(&mut self, enum_id: EnumId) {
|
||||
let data = self.db.enum_data(enum_id);
|
||||
let data = self.db.enum_variants(enum_id);
|
||||
|
||||
for (variant_id, _) in data.variants.iter() {
|
||||
self.validate_enum_variant_fields(*variant_id);
|
||||
|
|
|
|||
|
|
@ -642,7 +642,7 @@ fn missing_match_arms<'p>(
|
|||
}
|
||||
|
||||
let non_empty_enum = match scrut_ty.as_adt() {
|
||||
Some((AdtId::EnumId(e), _)) => !cx.db.enum_data(e).variants.is_empty(),
|
||||
Some((AdtId::EnumId(e), _)) => !cx.db.enum_variants(e).variants.is_empty(),
|
||||
_ => false,
|
||||
};
|
||||
let display_target = DisplayTarget::from_crate(cx.db, krate);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ impl EnumVariantContiguousIndex {
|
|||
}
|
||||
|
||||
fn to_enum_variant_id(self, db: &dyn HirDatabase, eid: EnumId) -> EnumVariantId {
|
||||
db.enum_data(eid).variants[self.0].0
|
||||
db.enum_variants(eid).variants[self.0].0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -449,7 +449,7 @@ impl PatCx for MatchCheckCtx<'_> {
|
|||
TyKind::Scalar(Scalar::Int(..) | Scalar::Uint(..)) => unhandled(),
|
||||
TyKind::Array(..) | TyKind::Slice(..) => unhandled(),
|
||||
&TyKind::Adt(AdtId(adt @ hir_def::AdtId::EnumId(enum_id)), ref subst) => {
|
||||
let enum_data = cx.db.enum_data(enum_id);
|
||||
let enum_data = cx.db.enum_variants(enum_id);
|
||||
let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive(adt);
|
||||
|
||||
if enum_data.variants.is_empty() && !is_declared_nonexhaustive {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pub(crate) fn has_drop_glue(db: &dyn HirDatabase, ty: Ty, env: Arc<TraitEnvironm
|
|||
// Unions cannot have fields with destructors.
|
||||
AdtId::UnionId(_) => DropGlue::None,
|
||||
AdtId::EnumId(id) => db
|
||||
.enum_data(id)
|
||||
.enum_variants(id)
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(variant, _)| {
|
||||
|
|
|
|||
|
|
@ -1587,7 +1587,7 @@ impl<'a> InferenceContext<'a> {
|
|||
// If we can resolve to an enum variant, it takes priority over associated type
|
||||
// of the same name.
|
||||
if let Some((AdtId::EnumId(id), _)) = ty.as_adt() {
|
||||
let enum_data = self.db.enum_data(id);
|
||||
let enum_data = self.db.enum_variants(id);
|
||||
if let Some(variant) = enum_data.variant(current_segment.name) {
|
||||
return if remaining_segments.len() == 1 {
|
||||
(ty, Some(variant.into()))
|
||||
|
|
@ -1701,7 +1701,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let segment = path.segments().last().unwrap();
|
||||
// this could be an enum variant or associated type
|
||||
if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
|
||||
let enum_data = self.db.enum_data(enum_id);
|
||||
let enum_data = self.db.enum_variants(enum_id);
|
||||
if let Some(variant) = enum_data.variant(segment) {
|
||||
return (ty, Some(variant.into()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ impl CastTy {
|
|||
let (AdtId::EnumId(id), _) = t.as_adt()? else {
|
||||
return None;
|
||||
};
|
||||
let enum_data = table.db.enum_data(id);
|
||||
let enum_data = table.db.enum_variants(id);
|
||||
if enum_data.is_payload_free(table.db.upcast()) {
|
||||
Some(Self::Int(Int::CEnum))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -963,7 +963,7 @@ impl InferenceContext<'_> {
|
|||
if let Some(variant) = self.result.variant_resolution_for_pat(p) {
|
||||
let adt = variant.adt_id(self.db.upcast());
|
||||
let is_multivariant = match adt {
|
||||
hir_def::AdtId::EnumId(e) => self.db.enum_data(e).variants.len() != 1,
|
||||
hir_def::AdtId::EnumId(e) => self.db.enum_variants(e).variants.len() != 1,
|
||||
_ => false,
|
||||
};
|
||||
if is_multivariant {
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ impl InferenceContext<'_> {
|
|||
Some((AdtId::EnumId(e), subst)) => (e, subst),
|
||||
_ => return None,
|
||||
};
|
||||
let enum_data = self.db.enum_data(enum_id);
|
||||
let enum_data = self.db.enum_variants(enum_id);
|
||||
let variant = enum_data.variant(name)?;
|
||||
self.write_variant_resolution(id, variant.into());
|
||||
Some((ValueNs::EnumVariantId(variant), subst.clone()))
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ impl UninhabitedFrom<'_> {
|
|||
AdtId::UnionId(_) => CONTINUE_OPAQUELY_INHABITED,
|
||||
AdtId::StructId(s) => self.visit_variant(s.into(), subst),
|
||||
AdtId::EnumId(e) => {
|
||||
let enum_data = self.db.enum_data(e);
|
||||
let enum_data = self.db.enum_variants(e);
|
||||
|
||||
for &(variant, _) in enum_data.variants.iter() {
|
||||
let variant_inhabitedness = self.visit_variant(variant.into(), subst);
|
||||
|
|
|
|||
|
|
@ -54,13 +54,13 @@ pub fn layout_of_adt_query(
|
|||
(r, data.repr.unwrap_or_default())
|
||||
}
|
||||
AdtId::EnumId(e) => {
|
||||
let data = db.enum_data(e);
|
||||
let r = data
|
||||
let variants = db.enum_variants(e);
|
||||
let r = variants
|
||||
.variants
|
||||
.iter()
|
||||
.map(|&(v, _)| handle_variant(v.into(), &db.enum_variant_data(v).variant_data))
|
||||
.collect::<Result<SmallVec<_>, _>>()?;
|
||||
(r, data.repr.unwrap_or_default())
|
||||
(r, db.enum_data(e).repr.unwrap_or_default())
|
||||
}
|
||||
};
|
||||
let variants = variants
|
||||
|
|
@ -80,7 +80,7 @@ pub fn layout_of_adt_query(
|
|||
|min, max| repr_discr(dl, &repr, min, max).unwrap_or((Integer::I8, false)),
|
||||
variants.iter_enumerated().filter_map(|(id, _)| {
|
||||
let AdtId::EnumId(e) = def else { return None };
|
||||
let d = db.const_eval_discriminant(db.enum_data(e).variants[id.0].0).ok()?;
|
||||
let d = db.const_eval_discriminant(db.enum_variants(e).variants[id.0].0).ok()?;
|
||||
Some((id, d))
|
||||
}),
|
||||
// FIXME: The current code for niche-filling relies on variant indices
|
||||
|
|
|
|||
|
|
@ -1641,7 +1641,8 @@ impl Evaluator<'_> {
|
|||
match &layout.variants {
|
||||
Variants::Empty => unreachable!(),
|
||||
Variants::Single { index } => {
|
||||
let r = self.const_eval_discriminant(self.db.enum_data(e).variants[index.0].0)?;
|
||||
let r =
|
||||
self.const_eval_discriminant(self.db.enum_variants(e).variants[index.0].0)?;
|
||||
Ok(r)
|
||||
}
|
||||
Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
|
|
@ -1666,7 +1667,7 @@ impl Evaluator<'_> {
|
|||
.unwrap_or(*untagged_variant)
|
||||
.0;
|
||||
let result =
|
||||
self.const_eval_discriminant(self.db.enum_data(e).variants[idx].0)?;
|
||||
self.const_eval_discriminant(self.db.enum_variants(e).variants[idx].0)?;
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ pub(crate) fn visit_module(
|
|||
visit_body(db, &body, cb);
|
||||
}
|
||||
ModuleDefId::AdtId(hir_def::AdtId::EnumId(it)) => {
|
||||
db.enum_data(it).variants.iter().for_each(|&(it, _)| {
|
||||
db.enum_variants(it).variants.iter().for_each(|&(it, _)| {
|
||||
let body = db.body(it.into());
|
||||
cb(it.into());
|
||||
visit_body(db, &body, cb);
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
let (var_id, var_layout) = match &layout.variants {
|
||||
hir_def::layout::Variants::Empty => unreachable!(),
|
||||
hir_def::layout::Variants::Single { index } => {
|
||||
(db.enum_data(e).variants[index.0].0, layout)
|
||||
(db.enum_variants(e).variants[index.0].0, layout)
|
||||
}
|
||||
hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
let size = tag.size(target_data_layout).bytes_usize();
|
||||
|
|
@ -379,7 +379,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
TagEncoding::Direct => {
|
||||
let (var_idx, layout) =
|
||||
variants.iter_enumerated().find_map(|(var_idx, v)| {
|
||||
let def = db.enum_data(e).variants[var_idx.0].0;
|
||||
let def = db.enum_variants(e).variants[var_idx.0].0;
|
||||
(db.const_eval_discriminant(def) == Ok(tag)).then_some((def, v))
|
||||
})?;
|
||||
(var_idx, layout)
|
||||
|
|
@ -392,7 +392,7 @@ pub(crate) fn detect_variant_from_bytes<'a>(
|
|||
.filter(|x| x != untagged_variant)
|
||||
.nth(candidate_tag)
|
||||
.unwrap_or(*untagged_variant);
|
||||
(db.enum_data(e).variants[variant.0].0, &variants[variant])
|
||||
(db.enum_variants(e).variants[variant.0].0, &variants[variant])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ impl Context<'_> {
|
|||
AdtId::StructId(s) => add_constraints_from_variant(VariantId::StructId(s)),
|
||||
AdtId::UnionId(u) => add_constraints_from_variant(VariantId::UnionId(u)),
|
||||
AdtId::EnumId(e) => {
|
||||
db.enum_data(e).variants.iter().for_each(|&(variant, _)| {
|
||||
db.enum_variants(e).variants.iter().for_each(|&(variant, _)| {
|
||||
add_constraints_from_variant(VariantId::EnumVariantId(variant))
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1519,7 +1519,11 @@ impl Enum {
|
|||
}
|
||||
|
||||
pub fn variants(self, db: &dyn HirDatabase) -> Vec<Variant> {
|
||||
db.enum_data(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
|
||||
db.enum_variants(self.id).variants.iter().map(|&(id, _)| Variant { id }).collect()
|
||||
}
|
||||
|
||||
pub fn num_variants(self, db: &dyn HirDatabase) -> usize {
|
||||
db.enum_variants(self.id).variants.len()
|
||||
}
|
||||
|
||||
pub fn repr(self, db: &dyn HirDatabase) -> Option<ReprOptions> {
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ impl ChildBySource for EnumId {
|
|||
let tree = loc.id.item_tree(db);
|
||||
let ast_id_map = db.ast_id_map(loc.id.file_id());
|
||||
|
||||
db.enum_data(*self).variants.iter().for_each(|&(variant, _)| {
|
||||
db.enum_variants(*self).variants.iter().for_each(|&(variant, _)| {
|
||||
res[keys::ENUM_VARIANT]
|
||||
.insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//! Completes constants and paths in unqualified patterns.
|
||||
|
||||
use hir::{db::DefDatabase, AssocItem, ScopeDef};
|
||||
use hir::{AssocItem, ScopeDef};
|
||||
use ide_db::syntax_helpers::suggest_name;
|
||||
use syntax::ast::Pat;
|
||||
|
||||
|
|
@ -60,7 +60,7 @@ pub(crate) fn complete_pattern(
|
|||
}
|
||||
|
||||
let refutable = pattern_ctx.refutability == PatternRefutability::Refutable;
|
||||
let single_variant_enum = |enum_: hir::Enum| ctx.db.enum_data(enum_.into()).variants.len() == 1;
|
||||
let single_variant_enum = |enum_: hir::Enum| enum_.num_variants(ctx.db) == 1;
|
||||
|
||||
if let Some(hir::Adt::Enum(e)) =
|
||||
ctx.expected_type.as_ref().and_then(|ty| ty.strip_references().as_adt())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue