Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/attrs.rs2
-rw-r--r--crates/hir-def/src/builtin_derive.rs61
-rw-r--r--crates/hir-def/src/item_scope.rs15
-rw-r--r--crates/hir-def/src/lang_item.rs51
-rw-r--r--crates/hir-def/src/lib.rs29
-rw-r--r--crates/hir-def/src/nameres/collector.rs213
-rw-r--r--crates/hir-def/src/nameres/tests/macros.rs8
-rw-r--r--crates/hir-expand/src/builtin/derive_macro.rs5
-rw-r--r--crates/hir-ty/src/builtin_derive.rs575
-rw-r--r--crates/hir-ty/src/drop.rs2
-rw-r--r--crates/hir-ty/src/lib.rs1
-rw-r--r--crates/hir-ty/src/lower.rs7
-rw-r--r--crates/hir-ty/src/method_resolution.rs54
-rw-r--r--crates/hir-ty/src/method_resolution/probe.rs6
-rw-r--r--crates/hir-ty/src/next_solver/def_id.rs74
-rw-r--r--crates/hir-ty/src/next_solver/generics.rs18
-rw-r--r--crates/hir-ty/src/next_solver/infer/select.rs8
-rw-r--r--crates/hir-ty/src/next_solver/interner.rs113
-rw-r--r--crates/hir-ty/src/next_solver/solver.rs10
-rw-r--r--crates/hir-ty/src/tests/incremental.rs40
-rw-r--r--crates/intern/src/symbol/symbols.rs2
21 files changed, 1143 insertions, 151 deletions
diff --git a/crates/hir-def/src/attrs.rs b/crates/hir-def/src/attrs.rs
index 34a9230794..e91d72a701 100644
--- a/crates/hir-def/src/attrs.rs
+++ b/crates/hir-def/src/attrs.rs
@@ -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;
}
}
diff --git a/crates/hir-def/src/builtin_derive.rs b/crates/hir-def/src/builtin_derive.rs
new file mode 100644
index 0000000000..e0e163783f
--- /dev/null
+++ b/crates/hir-def/src/builtin_derive.rs
@@ -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_);
+}
diff --git a/crates/hir-def/src/item_scope.rs b/crates/hir-def/src/item_scope.rs
index 3ffeebfaf2..4f3700e8e4 100644
--- a/crates/hir-def/src/item_scope.rs
+++ b/crates/hir-def/src/item_scope.rs
@@ -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();
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index fd693477a4..41d69c1fd6 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -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;
}
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 97af8ad93d..fde1e6ca17 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -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 {
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 7e1ec526a7..2fac0837de 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -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);
}
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index c8eb968b35..a943f6f0ac 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -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),
);
}
diff --git a/crates/hir-expand/src/builtin/derive_macro.rs b/crates/hir-expand/src/builtin/derive_macro.rs
index 6582f4b075..c805197425 100644
--- a/crates/hir-expand/src/builtin/derive_macro.rs
+++ b/crates/hir-expand/src/builtin/derive_macro.rs
@@ -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> {
diff --git a/crates/hir-ty/src/builtin_derive.rs b/crates/hir-ty/src/builtin_derive.rs
new file mode 100644
index 0000000000..15d9634cfa
--- /dev/null
+++ b/crates/hir-ty/src/builtin_derive.rs
@@ -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: [] })
+
+ "#]],
+ );
+ }
+}
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index 66692143bc..9d6869eee9 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -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)]
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 1674771413..7b414cd551 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -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;
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 62a5837f34..ebbf29e6ff 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1791,6 +1791,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
}
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index c370330a87..88f48fdbc6 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -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);
}
}
}
diff --git a/crates/hir-ty/src/method_resolution/probe.rs b/crates/hir-ty/src/method_resolution/probe.rs
index cb9b810686..4a7c7d9353 100644
--- a/crates/hir-ty/src/method_resolution/probe.rs
+++ b/crates/hir-ty/src/method_resolution/probe.rs
@@ -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),
}
diff --git a/crates/hir-ty/src/next_solver/def_id.rs b/crates/hir-ty/src/next_solver/def_id.rs
index b6167b4a09..aa6caefc4a 100644
--- a/crates/hir-ty/src/next_solver/def_id.rs
+++ b/crates/hir-ty/src/next_solver/def_id.rs
@@ -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
+ }
+}
diff --git a/crates/hir-ty/src/next_solver/generics.rs b/crates/hir-ty/src/next_solver/generics.rs
index 4d164a7e3b..a8288b4e82 100644
--- a/crates/hir-ty/src/next_solver/generics.rs
+++ b/crates/hir-ty/src/next_solver/generics.rs
@@ -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,
diff --git a/crates/hir-ty/src/next_solver/infer/select.rs b/crates/hir-ty/src/next_solver/infer/select.rs
index 52ad410df6..bd407fd157 100644
--- a/crates/hir-ty/src/next_solver/infer/select.rs
+++ b/crates/hir-ty/src/next_solver/infer/select.rs
@@ -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,
})
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 2ebc5b81ba..269474e015 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -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,
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index d800925ba4..21fbd64dd0 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -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) => {
diff --git a/crates/hir-ty/src/tests/incremental.rs b/crates/hir-ty/src/tests/incremental.rs
index 6558d2179f..ea33c9bcd4 100644
--- a/crates/hir-ty/src/tests/incremental.rs
+++ b/crates/hir-ty/src/tests/incremental.rs
@@ -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",
diff --git a/crates/intern/src/symbol/symbols.rs b/crates/intern/src/symbol/symbols.rs
index 6e9c6d26b5..aa7e40c658 100644
--- a/crates/intern/src/symbol/symbols.rs
+++ b/crates/intern/src/symbol/symbols.rs
@@ -525,5 +525,7 @@ define_symbols! {
arbitrary_self_types,
arbitrary_self_types_pointers,
supertrait_item_shadowing,
+ hash,
+ cmp,
define_opaque,
}