Merge pull request #21200 from ChayimFriedman2/fake-impls
perf: Do not really expand builtin derives, instead treat them specifically
This commit is contained in:
commit
50ed4e91fc
45 changed files with 2734 additions and 802 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
149
src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs
Normal file
149
src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
//! 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::{InFile, builtin::BuiltinDeriveExpander, name::Name};
|
||||
use intern::{Symbol, sym};
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, db::DefDatabase,
|
||||
};
|
||||
|
||||
macro_rules! declare_enum {
|
||||
( $( $trait:ident => [ $( $method:ident ),* ] ),* $(,)? ) => {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum BuiltinDeriveImplTrait {
|
||||
$( $trait, )*
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub enum BuiltinDeriveImplMethod {
|
||||
$( $( $method, )* )*
|
||||
}
|
||||
|
||||
impl BuiltinDeriveImplTrait {
|
||||
#[inline]
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
$( Self::$trait => sym::$trait, )*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option<crate::TraitId> {
|
||||
match self {
|
||||
$( Self::$trait => lang_items.$trait, )*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_method(self, method_name: &Symbol) -> Option<BuiltinDeriveImplMethod> {
|
||||
match self {
|
||||
$(
|
||||
Self::$trait => {
|
||||
match method_name {
|
||||
$( _ if *method_name == sym::$method => Some(BuiltinDeriveImplMethod::$method), )*
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn all_methods(self) -> &'static [BuiltinDeriveImplMethod] {
|
||||
match self {
|
||||
$( Self::$trait => &[ $(BuiltinDeriveImplMethod::$method),* ], )*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BuiltinDeriveImplMethod {
|
||||
#[inline]
|
||||
pub fn name(self) -> Symbol {
|
||||
match self {
|
||||
$( $( BuiltinDeriveImplMethod::$method => sym::$method, )* )*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
declare_enum!(
|
||||
Copy => [],
|
||||
Clone => [clone],
|
||||
Default => [default],
|
||||
Debug => [fmt],
|
||||
Hash => [hash],
|
||||
Ord => [cmp],
|
||||
PartialOrd => [partial_cmp],
|
||||
Eq => [],
|
||||
PartialEq => [eq],
|
||||
CoerceUnsized => [],
|
||||
DispatchFromDyn => [],
|
||||
);
|
||||
|
||||
impl BuiltinDeriveImplMethod {
|
||||
pub fn trait_method(
|
||||
self,
|
||||
db: &dyn DefDatabase,
|
||||
impl_: BuiltinDeriveImplId,
|
||||
) -> Option<FunctionId> {
|
||||
let loc = impl_.loc(db);
|
||||
let lang_items = crate::lang_item::lang_items(db, loc.krate(db));
|
||||
let trait_ = impl_.loc(db).trait_.get_id(lang_items)?;
|
||||
trait_.trait_items(db).method_by_name(&Name::new_symbol_root(self.name()))
|
||||
}
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
impl BuiltinDeriveImplLoc {
|
||||
pub fn source(&self, db: &dyn DefDatabase) -> InFile<TextRange> {
|
||||
let (adt_ast_id, module) = match self.adt {
|
||||
AdtId::StructId(adt) => {
|
||||
let adt_loc = adt.loc(db);
|
||||
(adt_loc.id.upcast(), adt_loc.container)
|
||||
}
|
||||
AdtId::UnionId(adt) => {
|
||||
let adt_loc = adt.loc(db);
|
||||
(adt_loc.id.upcast(), adt_loc.container)
|
||||
}
|
||||
AdtId::EnumId(adt) => {
|
||||
let adt_loc = adt.loc(db);
|
||||
(adt_loc.id.upcast(), adt_loc.container)
|
||||
}
|
||||
};
|
||||
let derive_range = self.derive_attr_id.find_derive_range(
|
||||
db,
|
||||
module.krate(db),
|
||||
adt_ast_id,
|
||||
self.derive_index,
|
||||
);
|
||||
adt_ast_id.with_value(derive_range)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,15 +9,15 @@ use indexmap::map::Entry;
|
|||
use itertools::Itertools;
|
||||
use la_arena::Idx;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use smallvec::SmallVec;
|
||||
use span::Edition;
|
||||
use stdx::format_to;
|
||||
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);
|
||||
}
|
||||
|
|
@ -522,12 +531,13 @@ impl ItemScope {
|
|||
adt: AstId<ast::Adt>,
|
||||
attr_id: AttrId,
|
||||
attr_call_id: MacroCallId,
|
||||
len: usize,
|
||||
mut derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
|
||||
) {
|
||||
derive_call_ids.shrink_to_fit();
|
||||
self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
|
||||
attr_id,
|
||||
attr_call_id,
|
||||
derive_call_ids: smallvec![None; len],
|
||||
derive_call_ids,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -811,6 +821,7 @@ impl ItemScope {
|
|||
unresolved,
|
||||
declarations,
|
||||
impls,
|
||||
builtin_derive_impls,
|
||||
unnamed_consts,
|
||||
unnamed_trait_imports,
|
||||
legacy_macros,
|
||||
|
|
@ -834,6 +845,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;
|
||||
|
|
@ -63,6 +64,7 @@ use base_db::{Crate, impl_intern_key};
|
|||
use hir_expand::{
|
||||
AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallStyles,
|
||||
MacroDefId, MacroDefKind,
|
||||
attrs::AttrId,
|
||||
builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
|
||||
db::ExpandDatabase,
|
||||
eager::expand_eager_macro_input,
|
||||
|
|
@ -80,6 +82,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 +334,21 @@ impl ImplId {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct BuiltinDeriveImplLoc {
|
||||
pub adt: AdtId,
|
||||
pub trait_: BuiltinDeriveImplTrait,
|
||||
pub derive_attr_id: AttrId,
|
||||
pub derive_index: u32,
|
||||
}
|
||||
|
||||
#[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);
|
||||
|
||||
|
|
@ -660,6 +678,18 @@ impl_from!(
|
|||
for ModuleDefId
|
||||
);
|
||||
|
||||
impl From<DefWithBodyId> for ModuleDefId {
|
||||
#[inline]
|
||||
fn from(value: DefWithBodyId) -> Self {
|
||||
match value {
|
||||
DefWithBodyId::FunctionId(id) => id.into(),
|
||||
DefWithBodyId::StaticId(id) => id.into(),
|
||||
DefWithBodyId::ConstId(id) => id.into(),
|
||||
DefWithBodyId::VariantId(id) => id.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A constant, which might appears as a const item, an anonymous const block in expressions
|
||||
/// or patterns, or as a constant in types with const generics.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
|
||||
|
|
@ -1009,6 +1039,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 {
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ use crate::{
|
|||
|
||||
#[track_caller]
|
||||
fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false);
|
||||
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
|
|
@ -80,10 +82,15 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
|
|||
.sorted_unstable_by_key(|(range, _)| range.start())
|
||||
.format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}")))
|
||||
.to_string();
|
||||
|
||||
crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true);
|
||||
|
||||
expect.assert_eq(&errors);
|
||||
}
|
||||
|
||||
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) {
|
||||
crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false);
|
||||
|
||||
let extra_proc_macros = vec![(
|
||||
r#"
|
||||
#[proc_macro_attribute]
|
||||
|
|
@ -246,6 +253,8 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
|
|||
}
|
||||
}
|
||||
|
||||
crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true);
|
||||
|
||||
expect.indent(false);
|
||||
expect.assert_eq(&expanded_text);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,16 +122,16 @@ struct Foo {
|
|||
v4: bool // No comma here
|
||||
}
|
||||
|
||||
#[attr1]
|
||||
#[derive(Bar)]
|
||||
#[attr2] struct S;
|
||||
#[attr1]
|
||||
#[my_cool_derive()] struct Foo {
|
||||
v1: i32, #[attr3]v2: fn(#[attr4]param2: u32), v3: Foo< {
|
||||
456
|
||||
}
|
||||
>,
|
||||
}
|
||||
#[attr1]
|
||||
#[derive(Bar)]
|
||||
#[attr2] struct S;"#]],
|
||||
}"#]],
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,25 @@ use crate::{
|
|||
|
||||
pub use self::path_resolution::ResolvePathResultPrefixInfo;
|
||||
|
||||
#[cfg(test)]
|
||||
thread_local! {
|
||||
/// HACK: In order to test builtin derive expansion, we gate their fast path with this atomic when cfg(test).
|
||||
pub(crate) static ENABLE_BUILTIN_DERIVE_FAST_PATH: std::cell::Cell<bool> =
|
||||
const { std::cell::Cell::new(true) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(test)]
|
||||
fn enable_builtin_derive_fast_path() -> bool {
|
||||
ENABLE_BUILTIN_DERIVE_FAST_PATH.get()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
#[cfg(not(test))]
|
||||
fn enable_builtin_derive_fast_path() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
const PREDEFINED_TOOLS: &[SmolStr] = &[
|
||||
SmolStr::new_static("clippy"),
|
||||
SmolStr::new_static("rustfmt"),
|
||||
|
|
|
|||
|
|
@ -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,17 @@ enum MacroDirectiveKind<'db> {
|
|||
},
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DeferredBuiltinDerive {
|
||||
call_id: MacroCallId,
|
||||
derive: BuiltinDeriveExpander,
|
||||
module_id: ModuleId,
|
||||
depth: usize,
|
||||
container: ItemContainerId,
|
||||
derive_attr_id: AttrId,
|
||||
derive_index: u32,
|
||||
}
|
||||
|
||||
/// Walks the tree of module recursively
|
||||
struct DefCollector<'db> {
|
||||
db: &'db dyn DefDatabase,
|
||||
|
|
@ -252,6 +266,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 +1260,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 +1290,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 +1302,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 +1325,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 +1339,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 +1347,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 +1374,8 @@ impl<'db> DefCollector<'db> {
|
|||
}
|
||||
}
|
||||
|
||||
push_resolved(directive, call_id);
|
||||
push_resolved(&mut resolved, directive, call_id);
|
||||
|
||||
res = ReachedFixedPoint::No;
|
||||
return Resolved::Yes;
|
||||
}
|
||||
|
|
@ -1460,29 +1481,85 @@ impl<'db> DefCollector<'db> {
|
|||
|
||||
let ast_id = ast_id.with_value(ast_adt_id);
|
||||
|
||||
let mut derive_call_ids = SmallVec::new();
|
||||
match attr.parse_path_comma_token_tree(self.db) {
|
||||
Some(derive_macros) => {
|
||||
let call_id = call_id();
|
||||
let mut len = 0;
|
||||
for (idx, (path, call_site, _)) in derive_macros.enumerate() {
|
||||
let ast_id = AstIdWithPath::new(
|
||||
file_id,
|
||||
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,
|
||||
});
|
||||
len = idx;
|
||||
|
||||
// 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 {
|
||||
derive_call_ids.push(Some(call_id));
|
||||
// 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 super::enable_builtin_derive_fast_path()
|
||||
&& 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,
|
||||
derive_attr_id: *attr_id,
|
||||
derive_index: idx as u32,
|
||||
});
|
||||
} else {
|
||||
push_resolved(&mut resolved, directive, call_id);
|
||||
}
|
||||
} else {
|
||||
derive_call_ids.push(None);
|
||||
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,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
|
||||
|
|
@ -1491,7 +1568,12 @@ impl<'db> DefCollector<'db> {
|
|||
// Check the comment in [`builtin_attr_macro`].
|
||||
self.def_map.modules[directive.module_id]
|
||||
.scope
|
||||
.init_derive_attribute(ast_id, *attr_id, call_id, len + 1);
|
||||
.init_derive_attribute(
|
||||
ast_id,
|
||||
*attr_id,
|
||||
call_id,
|
||||
derive_call_ids,
|
||||
);
|
||||
}
|
||||
None => {
|
||||
let diag = DefDiagnostic::malformed_derive(
|
||||
|
|
@ -1522,12 +1604,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 +1804,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 +1852,33 @@ 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_,
|
||||
derive_attr_id: deferred_derive.derive_attr_id,
|
||||
derive_index: deferred_derive.derive_index,
|
||||
},
|
||||
);
|
||||
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 +2056,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 +2080,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 +2102,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> {
|
||||
|
|
|
|||
599
src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
Normal file
599
src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
//! 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, ParamEnv, StoredEarlyBinder,
|
||||
StoredTy, TraitRef, Ty, TyKind, fold::fold_tys, generics::Generics,
|
||||
},
|
||||
};
|
||||
|
||||
fn coerce_pointee_new_type_param(trait_id: TraitId) -> TypeParamId {
|
||||
// HACK: Fake the param.
|
||||
// We cannot use a dummy param here, because it can leak into the IDE layer and that'll cause panics
|
||||
// when e.g. trying to display it. So we use an existing param.
|
||||
TypeParamId::from_unchecked(TypeOrConstParamId {
|
||||
parent: trait_id.into(),
|
||||
local_id: la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(1)),
|
||||
})
|
||||
}
|
||||
|
||||
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());
|
||||
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");
|
||||
generics.push_param(coerce_pointee_new_type_param(trait_id).into());
|
||||
generics
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generic_params_count(db: &dyn HirDatabase, id: BuiltinDeriveImplId) -> usize {
|
||||
let loc = id.loc(db);
|
||||
let adt_params = GenericParams::new(db, loc.adt.into());
|
||||
let extra_params_count = match loc.trait_ {
|
||||
BuiltinDeriveImplTrait::Copy
|
||||
| BuiltinDeriveImplTrait::Clone
|
||||
| BuiltinDeriveImplTrait::Default
|
||||
| BuiltinDeriveImplTrait::Debug
|
||||
| BuiltinDeriveImplTrait::Hash
|
||||
| BuiltinDeriveImplTrait::Ord
|
||||
| BuiltinDeriveImplTrait::PartialOrd
|
||||
| BuiltinDeriveImplTrait::Eq
|
||||
| BuiltinDeriveImplTrait::PartialEq => 0,
|
||||
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => 1,
|
||||
};
|
||||
adt_params.len() + extra_params_count
|
||||
}
|
||||
|
||||
pub 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, trait_id)
|
||||
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 fn 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());
|
||||
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::Debug
|
||||
| BuiltinDeriveImplTrait::Hash
|
||||
| BuiltinDeriveImplTrait::Ord
|
||||
| BuiltinDeriveImplTrait::PartialOrd
|
||||
| BuiltinDeriveImplTrait::Eq
|
||||
| BuiltinDeriveImplTrait::PartialEq => {
|
||||
simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id)
|
||||
}
|
||||
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, trait_id)
|
||||
}
|
||||
}
|
||||
BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
|
||||
let Some((pointee_param_idx, pointee_param_id, new_param_ty)) =
|
||||
coerce_pointee_params(interner, loc, &generic_params, trait_id)
|
||||
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(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Not cached in a query, currently used in `hir` only. If you need this in `hir-ty` consider introducing a query.
|
||||
pub fn param_env<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> ParamEnv<'db> {
|
||||
let predicates = predicates(interner.db, id);
|
||||
crate::lower::param_env_from_predicates(interner, predicates)
|
||||
}
|
||||
|
||||
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,
|
||||
trait_id: TraitId,
|
||||
) -> GenericPredicates {
|
||||
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,
|
||||
trait_id: TraitId,
|
||||
) -> 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 = coerce_pointee_new_type_param(trait_id);
|
||||
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::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 = super::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: [] })
|
||||
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1568,6 +1568,7 @@ const GOAL: u8 = {
|
|||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "builtin derive macros are currently not working with MIR eval"]
|
||||
fn builtin_derive_macro() {
|
||||
check_number(
|
||||
r#"
|
||||
|
|
|
|||
|
|
@ -2,10 +2,12 @@
|
|||
//! type inference-related queries.
|
||||
|
||||
use base_db::{Crate, target::TargetLoadError};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
|
||||
GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, VariantId,
|
||||
db::DefDatabase, hir::ExprId, layout::TargetDataLayout,
|
||||
AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
|
||||
FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
|
||||
TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId,
|
||||
layout::TargetDataLayout,
|
||||
};
|
||||
use la_arena::ArenaMap;
|
||||
use salsa::plumbing::AsId;
|
||||
|
|
@ -83,7 +85,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
|
|||
env: ParamEnvAndCrate<'db>,
|
||||
func: FunctionId,
|
||||
fn_subst: GenericArgs<'db>,
|
||||
) -> (FunctionId, GenericArgs<'db>);
|
||||
) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>);
|
||||
|
||||
// endregion:mir
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ use std::{
|
|||
mem,
|
||||
};
|
||||
|
||||
use base_db::Crate;
|
||||
use base_db::{Crate, FxIndexMap};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
|
||||
|
|
@ -143,11 +143,11 @@ impl<'db> BoundsFormattingCtx<'db> {
|
|||
}
|
||||
|
||||
impl<'db> HirFormatter<'_, 'db> {
|
||||
fn start_location_link(&mut self, location: ModuleDefId) {
|
||||
pub fn start_location_link(&mut self, location: ModuleDefId) {
|
||||
self.fmt.start_location_link(location);
|
||||
}
|
||||
|
||||
fn end_location_link(&mut self) {
|
||||
pub fn end_location_link(&mut self) {
|
||||
self.fmt.end_location_link();
|
||||
}
|
||||
|
||||
|
|
@ -1971,6 +1971,49 @@ fn write_bounds_like_dyn_trait<'db>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_params_bounds<'db>(
|
||||
f: &mut HirFormatter<'_, 'db>,
|
||||
predicates: &[Clause<'db>],
|
||||
) -> Result {
|
||||
// Use an FxIndexMap to keep user's order, as far as possible.
|
||||
let mut per_type = FxIndexMap::<_, Vec<_>>::default();
|
||||
for &predicate in predicates {
|
||||
let base_ty = match predicate.kind().skip_binder() {
|
||||
ClauseKind::Trait(clause) => Either::Left(clause.self_ty()),
|
||||
ClauseKind::RegionOutlives(clause) => Either::Right(clause.0),
|
||||
ClauseKind::TypeOutlives(clause) => Either::Left(clause.0),
|
||||
ClauseKind::Projection(clause) => Either::Left(clause.self_ty()),
|
||||
ClauseKind::ConstArgHasType(..)
|
||||
| ClauseKind::WellFormed(_)
|
||||
| ClauseKind::ConstEvaluatable(_)
|
||||
| ClauseKind::HostEffect(..)
|
||||
| ClauseKind::UnstableFeature(_) => continue,
|
||||
};
|
||||
per_type.entry(base_ty).or_default().push(predicate);
|
||||
}
|
||||
|
||||
for (base_ty, clauses) in per_type {
|
||||
f.write_str(" ")?;
|
||||
match base_ty {
|
||||
Either::Left(it) => it.hir_fmt(f)?,
|
||||
Either::Right(it) => it.hir_fmt(f)?,
|
||||
}
|
||||
f.write_str(": ")?;
|
||||
// Rudimentary approximation: type params are `Sized` by default, everything else not.
|
||||
// FIXME: This is not correct, really. But I'm not sure how we can from the ty representation
|
||||
// to extract the default sizedness, and if it's possible at all.
|
||||
let default_sized = match base_ty {
|
||||
Either::Left(ty) if matches!(ty.kind(), TyKind::Param(_)) => {
|
||||
SizedByDefault::Sized { anchor: f.krate() }
|
||||
}
|
||||
_ => SizedByDefault::NotSized,
|
||||
};
|
||||
write_bounds_like_dyn_trait(f, base_ty, &clauses, default_sized)?;
|
||||
f.write_str(",\n")?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'db> HirDisplay<'db> for TraitRef<'db> {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
let trait_ = self.def_id.0;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
pub 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
|
||||
|
|
@ -1848,6 +1855,20 @@ pub(crate) fn trait_environment_for_body_query(
|
|||
db.trait_environment(def)
|
||||
}
|
||||
|
||||
pub(crate) fn param_env_from_predicates<'db>(
|
||||
interner: DbInterner<'db>,
|
||||
predicates: &'db GenericPredicates,
|
||||
) -> ParamEnv<'db> {
|
||||
let clauses = rustc_type_ir::elaborate::elaborate(
|
||||
interner,
|
||||
predicates.all_predicates().iter_identity_copied(),
|
||||
);
|
||||
let clauses = Clauses::new_from_iter(interner, clauses);
|
||||
|
||||
// FIXME: We should normalize projections here, like rustc does.
|
||||
ParamEnv { clauses }
|
||||
}
|
||||
|
||||
pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> {
|
||||
return ParamEnv { clauses: trait_environment_query(db, def).as_ref() };
|
||||
|
||||
|
|
@ -1858,13 +1879,8 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId
|
|||
) -> StoredClauses {
|
||||
let module = def.module(db);
|
||||
let interner = DbInterner::new_with(db, module.krate(db));
|
||||
let predicates = GenericPredicates::query_all(db, def);
|
||||
let clauses =
|
||||
rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied());
|
||||
let clauses = Clauses::new_from_iter(interner, clauses);
|
||||
|
||||
// FIXME: We should normalize projections here, like rustc does.
|
||||
clauses.store()
|
||||
let predicates = GenericPredicates::query(db, def);
|
||||
param_env_from_predicates(interner, predicates).clauses.store()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,13 @@ 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,
|
||||
builtin_derive::BuiltinDeriveImplMethod,
|
||||
expr_store::path::GenericArgs as HirGenericArgs,
|
||||
hir::ExprId,
|
||||
lang_item::LangItems,
|
||||
nameres::{DefMap, block_def_map, crate_def_map},
|
||||
resolver::Resolver,
|
||||
};
|
||||
|
|
@ -37,7 +39,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 +134,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),
|
||||
}
|
||||
|
||||
|
|
@ -371,9 +373,13 @@ pub fn lookup_impl_const<'db>(
|
|||
};
|
||||
|
||||
lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
|
||||
.and_then(
|
||||
|assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None },
|
||||
)
|
||||
.and_then(|assoc| {
|
||||
if let (Either::Left(AssocItemId::ConstId(id)), s) = assoc {
|
||||
Some((id, s))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or((const_id, subs))
|
||||
}
|
||||
|
||||
|
|
@ -419,12 +425,12 @@ pub(crate) fn lookup_impl_method_query<'db>(
|
|||
env: ParamEnvAndCrate<'db>,
|
||||
func: FunctionId,
|
||||
fn_subst: GenericArgs<'db>,
|
||||
) -> (FunctionId, GenericArgs<'db>) {
|
||||
) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>) {
|
||||
let interner = DbInterner::new_with(db, env.krate);
|
||||
let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
|
||||
|
||||
let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
|
||||
return (func, fn_subst);
|
||||
return (Either::Left(func), fn_subst);
|
||||
};
|
||||
let trait_params = db.generic_params(trait_id.into()).len();
|
||||
let trait_ref = TraitRef::new_from_args(
|
||||
|
|
@ -434,16 +440,19 @@ pub(crate) fn lookup_impl_method_query<'db>(
|
|||
);
|
||||
|
||||
let name = &db.function_signature(func).name;
|
||||
let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(
|
||||
&infcx,
|
||||
trait_ref,
|
||||
env.param_env,
|
||||
name,
|
||||
)
|
||||
.and_then(|assoc| {
|
||||
if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
|
||||
}) else {
|
||||
return (func, fn_subst);
|
||||
let Some((impl_fn, impl_subst)) =
|
||||
lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then(
|
||||
|(assoc, impl_args)| {
|
||||
let assoc = match assoc {
|
||||
Either::Left(AssocItemId::FunctionId(id)) => Either::Left(id),
|
||||
Either::Right(it) => Either::Right(it),
|
||||
_ => return None,
|
||||
};
|
||||
Some((assoc, impl_args))
|
||||
},
|
||||
)
|
||||
else {
|
||||
return (Either::Left(func), fn_subst);
|
||||
};
|
||||
|
||||
(
|
||||
|
|
@ -460,22 +469,33 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>(
|
|||
trait_ref: TraitRef<'db>,
|
||||
env: ParamEnv<'db>,
|
||||
name: &Name,
|
||||
) -> Option<(AssocItemId, GenericArgs<'db>)> {
|
||||
) -> Option<(Either<AssocItemId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>)>
|
||||
{
|
||||
let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
|
||||
let impl_id = match impl_id {
|
||||
AnyImplId::ImplId(it) => it,
|
||||
AnyImplId::BuiltinDeriveImplId(impl_) => {
|
||||
return impl_
|
||||
.loc(infcx.interner.db)
|
||||
.trait_
|
||||
.get_method(name.symbol())
|
||||
.map(|method| (Either::Right((impl_, method)), impl_subst));
|
||||
}
|
||||
};
|
||||
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)),
|
||||
AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
|
||||
AssocItemId::TypeAliasId(_) => None,
|
||||
})?;
|
||||
Some((item, impl_subst))
|
||||
Some((Either::Left(item), impl_subst))
|
||||
}
|
||||
|
||||
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 +655,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 +670,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 +713,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 +726,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 +751,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,27 +796,41 @@ 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()
|
||||
}
|
||||
|
||||
pub fn for_trait(&self, trait_: TraitId, mut callback: impl FnMut(&[ImplId])) {
|
||||
pub fn for_trait(
|
||||
&self,
|
||||
trait_: TraitId,
|
||||
mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
|
||||
) {
|
||||
if let Some(impls) = self.map.get(&trait_) {
|
||||
callback(&impls.blanket_impls);
|
||||
callback(Either::Left(&impls.blanket_impls));
|
||||
for impls in impls.non_blanket_impls.values() {
|
||||
callback(impls);
|
||||
callback(Either::Left(&impls.0));
|
||||
callback(Either::Right(&impls.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) {
|
||||
pub fn for_self_ty(
|
||||
&self,
|
||||
self_ty: &SimplifiedType,
|
||||
mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
|
||||
) {
|
||||
for for_trait in self.map.values() {
|
||||
if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) {
|
||||
callback(for_ty);
|
||||
callback(Either::Left(&for_ty.0));
|
||||
callback(Either::Right(&for_ty.1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,12 +77,14 @@ macro_rules! from_bytes {
|
|||
}).into())
|
||||
};
|
||||
}
|
||||
use from_bytes;
|
||||
|
||||
macro_rules! not_supported {
|
||||
($it: expr) => {
|
||||
return Err(MirEvalError::NotSupported(format!($it)))
|
||||
return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it)))
|
||||
};
|
||||
}
|
||||
use not_supported;
|
||||
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)]
|
||||
pub struct VTableMap<'db> {
|
||||
|
|
@ -2622,6 +2624,9 @@ impl<'db> Evaluator<'db> {
|
|||
def,
|
||||
generic_args,
|
||||
);
|
||||
let Either::Left(imp) = imp else {
|
||||
not_supported!("evaluating builtin derive impls is not supported")
|
||||
};
|
||||
|
||||
let mir_body = self
|
||||
.db
|
||||
|
|
|
|||
|
|
@ -16,29 +16,14 @@ use crate::{
|
|||
mir::eval::{
|
||||
Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay,
|
||||
InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, Layout, Locals,
|
||||
Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16,
|
||||
Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported,
|
||||
pad16,
|
||||
},
|
||||
next_solver::Region,
|
||||
};
|
||||
|
||||
mod simd;
|
||||
|
||||
macro_rules! from_bytes {
|
||||
($ty:tt, $value:expr) => {
|
||||
($ty::from_le_bytes(match ($value).try_into() {
|
||||
Ok(it) => it,
|
||||
#[allow(unreachable_patterns)]
|
||||
Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! not_supported {
|
||||
($it: expr) => {
|
||||
return Err(MirEvalError::NotSupported(format!($it)))
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum EvalLangItem {
|
||||
BeginPanic,
|
||||
|
|
|
|||
|
|
@ -6,21 +6,6 @@ use crate::consteval::try_const_usize;
|
|||
|
||||
use super::*;
|
||||
|
||||
macro_rules! from_bytes {
|
||||
($ty:tt, $value:expr) => {
|
||||
($ty::from_le_bytes(match ($value).try_into() {
|
||||
Ok(it) => it,
|
||||
Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
|
||||
}))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! not_supported {
|
||||
($it: expr) => {
|
||||
return Err(MirEvalError::NotSupported(format!($it)))
|
||||
};
|
||||
}
|
||||
|
||||
impl<'db> Evaluator<'db> {
|
||||
fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> {
|
||||
match ty.kind() {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
use rustc_type_ir::{solve::GoalSource, solve::inspect::GoalEvaluation};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
|
||||
use crate::next_solver::infer::InferCtxt;
|
||||
use crate::next_solver::inspect::{InspectCandidate, InspectGoal};
|
||||
use crate::next_solver::{AnyImplId, infer::InferCtxt};
|
||||
use crate::next_solver::{DbInterner, Span};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
@ -76,14 +76,31 @@ impl<'a, 'db> ProofTreeSerializer<'a, 'db> {
|
|||
use rustc_type_ir::solve::inspect::ProbeKind;
|
||||
match candidate.kind() {
|
||||
ProbeKind::TraitCandidate { source, .. } => {
|
||||
use hir_def::{Lookup, src::HasSource};
|
||||
use rustc_type_ir::solve::CandidateSource;
|
||||
let db = self.infcx.interner.db;
|
||||
match source {
|
||||
CandidateSource::Impl(impl_def_id) => {
|
||||
use hir_def::{Lookup, src::HasSource};
|
||||
let db = self.infcx.interner.db;
|
||||
let impl_src = impl_def_id.0.lookup(db).source(db);
|
||||
Some(impl_src.value.to_string())
|
||||
}
|
||||
CandidateSource::Impl(impl_def_id) => match impl_def_id {
|
||||
AnyImplId::ImplId(impl_def_id) => {
|
||||
let impl_src = impl_def_id.lookup(db).source(db);
|
||||
Some(impl_src.value.to_string())
|
||||
}
|
||||
AnyImplId::BuiltinDeriveImplId(impl_id) => {
|
||||
let impl_loc = impl_id.loc(db);
|
||||
let adt_src = match impl_loc.adt {
|
||||
hir_def::AdtId::StructId(adt) => {
|
||||
adt.loc(db).source(db).value.to_string()
|
||||
}
|
||||
hir_def::AdtId::UnionId(adt) => {
|
||||
adt.loc(db).source(db).value.to_string()
|
||||
}
|
||||
hir_def::AdtId::EnumId(adt) => {
|
||||
adt.loc(db).source(db).value.to_string()
|
||||
}
|
||||
};
|
||||
Some(format!("#[derive(${})]\n{}", impl_loc.trait_.name(), adt_src))
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::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_query",
|
||||
"impl_signature_shim",
|
||||
"impl_signature_with_source_map_shim",
|
||||
"impl_self_ty_with_diagnostics_query",
|
||||
"struct_signature_shim",
|
||||
"struct_signature_with_source_map_shim",
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ pub enum AttrsOwner {
|
|||
Field(FieldId),
|
||||
LifetimeParam(LifetimeParamId),
|
||||
TypeOrConstParam(TypeOrConstParamId),
|
||||
/// Things that do not have attributes. Used for builtin derives.
|
||||
Dummy,
|
||||
}
|
||||
|
||||
impl AttrsOwner {
|
||||
|
|
@ -123,7 +125,9 @@ impl AttrsWithOwner {
|
|||
let owner = match self.owner {
|
||||
AttrsOwner::AttrDef(it) => Either::Left(it),
|
||||
AttrsOwner::Field(it) => Either::Right(it),
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return &[],
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
|
||||
return &[];
|
||||
}
|
||||
};
|
||||
self.attrs.doc_aliases(db, owner)
|
||||
}
|
||||
|
|
@ -133,7 +137,9 @@ impl AttrsWithOwner {
|
|||
let owner = match self.owner {
|
||||
AttrsOwner::AttrDef(it) => Either::Left(it),
|
||||
AttrsOwner::Field(it) => Either::Right(it),
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None,
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
self.attrs.cfgs(db, owner)
|
||||
}
|
||||
|
|
@ -143,7 +149,9 @@ impl AttrsWithOwner {
|
|||
match self.owner {
|
||||
AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(),
|
||||
AttrsOwner::Field(it) => AttrFlags::field_docs(db, it),
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None,
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -156,6 +164,9 @@ pub trait HasAttrs: Sized {
|
|||
AttrsOwner::Field(it) => AttrsWithOwner::new_field(db, it),
|
||||
AttrsOwner::LifetimeParam(it) => AttrsWithOwner::new_lifetime_param(db, it),
|
||||
AttrsOwner::TypeOrConstParam(it) => AttrsWithOwner::new_type_or_const_param(db, it),
|
||||
AttrsOwner::Dummy => {
|
||||
AttrsWithOwner { attrs: AttrFlags::empty(), owner: AttrsOwner::Dummy }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +178,9 @@ pub trait HasAttrs: Sized {
|
|||
match self.attr_id(db) {
|
||||
AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(),
|
||||
AttrsOwner::Field(it) => AttrFlags::field_docs(db, it),
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None,
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -190,12 +203,28 @@ impl_has_attrs![
|
|||
(Trait, TraitId),
|
||||
(TypeAlias, TypeAliasId),
|
||||
(Macro, MacroId),
|
||||
(Function, FunctionId),
|
||||
(Adt, AdtId),
|
||||
(Impl, ImplId),
|
||||
(ExternCrateDecl, ExternCrateId),
|
||||
];
|
||||
|
||||
impl HasAttrs for Function {
|
||||
fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner {
|
||||
match self.id {
|
||||
crate::AnyFunctionId::FunctionId(id) => AttrsOwner::AttrDef(id.into()),
|
||||
crate::AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrsOwner::Dummy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl HasAttrs for Impl {
|
||||
fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner {
|
||||
match self.id {
|
||||
hir_ty::next_solver::AnyImplId::ImplId(id) => AttrsOwner::AttrDef(id.into()),
|
||||
hir_ty::next_solver::AnyImplId::BuiltinDeriveImplId(..) => AttrsOwner::Dummy,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_has_attrs_enum {
|
||||
($($variant:ident),* for $enum:ident) => {$(
|
||||
impl HasAttrs for $variant {
|
||||
|
|
@ -294,7 +323,9 @@ fn resolve_doc_path_on_(
|
|||
AttrsOwner::AttrDef(AttrDefId::MacroId(it)) => it.resolver(db),
|
||||
AttrsOwner::AttrDef(AttrDefId::ExternCrateId(it)) => it.resolver(db),
|
||||
AttrsOwner::Field(it) => it.parent.resolver(db),
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None,
|
||||
AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let mut modpath = doc_modpath_from_str(link)?;
|
||||
|
|
|
|||
|
|
@ -2,19 +2,22 @@
|
|||
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
AdtId, GenericDefId,
|
||||
AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId,
|
||||
builtin_derive::BuiltinDeriveImplMethod,
|
||||
expr_store::ExpressionStore,
|
||||
hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate},
|
||||
item_tree::FieldsShape,
|
||||
signatures::{StaticFlags, TraitFlags},
|
||||
type_ref::{TypeBound, TypeRef, TypeRefId},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
use hir_ty::{
|
||||
GenericPredicates,
|
||||
db::HirDatabase,
|
||||
display::{
|
||||
HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault,
|
||||
hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
|
||||
hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_params_bounds,
|
||||
write_visibility,
|
||||
},
|
||||
next_solver::ClauseKind,
|
||||
};
|
||||
|
|
@ -22,25 +25,78 @@ use itertools::Itertools;
|
|||
use rustc_type_ir::inherent::IntoKind;
|
||||
|
||||
use crate::{
|
||||
Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
|
||||
Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
|
||||
ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
|
||||
Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type,
|
||||
TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
|
||||
};
|
||||
|
||||
fn write_builtin_derive_impl_method<'db>(
|
||||
f: &mut HirFormatter<'_, 'db>,
|
||||
impl_: BuiltinDeriveImplId,
|
||||
method: BuiltinDeriveImplMethod,
|
||||
) -> Result {
|
||||
let db = f.db;
|
||||
let loc = impl_.loc(db);
|
||||
let (adt_params, _adt_params_store) = db.generic_params_and_store(loc.adt.into());
|
||||
|
||||
if f.show_container_bounds() && !adt_params.is_empty() {
|
||||
f.write_str("impl")?;
|
||||
write_generic_params(loc.adt.into(), f)?;
|
||||
f.write_char(' ')?;
|
||||
let trait_id = loc.trait_.get_id(f.lang_items());
|
||||
if let Some(trait_id) = trait_id {
|
||||
f.start_location_link(trait_id.into());
|
||||
}
|
||||
write!(f, "{}", Name::new_symbol_root(loc.trait_.name()).display(db, f.edition()))?;
|
||||
if trait_id.is_some() {
|
||||
f.end_location_link();
|
||||
}
|
||||
f.write_str(" for ")?;
|
||||
f.start_location_link(loc.adt.into());
|
||||
write!(f, "{}", Adt::from(loc.adt).name(db).display(db, f.edition()))?;
|
||||
f.end_location_link();
|
||||
write_generic_args(loc.adt.into(), f)?;
|
||||
f.write_char('\n')?;
|
||||
}
|
||||
|
||||
let Some(trait_method) = method.trait_method(db, impl_) else {
|
||||
return write!(f, "fn {}(…)", method.name());
|
||||
};
|
||||
let has_written_where = write_function(f, trait_method)?;
|
||||
|
||||
if f.show_container_bounds() && !adt_params.is_empty() {
|
||||
if !has_written_where {
|
||||
f.write_str("\nwhere")?
|
||||
}
|
||||
write!(f, "\n // Bounds from impl:")?;
|
||||
|
||||
let predicates =
|
||||
hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
|
||||
write_params_bounds(f, predicates)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'db> HirDisplay<'db> for Function {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
let id = match self.id {
|
||||
AnyFunctionId::FunctionId(id) => id,
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
|
||||
return write_builtin_derive_impl_method(f, impl_, method);
|
||||
}
|
||||
};
|
||||
|
||||
let db = f.db;
|
||||
let data = db.function_signature(self.id);
|
||||
let container = self.as_assoc_item(db).map(|it| it.container(db));
|
||||
let mut module = self.module(db);
|
||||
let container = id.loc(db).container;
|
||||
|
||||
// Write container (trait or impl)
|
||||
let container_params = match container {
|
||||
Some(AssocItemContainer::Trait(trait_)) => {
|
||||
let (params, params_store) = f.db.generic_params_and_store(trait_.id.into());
|
||||
ItemContainerId::TraitId(trait_) => {
|
||||
let (params, params_store) = f.db.generic_params_and_store(trait_.into());
|
||||
if f.show_container_bounds() && !params.is_empty() {
|
||||
write_trait_header(&trait_, f)?;
|
||||
write_trait_header(trait_.into(), f)?;
|
||||
f.write_char('\n')?;
|
||||
has_disaplayable_predicates(f.db, ¶ms, ¶ms_store)
|
||||
.then_some((params, params_store))
|
||||
|
|
@ -48,10 +104,10 @@ impl<'db> HirDisplay<'db> for Function {
|
|||
None
|
||||
}
|
||||
}
|
||||
Some(AssocItemContainer::Impl(impl_)) => {
|
||||
let (params, params_store) = f.db.generic_params_and_store(impl_.id.into());
|
||||
ItemContainerId::ImplId(impl_) => {
|
||||
let (params, params_store) = f.db.generic_params_and_store(impl_.into());
|
||||
if f.show_container_bounds() && !params.is_empty() {
|
||||
write_impl_header(&impl_, f)?;
|
||||
write_impl_header(impl_, f)?;
|
||||
f.write_char('\n')?;
|
||||
has_disaplayable_predicates(f.db, ¶ms, ¶ms_store)
|
||||
.then_some((params, params_store))
|
||||
|
|
@ -59,124 +115,20 @@ impl<'db> HirDisplay<'db> for Function {
|
|||
None
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// Write signature of the function
|
||||
|
||||
// Block-local impls are "hoisted" to the nearest (non-block) module.
|
||||
if let Some(AssocItemContainer::Impl(_)) = container {
|
||||
module = module.nearest_non_block_module(db);
|
||||
}
|
||||
let module_id = module.id;
|
||||
|
||||
write_visibility(module_id, self.visibility(db), f)?;
|
||||
|
||||
if data.is_default() {
|
||||
f.write_str("default ")?;
|
||||
}
|
||||
if data.is_const() {
|
||||
f.write_str("const ")?;
|
||||
}
|
||||
if data.is_async() {
|
||||
f.write_str("async ")?;
|
||||
}
|
||||
// FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
|
||||
// (they are conditionally unsafe to call). We probably should show something else.
|
||||
if self.is_unsafe_to_call(db, None, f.edition()) {
|
||||
f.write_str("unsafe ")?;
|
||||
}
|
||||
if let Some(abi) = &data.abi {
|
||||
write!(f, "extern \"{}\" ", abi.as_str())?;
|
||||
}
|
||||
write!(f, "fn {}", data.name.display(f.db, f.edition()))?;
|
||||
|
||||
write_generic_params(GenericDefId::FunctionId(self.id), f)?;
|
||||
|
||||
f.write_char('(')?;
|
||||
|
||||
let mut first = true;
|
||||
let mut skip_self = 0;
|
||||
if let Some(self_param) = self.self_param(db) {
|
||||
self_param.hir_fmt(f)?;
|
||||
first = false;
|
||||
skip_self = 1;
|
||||
}
|
||||
|
||||
// FIXME: Use resolved `param.ty` once we no longer discard lifetimes
|
||||
let body = db.body(self.id.into());
|
||||
for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) {
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
let pat_id = body.params[param.idx - body.self_param.is_some() as usize];
|
||||
let pat_str = body.pretty_print_pat(db, self.id.into(), pat_id, true, f.edition());
|
||||
f.write_str(&pat_str)?;
|
||||
|
||||
f.write_str(": ")?;
|
||||
type_ref.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
|
||||
if data.is_varargs() {
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str("...")?;
|
||||
}
|
||||
|
||||
f.write_char(')')?;
|
||||
|
||||
// `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
|
||||
// Use ugly pattern match to strip the Future trait.
|
||||
// Better way?
|
||||
let ret_type = if !data.is_async() {
|
||||
data.ret_type
|
||||
} else if let Some(ret_type) = data.ret_type {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
||||
&TypeBound::Path(path, _) => Some(
|
||||
*data.store[path]
|
||||
.segments()
|
||||
.iter()
|
||||
.last()
|
||||
.unwrap()
|
||||
.args_and_bindings
|
||||
.unwrap()
|
||||
.bindings[0]
|
||||
.type_ref
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(ret_type) = ret_type {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
_ => {
|
||||
f.write_str(" -> ")?;
|
||||
ret_type.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write where clauses
|
||||
let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?;
|
||||
let has_written_where = write_function(f, id)?;
|
||||
if let Some((container_params, container_params_store)) = container_params {
|
||||
if !has_written_where {
|
||||
f.write_str("\nwhere")?;
|
||||
}
|
||||
let container_name = match container.unwrap() {
|
||||
AssocItemContainer::Trait(_) => "trait",
|
||||
AssocItemContainer::Impl(_) => "impl",
|
||||
let container_name = match container {
|
||||
ItemContainerId::TraitId(_) => "trait",
|
||||
ItemContainerId::ImplId(_) => "impl",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write!(f, "\n // Bounds from {container_name}:",)?;
|
||||
write_where_predicates(&container_params, &container_params_store, f)?;
|
||||
|
|
@ -185,14 +137,129 @@ impl<'db> HirDisplay<'db> for Function {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result<bool> {
|
||||
let db = f.db;
|
||||
let func = Function::from(func_id);
|
||||
let data = db.function_signature(func_id);
|
||||
|
||||
let mut module = func.module(db);
|
||||
// Block-local impls are "hoisted" to the nearest (non-block) module.
|
||||
if let ItemContainerId::ImplId(_) = func_id.loc(db).container {
|
||||
module = module.nearest_non_block_module(db);
|
||||
}
|
||||
let module_id = module.id;
|
||||
|
||||
write_visibility(module_id, func.visibility(db), f)?;
|
||||
|
||||
if data.is_default() {
|
||||
f.write_str("default ")?;
|
||||
}
|
||||
if data.is_const() {
|
||||
f.write_str("const ")?;
|
||||
}
|
||||
if data.is_async() {
|
||||
f.write_str("async ")?;
|
||||
}
|
||||
// FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
|
||||
// (they are conditionally unsafe to call). We probably should show something else.
|
||||
if func.is_unsafe_to_call(db, None, f.edition()) {
|
||||
f.write_str("unsafe ")?;
|
||||
}
|
||||
if let Some(abi) = &data.abi {
|
||||
write!(f, "extern \"{}\" ", abi.as_str())?;
|
||||
}
|
||||
write!(f, "fn {}", data.name.display(f.db, f.edition()))?;
|
||||
|
||||
write_generic_params(GenericDefId::FunctionId(func_id), f)?;
|
||||
|
||||
f.write_char('(')?;
|
||||
|
||||
let mut first = true;
|
||||
let mut skip_self = 0;
|
||||
if let Some(self_param) = func.self_param(db) {
|
||||
self_param.hir_fmt(f)?;
|
||||
first = false;
|
||||
skip_self = 1;
|
||||
}
|
||||
|
||||
// FIXME: Use resolved `param.ty` once we no longer discard lifetimes
|
||||
let body = db.body(func_id.into());
|
||||
for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) {
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
let pat_id = body.params[param.idx - body.self_param.is_some() as usize];
|
||||
let pat_str = body.pretty_print_pat(db, func_id.into(), pat_id, true, f.edition());
|
||||
f.write_str(&pat_str)?;
|
||||
|
||||
f.write_str(": ")?;
|
||||
type_ref.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
|
||||
if data.is_varargs() {
|
||||
if !first {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
f.write_str("...")?;
|
||||
}
|
||||
|
||||
f.write_char(')')?;
|
||||
|
||||
// `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
|
||||
// Use ugly pattern match to strip the Future trait.
|
||||
// Better way?
|
||||
let ret_type = if !data.is_async() {
|
||||
data.ret_type
|
||||
} else if let Some(ret_type) = data.ret_type {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::ImplTrait(bounds) => match &bounds[0] {
|
||||
&TypeBound::Path(path, _) => Some(
|
||||
*data.store[path]
|
||||
.segments()
|
||||
.iter()
|
||||
.last()
|
||||
.unwrap()
|
||||
.args_and_bindings
|
||||
.unwrap()
|
||||
.bindings[0]
|
||||
.type_ref
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(ret_type) = ret_type {
|
||||
match &data.store[ret_type] {
|
||||
TypeRef::Tuple(tup) if tup.is_empty() => {}
|
||||
_ => {
|
||||
f.write_str(" -> ")?;
|
||||
ret_type.hir_fmt(f, &data.store)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write where clauses
|
||||
let has_written_where = write_where_clause(GenericDefId::FunctionId(func_id), f)?;
|
||||
Ok(has_written_where)
|
||||
}
|
||||
|
||||
fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
let db = f.db;
|
||||
|
||||
f.write_str("impl")?;
|
||||
let def_id = GenericDefId::ImplId(impl_.id);
|
||||
let def_id = GenericDefId::ImplId(impl_);
|
||||
write_generic_params(def_id, f)?;
|
||||
|
||||
let impl_data = db.impl_signature(impl_.id);
|
||||
let impl_data = db.impl_signature(impl_);
|
||||
if let Some(target_trait) = &impl_data.target_trait {
|
||||
f.write_char(' ')?;
|
||||
hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?;
|
||||
|
|
@ -200,14 +267,28 @@ fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result
|
|||
}
|
||||
|
||||
f.write_char(' ')?;
|
||||
impl_.self_ty(db).hir_fmt(f)?;
|
||||
Impl::from(impl_).self_ty(db).hir_fmt(f)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl<'db> HirDisplay<'db> for SelfParam {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
let data = f.db.function_signature(self.func);
|
||||
let func = match self.func.id {
|
||||
AnyFunctionId::FunctionId(id) => id,
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
|
||||
BuiltinDeriveImplMethod::clone
|
||||
| BuiltinDeriveImplMethod::fmt
|
||||
| BuiltinDeriveImplMethod::hash
|
||||
| BuiltinDeriveImplMethod::cmp
|
||||
| BuiltinDeriveImplMethod::partial_cmp
|
||||
| BuiltinDeriveImplMethod::eq => return f.write_str("&self"),
|
||||
BuiltinDeriveImplMethod::default => {
|
||||
unreachable!("this trait method does not have a self param")
|
||||
}
|
||||
},
|
||||
};
|
||||
let data = f.db.function_signature(func);
|
||||
let param = *data.params.first().unwrap();
|
||||
match &data.store[param] {
|
||||
TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
|
||||
|
|
@ -553,6 +634,18 @@ impl<'db> HirDisplay<'db> for ConstParam {
|
|||
}
|
||||
|
||||
fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
write_generic_params_or_args(def, f, true)
|
||||
}
|
||||
|
||||
fn write_generic_args<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
write_generic_params_or_args(def, f, false)
|
||||
}
|
||||
|
||||
fn write_generic_params_or_args<'db>(
|
||||
def: GenericDefId,
|
||||
f: &mut HirFormatter<'_, 'db>,
|
||||
include_defaults: bool,
|
||||
) -> Result {
|
||||
let (params, store) = f.db.generic_params_and_store(def);
|
||||
if params.iter_lt().next().is_none()
|
||||
&& params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
|
||||
|
|
@ -587,7 +680,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -
|
|||
}
|
||||
delim(f)?;
|
||||
write!(f, "{}", name.display(f.db, f.edition()))?;
|
||||
if let Some(default) = &ty.default {
|
||||
if include_defaults && let Some(default) = &ty.default {
|
||||
f.write_str(" = ")?;
|
||||
default.hir_fmt(f, &store)?;
|
||||
}
|
||||
|
|
@ -597,7 +690,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -
|
|||
write!(f, "const {}: ", name.display(f.db, f.edition()))?;
|
||||
c.ty.hir_fmt(f, &store)?;
|
||||
|
||||
if let Some(default) = &c.default {
|
||||
if include_defaults && let Some(default) = &c.default {
|
||||
f.write_str(" = ")?;
|
||||
default.hir_fmt(f, &store)?;
|
||||
}
|
||||
|
|
@ -746,7 +839,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> {
|
|||
impl<'db> HirDisplay<'db> for Trait {
|
||||
fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
// FIXME(trait-alias) needs special handling to print the equal sign
|
||||
write_trait_header(self, f)?;
|
||||
write_trait_header(*self, f)?;
|
||||
let def_id = GenericDefId::TraitId(self.id);
|
||||
let has_where_clause = write_where_clause(def_id, f)?;
|
||||
|
||||
|
|
@ -783,7 +876,7 @@ impl<'db> HirDisplay<'db> for Trait {
|
|||
}
|
||||
}
|
||||
|
||||
fn write_trait_header<'db>(trait_: &Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
|
||||
write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
|
||||
let data = f.db.trait_signature(trait_.id);
|
||||
if data.flags.contains(TraitFlags::UNSAFE) {
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@
|
|||
//! are splitting the hir.
|
||||
|
||||
use hir_def::{
|
||||
AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId,
|
||||
ModuleDefId, VariantId,
|
||||
AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId,
|
||||
GenericParamId, ModuleDefId, VariantId,
|
||||
hir::{BindingId, LabelId},
|
||||
};
|
||||
use hir_ty::next_solver::AnyImplId;
|
||||
|
||||
use crate::{
|
||||
Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, ItemInNs, Label,
|
||||
Local, ModuleDef, Variant, VariantDef,
|
||||
Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam,
|
||||
ItemInNs, Label, Local, ModuleDef, Variant, VariantDef,
|
||||
};
|
||||
|
||||
macro_rules! from_id {
|
||||
|
|
@ -39,8 +40,8 @@ from_id![
|
|||
(hir_def::TraitId, crate::Trait),
|
||||
(hir_def::StaticId, crate::Static),
|
||||
(hir_def::ConstId, crate::Const),
|
||||
(hir_def::FunctionId, crate::Function),
|
||||
(hir_def::ImplId, crate::Impl),
|
||||
(crate::AnyFunctionId, crate::Function),
|
||||
(hir_ty::next_solver::AnyImplId, crate::Impl),
|
||||
(hir_def::TypeOrConstParamId, crate::TypeOrConstParam),
|
||||
(hir_def::TypeParamId, crate::TypeParam),
|
||||
(hir_def::ConstParamId, crate::ConstParam),
|
||||
|
|
@ -119,11 +120,15 @@ impl From<ModuleDefId> for ModuleDef {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ModuleDef> for ModuleDefId {
|
||||
fn from(id: ModuleDef) -> Self {
|
||||
match id {
|
||||
impl TryFrom<ModuleDef> for ModuleDefId {
|
||||
type Error = ();
|
||||
fn try_from(id: ModuleDef) -> Result<Self, Self::Error> {
|
||||
Ok(match id {
|
||||
ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()),
|
||||
ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()),
|
||||
ModuleDef::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(it) => it.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
|
||||
},
|
||||
ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()),
|
||||
ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()),
|
||||
ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()),
|
||||
|
|
@ -132,18 +137,22 @@ impl From<ModuleDef> for ModuleDefId {
|
|||
ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()),
|
||||
ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()),
|
||||
ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DefWithBody> for DefWithBodyId {
|
||||
fn from(def: DefWithBody) -> Self {
|
||||
match def {
|
||||
DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
|
||||
impl TryFrom<DefWithBody> for DefWithBodyId {
|
||||
type Error = ();
|
||||
fn try_from(def: DefWithBody) -> Result<Self, ()> {
|
||||
Ok(match def {
|
||||
DefWithBody::Function(it) => match it.id {
|
||||
AnyFunctionId::FunctionId(it) => it.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
|
||||
},
|
||||
DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
|
||||
DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
|
||||
DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,17 +177,11 @@ impl From<AssocItemId> for AssocItem {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<GenericDef> for GenericDefId {
|
||||
fn from(def: GenericDef) -> Self {
|
||||
match def {
|
||||
GenericDef::Function(it) => GenericDefId::FunctionId(it.id),
|
||||
GenericDef::Adt(it) => GenericDefId::AdtId(it.into()),
|
||||
GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
|
||||
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
|
||||
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
|
||||
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
|
||||
GenericDef::Static(it) => GenericDefId::StaticId(it.id),
|
||||
}
|
||||
impl TryFrom<GenericDef> for GenericDefId {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(def: GenericDef) -> Result<Self, Self::Error> {
|
||||
def.id().ok_or(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,13 +241,17 @@ impl From<FieldId> for Field {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AssocItem> for GenericDefId {
|
||||
fn from(item: AssocItem) -> Self {
|
||||
match item {
|
||||
AssocItem::Function(f) => f.id.into(),
|
||||
impl TryFrom<AssocItem> for GenericDefId {
|
||||
type Error = ();
|
||||
fn try_from(item: AssocItem) -> Result<Self, Self::Error> {
|
||||
Ok(match item {
|
||||
AssocItem::Function(f) => match f.id {
|
||||
AnyFunctionId::FunctionId(it) => it.into(),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
|
||||
},
|
||||
AssocItem::Const(c) => c.id.into(),
|
||||
AssocItem::TypeAlias(t) => t.id.into(),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -270,13 +277,14 @@ impl From<hir_def::item_scope::ItemInNs> for ItemInNs {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ItemInNs> for hir_def::item_scope::ItemInNs {
|
||||
fn from(it: ItemInNs) -> Self {
|
||||
match it {
|
||||
ItemInNs::Types(it) => Self::Types(it.into()),
|
||||
ItemInNs::Values(it) => Self::Values(it.into()),
|
||||
impl TryFrom<ItemInNs> for hir_def::item_scope::ItemInNs {
|
||||
type Error = ();
|
||||
fn try_from(it: ItemInNs) -> Result<Self, Self::Error> {
|
||||
Ok(match it {
|
||||
ItemInNs::Types(it) => Self::Types(it.try_into()?),
|
||||
ItemInNs::Values(it) => Self::Values(it.try_into()?),
|
||||
ItemInNs::Macros(it) => Self::Macros(it.into()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -291,3 +299,21 @@ impl From<BuiltinType> for hir_def::builtin_type::BuiltinType {
|
|||
it.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl From<hir_def::ImplId> for crate::Impl {
|
||||
fn from(value: hir_def::ImplId) -> Self {
|
||||
crate::Impl { id: AnyImplId::ImplId(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuiltinDeriveImplId> for crate::Impl {
|
||||
fn from(value: BuiltinDeriveImplId) -> Self {
|
||||
crate::Impl { id: AnyImplId::BuiltinDeriveImplId(value) }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<hir_def::FunctionId> for crate::Function {
|
||||
fn from(value: hir_def::FunctionId) -> Self {
|
||||
crate::Function { id: AnyFunctionId::FunctionId(value) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,18 +7,18 @@ use hir_def::{
|
|||
src::{HasChildSource, HasSource as _},
|
||||
};
|
||||
use hir_expand::{EditionedFileId, HirFileId, InFile};
|
||||
use hir_ty::db::InternedClosure;
|
||||
use syntax::ast;
|
||||
use hir_ty::{db::InternedClosure, next_solver::AnyImplId};
|
||||
use syntax::{AstNode, ast};
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
|
||||
Adt, AnyFunctionId, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
|
||||
InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static,
|
||||
Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase,
|
||||
};
|
||||
|
||||
pub trait HasSource {
|
||||
type Ast;
|
||||
pub trait HasSource: Sized {
|
||||
type Ast: AstNode;
|
||||
/// Fetches the definition's source node.
|
||||
/// Using [`crate::SemanticsImpl::source`] is preferred when working with [`crate::Semantics`],
|
||||
/// as that caches the parsed file in the semantics' cache.
|
||||
|
|
@ -27,6 +27,20 @@ pub trait HasSource {
|
|||
/// But we made this method `Option` to support rlib in the future
|
||||
/// by <https://github.com/rust-lang/rust-analyzer/issues/6913>
|
||||
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
|
||||
|
||||
/// Fetches the source node, along with its full range.
|
||||
///
|
||||
/// The reason for the separate existence of this method is that some things, notably builtin derive impls,
|
||||
/// do not really have a source node, at least not of the correct type. But we still can trace them
|
||||
/// to source code (the derive producing them). So this method will return the range if it is supported,
|
||||
/// and if the node is supported too it will return it as well.
|
||||
fn source_with_range(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
|
||||
let source = self.source(db)?;
|
||||
Some(source.map(|node| (node.syntax().text_range(), Some(node))))
|
||||
}
|
||||
}
|
||||
|
||||
/// NB: Module is !HasSource, because it has two source nodes at the same time:
|
||||
|
|
@ -146,7 +160,30 @@ impl HasSource for Variant {
|
|||
impl HasSource for Function {
|
||||
type Ast = ast::Fn;
|
||||
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
Some(self.id.lookup(db).source(db))
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => Some(id.loc(db).source(db)),
|
||||
// When calling `source()`, we use the trait method source, but when calling `source_with_range()`,
|
||||
// we return `None` as the syntax node source. This is relying on the assumption that if you are calling
|
||||
// `source_with_range()` (e.g. in navigation) you're prepared to deal with no source node, while if
|
||||
// you call `source()` maybe you don't - therefore we fall back to the trait method, to not lose features.
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => method
|
||||
.trait_method(db, impl_)
|
||||
.and_then(|trait_method| Function::from(trait_method).source(db)),
|
||||
}
|
||||
}
|
||||
|
||||
fn source_with_range(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
|
||||
match self.id {
|
||||
AnyFunctionId::FunctionId(id) => Some(
|
||||
id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))),
|
||||
),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
|
||||
Some(impl_.loc(db).source(db).map(|range| (range, None)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
impl HasSource for Const {
|
||||
|
|
@ -190,7 +227,24 @@ impl HasSource for Macro {
|
|||
impl HasSource for Impl {
|
||||
type Ast = ast::Impl;
|
||||
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
Some(self.id.lookup(db).source(db))
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => Some(id.loc(db).source(db)),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn source_with_range(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
|
||||
match self.id {
|
||||
AnyImplId::ImplId(id) => Some(
|
||||
id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))),
|
||||
),
|
||||
AnyImplId::BuiltinDeriveImplId(impl_) => {
|
||||
Some(impl_.loc(db).source(db).map(|range| (range, None)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +278,7 @@ impl HasSource for Param<'_> {
|
|||
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
match self.func {
|
||||
Callee::Def(CallableDefId::FunctionId(func)) => {
|
||||
let InFile { file_id, value } = Function { id: func }.source(db)?;
|
||||
let InFile { file_id, value } = Function::from(func).source(db)?;
|
||||
let params = value.param_list()?;
|
||||
if let Some(self_param) = params.self_param() {
|
||||
if let Some(idx) = self.idx.checked_sub(1) {
|
||||
|
|
@ -261,7 +315,7 @@ impl HasSource for SelfParam {
|
|||
type Ast = ast::SelfParam;
|
||||
|
||||
fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
|
||||
let InFile { file_id, value } = Function::from(self.func).source(db)?;
|
||||
let InFile { file_id, value } = self.func.source(db)?;
|
||||
value
|
||||
.param_list()
|
||||
.and_then(|params| params.self_param())
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -13,7 +13,7 @@ use std::{
|
|||
use base_db::FxIndexSet;
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
|
||||
DefWithBodyId, MacroId, StructId, TraitId, VariantId,
|
||||
attrs::parse_extra_crate_attrs,
|
||||
expr_store::{Body, ExprOrPatSource, HygieneId, path::Path},
|
||||
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
|
||||
|
|
@ -34,7 +34,7 @@ use hir_ty::{
|
|||
diagnostics::{unsafe_operations, unsafe_operations_for_body},
|
||||
infer_query_with_inspect,
|
||||
next_solver::{
|
||||
DbInterner, Span,
|
||||
AnyImplId, DbInterner, Span,
|
||||
format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
|
||||
},
|
||||
};
|
||||
|
|
@ -53,11 +53,11 @@ use syntax::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam,
|
||||
Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource, Impl,
|
||||
InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
|
||||
Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TupleField, Type,
|
||||
TypeAlias, TypeParam, Union, Variant, VariantDef,
|
||||
Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
|
||||
ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution,
|
||||
HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
|
||||
Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait,
|
||||
TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
|
||||
db::HirDatabase,
|
||||
semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
|
||||
source_analyzer::{SourceAnalyzer, resolve_hir_path},
|
||||
|
|
@ -106,7 +106,10 @@ impl PathResolution {
|
|||
| PathResolution::DeriveHelper(_)
|
||||
| PathResolution::ConstParam(_) => None,
|
||||
PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
|
||||
PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
|
||||
PathResolution::SelfType(impl_def) => match impl_def.id {
|
||||
AnyImplId::ImplId(id) => Some(TypeNs::SelfType(id)),
|
||||
AnyImplId::BuiltinDeriveImplId(_) => None,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -345,23 +348,23 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
|
|||
}
|
||||
|
||||
pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
|
||||
self.imp.resolve_await_to_poll(await_expr).map(Function::from)
|
||||
self.imp.resolve_await_to_poll(await_expr)
|
||||
}
|
||||
|
||||
pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
|
||||
self.imp.resolve_prefix_expr(prefix_expr).map(Function::from)
|
||||
self.imp.resolve_prefix_expr(prefix_expr)
|
||||
}
|
||||
|
||||
pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
|
||||
self.imp.resolve_index_expr(index_expr).map(Function::from)
|
||||
self.imp.resolve_index_expr(index_expr)
|
||||
}
|
||||
|
||||
pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
|
||||
self.imp.resolve_bin_expr(bin_expr).map(Function::from)
|
||||
self.imp.resolve_bin_expr(bin_expr)
|
||||
}
|
||||
|
||||
pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
|
||||
self.imp.resolve_try_expr(try_expr).map(Function::from)
|
||||
self.imp.resolve_try_expr(try_expr)
|
||||
}
|
||||
|
||||
pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
|
||||
|
|
@ -1749,6 +1752,7 @@ impl<'db> SemanticsImpl<'db> {
|
|||
func: Function,
|
||||
subst: impl IntoIterator<Item = Type<'db>>,
|
||||
) -> Option<Function> {
|
||||
let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) };
|
||||
let interner = DbInterner::new_no_crate(self.db);
|
||||
let mut subst = subst.into_iter();
|
||||
let substs =
|
||||
|
|
@ -1757,7 +1761,12 @@ impl<'db> SemanticsImpl<'db> {
|
|||
subst.next().expect("too few subst").ty.into()
|
||||
});
|
||||
assert!(subst.next().is_none(), "too many subst");
|
||||
Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into())
|
||||
Some(match self.db.lookup_impl_method(env.env, func, substs).0 {
|
||||
Either::Left(it) => it.into(),
|
||||
Either::Right((impl_, method)) => {
|
||||
Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
|
||||
|
|
@ -1768,23 +1777,23 @@ impl<'db> SemanticsImpl<'db> {
|
|||
self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
|
||||
}
|
||||
|
||||
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
|
||||
fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
|
||||
self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
|
||||
}
|
||||
|
||||
fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
|
||||
fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
|
||||
self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
|
||||
}
|
||||
|
||||
fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
|
||||
fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
|
||||
self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
|
||||
}
|
||||
|
||||
fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
|
||||
fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
|
||||
self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
|
||||
}
|
||||
|
||||
fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
|
||||
fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
|
||||
self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
|
||||
}
|
||||
|
||||
|
|
@ -1861,7 +1870,9 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
|
||||
let def = DefWithBodyId::from(def);
|
||||
let Ok(def) = DefWithBodyId::try_from(def) else {
|
||||
return FxHashSet::default();
|
||||
};
|
||||
let (body, source_map) = self.db.body_with_source_map(def);
|
||||
let infer = InferenceResult::for_body(self.db, def);
|
||||
let mut res = FxHashSet::default();
|
||||
|
|
@ -1877,7 +1888,9 @@ impl<'db> SemanticsImpl<'db> {
|
|||
always!(block.unsafe_token().is_some());
|
||||
let block = self.wrap_node_infile(ast::Expr::from(block));
|
||||
let Some(def) = self.body_for(block.syntax()) else { return Vec::new() };
|
||||
let def = def.into();
|
||||
let Ok(def) = def.try_into() else {
|
||||
return Vec::new();
|
||||
};
|
||||
let (body, source_map) = self.db.body_with_source_map(def);
|
||||
let infer = InferenceResult::for_body(self.db, def);
|
||||
let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else {
|
||||
|
|
@ -2023,16 +2036,22 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
/// Search for a definition's source and cache its syntax tree
|
||||
pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
|
||||
where
|
||||
Def::Ast: AstNode,
|
||||
{
|
||||
pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> {
|
||||
// FIXME: source call should go through the parse cache
|
||||
let res = def.source(self.db)?;
|
||||
self.cache(find_root(res.value.syntax()), res.file_id);
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn source_with_range<Def: HasSource>(
|
||||
&self,
|
||||
def: Def,
|
||||
) -> Option<InFile<(TextRange, Option<Def::Ast>)>> {
|
||||
let res = def.source_with_range(self.db)?;
|
||||
self.parse_or_expand(res.file_id);
|
||||
Some(res)
|
||||
}
|
||||
|
||||
pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
|
||||
let container = self.with_ctx(|ctx| ctx.find_container(node))?;
|
||||
|
||||
|
|
@ -2162,9 +2181,10 @@ impl<'db> SemanticsImpl<'db> {
|
|||
|
||||
let def = match &enclosing_item {
|
||||
Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
|
||||
Either::Left(ast::Item::Fn(it)) => {
|
||||
self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId)
|
||||
}
|
||||
Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id {
|
||||
AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)),
|
||||
AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
|
||||
})(),
|
||||
Either::Left(ast::Item::Const(it)) => {
|
||||
self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
|
||||
}
|
||||
|
|
@ -2201,7 +2221,11 @@ impl<'db> SemanticsImpl<'db> {
|
|||
}
|
||||
|
||||
pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
|
||||
let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db);
|
||||
let id = match impl_.id {
|
||||
AnyImplId::ImplId(id) => id,
|
||||
AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()),
|
||||
};
|
||||
let source = hir_def::src::HasSource::ast_ptr(&id.loc(self.db), self.db);
|
||||
let mut file_id = source.file_id;
|
||||
let adt_ast_id = loop {
|
||||
let macro_call = file_id.macro_file()?;
|
||||
|
|
|
|||
|
|
@ -57,9 +57,9 @@ use syntax::{
|
|||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field,
|
||||
Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait,
|
||||
TupleField, Type, TypeAlias, Variant,
|
||||
Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const,
|
||||
DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct,
|
||||
ToolModule, Trait, TupleField, Type, TypeAlias, Variant,
|
||||
db::HirDatabase,
|
||||
semantics::{PathResolution, PathResolutionPerNs},
|
||||
};
|
||||
|
|
@ -431,7 +431,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
|
||||
let (f_in_trait, substs) = self.infer()?.method_resolution(expr_id)?;
|
||||
|
||||
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
|
||||
Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
|
||||
}
|
||||
|
||||
pub(crate) fn resolve_method_call_fallback(
|
||||
|
|
@ -446,8 +446,8 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
let (fn_, subst) =
|
||||
self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs);
|
||||
Some((
|
||||
Either::Left(fn_.into()),
|
||||
Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))),
|
||||
Either::Left(fn_),
|
||||
GenericSubstitution::new_from_fn(fn_, subst, self.trait_environment(db)),
|
||||
))
|
||||
}
|
||||
None => {
|
||||
|
|
@ -519,8 +519,8 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
None => inference_result.method_resolution(expr_id).map(|(f, substs)| {
|
||||
let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs);
|
||||
(
|
||||
Either::Right(f.into()),
|
||||
Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))),
|
||||
Either::Right(f),
|
||||
GenericSubstitution::new_from_fn(f, subst, self.trait_environment(db)),
|
||||
)
|
||||
}),
|
||||
}
|
||||
|
|
@ -569,7 +569,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
await_expr: &ast::AwaitExpr,
|
||||
) -> Option<FunctionId> {
|
||||
) -> Option<Function> {
|
||||
let mut ty = self.ty_of_expr(await_expr.expr()?)?;
|
||||
|
||||
let into_future_trait = self
|
||||
|
|
@ -605,7 +605,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
prefix_expr: &ast::PrefixExpr,
|
||||
) -> Option<FunctionId> {
|
||||
) -> Option<Function> {
|
||||
let (_op_trait, op_fn) = match prefix_expr.op_kind()? {
|
||||
ast::UnaryOp::Deref => {
|
||||
// This can be either `Deref::deref` or `DerefMut::deref_mut`.
|
||||
|
|
@ -650,7 +650,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
index_expr: &ast::IndexExpr,
|
||||
) -> Option<FunctionId> {
|
||||
) -> Option<Function> {
|
||||
let base_ty = self.ty_of_expr(index_expr.base()?)?;
|
||||
let index_ty = self.ty_of_expr(index_expr.index()?)?;
|
||||
|
||||
|
|
@ -679,7 +679,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
binop_expr: &ast::BinExpr,
|
||||
) -> Option<FunctionId> {
|
||||
) -> Option<Function> {
|
||||
let op = binop_expr.op_kind()?;
|
||||
let lhs = self.ty_of_expr(binop_expr.lhs()?)?;
|
||||
let rhs = self.ty_of_expr(binop_expr.rhs()?)?;
|
||||
|
|
@ -699,7 +699,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
try_expr: &ast::TryExpr,
|
||||
) -> Option<FunctionId> {
|
||||
) -> Option<Function> {
|
||||
let ty = self.ty_of_expr(try_expr.expr()?)?;
|
||||
|
||||
let op_fn = self.lang_items(db).TryTraitBranch?;
|
||||
|
|
@ -905,7 +905,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
subs,
|
||||
self.trait_environment(db),
|
||||
);
|
||||
(AssocItemId::from(f_in_trait), subst)
|
||||
(AssocItem::Function(f_in_trait.into()), Some(subst))
|
||||
}
|
||||
Some(func_ty) => {
|
||||
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() {
|
||||
|
|
@ -913,19 +913,19 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
.resolve_impl_method_or_trait_def_with_subst(
|
||||
db, f_in_trait, subs,
|
||||
);
|
||||
let subst = GenericSubstitution::new(
|
||||
fn_.into(),
|
||||
let subst = GenericSubstitution::new_from_fn(
|
||||
fn_,
|
||||
subst,
|
||||
self.trait_environment(db),
|
||||
);
|
||||
(fn_.into(), subst)
|
||||
(AssocItem::Function(fn_), subst)
|
||||
} else {
|
||||
let subst = GenericSubstitution::new(
|
||||
f_in_trait.into(),
|
||||
subs,
|
||||
self.trait_environment(db),
|
||||
);
|
||||
(f_in_trait.into(), subst)
|
||||
(AssocItem::Function(f_in_trait.into()), Some(subst))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -938,11 +938,11 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
subst,
|
||||
self.trait_environment(db),
|
||||
);
|
||||
(konst.into(), subst)
|
||||
(AssocItem::Const(konst.into()), Some(subst))
|
||||
}
|
||||
};
|
||||
|
||||
return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));
|
||||
return Some((PathResolution::Def(assoc.into()), subst));
|
||||
}
|
||||
if let Some(VariantId::EnumVariantId(variant)) =
|
||||
infer.variant_resolution_for_expr_or_pat(expr_id)
|
||||
|
|
@ -1401,7 +1401,7 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
db: &'db dyn HirDatabase,
|
||||
func: FunctionId,
|
||||
substs: GenericArgs<'db>,
|
||||
) -> FunctionId {
|
||||
) -> Function {
|
||||
self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0
|
||||
}
|
||||
|
||||
|
|
@ -1410,13 +1410,19 @@ impl<'db> SourceAnalyzer<'db> {
|
|||
db: &'db dyn HirDatabase,
|
||||
func: FunctionId,
|
||||
substs: GenericArgs<'db>,
|
||||
) -> (FunctionId, GenericArgs<'db>) {
|
||||
) -> (Function, GenericArgs<'db>) {
|
||||
let owner = match self.resolver.body_owner() {
|
||||
Some(it) => it,
|
||||
None => return (func, substs),
|
||||
None => return (func.into(), substs),
|
||||
};
|
||||
let env = self.param_and(db.trait_environment_for_body(owner));
|
||||
db.lookup_impl_method(env, func, substs)
|
||||
let (func, args) = db.lookup_impl_method(env, func, substs);
|
||||
match func {
|
||||
Either::Left(func) => (func.into(), args),
|
||||
Either::Right((impl_, method)) => {
|
||||
(Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }, args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_impl_const_or_trait_def_with_subst(
|
||||
|
|
|
|||
|
|
@ -734,11 +734,11 @@
|
|||
FileSymbol {
|
||||
name: "generic_impl_fn",
|
||||
def: Function(
|
||||
Function {
|
||||
id: FunctionId(
|
||||
FunctionId(
|
||||
FunctionId(
|
||||
6402,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
|
|
@ -769,11 +769,11 @@
|
|||
FileSymbol {
|
||||
name: "impl_fn",
|
||||
def: Function(
|
||||
Function {
|
||||
id: FunctionId(
|
||||
FunctionId(
|
||||
FunctionId(
|
||||
6401,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
|
|
@ -839,11 +839,11 @@
|
|||
FileSymbol {
|
||||
name: "main",
|
||||
def: Function(
|
||||
Function {
|
||||
id: FunctionId(
|
||||
FunctionId(
|
||||
FunctionId(
|
||||
6400,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
|
|
@ -907,11 +907,11 @@
|
|||
FileSymbol {
|
||||
name: "trait_fn",
|
||||
def: Function(
|
||||
Function {
|
||||
id: FunctionId(
|
||||
FunctionId(
|
||||
FunctionId(
|
||||
6403,
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
loc: DeclarationLocation {
|
||||
hir_file_id: FileId(
|
||||
|
|
|
|||
|
|
@ -767,14 +767,30 @@ fn label_of_ty(
|
|||
)
|
||||
});
|
||||
|
||||
let module_def_location = |label_builder: &mut InlayHintLabelBuilder<'_>,
|
||||
def: ModuleDef,
|
||||
name| {
|
||||
let def = def.try_into();
|
||||
if let Ok(def) = def {
|
||||
label_builder.start_location_link(def);
|
||||
}
|
||||
#[expect(
|
||||
clippy::question_mark,
|
||||
reason = "false positive; replacing with `?` leads to 'type annotations needed' error"
|
||||
)]
|
||||
if let Err(err) = label_builder.write_str(name) {
|
||||
return Err(err);
|
||||
}
|
||||
if def.is_ok() {
|
||||
label_builder.end_location_link();
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
|
||||
label_builder.write_str(LABEL_START)?;
|
||||
label_builder.start_location_link(ModuleDef::from(iter_trait).into());
|
||||
label_builder.write_str(LABEL_ITERATOR)?;
|
||||
label_builder.end_location_link();
|
||||
module_def_location(label_builder, ModuleDef::from(iter_trait), LABEL_ITERATOR)?;
|
||||
label_builder.write_str(LABEL_MIDDLE)?;
|
||||
label_builder.start_location_link(ModuleDef::from(item).into());
|
||||
label_builder.write_str(LABEL_ITEM)?;
|
||||
label_builder.end_location_link();
|
||||
module_def_location(label_builder, ModuleDef::from(item), LABEL_ITEM)?;
|
||||
label_builder.write_str(LABEL_MIDDLE2)?;
|
||||
rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?;
|
||||
label_builder.write_str(LABEL_END)?;
|
||||
|
|
|
|||
|
|
@ -34,9 +34,10 @@ pub(super) fn hints(
|
|||
let def = sema.to_def(node)?;
|
||||
let def: DefWithBody = def.into();
|
||||
|
||||
let (hir, source_map) = sema.db.body_with_source_map(def.into());
|
||||
let def = def.try_into().ok()?;
|
||||
let (hir, source_map) = sema.db.body_with_source_map(def);
|
||||
|
||||
let mir = sema.db.mir_body(def.into()).ok()?;
|
||||
let mir = sema.db.mir_body(def).ok()?;
|
||||
|
||||
let local_to_binding = mir.local_to_binding_map();
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ use arrayvec::ArrayVec;
|
|||
use either::Either;
|
||||
use hir::{
|
||||
AssocItem, Crate, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId,
|
||||
InFile, LocalSource, ModuleSource, Semantics, Symbol, db::ExpandDatabase, sym,
|
||||
InFile, LocalSource, ModuleSource, Name, Semantics, Symbol, db::ExpandDatabase, sym,
|
||||
symbols::FileSymbol,
|
||||
};
|
||||
use ide_db::{
|
||||
|
|
@ -204,6 +204,22 @@ impl NavigationTarget {
|
|||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_named_with_range(
|
||||
db: &RootDatabase,
|
||||
ranges: InFile<(TextRange, Option<TextRange>)>,
|
||||
name: Option<Name>,
|
||||
kind: SymbolKind,
|
||||
) -> UpmappingResult<NavigationTarget> {
|
||||
let InFile { file_id, value: (full_range, focus_range) } = ranges;
|
||||
let name = name.map(|name| name.symbol().clone()).unwrap_or_else(|| sym::underscore);
|
||||
|
||||
orig_range_with_focus_r(db, file_id, full_range, focus_range).map(
|
||||
|(FileRange { file_id, range: full_range }, focus_range)| {
|
||||
NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn from_syntax(
|
||||
file_id: FileId,
|
||||
name: Symbol,
|
||||
|
|
@ -414,7 +430,13 @@ impl ToNavFromAst for hir::Trait {
|
|||
|
||||
impl<D> TryToNav for D
|
||||
where
|
||||
D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate,
|
||||
D: HasSource
|
||||
+ ToNavFromAst
|
||||
+ Copy
|
||||
+ HasDocs
|
||||
+ for<'db> HirDisplay<'db>
|
||||
+ HasCrate
|
||||
+ hir::HasName,
|
||||
D::Ast: ast::HasName,
|
||||
{
|
||||
fn try_to_nav(
|
||||
|
|
@ -422,11 +444,19 @@ where
|
|||
sema: &Semantics<'_, RootDatabase>,
|
||||
) -> Option<UpmappingResult<NavigationTarget>> {
|
||||
let db = sema.db;
|
||||
let src = self.source(db)?;
|
||||
let src = self.source_with_range(db)?;
|
||||
Some(
|
||||
NavigationTarget::from_named(
|
||||
NavigationTarget::from_named_with_range(
|
||||
db,
|
||||
src.as_ref().map(|it| it as &dyn ast::HasName),
|
||||
src.map(|(full_range, node)| {
|
||||
(
|
||||
full_range,
|
||||
node.and_then(|node| {
|
||||
Some(ast::HasName::name(&node)?.syntax().text_range())
|
||||
}),
|
||||
)
|
||||
}),
|
||||
self.name(db),
|
||||
D::KIND,
|
||||
)
|
||||
.map(|mut res| {
|
||||
|
|
@ -477,16 +507,16 @@ impl TryToNav for hir::Impl {
|
|||
sema: &Semantics<'_, RootDatabase>,
|
||||
) -> Option<UpmappingResult<NavigationTarget>> {
|
||||
let db = sema.db;
|
||||
let InFile { file_id, value } = self.source(db)?;
|
||||
let derive_path = self.as_builtin_derive_path(db);
|
||||
let InFile { file_id, value: (full_range, source) } = self.source_with_range(db)?;
|
||||
|
||||
let (file_id, focus, syntax) = match &derive_path {
|
||||
Some(attr) => (attr.file_id.into(), None, attr.value.syntax()),
|
||||
None => (file_id, value.self_ty(), value.syntax()),
|
||||
};
|
||||
|
||||
Some(orig_range_with_focus(db, file_id, syntax, focus).map(
|
||||
|(FileRange { file_id, range: full_range }, focus_range)| {
|
||||
Some(
|
||||
orig_range_with_focus_r(
|
||||
db,
|
||||
file_id,
|
||||
full_range,
|
||||
source.and_then(|source| Some(source.self_ty()?.syntax().text_range())),
|
||||
)
|
||||
.map(|(FileRange { file_id, range: full_range }, focus_range)| {
|
||||
NavigationTarget::from_syntax(
|
||||
file_id,
|
||||
sym::kw_impl,
|
||||
|
|
@ -494,8 +524,8 @@ impl TryToNav for hir::Impl {
|
|||
full_range,
|
||||
SymbolKind::Impl,
|
||||
)
|
||||
},
|
||||
))
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2503,7 +2503,7 @@ fn r#fn$0() {}
|
|||
fn main() { r#fn(); }
|
||||
"#,
|
||||
expect![[r#"
|
||||
r#fn Function FileId(0) 0..12 3..7
|
||||
fn Function FileId(0) 0..12 3..7
|
||||
|
||||
FileId(0) 25..29
|
||||
"#]],
|
||||
|
|
|
|||
|
|
@ -1679,11 +1679,11 @@ mod r#mod {
|
|||
[
|
||||
"(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..461, focus_range: 5..10, name: \"mod\", kind: Module, description: \"mod r#mod\" })",
|
||||
"(Test, NavigationTarget { file_id: FileId(0), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"r#for\", container_name: \"mod\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"r#struct\", container_name: \"mod\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"for\", container_name: \"mod\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"struct\", container_name: \"mod\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"r#fn\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"r#fn\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"fn\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"fn\" })",
|
||||
"(DocTest, NavigationTarget { file_id: FileId(0), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })",
|
||||
]
|
||||
"#]],
|
||||
|
|
|
|||
|
|
@ -525,5 +525,10 @@ define_symbols! {
|
|||
arbitrary_self_types,
|
||||
arbitrary_self_types_pointers,
|
||||
supertrait_item_shadowing,
|
||||
hash,
|
||||
partial_cmp,
|
||||
cmp,
|
||||
CoerceUnsized,
|
||||
DispatchFromDyn,
|
||||
define_opaque,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -693,21 +693,24 @@ impl flags::AnalysisStats {
|
|||
let mut sw = self.stop_watch();
|
||||
let mut all = 0;
|
||||
let mut fail = 0;
|
||||
for &body_id in bodies {
|
||||
for &body in bodies {
|
||||
bar.set_message(move || {
|
||||
format!("mir lowering: {}", full_name(db, body_id, body_id.module(db)))
|
||||
format!("mir lowering: {}", full_name(db, body, body.module(db)))
|
||||
});
|
||||
bar.inc(1);
|
||||
if matches!(body_id, DefWithBody::Variant(_)) {
|
||||
if matches!(body, DefWithBody::Variant(_)) {
|
||||
continue;
|
||||
}
|
||||
let module = body_id.module(db);
|
||||
if !self.should_process(db, body_id, module) {
|
||||
let module = body.module(db);
|
||||
if !self.should_process(db, body, module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
all += 1;
|
||||
let Err(e) = db.mir_body(body_id.into()) else {
|
||||
let Ok(body_id) = body.try_into() else {
|
||||
continue;
|
||||
};
|
||||
let Err(e) = db.mir_body(body_id) else {
|
||||
continue;
|
||||
};
|
||||
if verbosity.is_spammy() {
|
||||
|
|
@ -716,7 +719,7 @@ impl flags::AnalysisStats {
|
|||
.into_iter()
|
||||
.rev()
|
||||
.filter_map(|it| it.name(db))
|
||||
.chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
|
||||
.chain(Some(body.name(db).unwrap_or_else(Name::missing)))
|
||||
.map(|it| it.display(db, Edition::LATEST).to_string())
|
||||
.join("::");
|
||||
bar.println(format!("Mir body for {full_name} failed due {e:?}"));
|
||||
|
|
@ -747,11 +750,12 @@ impl flags::AnalysisStats {
|
|||
|
||||
if self.parallel {
|
||||
let mut inference_sw = self.stop_watch();
|
||||
let bodies = bodies.iter().filter_map(|&body| body.try_into().ok()).collect::<Vec<_>>();
|
||||
bodies
|
||||
.par_iter()
|
||||
.map_with(db.clone(), |snap, &body| {
|
||||
snap.body(body.into());
|
||||
InferenceResult::for_body(snap, body.into());
|
||||
snap.body(body);
|
||||
InferenceResult::for_body(snap, body);
|
||||
})
|
||||
.count();
|
||||
eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed());
|
||||
|
|
@ -769,6 +773,7 @@ impl flags::AnalysisStats {
|
|||
let mut num_pat_type_mismatches = 0;
|
||||
let mut panics = 0;
|
||||
for &body_id in bodies {
|
||||
let Ok(body_def_id) = body_id.try_into() else { continue };
|
||||
let name = body_id.name(db).unwrap_or_else(Name::missing);
|
||||
let module = body_id.module(db);
|
||||
let display_target = module.krate(db).to_display_target(db);
|
||||
|
|
@ -807,9 +812,9 @@ impl flags::AnalysisStats {
|
|||
bar.println(msg());
|
||||
}
|
||||
bar.set_message(msg);
|
||||
let body = db.body(body_id.into());
|
||||
let body = db.body(body_def_id);
|
||||
let inference_result =
|
||||
catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_id.into())));
|
||||
catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_def_id)));
|
||||
let inference_result = match inference_result {
|
||||
Ok(inference_result) => inference_result,
|
||||
Err(p) => {
|
||||
|
|
@ -826,7 +831,7 @@ impl flags::AnalysisStats {
|
|||
}
|
||||
};
|
||||
// This query is LRU'd, so actually calling it will skew the timing results.
|
||||
let sm = || db.body_with_source_map(body_id.into()).1;
|
||||
let sm = || db.body_with_source_map(body_def_id).1;
|
||||
|
||||
// region:expressions
|
||||
let (previous_exprs, previous_unknown, previous_partially_unknown) =
|
||||
|
|
@ -1081,6 +1086,7 @@ impl flags::AnalysisStats {
|
|||
let mut sw = self.stop_watch();
|
||||
bar.tick();
|
||||
for &body_id in bodies {
|
||||
let Ok(body_def_id) = body_id.try_into() else { continue };
|
||||
let module = body_id.module(db);
|
||||
if !self.should_process(db, body_id, module) {
|
||||
continue;
|
||||
|
|
@ -1114,7 +1120,7 @@ impl flags::AnalysisStats {
|
|||
bar.println(msg());
|
||||
}
|
||||
bar.set_message(msg);
|
||||
db.body(body_id.into());
|
||||
db.body(body_def_id);
|
||||
bar.inc(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue