Merge pull request #18825 from Veykril/push-sllokkprznkq

minor: Encode TraitData bools as bitflags
This commit is contained in:
Lukas Wirth 2025-01-03 12:01:08 +00:00 committed by GitHub
commit b67de74de9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 81 additions and 50 deletions

View file

@ -229,20 +229,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)] #[derive(Debug, Clone, PartialEq, Eq)]
pub struct TraitData { pub struct TraitData {
pub name: Name, pub name: Name,
pub items: Vec<(Name, AssocItemId)>, pub items: Vec<(Name, AssocItemId)>,
pub is_auto: bool, pub flags: TraitFlags,
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 visibility: RawVisibility, 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 // box it as the vec is usually empty anyways
pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>, pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
} }
@ -261,10 +265,24 @@ impl TraitData {
let item_tree = tree_id.item_tree(db); let item_tree = tree_id.item_tree(db);
let tr_def = &item_tree[tree_id.value]; let tr_def = &item_tree[tree_id.value];
let name = tr_def.name.clone(); 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 visibility = item_tree[tr_def.visibility].clone();
let attrs = item_tree.attrs(db, module_id.krate(), ModItem::from(tree_id.value).into()); 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 = let mut skip_array_during_method_dispatch =
attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists(); attrs.by_key(&sym::rustc_skip_array_during_method_dispatch).exists();
let mut skip_boxed_slice_during_method_dispatch = false; let mut skip_boxed_slice_during_method_dispatch = false;
@ -276,27 +294,21 @@ impl TraitData {
} }
} }
} }
let rustc_has_incoherent_inherent_impls =
attrs.by_key(&sym::rustc_has_incoherent_inherent_impls).exists(); if skip_array_during_method_dispatch {
let fundamental = attrs.by_key(&sym::fundamental).exists(); 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 = let mut collector =
AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr)); AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items); collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
let (items, macro_calls, diagnostics) = collector.finish(); let (items, macro_calls, diagnostics) = collector.finish();
( (
Arc::new(TraitData { Arc::new(TraitData { name, macro_calls, items, visibility, flags }),
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,
}),
DefDiagnostics::new(diagnostics), DefDiagnostics::new(diagnostics),
) )
} }

View file

@ -13,7 +13,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
use base_db::CrateId; use base_db::CrateId;
use hir_def::{ use hir_def::{
data::adt::StructFlags, data::{adt::StructFlags, TraitFlags},
hir::Movability, hir::Movability,
lang_item::{LangItem, LangItemTarget}, lang_item::{LangItem, LangItemTarget},
AssocItemId, BlockId, CallableDefId, GenericDefId, HasModule, ItemContainerId, Lookup, 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 generic_params = generics(db.upcast(), trait_.into());
let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST); let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
let flags = rust_ir::TraitFlags { 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, upstream: trait_.lookup(db.upcast()).container.krate() != krate,
non_enumerable: true, non_enumerable: true,
coinductive: false, // only relevant for Chalk testing coinductive: false, // only relevant for Chalk testing
// FIXME: set these flags correctly // FIXME: set these flags correctly
marker: false, 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 where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars);
let associated_ty_ids = trait_data.associated_types().map(to_assoc_type_id).collect(); 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 chalk_solve::rust_ir::InlineBound;
use hir_def::{ use hir_def::{
lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, data::TraitFlags, lang_item::LangItem, AssocItemId, ConstId, FunctionId, GenericDefId,
TypeAliasId, HasModule, TraitId, TypeAliasId,
}; };
use rustc_hash::FxHashSet; use rustc_hash::FxHashSet;
use smallvec::SmallVec; use smallvec::SmallVec;
@ -432,7 +432,7 @@ where
// Allow `impl AutoTrait` predicates // Allow `impl AutoTrait` predicates
if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred { if let WhereClause::Implemented(TraitRef { trait_id, substitution }) = pred {
let trait_data = db.trait_data(from_chalk_trait_id(*trait_id)); 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 && substitution
.as_slice(Interner) .as_slice(Interner)
.first() .first()

View file

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

View file

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

View file

@ -1,7 +1,10 @@
//! HirDisplay implementations for various hir types. //! HirDisplay implementations for various hir types.
use either::Either; use either::Either;
use hir_def::{ use hir_def::{
data::adt::{StructKind, VariantData}, data::{
adt::{StructKind, VariantData},
TraitFlags,
},
generics::{ generics::{
GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget, WherePredicateTypeTarget,
@ -791,10 +794,10 @@ impl HirDisplay for Trait {
fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
let data = f.db.trait_data(trait_.id); let data = f.db.trait_data(trait_.id);
if data.is_unsafe { if data.flags.contains(TraitFlags::IS_UNSAFE) {
f.write_str("unsafe ")?; f.write_str("unsafe ")?;
} }
if data.is_auto { if data.flags.contains(TraitFlags::IS_AUTO) {
f.write_str("auto ")?; f.write_str("auto ")?;
} }
write!(f, "trait {}", data.name.display(f.db.upcast(), f.edition()))?; 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 either::Either;
use hir_def::{ use hir_def::{
body::BodyDiagnostic, body::BodyDiagnostic,
data::adt::VariantData, data::{adt::VariantData, TraitFlags},
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance}, generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat}, hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode}, item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
@ -2778,11 +2778,11 @@ impl Trait {
} }
pub fn is_auto(self, db: &dyn HirDatabase) -> bool { 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 { 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( pub fn type_or_const_param_count(