minor: Encode TraitData bools as bitflags

This commit is contained in:
Lukas Wirth 2025-01-03 12:46:07 +01:00
parent 7e639ee3dd
commit 4d66fa797f
7 changed files with 81 additions and 50 deletions

View file

@ -227,20 +227,24 @@ impl TypeAliasData {
}
}
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
pub struct TraitFlags: u8 {
const IS_AUTO = 1 << 0;
const IS_UNSAFE = 1 << 1;
const IS_FUNDAMENTAL = 1 << 2;
const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 3;
const SKIP_ARRAY_DURING_METHOD_DISPATCH = 1 << 4;
const SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH = 1 << 5;
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData {
pub name: Name,
pub items: Vec<(Name, AssocItemId)>,
pub is_auto: bool,
pub is_unsafe: bool,
pub rustc_has_incoherent_inherent_impls: bool,
pub skip_array_during_method_dispatch: bool,
pub skip_boxed_slice_during_method_dispatch: bool,
pub fundamental: bool,
pub flags: TraitFlags,
pub visibility: RawVisibility,
/// Whether the trait has `#[rust_skip_array_during_method_dispatch]`. `hir_ty` will ignore
/// method calls to this trait's methods when the receiver is an array and the crate edition is
/// 2015 or 2018.
// box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
}
@ -259,10 +263,24 @@ impl TraitData {
let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value];
let name = tr_def.name.clone();
let is_auto = tr_def.is_auto;
let is_unsafe = tr_def.is_unsafe;
let visibility = item_tree[tr_def.visibility].clone();
let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into());
let mut flags = TraitFlags::empty();
if tr_def.is_auto {
flags |= TraitFlags::IS_AUTO;
}
if tr_def.is_unsafe {
flags |= TraitFlags::IS_UNSAFE;
}
if attrs.by_key(&sym::fundamental).exists() {
flags |= TraitFlags::IS_FUNDAMENTAL;
}
if attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists() {
flags |= TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
}
let mut skip_array_during_method_dispatch =
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
let mut skip_boxed_slice_during_method_dispatch = false;
@ -274,27 +292,21 @@ impl TraitData {
}
}
}
let rustc_has_incoherent_inherent_impls =
attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists();
let fundamental = attrs.by_key(&sym::fundamental).exists();
if skip_array_during_method_dispatch {
flags |= TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH;
}
if skip_boxed_slice_during_method_dispatch {
flags |= TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH;
}
let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
let (items, macro_calls, diagnostics) = collector.finish();
(
Arc::new(TraitData {
name,
macro_calls,
items,
is_auto,
is_unsafe,
visibility,
skip_array_during_method_dispatch,
skip_boxed_slice_during_method_dispatch,
rustc_has_incoherent_inherent_impls,
fundamental,
}),
Arc::new(TraitData { name, macro_calls, items, visibility, flags }),
DefDiagnostics::new(diagnostics),
)
}

View file

@ -13,7 +13,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId;
use hir_def::{
data::adt::StructFlags,
data::{adt::StructFlags, TraitFlags},
hir::Movability,
lang_item::{LangItem, LangItemTarget},
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup,
@ -675,13 +675,13 @@ pub(crate) fn trait_datum_query(
let generic_params = generics(db.upcast(), trait_.into());
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
let flags = rust_ir::TraitFlags {
auto: trait_data.is_auto,
auto: trait_data.flags.contains(TraitFlags::IS_AUTO),
upstream: trait_.lookup(db.upcast()).container.krate() != krate,
non_enumerable: true,
coinductive: false, // only relevant for Chalk testing
// FIXME: set these flags correctly
marker: false,
fundamental: trait_data.fundamental,
fundamental: trait_data.flags.contains(TraitFlags::IS_FUNDAMENTAL),
};
let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect();

View file

@ -9,8 +9,8 @@ use chalk_ir::{
};
use chalk_solve::rust_ir::InlineBound;
use hir_def::{
lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId,
TypeAliasId,
data::TraitFlags, lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId,
HasModule, TraitId, TypeAliasId,
};
use rustc_hash::FxHashSet;
use smallvec::SmallVec;
@ -432,7 +432,7 @@ where
// Allow `impl AutoTrait` predicates
if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred {
let trait_data = db.trait_data(from_chalk_trait_id(*trait_id));
if trait_data.is_auto
if trait_data.flags.contains(TraitFlags::IS_AUTO)
&& substitution
.as_slice(Interner)
.first()

View file

@ -25,7 +25,7 @@ use either::Either;
use hir_def::{
body::HygieneId,
builtin_type::BuiltinType,
data::adt::StructKind,
data::{adt::StructKind, TraitFlags},
expander::Expander,
generics::{
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
@ -1567,9 +1567,17 @@ impl<'a> TyLoweringContext<'a> {
match (lhs.skip_binders(), rhs.skip_binders()) {
(WhereClause::Implemented(lhs), WhereClause::Implemented(rhs)) => {
let lhs_id = lhs.trait_id;
let lhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(lhs_id)).is_auto;
let lhs_is_auto = ctx
.db
.trait_data(from_chalk_trait_id(lhs_id))
.flags
.contains(TraitFlags::IS_AUTO);
let rhs_id = rhs.trait_id;
let rhs_is_auto = ctx.db.trait_data(from_chalk_trait_id(rhs_id)).is_auto;
let rhs_is_auto = ctx
.db
.trait_data(from_chalk_trait_id(rhs_id))
.flags
.contains(TraitFlags::IS_AUTO);
if !lhs_is_auto && !rhs_is_auto {
multiple_regular_traits = true;

View file

@ -7,7 +7,7 @@ use std::ops::ControlFlow;
use base_db::CrateId;
use chalk_ir::{cast::Cast, UniverseIndex, WithKind};
use hir_def::{
data::{adt::StructFlags, ImplData},
data::{adt::StructFlags, ImplData, TraitFlags},
nameres::DefMap,
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
ModuleId, TraitId,
@ -419,11 +419,17 @@ pub fn def_crates(
}
TyKind::Dyn(_) => {
let trait_id = ty.dyn_trait()?;
Some(if db.trait_data(trait_id).rustc_has_incoherent_inherent_impls {
Some(
if db
.trait_data(trait_id)
.flags
.contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
{
db.incoherent_inherent_impl_crates(cur_crate, TyFingerprint::Dyn(trait_id))
} else {
smallvec![trait_id.module(db.upcast()).krate()]
})
},
)
}
// for primitives, there may be impls in various places (core and alloc
// mostly). We just check the whole crate graph for crates with impls
@ -835,7 +841,9 @@ fn is_inherent_impl_coherent(
hir_def::AdtId::EnumId(it) => db.enum_data(it).rustc_has_incoherent_inherent_impls,
},
TyKind::Dyn(it) => it.principal_id().map_or(false, |trait_id| {
db.trait_data(from_chalk_trait_id(trait_id)).rustc_has_incoherent_inherent_impls
db.trait_data(from_chalk_trait_id(trait_id))
.flags
.contains(TraitFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS)
}),
_ => false,
@ -1204,7 +1212,7 @@ fn iterate_trait_method_candidates(
// 2021.
// This is to make `[a].into_iter()` not break code with the new `IntoIterator` impl for
// arrays.
if data.skip_array_during_method_dispatch
if data.flags.contains(TraitFlags::SKIP_ARRAY_DURING_METHOD_DISPATCH)
&& matches!(self_ty.kind(Interner), TyKind::Array(..))
{
// FIXME: this should really be using the edition of the method name's span, in case it
@ -1213,7 +1221,7 @@ fn iterate_trait_method_candidates(
continue;
}
}
if data.skip_boxed_slice_during_method_dispatch
if data.flags.contains(TraitFlags::SKIP_BOXED_SLICE_DURING_METHOD_DISPATCH)
&& matches!(
self_ty.kind(Interner), TyKind::Adt(AdtId(def), subst)
if is_box(table.db, *def)

View file

@ -1,7 +1,10 @@
//! HirDisplay implementations for various hir types.
use either::Either;
use hir_def::{
data::adt::{StructKind, VariantData},
data::{
adt::{StructKind, VariantData},
TraitFlags,
},
generics::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
@ -791,10 +794,10 @@ impl HirDisplay for Trait {
fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
let data = f.db.trait_data(trait_.id);
if data.is_unsafe {
if data.flags.contains(TraitFlags::IS_UNSAFE) {
f.write_str("unsafe ")?;
}
if data.is_auto {
if data.flags.contains(TraitFlags::IS_AUTO) {
f.write_str("auto ")?;
}
write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?;

View file

@ -43,7 +43,7 @@ use base_db::{CrateDisplayName, CrateId, CrateOrigin};
use either::Either;
use hir_def::{
body::BodyDiagnostic,
data::adt::VariantData,
data::{adt::VariantData, TraitFlags},
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
@ -2778,11 +2778,11 @@ impl Trait {
}
pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
db.trait_data(self.id).is_auto
db.trait_data(self.id).flags.contains(TraitFlags::IS_AUTO)
}
pub fn is_unsafe(&self, db: &dyn HirDatabase) -> bool {
db.trait_data(self.id).is_unsafe
db.trait_data(self.id).flags.contains(TraitFlags::IS_UNSAFE)
}
pub fn type_or_const_param_count(