Make builtin derives cheaper, by not really expanding them, instead store them unexpanded

This commit is contained in:
Chayim Refael Friedman 2025-12-02 13:54:28 +02:00
parent 9581ba4daf
commit 5fbff1d7fb
21 changed files with 1143 additions and 151 deletions

View File

@ -188,6 +188,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal
"deprecated" => attr_flags.insert(AttrFlags::IS_DEPRECATED),
"macro_export" => attr_flags.insert(AttrFlags::IS_MACRO_EXPORT),
"no_mangle" => attr_flags.insert(AttrFlags::NO_MANGLE),
"pointee" => attr_flags.insert(AttrFlags::IS_POINTEE),
"non_exhaustive" => attr_flags.insert(AttrFlags::NON_EXHAUSTIVE),
"ignore" => attr_flags.insert(AttrFlags::IS_IGNORE),
"bench" => attr_flags.insert(AttrFlags::IS_BENCH),
@ -289,6 +290,7 @@ bitflags::bitflags! {
const RUSTC_PAREN_SUGAR = 1 << 42;
const RUSTC_COINDUCTIVE = 1 << 43;
const RUSTC_FORCE_INLINE = 1 << 44;
const IS_POINTEE = 1 << 45;
}
}

View File

@ -0,0 +1,61 @@
//! Definition of builtin derive impls.
//!
//! To save time and memory, builtin derives are not really expanded. Instead, we record them
//! and create their impls based on lowered data, see crates/hir-ty/src/builtin_derive.rs.
use hir_expand::builtin::BuiltinDeriveExpander;
macro_rules! declare_enum {
( $( $trait:ident ),* $(,)? ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinDeriveImplTrait {
$( $trait, )*
}
impl BuiltinDeriveImplTrait {
#[inline]
pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option<crate::TraitId> {
match self {
$( Self::$trait => lang_items.$trait, )*
}
}
}
};
}
declare_enum!(
Copy,
Clone,
Default,
Debug,
Hash,
Ord,
PartialOrd,
Eq,
PartialEq,
CoerceUnsized,
DispatchFromDyn,
);
pub(crate) fn with_derive_traits(
derive: BuiltinDeriveExpander,
mut f: impl FnMut(BuiltinDeriveImplTrait),
) {
let trait_ = match derive {
BuiltinDeriveExpander::Copy => BuiltinDeriveImplTrait::Copy,
BuiltinDeriveExpander::Clone => BuiltinDeriveImplTrait::Clone,
BuiltinDeriveExpander::Default => BuiltinDeriveImplTrait::Default,
BuiltinDeriveExpander::Debug => BuiltinDeriveImplTrait::Debug,
BuiltinDeriveExpander::Hash => BuiltinDeriveImplTrait::Hash,
BuiltinDeriveExpander::Ord => BuiltinDeriveImplTrait::Ord,
BuiltinDeriveExpander::PartialOrd => BuiltinDeriveImplTrait::PartialOrd,
BuiltinDeriveExpander::Eq => BuiltinDeriveImplTrait::Eq,
BuiltinDeriveExpander::PartialEq => BuiltinDeriveImplTrait::PartialEq,
BuiltinDeriveExpander::CoercePointee => {
f(BuiltinDeriveImplTrait::CoerceUnsized);
f(BuiltinDeriveImplTrait::DispatchFromDyn);
return;
}
};
f(trait_);
}

View File

@ -16,8 +16,8 @@ use syntax::ast;
use thin_vec::ThinVec;
use crate::{
AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
AdtId, BuiltinDeriveImplId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap,
HasModule, ImplId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
db::DefDatabase,
per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
visibility::Visibility,
@ -159,6 +159,7 @@ pub struct ItemScope {
declarations: ThinVec<ModuleDefId>,
impls: ThinVec<ImplId>,
builtin_derive_impls: ThinVec<BuiltinDeriveImplId>,
extern_blocks: ThinVec<ExternBlockId>,
unnamed_consts: ThinVec<ConstId>,
/// Traits imported via `use Trait as _;`.
@ -329,6 +330,10 @@ impl ItemScope {
self.impls.iter().copied()
}
pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator<Item = BuiltinDeriveImplId> + '_ {
self.builtin_derive_impls.iter().copied()
}
pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
self.derive_macros.values().flat_map(|it| {
@ -471,6 +476,10 @@ impl ItemScope {
self.impls.push(imp);
}
pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) {
self.builtin_derive_impls.push(imp);
}
pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
self.extern_blocks.push(extern_block);
}
@ -811,6 +820,7 @@ impl ItemScope {
unresolved,
declarations,
impls,
builtin_derive_impls,
unnamed_consts,
unnamed_trait_imports,
legacy_macros,
@ -834,6 +844,7 @@ impl ItemScope {
unresolved.shrink_to_fit();
declarations.shrink_to_fit();
impls.shrink_to_fit();
builtin_derive_impls.shrink_to_fit();
unnamed_consts.shrink_to_fit();
unnamed_trait_imports.shrink_to_fit();
legacy_macros.shrink_to_fit();

View File

@ -2,6 +2,7 @@
//!
//! This attribute to tell the compiler about semi built-in std library
//! features, such as Fn family of traits.
use hir_expand::name::Name;
use intern::{Symbol, sym};
use stdx::impl_from;
@ -10,7 +11,7 @@ use crate::{
StaticId, StructId, TraitId, TypeAliasId, UnionId,
attrs::AttrFlags,
db::DefDatabase,
nameres::{assoc::TraitItems, crate_def_map, crate_local_def_map},
nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map},
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -93,6 +94,10 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
}
}
if matches!(krate.data(db).origin, base_db::CrateOrigin::Lang(base_db::LangCrateOrigin::Core)) {
lang_items.fill_non_lang_core_traits(db, crate_def_map);
}
if lang_items.is_empty() { None } else { Some(Box::new(lang_items)) }
}
@ -135,6 +140,31 @@ impl LangItems {
}
}
fn resolve_core_trait(
db: &dyn DefDatabase,
core_def_map: &DefMap,
modules: &[Symbol],
name: Symbol,
) -> Option<TraitId> {
let mut current = &core_def_map[core_def_map.root];
for module in modules {
let Some((ModuleDefId::ModuleId(cur), _)) =
current.scope.type_(&Name::new_symbol_root(module.clone()))
else {
return None;
};
if cur.krate(db) != core_def_map.krate() || cur.block(db) != core_def_map.block_id() {
return None;
}
current = &core_def_map[cur];
}
let Some((ModuleDefId::TraitId(trait_), _)) = current.scope.type_(&Name::new_symbol_root(name))
else {
return None;
};
Some(trait_)
}
#[salsa::tracked(returns(as_deref))]
pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
let mut traits = Vec::new();
@ -158,6 +188,10 @@ macro_rules! language_item_table {
(
$LangItems:ident =>
$( $(#[$attr:meta])* $lang_item:ident, $module:ident :: $name:ident, $target:ident; )*
@non_lang_core_traits:
$( core::$($non_lang_module:ident)::*, $non_lang_trait:ident; )*
) => {
#[allow(non_snake_case)] // FIXME: Should we remove this?
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
@ -166,6 +200,9 @@ macro_rules! language_item_table {
$(#[$attr])*
pub $lang_item: Option<$target>,
)*
$(
pub $non_lang_trait: Option<TraitId>,
)*
}
impl LangItems {
@ -176,6 +213,7 @@ macro_rules! language_item_table {
/// Merges `self` with `other`, with preference to `self` items.
fn merge_prefer_self(&mut self, other: &Self) {
$( self.$lang_item = self.$lang_item.or(other.$lang_item); )*
$( self.$non_lang_trait = self.$non_lang_trait.or(other.$non_lang_trait); )*
}
fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) {
@ -190,6 +228,10 @@ macro_rules! language_item_table {
_ => {}
}
}
fn fill_non_lang_core_traits(&mut self, db: &dyn DefDatabase, core_def_map: &DefMap) {
$( self.$non_lang_trait = resolve_core_trait(db, core_def_map, &[ $(sym::$non_lang_module),* ], sym::$non_lang_trait); )*
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -426,4 +468,11 @@ language_item_table! { LangItems =>
String, sym::String, StructId;
CStr, sym::CStr, StructId;
Ordering, sym::Ordering, EnumId;
@non_lang_core_traits:
core::default, Default;
core::fmt, Debug;
core::hash, Hash;
core::cmp, Ord;
core::cmp, Eq;
}

View File

@ -30,6 +30,7 @@ pub mod dyn_map;
pub mod item_tree;
pub mod builtin_derive;
pub mod lang_item;
pub mod hir;
@ -80,6 +81,7 @@ pub use hir_expand::{Intern, Lookup, tt};
use crate::{
attrs::AttrFlags,
builtin_derive::BuiltinDeriveImplTrait,
builtin_type::BuiltinType,
db::DefDatabase,
expr_store::ExpressionStoreSourceMap,
@ -331,6 +333,19 @@ impl ImplId {
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct BuiltinDeriveImplLoc {
pub adt: AdtId,
pub trait_: BuiltinDeriveImplTrait,
}
#[salsa::interned(debug, no_lifetime)]
#[derive(PartialOrd, Ord)]
pub struct BuiltinDeriveImplId {
#[returns(ref)]
pub loc: BuiltinDeriveImplLoc,
}
type UseLoc = ItemLoc<ast::Use>;
impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
@ -1009,6 +1024,20 @@ fn module_for_assoc_item_loc<'db>(
id.lookup(db).container.module(db)
}
impl HasModule for BuiltinDeriveImplLoc {
#[inline]
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
self.adt.module(db)
}
}
impl HasModule for BuiltinDeriveImplId {
#[inline]
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
self.loc(db).module(db)
}
}
impl HasModule for FunctionId {
#[inline]
fn module(&self, db: &dyn DefDatabase) -> ModuleId {

View File

@ -12,7 +12,7 @@ use hir_expand::{
AttrMacroAttrIds, EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId,
MacroCallKind, MacroDefId, MacroDefKind,
attrs::{Attr, AttrId},
builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
builtin::{BuiltinDeriveExpander, find_builtin_attr, find_builtin_derive, find_builtin_macro},
mod_path::{ModPath, PathKind},
name::{AsName, Name},
proc_macro::CustomProcMacroExpander,
@ -23,15 +23,17 @@ use la_arena::Idx;
use rustc_hash::{FxHashMap, FxHashSet};
use smallvec::SmallVec;
use span::{Edition, FileAstId, SyntaxContext};
use stdx::always;
use syntax::ast;
use triomphe::Arc;
use crate::{
AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, EnumLoc, ExternBlockLoc, ExternCrateId,
ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, ItemContainerId, Lookup,
Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags,
ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc,
UnionLoc, UnresolvedMacro, UseId, UseLoc,
AdtId, AssocItemId, AstId, AstIdWithPath, BuiltinDeriveImplId, BuiltinDeriveImplLoc, ConstLoc,
EnumLoc, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap,
ImplLoc, Intern, ItemContainerId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId,
UseLoc,
db::DefDatabase,
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
item_tree::{
@ -104,6 +106,7 @@ pub(super) fn collect_defs(
prev_active_attrs: Default::default(),
unresolved_extern_crates: Default::default(),
is_proc_macro: krate.is_proc_macro,
deferred_builtin_derives: Default::default(),
};
if tree_id.is_block() {
collector.seed_with_inner(tree_id);
@ -214,6 +217,15 @@ enum MacroDirectiveKind<'db> {
},
}
#[derive(Debug)]
struct DeferredBuiltinDerive {
call_id: MacroCallId,
derive: BuiltinDeriveExpander,
module_id: ModuleId,
depth: usize,
container: ItemContainerId,
}
/// Walks the tree of module recursively
struct DefCollector<'db> {
db: &'db dyn DefDatabase,
@ -252,6 +264,11 @@ struct DefCollector<'db> {
/// on the same item. Therefore, this holds all active attributes that we already
/// expanded.
prev_active_attrs: FxHashMap<AstId<ast::Item>, SmallVec<[AttrId; 1]>>,
/// To save memory, we do not really expand builtin derives. Instead, we save them as a `BuiltinDeriveImplId`.
///
/// However, we can only do that when the derive is directly above the item, and there is no attribute in between.
/// Otherwise, all sorts of weird things can happen, like the item name resolving to something else.
deferred_builtin_derives: FxHashMap<AstId<ast::Item>, Vec<DeferredBuiltinDerive>>,
}
impl<'db> DefCollector<'db> {
@ -1241,7 +1258,7 @@ impl<'db> DefCollector<'db> {
fn resolve_macros(&mut self) -> ReachedFixedPoint {
let mut macros = mem::take(&mut self.unresolved_macros);
let mut resolved = Vec::new();
let mut push_resolved = |directive: &MacroDirective<'_>, call_id| {
let push_resolved = |resolved: &mut Vec<_>, directive: &MacroDirective<'_>, call_id| {
let attr_macro_item = match &directive.kind {
MacroDirectiveKind::Attr { ast_id, .. } => Some(ast_id.ast_id),
MacroDirectiveKind::FnLike { .. } | MacroDirectiveKind::Derive { .. } => None,
@ -1271,8 +1288,8 @@ impl<'db> DefCollector<'db> {
MacroSubNs::Attr
}
};
let resolver = |path: &_| {
let resolved_res = self.def_map.resolve_path_fp_with_macro(
let resolver = |def_map: &DefMap, path: &_| {
let resolved_res = def_map.resolve_path_fp_with_macro(
self.crate_local_def_map.unwrap_or(&self.local_def_map),
self.db,
ResolveMode::Other,
@ -1283,7 +1300,7 @@ impl<'db> DefCollector<'db> {
);
resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it)))
};
let resolver_def_id = |path: &_| resolver(path).map(|(_, it)| it);
let resolver_def_id = |path: &_| resolver(&self.def_map, path).map(|(_, it)| it);
match &directive.kind {
MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => {
@ -1306,7 +1323,7 @@ impl<'db> DefCollector<'db> {
.scope
.add_macro_invoc(ast_id.ast_id, call_id);
push_resolved(directive, call_id);
push_resolved(&mut resolved, directive, call_id);
res = ReachedFixedPoint::No;
return Resolved::Yes;
@ -1320,6 +1337,7 @@ impl<'db> DefCollector<'db> {
ctxt: call_site,
derive_macro_id,
} => {
// FIXME: This code is almost duplicate below.
let id = derive_macro_as_call_id(
self.db,
ast_id,
@ -1327,7 +1345,7 @@ impl<'db> DefCollector<'db> {
*derive_pos as u32,
*call_site,
self.def_map.krate,
resolver,
|path| resolver(&self.def_map, path),
*derive_macro_id,
);
@ -1354,7 +1372,8 @@ impl<'db> DefCollector<'db> {
}
}
push_resolved(directive, call_id);
push_resolved(&mut resolved, directive, call_id);
res = ReachedFixedPoint::No;
return Resolved::Yes;
}
@ -1470,18 +1489,78 @@ impl<'db> DefCollector<'db> {
ast_id.value,
Interned::new(path),
);
self.unresolved_macros.push(MacroDirective {
module_id: directive.module_id,
depth: directive.depth + 1,
kind: MacroDirectiveKind::Derive {
ast_id,
derive_attr: *attr_id,
derive_pos: idx,
ctxt: call_site.ctx,
derive_macro_id: call_id,
},
container: directive.container,
});
// Try to resolve the derive immediately. If we succeed, we can also use the fast path
// for builtin derives. If not, we cannot use it, as it can cause the ADT to become
// interned while the derive is still unresolved, which will cause it to get forgotten.
let id = derive_macro_as_call_id(
self.db,
&ast_id,
*attr_id,
idx as u32,
call_site.ctx,
self.def_map.krate,
|path| resolver(&self.def_map, path),
call_id,
);
if let Ok((macro_id, def_id, call_id)) = id {
self.def_map.modules[directive.module_id]
.scope
.set_derive_macro_invoc(
ast_id.ast_id,
call_id,
*attr_id,
idx,
);
// Record its helper attributes.
if def_id.krate != self.def_map.krate {
let def_map = crate_def_map(self.db, def_id.krate);
if let Some(helpers) =
def_map.data.exported_derives.get(&macro_id)
{
self.def_map
.derive_helpers_in_scope
.entry(ast_id.ast_id.map(|it| it.upcast()))
.or_default()
.extend(izip!(
helpers.iter().cloned(),
iter::repeat(macro_id),
iter::repeat(call_id),
));
}
}
if let MacroDefKind::BuiltInDerive(_, builtin_derive) =
def_id.kind
{
self.deferred_builtin_derives
.entry(ast_id.ast_id.upcast())
.or_default()
.push(DeferredBuiltinDerive {
call_id,
derive: builtin_derive,
module_id: directive.module_id,
container: directive.container,
depth: directive.depth,
});
} else {
push_resolved(&mut resolved, directive, call_id);
}
} else {
self.unresolved_macros.push(MacroDirective {
module_id: directive.module_id,
depth: directive.depth + 1,
kind: MacroDirectiveKind::Derive {
ast_id,
derive_attr: *attr_id,
derive_pos: idx,
ctxt: call_site.ctx,
derive_macro_id: call_id,
},
container: directive.container,
});
}
len = idx;
}
@ -1522,12 +1601,25 @@ impl<'db> DefCollector<'db> {
}
}
// Clear deferred derives for this item, unfortunately we cannot use them due to the attribute.
if let Some(deferred_derives) = self.deferred_builtin_derives.remove(&ast_id) {
resolved.extend(deferred_derives.into_iter().map(|derive| {
(
derive.module_id,
derive.depth,
derive.container,
derive.call_id,
Some(ast_id),
)
}));
}
let call_id = call_id();
self.def_map.modules[directive.module_id]
.scope
.add_attr_macro_invoc(ast_id, call_id);
push_resolved(directive, call_id);
push_resolved(&mut resolved, directive, call_id);
res = ReachedFixedPoint::No;
return Resolved::Yes;
}
@ -1709,6 +1801,12 @@ impl<'db> DefCollector<'db> {
));
}
always!(
self.deferred_builtin_derives.is_empty(),
"self.deferred_builtin_derives={:#?}",
self.deferred_builtin_derives,
);
(self.def_map, self.local_def_map)
}
}
@ -1751,6 +1849,26 @@ impl ModCollector<'_, '_> {
}
let db = self.def_collector.db;
let module_id = self.module_id;
let consider_deferred_derives =
|file_id: HirFileId,
deferred_derives: &mut FxHashMap<_, Vec<DeferredBuiltinDerive>>,
ast_id: FileAstId<ast::Adt>,
id: AdtId,
def_map: &mut DefMap| {
let Some(deferred_derives) =
deferred_derives.remove(&InFile::new(file_id, ast_id.upcast()))
else {
return;
};
let module = &mut def_map.modules[module_id];
for deferred_derive in deferred_derives {
crate::builtin_derive::with_derive_traits(deferred_derive.derive, |trait_| {
let impl_id =
BuiltinDeriveImplId::new(db, BuiltinDeriveImplLoc { adt: id, trait_ });
module.scope.define_builtin_derive_impl(impl_id);
});
}
};
let update_def =
|def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
def_collector.def_map.modules[module_id].scope.declare(id);
@ -1928,11 +2046,21 @@ impl ModCollector<'_, '_> {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
let interned = StructLoc {
container: module_id,
id: InFile::new(self.tree_id.file_id(), id),
}
.intern(db);
consider_deferred_derives(
self.tree_id.file_id(),
&mut self.def_collector.deferred_builtin_derives,
id.upcast(),
interned.into(),
def_map,
);
update_def(
self.def_collector,
StructLoc { container: module_id, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
interned.into(),
&it.name,
vis,
!matches!(it.shape, FieldsShape::Record),
@ -1942,15 +2070,19 @@ impl ModCollector<'_, '_> {
let it = &self.item_tree[id];
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(
self.def_collector,
UnionLoc { container: module_id, id: InFile::new(self.file_id(), id) }
.intern(db)
.into(),
&it.name,
vis,
false,
let interned = UnionLoc {
container: module_id,
id: InFile::new(self.tree_id.file_id(), id),
}
.intern(db);
consider_deferred_derives(
self.tree_id.file_id(),
&mut self.def_collector.deferred_builtin_derives,
id.upcast(),
interned.into(),
def_map,
);
update_def(self.def_collector, interned.into(), &it.name, vis, false);
}
ModItemId::Enum(id) => {
let it = &self.item_tree[id];
@ -1960,6 +2092,13 @@ impl ModCollector<'_, '_> {
}
.intern(db);
consider_deferred_derives(
self.tree_id.file_id(),
&mut self.def_collector.deferred_builtin_derives,
id.upcast(),
enum_.into(),
def_map,
);
let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
update_def(self.def_collector, enum_.into(), &it.name, vis, false);
}

View File

@ -784,7 +784,7 @@ macro_rules! foo {
pub use core::clone::Clone;
"#,
|map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
|map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
);
}
@ -806,7 +806,7 @@ pub macro Copy {}
#[rustc_builtin_macro]
pub macro Clone {}
"#,
|map| assert_eq!(map.modules[map.root].scope.impls().len(), 2),
|map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 2),
);
}
@ -849,7 +849,7 @@ pub macro derive($item:item) {}
#[rustc_builtin_macro]
pub macro Clone {}
"#,
|map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
|map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
);
}
@ -1609,7 +1609,7 @@ macro_rules! derive { () => {} }
#[derive(Clone)]
struct S;
"#,
|map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
|map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
);
}

View File

@ -28,7 +28,7 @@ use syntax::{
};
macro_rules! register_builtin {
( $($trait:ident => $expand:ident),* ) => {
( $($trait:ident => $expand:ident),* $(,)? ) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BuiltinDeriveExpander {
$($trait),*
@ -48,7 +48,6 @@ macro_rules! register_builtin {
}
}
}
};
}
@ -75,7 +74,7 @@ register_builtin! {
PartialOrd => partial_ord_expand,
Eq => eq_expand,
PartialEq => partial_eq_expand,
CoercePointee => coerce_pointee_expand
CoercePointee => coerce_pointee_expand,
}
pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander> {

View File

@ -0,0 +1,575 @@
//! Implementation of builtin derive impls.
use std::ops::ControlFlow;
use hir_def::{
AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, HasModule, LocalFieldId, TraitId,
TypeOrConstParamId, TypeParamId,
attrs::AttrFlags,
builtin_derive::BuiltinDeriveImplTrait,
hir::generics::{GenericParams, TypeOrConstParamData},
};
use itertools::Itertools;
use la_arena::ArenaMap;
use rustc_type_ir::{
AliasTyKind, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
inherent::{GenericArgs as _, IntoKind},
};
use crate::{
GenericPredicates,
db::HirDatabase,
next_solver::{
Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, StoredEarlyBinder, StoredTy,
TraitRef, Ty, TyKind, fold::fold_tys, generics::Generics,
},
};
fn fake_type_param(adt: AdtId) -> TypeParamId {
// HACK: Fake the param.
TypeParamId::from_unchecked(TypeOrConstParamId {
parent: adt.into(),
local_id: la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(u32::MAX)),
})
}
pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> Generics {
let db = interner.db;
let loc = id.loc(db);
match loc.trait_ {
BuiltinDeriveImplTrait::Copy
| BuiltinDeriveImplTrait::Clone
| BuiltinDeriveImplTrait::Default
| BuiltinDeriveImplTrait::Debug
| BuiltinDeriveImplTrait::Hash
| BuiltinDeriveImplTrait::Ord
| BuiltinDeriveImplTrait::PartialOrd
| BuiltinDeriveImplTrait::Eq
| BuiltinDeriveImplTrait::PartialEq => interner.generics_of(loc.adt.into()),
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
let mut generics = interner.generics_of(loc.adt.into());
generics.push_param(fake_type_param(loc.adt).into());
generics
}
}
}
pub(crate) fn impl_trait<'db>(
interner: DbInterner<'db>,
id: BuiltinDeriveImplId,
) -> EarlyBinder<'db, TraitRef<'db>> {
let db = interner.db;
let loc = id.loc(db);
let trait_id = loc
.trait_
.get_id(interner.lang_items())
.expect("we don't pass the impl to the solver if we can't resolve the trait");
match loc.trait_ {
BuiltinDeriveImplTrait::Copy
| BuiltinDeriveImplTrait::Clone
| BuiltinDeriveImplTrait::Default
| BuiltinDeriveImplTrait::Debug
| BuiltinDeriveImplTrait::Hash
| BuiltinDeriveImplTrait::Ord
| BuiltinDeriveImplTrait::Eq => {
let self_ty = Ty::new_adt(
interner,
loc.adt,
GenericArgs::identity_for_item(interner, loc.adt.into()),
);
EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty]))
}
BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::PartialEq => {
let self_ty = Ty::new_adt(
interner,
loc.adt,
GenericArgs::identity_for_item(interner, loc.adt.into()),
);
EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty, self_ty]))
}
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
let generic_params = GenericParams::new(db, loc.adt.into());
let interner = DbInterner::new_no_crate(db);
let args = GenericArgs::identity_for_item(interner, loc.adt.into());
let self_ty = Ty::new_adt(interner, loc.adt, args);
let Some((pointee_param_idx, _, new_param_ty)) =
coerce_pointee_params(interner, loc, &generic_params)
else {
// Malformed derive.
return EarlyBinder::bind(TraitRef::new(
interner,
trait_id.into(),
[self_ty, self_ty],
));
};
let changed_args = replace_pointee(interner, pointee_param_idx, new_param_ty, args);
let changed_self_ty = Ty::new_adt(interner, loc.adt, changed_args);
EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty, changed_self_ty]))
}
}
}
#[salsa::tracked(returns(ref), unsafe(non_update_types))]
pub(crate) fn builtin_derive_predicates<'db>(
db: &'db dyn HirDatabase,
impl_: BuiltinDeriveImplId,
) -> GenericPredicates {
let loc = impl_.loc(db);
let generic_params = GenericParams::new(db, loc.adt.into());
let interner = DbInterner::new_with(db, loc.module(db).krate(db));
let adt_predicates = GenericPredicates::query(db, loc.adt.into());
match loc.trait_ {
BuiltinDeriveImplTrait::Copy
| BuiltinDeriveImplTrait::Clone
| BuiltinDeriveImplTrait::Debug
| BuiltinDeriveImplTrait::Hash
| BuiltinDeriveImplTrait::Ord
| BuiltinDeriveImplTrait::PartialOrd
| BuiltinDeriveImplTrait::Eq
| BuiltinDeriveImplTrait::PartialEq => {
simple_trait_predicates(interner, loc, &generic_params, adt_predicates)
}
BuiltinDeriveImplTrait::Default => {
if matches!(loc.adt, AdtId::EnumId(_)) {
// Enums don't have extra bounds.
GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
Clauses::new_from_slice(adt_predicates.explicit_predicates().skip_binder())
.store(),
))
} else {
simple_trait_predicates(interner, loc, &generic_params, adt_predicates)
}
}
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
let Some((pointee_param_idx, pointee_param_id, new_param_ty)) =
coerce_pointee_params(interner, loc, &generic_params)
else {
// Malformed derive.
return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
Clauses::default().store(),
));
};
let duplicated_bounds =
adt_predicates.explicit_predicates().iter_identity_copied().filter_map(|pred| {
let mentions_pointee =
pred.visit_with(&mut MentionsPointee { pointee_param_idx }).is_break();
if !mentions_pointee {
return None;
}
let transformed =
replace_pointee(interner, pointee_param_idx, new_param_ty, pred);
Some(transformed)
});
let unsize_trait = interner.lang_items().Unsize;
let unsize_bound = unsize_trait.map(|unsize_trait| {
let pointee_param_ty = Ty::new_param(interner, pointee_param_id, pointee_param_idx);
TraitRef::new(interner, unsize_trait.into(), [pointee_param_ty, new_param_ty])
.upcast(interner)
});
GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
Clauses::new_from_iter(
interner,
adt_predicates
.explicit_predicates()
.iter_identity_copied()
.chain(duplicated_bounds)
.chain(unsize_bound),
)
.store(),
))
}
}
}
struct MentionsPointee {
pointee_param_idx: u32,
}
impl<'db> TypeVisitor<DbInterner<'db>> for MentionsPointee {
type Result = ControlFlow<()>;
fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
if let TyKind::Param(param) = t.kind()
&& param.index == self.pointee_param_idx
{
ControlFlow::Break(())
} else {
t.super_visit_with(self)
}
}
}
fn replace_pointee<'db, T: TypeFoldable<DbInterner<'db>>>(
interner: DbInterner<'db>,
pointee_param_idx: u32,
new_param_ty: Ty<'db>,
t: T,
) -> T {
fold_tys(interner, t, |ty| match ty.kind() {
TyKind::Param(param) if param.index == pointee_param_idx => new_param_ty,
_ => ty,
})
}
fn simple_trait_predicates<'db>(
interner: DbInterner<'db>,
loc: &BuiltinDeriveImplLoc,
generic_params: &GenericParams,
adt_predicates: &GenericPredicates,
) -> GenericPredicates {
let trait_id = loc
.trait_
.get_id(interner.lang_items())
.expect("we don't pass the impl to the solver if we can't resolve the trait");
let extra_predicates = generic_params
.iter_type_or_consts()
.filter(|(_, data)| matches!(data, TypeOrConstParamData::TypeParamData(_)))
.map(|(param_idx, _)| {
let param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
parent: loc.adt.into(),
local_id: param_idx,
});
let param_idx =
param_idx.into_raw().into_u32() + (generic_params.len_lifetimes() as u32);
let param_ty = Ty::new_param(interner, param_id, param_idx);
let trait_ref = TraitRef::new(interner, trait_id.into(), [param_ty]);
trait_ref.upcast(interner)
});
let mut assoc_type_bounds = Vec::new();
match loc.adt {
AdtId::StructId(id) => extend_assoc_type_bounds(
interner,
&mut assoc_type_bounds,
interner.db.field_types(id.into()),
trait_id,
),
AdtId::UnionId(id) => extend_assoc_type_bounds(
interner,
&mut assoc_type_bounds,
interner.db.field_types(id.into()),
trait_id,
),
AdtId::EnumId(id) => {
for &(variant_id, _, _) in &id.enum_variants(interner.db).variants {
extend_assoc_type_bounds(
interner,
&mut assoc_type_bounds,
interner.db.field_types(variant_id.into()),
trait_id,
)
}
}
}
GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
Clauses::new_from_iter(
interner,
adt_predicates
.explicit_predicates()
.iter_identity_copied()
.chain(extra_predicates)
.chain(assoc_type_bounds),
)
.store(),
))
}
fn extend_assoc_type_bounds<'db>(
interner: DbInterner<'db>,
assoc_type_bounds: &mut Vec<Clause<'db>>,
fields: &ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>,
trait_: TraitId,
) {
struct ProjectionFinder<'a, 'db> {
interner: DbInterner<'db>,
assoc_type_bounds: &'a mut Vec<Clause<'db>>,
trait_: TraitId,
}
impl<'db> TypeVisitor<DbInterner<'db>> for ProjectionFinder<'_, 'db> {
type Result = ();
fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
if let TyKind::Alias(AliasTyKind::Projection, _) = t.kind() {
self.assoc_type_bounds.push(
TraitRef::new(self.interner, self.trait_.into(), [t]).upcast(self.interner),
);
}
t.super_visit_with(self)
}
}
let mut visitor = ProjectionFinder { interner, assoc_type_bounds, trait_ };
for (_, field) in fields.iter() {
field.get().instantiate_identity().visit_with(&mut visitor);
}
}
fn coerce_pointee_params<'db>(
interner: DbInterner<'db>,
loc: &BuiltinDeriveImplLoc,
generic_params: &GenericParams,
) -> Option<(u32, TypeParamId, Ty<'db>)> {
let pointee_param = {
if let Ok((pointee_param, _)) = generic_params
.iter_type_or_consts()
.filter(|param| matches!(param.1, TypeOrConstParamData::TypeParamData(_)))
.exactly_one()
{
pointee_param
} else {
let (_, generic_param_attrs) =
AttrFlags::query_generic_params(interner.db, loc.adt.into());
generic_param_attrs
.iter()
.find(|param| param.1.contains(AttrFlags::IS_POINTEE))
.map(|(param, _)| param)
.or_else(|| {
generic_params
.iter_type_or_consts()
.find(|param| matches!(param.1, TypeOrConstParamData::TypeParamData(_)))
.map(|(idx, _)| idx)
})?
}
};
let pointee_param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
parent: loc.adt.into(),
local_id: pointee_param,
});
let pointee_param_idx =
pointee_param.into_raw().into_u32() + (generic_params.len_lifetimes() as u32);
let new_param_idx = generic_params.len() as u32;
let new_param_id = fake_type_param(loc.adt);
let new_param_ty = Ty::new_param(interner, new_param_id, new_param_idx);
Some((pointee_param_idx, pointee_param_id, new_param_ty))
}
#[cfg(test)]
mod tests {
use expect_test::{Expect, expect};
use hir_def::nameres::crate_def_map;
use itertools::Itertools;
use stdx::format_to;
use test_fixture::WithFixture;
use crate::{
builtin_derive::{builtin_derive_predicates, impl_trait},
next_solver::DbInterner,
test_db::TestDB,
};
fn check_trait_refs(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) {
let db = TestDB::with_files(ra_fixture);
let def_map = crate_def_map(&db, db.test_crate());
let interner = DbInterner::new_with(&db, db.test_crate());
crate::attach_db(&db, || {
let mut trait_refs = Vec::new();
for (_, module) in def_map.modules() {
for derive in module.scope.builtin_derive_impls() {
let trait_ref = impl_trait(interner, derive).skip_binder();
trait_refs.push(format!("{trait_ref:?}"));
}
}
expectation.assert_eq(&trait_refs.join("\n"));
});
}
fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) {
let db = TestDB::with_files(ra_fixture);
let def_map = crate_def_map(&db, db.test_crate());
crate::attach_db(&db, || {
let mut predicates = String::new();
for (_, module) in def_map.modules() {
for derive in module.scope.builtin_derive_impls() {
let preds =
builtin_derive_predicates(&db, derive).all_predicates().skip_binder();
format_to!(
predicates,
"{}\n\n",
preds.iter().format_with("\n", |pred, formatter| formatter(&format_args!(
"{pred:?}"
))),
);
}
}
expectation.assert_eq(&predicates);
});
}
#[test]
fn simple_macros_trait_ref() {
check_trait_refs(
r#"
//- minicore: derive, clone, copy, eq, ord, hash, fmt
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Simple;
trait Trait {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]);
"#,
expect![[r#"
Simple: Debug
Simple: Clone
Simple: Copy
Simple: PartialEq<[Simple]>
Simple: Eq
Simple: PartialOrd<[Simple]>
Simple: Ord
Simple: Hash
WithGenerics<#0, #1, #2>: Debug
WithGenerics<#0, #1, #2>: Clone
WithGenerics<#0, #1, #2>: Copy
WithGenerics<#0, #1, #2>: PartialEq<[WithGenerics<#0, #1, #2>]>
WithGenerics<#0, #1, #2>: Eq
WithGenerics<#0, #1, #2>: PartialOrd<[WithGenerics<#0, #1, #2>]>
WithGenerics<#0, #1, #2>: Ord
WithGenerics<#0, #1, #2>: Hash"#]],
);
}
#[test]
fn coerce_pointee_trait_ref() {
check_trait_refs(
r#"
//- minicore: derive, coerce_pointee
use core::marker::CoercePointee;
#[derive(CoercePointee)]
struct Simple<T: ?Sized>(*const T);
#[derive(CoercePointee)]
struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U);
"#,
expect![[r#"
Simple<#0>: CoerceUnsized<[Simple<#1>]>
Simple<#0>: DispatchFromDyn<[Simple<#1>]>
MultiGenericParams<#0, #1, #2, #3>: CoerceUnsized<[MultiGenericParams<#0, #1, #4, #3>]>
MultiGenericParams<#0, #1, #2, #3>: DispatchFromDyn<[MultiGenericParams<#0, #1, #4, #3>]>"#]],
);
}
#[test]
fn simple_macros_predicates() {
check_predicates(
r#"
//- minicore: derive, clone, copy, eq, ord, hash, fmt
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct Simple;
trait Trait {}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]);
"#,
expect![[r#"
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Debug, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Clone, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Copy, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: PartialEq, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Eq, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: PartialOrd, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Ord, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Hash, polarity:Positive), bound_vars: [] })
"#]],
);
}
#[test]
fn coerce_pointee_predicates() {
check_predicates(
r#"
//- minicore: derive, coerce_pointee
use core::marker::CoercePointee;
#[derive(CoercePointee)]
struct Simple<T: ?Sized>(*const T);
trait Trait<T> {}
#[derive(CoercePointee)]
struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U)
where
T: Trait<U>,
U: Trait<U>;
"#,
expect![[r#"
Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] })
Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] })
"#]],
);
}
}

View File

@ -32,7 +32,7 @@ fn has_destructor(interner: DbInterner<'_>, adt: AdtId) -> bool {
},
None => TraitImpls::for_crate(db, module.krate(db)),
};
!impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty()
!impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).0.is_empty()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]

View File

@ -25,6 +25,7 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
extern crate self as hir_ty;
mod builtin_derive;
mod infer;
mod inhabitedness;
mod lower;

View File

@ -1790,6 +1790,13 @@ impl<'db> GenericPredicates {
}
impl GenericPredicates {
#[inline]
pub(crate) fn from_explicit_own_predicates(
predicates: StoredEarlyBinder<StoredClauses>,
) -> Self {
Self { predicates, own_predicates_start: 0, is_trait: false, parent_is_trait: false }
}
#[inline]
pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates {
&Self::query_with_diagnostics(db, def).0

View File

@ -13,11 +13,12 @@ use tracing::{debug, instrument};
use base_db::Crate;
use hir_def::{
AssocItemId, BlockId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId,
ModuleId, TraitId,
AssocItemId, BlockId, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule,
ImplId, ItemContainerId, ModuleId, TraitId,
attrs::AttrFlags,
expr_store::path::GenericArgs as HirGenericArgs,
hir::ExprId,
lang_item::LangItems,
nameres::{DefMap, block_def_map, crate_def_map},
resolver::Resolver,
};
@ -37,7 +38,7 @@ use crate::{
infer::{InferenceContext, unify::InferenceTable},
lower::GenericPredicates,
next_solver::{
Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
AnyImplId, Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode,
infer::{
BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk,
@ -132,7 +133,7 @@ pub enum MethodError<'db> {
// candidate can arise. Used for error reporting only.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum CandidateSource {
Impl(ImplId),
Impl(AnyImplId),
Trait(TraitId),
}
@ -462,6 +463,10 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>(
name: &Name,
) -> Option<(AssocItemId, GenericArgs<'db>)> {
let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
let AnyImplId::ImplId(impl_id) = impl_id else {
// FIXME: Handle resolution to builtin derive.
return None;
};
let item =
impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
@ -475,7 +480,7 @@ pub(crate) fn find_matching_impl<'db>(
infcx: &InferCtxt<'db>,
env: ParamEnv<'db>,
trait_ref: TraitRef<'db>,
) -> Option<(ImplId, GenericArgs<'db>)> {
) -> Option<(AnyImplId, GenericArgs<'db>)> {
let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?;
let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref);
@ -635,13 +640,13 @@ impl InherentImpls {
#[derive(Debug, PartialEq)]
struct OneTraitImpls {
non_blanket_impls: FxHashMap<SimplifiedType, Box<[ImplId]>>,
non_blanket_impls: FxHashMap<SimplifiedType, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>,
blanket_impls: Box<[ImplId]>,
}
#[derive(Default)]
struct OneTraitImplsBuilder {
non_blanket_impls: FxHashMap<SimplifiedType, Vec<ImplId>>,
non_blanket_impls: FxHashMap<SimplifiedType, (Vec<ImplId>, Vec<BuiltinDeriveImplId>)>,
blanket_impls: Vec<ImplId>,
}
@ -650,7 +655,9 @@ impl OneTraitImplsBuilder {
let mut non_blanket_impls = self
.non_blanket_impls
.into_iter()
.map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice()))
.map(|(self_ty, (impls, builtin_derive_impls))| {
(self_ty, (impls.into_boxed_slice(), builtin_derive_impls.into_boxed_slice()))
})
.collect::<FxHashMap<_, _>>();
non_blanket_impls.shrink_to_fit();
let blanket_impls = self.blanket_impls.into_boxed_slice();
@ -691,8 +698,9 @@ impl TraitImpls {
impl TraitImpls {
fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self {
let lang_items = hir_def::lang_item::lang_items(db, def_map.krate());
let mut map = FxHashMap::default();
collect(db, def_map, &mut map);
collect(db, def_map, lang_items, &mut map);
let mut map = map
.into_iter()
.map(|(trait_id, trait_map)| (trait_id, trait_map.finish()))
@ -703,6 +711,7 @@ impl TraitImpls {
fn collect(
db: &dyn HirDatabase,
def_map: &DefMap,
lang_items: &LangItems,
map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>,
) {
for (_module_id, module_data) in def_map.modules() {
@ -727,18 +736,29 @@ impl TraitImpls {
let entry = map.entry(trait_ref.def_id.0).or_default();
match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) {
Some(self_ty) => {
entry.non_blanket_impls.entry(self_ty).or_default().push(impl_id)
entry.non_blanket_impls.entry(self_ty).or_default().0.push(impl_id)
}
None => entry.blanket_impls.push(impl_id),
}
}
for impl_id in module_data.scope.builtin_derive_impls() {
let loc = impl_id.loc(db);
let Some(trait_id) = loc.trait_.get_id(lang_items) else { continue };
let entry = map.entry(trait_id).or_default();
let entry = entry
.non_blanket_impls
.entry(SimplifiedType::Adt(loc.adt.into()))
.or_default();
entry.1.push(impl_id);
}
// To better support custom derives, collect impls in all unnamed const items.
// const _: () = { ... };
for konst in module_data.scope.unnamed_consts() {
let body = db.body(konst.into());
for (_, block_def_map) in body.blocks(db) {
collect(db, block_def_map, map);
collect(db, block_def_map, lang_items, map);
}
}
}
@ -761,11 +781,15 @@ impl TraitImpls {
})
}
pub fn for_trait_and_self_ty(&self, trait_: TraitId, self_ty: &SimplifiedType) -> &[ImplId] {
pub fn for_trait_and_self_ty(
&self,
trait_: TraitId,
self_ty: &SimplifiedType,
) -> (&[ImplId], &[BuiltinDeriveImplId]) {
self.map
.get(&trait_)
.and_then(|map| map.non_blanket_impls.get(self_ty))
.map(|it| &**it)
.map(|it| (&*it.0, &*it.1))
.unwrap_or_default()
}
@ -773,7 +797,7 @@ impl TraitImpls {
if let Some(impls) = self.map.get(&trait_) {
callback(&impls.blanket_impls);
for impls in impls.non_blanket_impls.values() {
callback(impls);
callback(&impls.0);
}
}
}
@ -781,7 +805,7 @@ impl TraitImpls {
pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) {
for for_trait in self.map.values() {
if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) {
callback(for_ty);
callback(&for_ty.0);
}
}
}

View File

@ -1001,7 +1001,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
self.with_impl_item(impl_def_id, |this, item| {
if !this.has_applicable_self(item) {
// No receiver declared. Not a candidate.
this.record_static_candidate(CandidateSource::Impl(impl_def_id));
this.record_static_candidate(CandidateSource::Impl(impl_def_id.into()));
return;
}
this.push_candidate(
@ -1490,7 +1490,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
/// so do not use to make a decision that may lead to a successful compilation.
fn candidate_source(&self, candidate: &Candidate<'db>, self_ty: Ty<'db>) -> CandidateSource {
match candidate.kind {
InherentImplCandidate { impl_def_id, .. } => CandidateSource::Impl(impl_def_id),
InherentImplCandidate { impl_def_id, .. } => CandidateSource::Impl(impl_def_id.into()),
ObjectCandidate(trait_ref) | WhereClauseCandidate(trait_ref) => {
CandidateSource::Trait(trait_ref.def_id().0)
}
@ -1524,7 +1524,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
fn candidate_source_from_pick(&self, pick: &Pick<'db>) -> CandidateSource {
match pick.kind {
InherentImplPick(impl_) => CandidateSource::Impl(impl_),
InherentImplPick(impl_) => CandidateSource::Impl(impl_.into()),
ObjectPick(trait_) | TraitPick(trait_) => CandidateSource::Trait(trait_),
WhereClausePick(trait_ref) => CandidateSource::Trait(trait_ref.skip_binder().def_id.0),
}

View File

@ -1,9 +1,9 @@
//! Definition of `SolverDefId`
use hir_def::{
AdtId, AttrDefId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
GeneralConstId, GenericDefId, HasModule, ImplId, ModuleId, StaticId, StructId, TraitId,
TypeAliasId, UnionId, db::DefDatabase,
AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId,
EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId,
TypeAliasId, UnionId,
};
use rustc_type_ir::inherent;
use stdx::impl_from;
@ -24,6 +24,7 @@ pub enum SolverDefId {
ConstId(ConstId),
FunctionId(FunctionId),
ImplId(ImplId),
BuiltinDeriveImplId(BuiltinDeriveImplId),
StaticId(StaticId),
TraitId(TraitId),
TypeAliasId(TypeAliasId),
@ -57,6 +58,7 @@ impl std::fmt::Debug for SolverDefId {
f.debug_tuple("FunctionId").field(&db.function_signature(id).name.as_str()).finish()
}
SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
SolverDefId::BuiltinDeriveImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
SolverDefId::StaticId(id) => {
f.debug_tuple("StaticId").field(&db.static_signature(id).name.as_str()).finish()
}
@ -108,6 +110,7 @@ impl_from!(
ConstId,
FunctionId,
ImplId,
BuiltinDeriveImplId,
StaticId,
TraitId,
TypeAliasId,
@ -170,7 +173,8 @@ impl TryFrom<SolverDefId> for AttrDefId {
SolverDefId::EnumVariantId(it) => Ok(it.into()),
SolverDefId::Ctor(Ctor::Struct(it)) => Ok(it.into()),
SolverDefId::Ctor(Ctor::Enum(it)) => Ok(it.into()),
SolverDefId::InternedClosureId(_)
SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_)
| SolverDefId::InternedOpaqueTyId(_) => Err(()),
}
@ -191,6 +195,7 @@ impl TryFrom<SolverDefId> for DefWithBodyId {
| SolverDefId::TraitId(_)
| SolverDefId::TypeAliasId(_)
| SolverDefId::ImplId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_)
| SolverDefId::Ctor(Ctor::Struct(_))
@ -216,6 +221,7 @@ impl TryFrom<SolverDefId> for GenericDefId {
| SolverDefId::InternedCoroutineId(_)
| SolverDefId::InternedOpaqueTyId(_)
| SolverDefId::EnumVariantId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::Ctor(_) => return Err(()),
})
}
@ -241,28 +247,6 @@ impl SolverDefId {
}
}
impl HasModule for SolverDefId {
fn module(&self, db: &dyn DefDatabase) -> ModuleId {
match *self {
SolverDefId::AdtId(id) => id.module(db),
SolverDefId::ConstId(id) => id.module(db),
SolverDefId::FunctionId(id) => id.module(db),
SolverDefId::ImplId(id) => id.module(db),
SolverDefId::StaticId(id) => id.module(db),
SolverDefId::TraitId(id) => id.module(db),
SolverDefId::TypeAliasId(id) => id.module(db),
SolverDefId::InternedClosureId(id) => id.loc(db).0.module(db),
SolverDefId::InternedCoroutineId(id) => id.loc(db).0.module(db),
SolverDefId::InternedOpaqueTyId(id) => match id.loc(db) {
crate::ImplTraitId::ReturnTypeImplTrait(owner, _) => owner.module(db),
crate::ImplTraitId::TypeAliasImplTrait(owner, _) => owner.module(db),
},
SolverDefId::Ctor(Ctor::Enum(id)) | SolverDefId::EnumVariantId(id) => id.module(db),
SolverDefId::Ctor(Ctor::Struct(id)) => id.module(db),
}
}
}
impl<'db> inherent::DefId<DbInterner<'db>> for SolverDefId {
fn as_local(self) -> Option<SolverDefId> {
Some(self)
@ -332,7 +316,6 @@ declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId);
declare_id_wrapper!(ClosureIdWrapper, InternedClosureId);
declare_id_wrapper!(CoroutineIdWrapper, InternedCoroutineId);
declare_id_wrapper!(AdtIdWrapper, AdtId);
declare_id_wrapper!(ImplIdWrapper, ImplId);
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub struct GeneralConstIdWrapper(pub GeneralConstId);
@ -433,3 +416,40 @@ impl<'db> inherent::DefId<DbInterner<'db>> for CallableIdWrapper {
true
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AnyImplId {
ImplId(ImplId),
BuiltinDeriveImplId(BuiltinDeriveImplId),
}
impl_from!(ImplId, BuiltinDeriveImplId for AnyImplId);
impl From<AnyImplId> for SolverDefId {
#[inline]
fn from(value: AnyImplId) -> SolverDefId {
match value {
AnyImplId::ImplId(it) => it.into(),
AnyImplId::BuiltinDeriveImplId(it) => it.into(),
}
}
}
impl TryFrom<SolverDefId> for AnyImplId {
type Error = ();
#[inline]
fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
match value {
SolverDefId::ImplId(it) => Ok(it.into()),
SolverDefId::BuiltinDeriveImplId(it) => Ok(it.into()),
_ => Err(()),
}
}
}
impl<'db> inherent::DefId<DbInterner<'db>> for AnyImplId {
fn as_local(self) -> Option<SolverDefId> {
Some(self.into())
}
fn is_local(self) -> bool {
true
}
}

View File

@ -4,14 +4,15 @@ use hir_def::{
ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
hir::generics::{GenericParams, TypeOrConstParamData},
};
use rustc_type_ir::inherent::GenericsOf;
use crate::{db::HirDatabase, generics::parent_generic_def};
use crate::generics::parent_generic_def;
use super::SolverDefId;
use super::DbInterner;
pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics {
let mk_lt = |parent, index, local_id| {
let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
GenericParamDef { index, id }
@ -50,6 +51,7 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
result
};
let db = interner.db;
let (parent, own_params) = match (def.try_into(), def) {
(Ok(def), _) => (
parent_generic_def(db, def),
@ -66,9 +68,12 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
}
}
}
(_, SolverDefId::BuiltinDeriveImplId(id)) => {
return crate::builtin_derive::generics_of(interner, id);
}
_ => panic!("No generics for {def:?}"),
};
let parent_generics = parent.map(|def| Box::new(generics(db, def.into())));
let parent_generics = parent.map(|def| Box::new(generics(interner, def.into())));
Generics {
parent,
@ -84,6 +89,13 @@ pub struct Generics {
pub own_params: Vec<GenericParamDef>,
}
impl Generics {
pub(crate) fn push_param(&mut self, id: GenericParamId) {
let index = self.count() as u32;
self.own_params.push(GenericParamDef { index, id });
}
}
#[derive(Debug)]
pub struct GenericParamDef {
index: u32,

View File

@ -2,7 +2,7 @@
use std::ops::ControlFlow;
use hir_def::{ImplId, TraitId};
use hir_def::TraitId;
use macros::{TypeFoldable, TypeVisitable};
use rustc_type_ir::{
Interner,
@ -12,7 +12,7 @@ use rustc_type_ir::{
use crate::{
db::InternedOpaqueTyId,
next_solver::{
Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
AnyImplId, Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
infer::{
InferCtxt,
select::EvaluationResult::*,
@ -249,7 +249,7 @@ impl<'db, N> ImplSource<'db, N> {
pub(crate) struct ImplSourceUserDefinedData<'db, N> {
#[type_visitable(ignore)]
#[type_foldable(identity)]
pub(crate) impl_def_id: ImplId,
pub(crate) impl_def_id: AnyImplId,
pub(crate) args: GenericArgs<'db>,
pub(crate) nested: Vec<N>,
}
@ -395,7 +395,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>>
// FIXME: Remove this in favor of storing this in the tree
// For impl candidates, we do the rematch manually to compute the args.
ImplSource::UserDefined(ImplSourceUserDefinedData {
impl_def_id: impl_def_id.0,
impl_def_id,
args: cand.instantiate_impl_args(),
nested,
})

View File

@ -38,10 +38,10 @@ use crate::{
lower::GenericPredicates,
method_resolution::TraitImpls,
next_solver::{
AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, ImplIdWrapper,
OpaqueTypeKey, RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds,
TraitIdWrapper, TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
AdtIdWrapper, AnyImplId, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, OpaqueTypeKey,
RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds, TraitIdWrapper,
TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
},
};
@ -1020,7 +1020,7 @@ impl<'db> Interner for DbInterner<'db> {
type CoroutineClosureId = CoroutineIdWrapper;
type CoroutineId = CoroutineIdWrapper;
type AdtId = AdtIdWrapper;
type ImplId = ImplIdWrapper;
type ImplId = AnyImplId;
type UnevaluatedConstId = GeneralConstIdWrapper;
type Span = Span;
@ -1164,7 +1164,7 @@ impl<'db> Interner for DbInterner<'db> {
}
fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf {
generics(self.db(), def_id)
generics(self, def_id)
}
fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
@ -1190,6 +1190,7 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::TraitId(_)
| SolverDefId::TypeAliasId(_)
| SolverDefId::ImplId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_) => {
return VariancesOf::empty(self);
@ -1327,6 +1328,7 @@ impl<'db> Interner for DbInterner<'db> {
| SolverDefId::AdtId(_)
| SolverDefId::TraitId(_)
| SolverDefId::ImplId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::EnumVariantId(..)
| SolverDefId::Ctor(..)
| SolverDefId::InternedOpaqueTyId(..) => panic!(),
@ -1445,8 +1447,7 @@ impl<'db> Interner for DbInterner<'db> {
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
GenericPredicates::query_all(self.db, def_id.try_into().unwrap())
.map_bound(|it| it.iter().copied())
predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied())
}
#[tracing::instrument(level = "debug", skip(self), ret)]
@ -1454,8 +1455,7 @@ impl<'db> Interner for DbInterner<'db> {
self,
def_id: Self::DefId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
GenericPredicates::query_own(self.db, def_id.try_into().unwrap())
.map_bound(|it| it.iter().copied())
predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied())
}
#[tracing::instrument(skip(self), ret)]
@ -1500,32 +1500,30 @@ impl<'db> Interner for DbInterner<'db> {
}
}
GenericPredicates::query_explicit(self.db, def_id.try_into().unwrap()).map_bound(
|predicates| {
predicates
.iter()
.copied()
.filter(|p| match p.kind().skip_binder() {
ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
// FIXME: Not sure is this correct to allow other clauses but we might replace
// `generic_predicates_ns` query here with something closer to rustc's
// `implied_bounds_with_filter`, which is more granular lowering than this
// "lower at once and then filter" implementation.
_ => true,
})
.map(|p| (p, Span::dummy()))
},
)
predicates_of(self.db, def_id).explicit_predicates().map_bound(|predicates| {
predicates
.iter()
.copied()
.filter(|p| match p.kind().skip_binder() {
ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
// FIXME: Not sure is this correct to allow other clauses but we might replace
// `generic_predicates_ns` query here with something closer to rustc's
// `implied_bounds_with_filter`, which is more granular lowering than this
// "lower at once and then filter" implementation.
_ => true,
})
.map(|p| (p, Span::dummy()))
})
}
fn impl_super_outlives(
self,
impl_id: Self::ImplId,
) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait");
let trait_ref = self.impl_trait_ref(impl_id);
trait_ref.map_bound(|trait_ref| {
let clause: Clause<'_> = trait_ref.upcast(self);
elaborate(self, [clause]).filter(|clause| {
@ -1790,6 +1788,7 @@ impl<'db> Interner for DbInterner<'db> {
SolverDefId::ConstId(_)
| SolverDefId::FunctionId(_)
| SolverDefId::ImplId(_)
| SolverDefId::BuiltinDeriveImplId(_)
| SolverDefId::StaticId(_)
| SolverDefId::InternedClosureId(_)
| SolverDefId::InternedCoroutineId(_)
@ -1805,7 +1804,12 @@ impl<'db> Interner for DbInterner<'db> {
type_block,
trait_block,
&mut |impls| {
for &impl_ in impls.for_trait_and_self_ty(trait_def_id.0, &simp) {
let (regular_impls, builtin_derive_impls) =
impls.for_trait_and_self_ty(trait_def_id.0, &simp);
for &impl_ in regular_impls {
f(impl_.into());
}
for &impl_ in builtin_derive_impls {
f(impl_.into());
}
},
@ -1927,7 +1931,10 @@ impl<'db> Interner for DbInterner<'db> {
}
fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool {
self.db.impl_signature(impl_def_id.0).is_default()
match impl_def_id {
AnyImplId::ImplId(impl_id) => self.db.impl_signature(impl_id).is_default(),
AnyImplId::BuiltinDeriveImplId(_) => false,
}
}
#[tracing::instrument(skip(self), ret)]
@ -1935,14 +1942,24 @@ impl<'db> Interner for DbInterner<'db> {
self,
impl_id: Self::ImplId,
) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> {
let db = self.db();
db.impl_trait(impl_id.0)
// ImplIds for impls where the trait ref can't be resolved should never reach trait solving
.expect("invalid impl passed to trait solver")
match impl_id {
AnyImplId::ImplId(impl_id) => {
let db = self.db();
db.impl_trait(impl_id)
// ImplIds for impls where the trait ref can't be resolved should never reach trait solving
.expect("invalid impl passed to trait solver")
}
AnyImplId::BuiltinDeriveImplId(impl_id) => {
crate::builtin_derive::impl_trait(self, impl_id)
}
}
}
fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity {
let impl_data = self.db().impl_signature(impl_id.0);
let AnyImplId::ImplId(impl_id) = impl_id else {
return ImplPolarity::Positive;
};
let impl_data = self.db().impl_signature(impl_id);
if impl_data.flags.contains(ImplFlags::NEGATIVE) {
ImplPolarity::Negative
} else {
@ -2230,11 +2247,13 @@ impl<'db> Interner for DbInterner<'db> {
specializing_impl_def_id: Self::ImplId,
parent_impl_def_id: Self::ImplId,
) -> bool {
crate::specialization::specializes(
self.db,
specializing_impl_def_id.0,
parent_impl_def_id.0,
)
let (AnyImplId::ImplId(specializing_impl_def_id), AnyImplId::ImplId(parent_impl_def_id)) =
(specializing_impl_def_id, parent_impl_def_id)
else {
// No builtin derive allow specialization currently.
return false;
};
crate::specialization::specializes(self.db, specializing_impl_def_id, parent_impl_def_id)
}
fn next_trait_solver_globally(self) -> bool {
@ -2349,6 +2368,14 @@ impl<'db> DbInterner<'db> {
}
}
fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates {
if let SolverDefId::BuiltinDeriveImplId(impl_) = def_id {
crate::builtin_derive::builtin_derive_predicates(db, impl_)
} else {
GenericPredicates::query(db, def_id.try_into().unwrap())
}
}
macro_rules! TrivialTypeTraversalImpls {
($($ty:ty,)+) => {
$(
@ -2396,7 +2423,7 @@ TrivialTypeTraversalImpls! {
ClosureIdWrapper,
CoroutineIdWrapper,
AdtIdWrapper,
ImplIdWrapper,
AnyImplId,
GeneralConstIdWrapper,
Safety,
FnAbi,

View File

@ -12,7 +12,7 @@ use rustc_type_ir::{
use tracing::debug;
use crate::next_solver::{
AliasTy, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs, ImplIdWrapper,
AliasTy, AnyImplId, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs,
ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, fold::fold_tys,
util::sizedness_fast_path,
};
@ -174,9 +174,13 @@ impl<'db> SolverDelegate for SolverContext<'db> {
&self,
_goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
trait_assoc_def_id: SolverDefId,
impl_id: ImplIdWrapper,
impl_id: AnyImplId,
) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
let impl_items = impl_id.0.impl_items(self.0.interner.db());
let AnyImplId::ImplId(impl_id) = impl_id else {
// Builtin derive traits don't have type/consts assoc items.
return Ok(None);
};
let impl_items = impl_id.impl_items(self.0.interner.db());
let id =
match trait_assoc_def_id {
SolverDefId::TypeAliasId(trait_assoc_id) => {

View File

@ -243,6 +243,10 @@ $0",
"parse_shim",
"real_span_map_shim",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -279,6 +283,10 @@ pub struct NewStruct {
"real_span_map_shim",
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -314,6 +322,10 @@ $0",
"parse_shim",
"real_span_map_shim",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -351,6 +363,13 @@ pub enum SomeEnum {
"real_span_map_shim",
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
"AttrFlags::query_",
"EnumVariants::of_",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -386,6 +405,10 @@ $0",
"parse_shim",
"real_span_map_shim",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -420,6 +443,9 @@ fn bar() -> f32 {
"real_span_map_shim",
"crate_local_def_map",
"TraitImpls::for_crate_",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -459,6 +485,11 @@ $0",
"parse_shim",
"real_span_map_shim",
"TraitImpls::for_crate_",
"lang_items",
"crate_lang_items",
"AttrFlags::query_",
"AttrFlags::query_",
"AttrFlags::query_",
]
"#]],
);
@ -501,17 +532,16 @@ impl SomeStruct {
"real_span_map_shim",
"crate_local_def_map",
"TraitImpls::for_crate_",
"AttrFlags::query_",
"impl_trait_with_diagnostics_query",
"impl_signature_shim",
"impl_signature_with_source_map_shim",
"lang_items",
"crate_lang_items",
"AttrFlags::query_",
"ImplItems::of_",
"AttrFlags::query_",
"AttrFlags::query_",
"AttrFlags::query_",
"AttrFlags::query_",
"impl_trait_with_diagnostics_shim",
"impl_signature_shim",
"impl_signature_with_source_map_shim",
"impl_self_ty_with_diagnostics_query",
"struct_signature_shim",
"struct_signature_with_source_map_shim",

View File

@ -525,5 +525,7 @@ define_symbols! {
arbitrary_self_types,
arbitrary_self_types_pointers,
supertrait_item_shadowing,
hash,
cmp,
define_opaque,
}