mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-27 16:07:46 +00:00
Make builtin derives cheaper, by not really expanding them, instead store them unexpanded
This commit is contained in:
parent
9581ba4daf
commit
5fbff1d7fb
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
61
crates/hir-def/src/builtin_derive.rs
Normal file
61
crates/hir-def/src/builtin_derive.rs
Normal 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_);
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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(¯o_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);
|
||||
}
|
||||
|
||||
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -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> {
|
||||
|
||||
575
crates/hir-ty/src/builtin_derive.rs
Normal file
575
crates/hir-ty/src/builtin_derive.rs
Normal 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: [] })
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -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)]
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
})
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) => {
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -525,5 +525,7 @@ define_symbols! {
|
||||
arbitrary_self_types,
|
||||
arbitrary_self_types_pointers,
|
||||
supertrait_item_shadowing,
|
||||
hash,
|
||||
cmp,
|
||||
define_opaque,
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user